• Stars
    star
    770
  • Rank 56,767 (Top 2 %)
  • Language
    Rust
  • License
    MIT License
  • Created over 7 years ago
  • Updated 12 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Key remapper for X11 and Wayland

𝑋𝑟𝑒𝑚𝑎𝑝 ⌨️ cargo

xremap is a key remapper for Linux. Unlike xmodmap, it supports app-specific remapping and Wayland.

Concept

  • Fast - Xremap is written in Rust, which is faster than JIT-less interpreters like Python.

  • Cross-platform - Xremap uses evdev and uinput, which works whether you use X11 or Wayland.

  • Language-agnostic - The config is JSON-compatible. Generate it from any language, e.g. Ruby, Python.

Features

  • Remap any keys, e.g. Ctrl or CapsLock.
  • Remap any key combination to another, even to a key sequence.
  • Remap a key sequence as well. You could do something like Emacs's C-x C-c.
  • Remap a key to two different keys depending on whether it's pressed alone or held.
  • Application-specific remapping. Even if it's not supported by your application, xremap can.
  • Automatically remap newly connected devices by starting xremap with --watch.
  • Support Emacs-like key remapping, including the mark mode.
  • Trigger commands on key press/release events.
  • Use a non-modifier key as a virtual modifier key.

Installation

Download a binary from Releases.

If it doesn't work, please install Rust and run one of the following commands:

cargo install xremap --features x11   # X11
cargo install xremap --features gnome # GNOME Wayland
cargo install xremap --features kde   # KDE-Plasma Wayland
cargo install xremap --features sway  # Sway
cargo install xremap --features hypr  # Hyprland
cargo install xremap                  # Others

You may also need to install libx11-dev to run the xremap binary for X11.

Arch Linux

If you are on Arch Linux and X11, you can install xremap-x11-bin from AUR.

NixOS

If you are using NixOS, xremap can be installed and configured through a flake.

Usage

Write a config file directly, or generate it with xremap-ruby or xremap-python. Then run:

sudo xremap config.yml
If you want to run xremap without sudo, click here.

Running xremap without sudo

To do so, your normal user should be able to use evdev and uinput without sudo. In Ubuntu, this can be configured by running the following commands and rebooting your machine.

sudo gpasswd -a YOUR_USER input
echo 'KERNEL=="uinput", GROUP="input", TAG+="uaccess"' | sudo tee /etc/udev/rules.d/input.rules

Arch Linux

The following can be used on Arch.

lsmod | grep uinput

If this module is not loaded, add to /etc/modules-load.d/uinput.conf:

uinput

Then add udev rule.

echo 'KERNEL=="uinput", GROUP="input", TAG+="uaccess"' | sudo tee /etc/udev/rules.d/99-input.rules

Then reboot the machine.

Debian

Make sure uinput is loaded same as in Arch:

lsmod | grep uinput

If it shows up empty:

echo uinput | sudo tee /etc/modules-load.d/uinput.conf

Add your user to the input group and add the same udev rule as in Ubuntu:

sudo gpasswd -a YOUR_USER input
echo 'KERNEL=="uinput", GROUP="input", TAG+="uaccess"' | sudo tee /etc/udev/rules.d/input.rules

Reboot the machine afterwards or try:

sudo modprobe uinput
sudo udevadm control --reload-rules && sudo udevadm trigger

Other platforms

In other platforms, you might need to create an input group first and run echo 'KERNEL=="event*", NAME="input/%k", MODE="660", GROUP="input"' | sudo tee /etc/udev/rules.d/input.rules as well.

If you do this, in some environments, --watch may fail to recognize new devices due to temporary permission issues. Using sudo might be more useful in such cases.


See the following instructions for your environment to make application-specific remapping work.

X11

If you use sudo to run xremap, you may need to run xhost +SI:localuser:root if you see No protocol specified.

GNOME Wayland

Install xremap's GNOME Shell extension from this link, switching OFF to ON.

If you use sudo to run xremap, also click here.

Update /usr/share/dbus-1/session.conf as follows, and reboot your machine.

   <policy context="default">
+    <allow user="root"/>
     <!-- Allow everything to be sent -->
     <allow send_destination="*" eavesdrop="true"/>
     <!-- Allow everything to be received -->

KDE-Plasma Wayland

Xremap cannot be run as root. Follow the instructions above to run xremap without sudo.

Configuration

Your config.yml should look like this:

modmap:
  - name: Except Chrome
    application:
      not: Google-chrome
    remap:
      CapsLock: Esc
keymap:
  - name: Emacs binding
    application:
      only: Slack
    remap:
      C-b: left
      C-f: right
      C-p: up
      C-n: down

