Go to file
2022-01-12 20:37:16 -08:00
.github Cache cargo test on CI 2021-12-31 22:35:31 -08:00
example Implement mark 2021-12-31 22:32:26 -08:00
src support more mouse buttons 2022-01-11 23:46:04 +09:00
.gitignore cargo init 2021-12-11 23:27:29 -08:00
Cargo.lock Version 0.2.2 2022-01-11 11:54:59 -08:00
Cargo.toml Version 0.2.2 2022-01-11 11:54:59 -08:00
CHANGELOG.md Version 0.2.2 2022-01-11 11:54:59 -08:00
LICENSE Update LICENSE 2021-12-22 23:40:43 -08:00
README.md Some wording changes 2022-01-12 20:37:16 -08:00
rustfmt.toml Add troubleshooting messages for X11 2021-12-22 00:12:33 -08:00

𝑋𝑟𝑒𝑚𝑎𝑝 ⌨️ 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.

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 sway  # Sway
cargo install xremap                  # Others

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

Usage

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

sudo xremap config.yml

Dynamic binding

Xremap supports application-specific key remapping.

While Xremap uses evdev and uinput for key remapping, which is a lower layer than X11 and Wayland, Xremap also uses X11 or Wayland compositor-specific protocols to support application config. If you use this feature, make sure you use the appropriate binary for your platform, and follow one of the following options to make it work.

Option 1: Allow root to talk to the compositor

If you use sudo xremap, root user usually cannot interact with the compositor for your normal user. You may need to allow it as follows:

X11

You may need to run xhost +SI:localuser:root if you see No protocol specified.

GNOME Wayland

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 -->
Option 2: Run xremap without sudo

Alternatively, you could run xremap without sudo to solve the problem. 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"' | sudo tee /etc/udev/rules.d/input.rules

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 take this path, in some environments, --watch may fail to recognize new devices due to temporary permission issues. Option 1 might be more useful in such cases.

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
    remap: # Required
      KEY_XXX: KEY_YYY # Required
      # or
      KEY_XXX:
        held: KEY_YYY # Required
        alone: KEY_ZZZ # Required
        alone_timeout_millis: 1000 # Optional
    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
      # 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 }
    application: # Optional
      not: [Application, ...]
      # or
      only: [Application, ...]

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.

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, ...]

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

X11

$ wmctrl -x -l
0x0280000a  0 gnome-terminal-server.Gnome-terminal  ubuntu-focal Terminal
0x02600001  0 nocturn.Nocturn       ubuntu-focal Nocturn

Use the name after . in the third column (WM_CLASS), i.e. Gnome-terminal or Nocturn in the above output.

GNOME Wayland

busctl --user call org.gnome.Shell /org/gnome/Shell org.gnome.Shell Eval s 'global.get_window_actors().map(a => a.get_meta_window().get_wm_class());'

Sway

swaymsg -t get_tree

Locate app_id in the output.

License

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