See also: example/config.yml and example/emacs.yml

modmap

modmap is for key-to-key remapping like xmodmap. Note that remapping a key to a modifier key, e.g. CapsLock to Control_L, is supported only in modmap since keymap handles modifier keys differently.

modmap:
  - name: Name # Optional
    exact_match: false # Optional, defaults to false
    remap: # Required
      # Replace a key with another
      KEY_XXX: KEY_YYY # Required
      # Dispatch different keys depending on whether you hold it or press it alone
      KEY_XXX:
        held: KEY_YYY # Required
        alone: KEY_ZZZ # Required
        alone_timeout_millis: 1000 # Optional
      # Hook `keymap` action on key press/release events.
      KEY_XXX:
        press: { launch: ["xdotool", "mousemove", "0", "7200"] } # Required
        release: { launch: ["xdotool", "mousemove", "0", "0"] } # Required
    application: # Optional
      not: [Application, ...]
      # or
      only: [Application, ...]

For KEY_XXX and KEY_YYY, use these names. You can skip KEY_ and the name is case-insensitive. So KEY_CAPSLOCK, CAPSLOCK, and CapsLock are the same thing. Some custom aliases like SHIFT_R, CONTROL_L, etc. are provided.

If you specify a map containing held and alone, you can use the key for two purposes. The key is considered alone if it's pressed and released within alone_timeout_millis (default: 1000) before any other key is pressed. Otherwise it's considered held.

keymap

keymap is for remapping a sequence of key combinations to another sequence of key combinations or other actions.

keymap:
  - name: Name # Optional
    remap: # Required
      # Key press -> Key press
      MOD1-KEY_XXX: MOD2-KEY_YYY
      # Sequence (MOD1-KEY_XXX, MOD2-KEY_YYY) -> Key press (MOD3-KEY_ZZZ)
      MOD1-KEY_XXX:
        remap:
          MOD2-KEY_YYY: MOD3-KEY_ZZZ
        timeout_millis: 200 # Optional. No timeout by default.
      # Key press (MOD1-KEY_XXX) -> Sequence (MOD2-KEY_YYY, MOD3-KEY_ZZZ)
      MOD1-KEY_XXX: [MOD2-KEY_YYY, MOD3-KEY_ZZZ]
      # Execute a command
      MOD1-KEY_XXX:
        launch: ["bash", "-c", "echo hello > /tmp/test"]
      # Let `with_mark` also press a Shift key (useful for Emacs emulation)
      MOD1-KEY_XXX: { set_mark: true } # use { set_mark: false } to disable it
      # Also press Shift only when { set_mark: true } is used before
      MOD1-KEY_XXX: { with_mark: MOD2-KEY_YYY }
      # The next key press will ignore keymap
      MOD1-KEY_XXX: { escape_next_key: true }
      # Set mode to configure Vim-like modal remapping
      MOD1-KEY_XXX: { set_mode: default }
    application: # Optional
      not: [Application, ...]
      # or
      only: [Application, ...]
    mode: default # Optional
default_mode: default # Optional

For KEY_XXX, use these names. You can skip KEY_ and the name is case-insensitive. So KEY_CAPSLOCK, CAPSLOCK, and CapsLock are the same thing.

For the MOD1- part, the following prefixes can be used (also case-insensitive):

  • Shift: SHIFT-
  • Control: C-, CTRL-, CONTROL-
  • Alt: M-, ALT-
  • Windows: SUPER-, WIN-, WINDOWS-

You can use multiple prefixes like C-M-Shift-a. You may also suffix them with _L or _R (case-insensitive) so that remapping is triggered only on a left or right modifier, e.g. Ctrl_L-a.

If you use virtual_modifiers explained below, you can use it in the MOD1- part too.

exact_match defines whether to use exact match when matching key presses. For example, given a mapping of C-n: down and exact_match: false (default), and you pressed C-Shift-n, it will automatically be remapped to Shift-down, without you having to define a mapping for C-Shift-n, which you would have to do if you use exact_match: true.

application

application can be used for both modmap and keymap, which allows you to specify application-specific remapping.

application:
  not: Application
  # or
  not: [Application, ...]
  # or
  only: Application
  # or
  only: [Application, ...]

The application name can be specified as a normal string to exactly match the name, or a regex surrounded by /s like /application/.

To check the application names, you can use the following commands:

X11

$ wmctrl -x -l
0x02800003  0 slack.Slack           ubuntu-jammy Slack | general | ruby-jp
0x05400003  0 code.Code             ubuntu-jammy application.rs - xremap - Visual Studio Code

You may use the entire string of the third column (slack.Slack, code.Code), or just the last segment after . (Slack, Code).

GNOME Wayland

Use the following command or check windows' WMClass by pressing Alt+F2 and running lg command in LookingGlass:

busctl --user call org.gnome.Shell /com/k0kubun/Xremap com.k0kubun.Xremap WMClasses

KDE-Plasma Wayland

Xremap prints the active window to the console. However, it will only start printing, once a mapping has been triggered that uses an application filter. So you have to create a mapping with a filter using a dummy application name and trigger it. Then each time you switch to a new window xremap will print its caption, class, and name in the following style: active window: caption: '<caption>', class: '<class>', name: '<name>' You want to use the class for the filter.

If you use a systemd-daemon to manage xremap, the prints will be visible in the system-logs (Can be opened with journalctl -f)

Sway

swaymsg -t get_tree

Locate app_id in the output.

application-specific key overrides

Sometimes you want to define a generic key map that is available in all applications, but give specific keys in that map their own definition in specific applications. You can do this by putting the generic map at the bottom of the config, after any specific overrides, as follows.

# Emacs-style word-forward and word-back
keymap:
  - name: override to make libreoffice-writer go to end of word but before final space like emacs
    application:
      only: libreoffice-writter
    remap:
      Alt-f: [right, C-right, left]
  - name: generic for all apps
    remap:
      Alt-f: C-right
      Alt-b: C-left

Note how Alt-f and Alt-b work in all apps, but the definition of Alt-f is slightly different in LibreOffice Writer. When that app is active, the first definition overrides the second definition; but for any other app, only the second definition is found. This is because xremap uses the first matching definition that it finds.

virtual_modifiers

You can declare keys that should act like a modifier.

virtual_modifiers:
  - CapsLock
keymap:
  - remap:
      CapsLock-i: Up
      CapsLock-j: Left
      CapsLock-k: Down
      CapsLock-l: Right

keypress_delay_ms

Some applications have trouble understanding synthesized key events, especially on Wayland. keypress_delay_ms can be used to workaround the issue. See #179 for the detail.

License

xremap is available as open source under the terms of the MIT License.

More Repositories

1

pp

Colored pretty printer for Go language
Go
1,679
star
2

hamlit

High Performance Haml Implementation
Ruby
979
star
3

md2key

Convert markdown to keynote
Ruby
977
star
4

Nocturn

Multi-platform Twitter Client built with React, Redux and Electron
JavaScript
714
star
5

gitstar-ranking

GitHub star ranking for users, organizations and repositories
Kotlin
700
star
6

llrb

LLVM-based JIT Compiler for Ruby
C
303
star
7

rack-user_agent

Rack::Request extension for handling User-Agent
Ruby
187
star
8

activerecord-precount

N+1 count query killer for ActiveRecord
Ruby
154
star
9

activerecord-precounter

Yet Another N+1 COUNT Query Killer for ActiveRecord
Ruby
102
star
10

go-ansi

Windows-portable ANSI escape sequence utility for Go language
Go
85
star
11

tetris

TETRIS for your terminal
Go
76
star
12

yarv-mjit

MRI method JIT compiler based on original stack-based YARV instructions (Development Repository of ruby/ruby#1782, already merged)
Ruby
65
star
13

itamae-plugin-recipe-rbenv

Itamae/MItamae plugin to install ruby with rbenv
Ruby
56
star
14

jjvm

JVM implementation written in Java
Java
53
star
15

karabiner-ruby

Lightweight keyremap configuration DSL for Karabiner
Ruby
53
star
16

ruby-jit-challenge

Tutorial to write a Ruby JIT
Ruby
51
star
17

itamae-go

Go implementation of itamae embedding mruby
Go
50
star
18

dotfiles

Bootstrap development environment
Shell
49
star
19

hescape

C library for fast HTML escape using SSE instructions
C
48
star
20

railsbench

Rails 6.1 version of headius/pgrailsbench with database seeds
Ruby
43
star
21

gem-default

Change a non-default gem to a default gem in your local environment
Ruby
37
star
22

rebuild

Development environment bootstrap automation toolkit for OSX
Ruby
31
star
23

vim-open-github

Quickly open your current buffer in GitHub.
Ruby
29
star
24

graphql-query-builder

GraphQL query builder for Java
Java
23
star
25

perf-profile

Profiling C code with Linux perf made easy
Python
19
star
26

wrap-bootstrap-rails

Rails plugin generator for Wrap Bootstrap design templates
Ruby
18
star
27

gosick

Scheme implementation by Go language
Go
18
star
28

hescape-ruby

HTML escape utility for Ruby
Ruby
17
star
29

twitter-auth

Twitter access token generator for CLI
Go
14
star
30

fluent-logger-go

A structured logger for Fluentd in Golang
Go
13
star
31

thunderbolt

Twitter client using Streaming API in Go language
Go
13
star
32

lineprof

Easy-to-use line profiler for Ruby
Ruby
13
star
33

itamae-template

Itamae template generator for roles and cookbooks
Ruby
11
star
34

stackflame

Stackflame provides a simple API to deal with Flamegraph of stackprof
Ruby
9
star
35

itamae-plugin-recipe-docker

Itamae recipe to install docker
Ruby
9
star
36

ghq-cache

Show frequently used repositories first in ghq list
Ruby
9
star
37

github_api-v4-client

A very thin GitHub GraphQL API v4 client
Ruby
7
star
38

go-keybind

Multi-platform terminal key input reader for Go language
Go
7
star
39

clannad

C language compiler
C
7
star
40

action-slack

Notify Slack with incoming webhook for GitHub Actions
TypeScript
6
star
41

tomodachi

Automatic follow back tool with Twitter streaming API
Ruby
5
star
42

twitter

Tiny twitter client library for Go language
Go
5
star
43

dwarftree

A wrapper of objdump --dwarf=info to visualize an object's structure and show code size
Ruby
5
star
44

legacy-dotfiles

Configuration for my client machines
Common Lisp
4
star
45

rack-stackprof

Periodically dump StackProf profile result to `tmp` with easy-to-understand filenames
Ruby
4
star
46

go-termios

Go bindings for termios
Go
4
star
47

misc

Miscellaneous scripts and stuff
JavaScript
4
star
48

github-stream

GitHub Events API v3 client for Go language
Go
3
star
49

ajax_render

Rails plugin to simplify your ajax implementation
Ruby
3
star
50

isucon4-qualifier

My answer for ISUCON4 qualifier
Go
3
star
51

sandal

Fault-aware model checker for message passing systems
Go
3
star
52

perf

Use Linux perf for some region of Ruby code easily
Ruby
3
star
53

rockstar

Colorful GitHub user summarizer
Go
3
star
54

mitamae-plugin-resource-deploy_directory

Fork of mitamae-plugin-resource-deploy_revision to deploy directory instead of git repository
Ruby
3
star
55

itamae-plugin-resource-ghq

Itamae resource plugin to manage repositories with ghq
Ruby
3
star
56

itamae-plugin-resource-cask

Itamae resource plugin for homebrew cask
Ruby
2
star
57

chrome-response-time

Chrome extension to show response time on badge
JavaScript
2
star
58

ruby-color

ruby-color foo.rb
Ruby
2
star
59

mitamae-plugin-resource-cron

MItamae plugin to reproduce the behavior of cron resource in Chef
Ruby
2
star
60

ruboty

My Ruboty configuration
Ruby
2
star
61

sigcdump

Sigdump for C backtrace
Ruby
2
star
62

userstream

Twitter UserStream client with OAuth for Go language
Go
2
star
63

xraise

Fast X Window Raiser
Rust
2
star
64

libx11-ruby

Ruby binding of libx11 mostly for xlib
Ruby
2
star
65

mjit-disable

Unofficial gem to disable MJIT dynamically
Ruby
1
star
66

itamae-sandbox

Ruby
1
star
67

erb-trim

An ERB extension that supports <%-=
Ruby
1
star
68

ruboty-local_yaml

Store Ruboty's memory in local yaml file.
Ruby
1
star
69

PKGBUILDs

PKGBUILDs for Arch Linux
Shell
1
star
70

GomokuAI

Artificial Intelligence for Gomoku
C++
1
star
71

picturesque

Personal web server for image distribution
Go
1
star
72

changelogger

Local file change logger
Go
1
star
73

ruby-prehistory

A repository generated by https://github.com/yhara/ruby-prehistory
C
1
star
74

ruby-cvs

cvs2git from https://github.com/takahashim/rhg-repository
C
1
star
75

isucon2-ruby

My answer for ISUCON2
Ruby
1
star
76

mitamae-plugin-recipe-rvm

MItamae plugin similar to sous-chefs/rvm
Ruby
1
star
77

ruboty-ghibli

A Ruboty plugin
Ruby
1
star
78

mitamae-plugin-recipe-buildpack

MItamae plugin to run heroku-buildpack
Ruby
1
star
79

submarine

Ruby
1
star
80

erb-indent

ERB with de-indentation
Ruby
1
star
81

vagrant-box-arch

Arch Linux Vagrant box for VirtualBox provider
1
star
82

lambda-gyazo-s3

Gyazo server clone implemented with AWS Lambda and API Gateway
Java
1
star
83

each_with_rank

Rank iterator for Enumerable
Ruby
1
star
84

pr_viewer

Pull requests viewer
Go
1
star