xremap 0.15.7

Dynamic key remap for X and Wayland
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
# <img src='.github/xremap.png' style='height: 32px; margin-top: 8px; margin-bottom: -4px;' alt='Xremap'> :keyboard:

![crates.io](https://img.shields.io/crates/v/xremap) [![GitHub Actions](https://github.com/k0kubun/xremap/actions/workflows/build.yml/badge.svg)](https://github.com/k0kubun/xremap/actions/workflows/build.yml)

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

## Table of contents

- [Concept]#Concept
- [Features]#Features
- [Installation]#Installation
- [Usage]#Usage
- [Configuration]#Configuration
- [Commandline arguments]#Commandline-arguments
- [Documentation]doc/README.md
- [Troubleshooting]doc/troubleshooting.md
- [Maintainers]#Maintainers
- [License]#License

## 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]https://github.com/xremap/xremap-ruby, [Python]https://github.com/xremap/xremap-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.
- Device-specific remapping.
- Automatically remap newly connected devices by starting xremap with `--watch`.
- Support [Emacs-like key remapping]example/emacs.yml, 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](https://github.com/k0kubun/xremap/releases).

If it doesn't work, please [install Rust](https://doc.rust-lang.org/cargo/getting-started/installation.html)
and run one of the following commands:

```bash
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 wlroots  # Sway, Wayfire, etc.
cargo install xremap --features hypr     # Hyprland
cargo install xremap --features niri     # Niri
cargo install xremap --features cosmic   # COSMIC Wayland
cargo install xremap --features pantheon # Pantheon Wayland (aka Secure)
cargo install xremap --features socket   # Variant for system service
cargo install xremap                     # Others
```

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

You may find a list of supported compositors for wlroots [here](https://wayland.app/protocols/wlr-foreign-toplevel-management-unstable-v1#compositor-support).

#### Arch Linux

If you are on Arch Linux and X11, you can install [xremap-x11-bin](https://aur.archlinux.org/packages/xremap-x11-bin/) from AUR.

#### NixOS

If you are using NixOS, xremap can be installed and configured through a [flake](https://github.com/xremap/nix-flake/).

#### Fedora Linux

If you are using Fedora, xremap can be installed via this [Fedora Copr](https://copr.fedorainfracloud.org/coprs/blakegardner/xremap/) repository.

#### Gentoo Linux

If you are using Gentoo Linux, xremap can be installed via [::guru overlay](https://codeberg.org/gentoo/guru/src/branch/master/gui-apps/xremap).

## Usage

If something isn't working take a look at the [troubleshooting section](doc/troubleshooting.md)

#### Run with sudo

First perform these installation instructions: [Running xremap with sudo](doc/running_with_sudo.md)

```
sudo xremap config.yml
```

#### Run without sudo

First perform these installation instructions: [Running xremap without sudo](doc/running_without_sudo.md)

```
xremap config.yml
```

## Configuration

Your `config.yml` should look like this:

```yml
modmap:
  - remap:
      CapsLock: Esc
keymap:
  - remap:
      Ctrl-P: Up
      Ctrl-N: Down
```

A configuration file has 3 parts: `modmap`, `keymap` and [Configuration options](doc/reference_config_options.md).
`modmap` and `keymap` are described below.

There are examples of [a more realistic config](example/config.yml) and [an emacs inspired config](example/emacs.yml).

#### Key names

All possible keys are [listed here](https://github.com/emberian/evdev/blob/1d020f11b283b0648427a2844b6b980f1a268221/src/scancodes.rs#L26-L572).
You can skip `KEY_` and the names are case-insensitive. So `KEY_CAPSLOCK`, `CAPSLOCK`, and `CapsLock` are the same thing.

The keys are described in more detail in [Key names](doc/reference_key_names.md). Some custom aliases like `Shift_R` and `Control_L` also exists.

In case you don't know the name of a key, you can find out by enabling debug output:

```bash
RUST_LOG=debug xremap config.yml
```

Then press the key you want to know the name of. Remember `sudo` if that's needed.

### Examples

In the examples, note whether they use `modmap` or `keymap`.

#### Exchange `Capslock` and `Esc`

```yml
modmap:
  - remap:
      Capslock: Esc
      Esc: Capslock
```

The remapping will also be used in `keymap`, e.g. definitions with
`Esc` in `keymap` will match the physical `Capslock` key. This is because
the output of `modmap` goes through `keymap`.

#### Disable a key

```yml
modmap:
  - remap:
      F9: []
```

The meaning of the config is: `F9` remaps to an empty list of keys.

#### Remap a key combo to another key combo

```yml
keymap:
  - remap:
      Ctrl-P: Up
      Ctrl-N: Down
```

This configuration allows extra modfiers to be pressed. This means if `Ctrl`, `Shift` and `P` are pressed,
it will remap to `Shift-Up`, allowing to select text up and down.

#### Remap an exact key combo

To make the remapping `Ctrl-P: Up` only match with the exact modifiers pressed:

```yml
keymap:
  - exact_match: true
    remap:
      Ctrl-P: Up
      Ctrl-N: Down
```

This means if `Ctrl`, `Shift` and `P` are pressed, it won't match. The keys are
passed through as is, and the combo `Ctrl-Shift-P` does the same thing it does without xremap running.

#### Different remap for left and right modifiers

```yml
keymap:
  - remap:
      Ctrl_R-C: End
      Ctrl_R-X: Home
```

Pressing right `Ctrl` and `C` remaps to `End`. This leaves the normal remapping of `Ctrl-C` using left `Ctrl` to copy text.

### 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.

```yml
default_mode: default # Optional
modmap:
  - name: Name # Optional
    remap:
      # Replace a key with multiple keys (pressed and released simultaneously)
      KEY_XXX2: [KEY_YYY, KEY_ZZZ]
      # Dispatch different keys depending on whether you hold it or press it alone
      KEY_XXX4:
        held: KEY_YYY # Required, also accepts arrays
        alone: KEY_ZZZ # Required, also accepts arrays
        hold_threshold_millis: 100 # Optional, defaults to 0
        alone_timeout_millis: 1000 # Optional, defaults to 1000
      # Dispatch keymap-action when key is pressed or releaseed.
      KEY_XXX5:
        skip_key_event: true # Optional, skip original key event, defaults to false
        press: [{ press: KEY_YYY }, { launch: ["xdotool", "mousemove", "0", "7200"] }] # Optional, default to no action
        repeat: { repeat: KEY_YYY } # Optional, default to no action
        release: [{ release: KEY_YYY }, { set_mode: my_mode }] # Optional, defaults to no action
    application: # Optional
      not: [Application, ...]
      # or
      only: [Application, ...]
    window: # Optional
      not: [/regex of window title/, ...]
      # or
      only: [/regex of window title/, ...]
    device: # Optional
      not: [Device, ...]
      # or
      only: [Device, ...]
    mode: default # Optional
    # or
    mode: [ default, my_mode ]
```

### keymap

`keymap` is for remapping a sequence of key combinations to another sequence of key combinations or other actions.
Key actions in `keymap` will generally press and release keys right away
when the last key in the trigger combination is pressed.

```yml
default_mode: default # Optional
keymap:
  - name: Name # Optional
    exact_match: false # Optional, defaults to false
    remap:
      # Sequence (MOD1-KEY_XXX2, MOD2-KEY_YYY) -> Key press (MOD3-KEY_ZZZ)
      MOD1-KEY_XXX2:
        remap:
          MOD2-KEY_YYY: MOD3-KEY_ZZZ
        timeout_millis: 200 # Optional. No timeout by default.
        timeout_key: KEY_A # Optional. Defaults to nothing. Can also be an array.
      # Key press (MOD1-KEY_XXX3) -> Sequence (MOD2-KEY_YYY, MOD3-KEY_ZZZ)
      MOD1-KEY_XXX3: [MOD2-KEY_YYY, MOD3-KEY_ZZZ]
      # Execute a command
      MOD1-KEY_XXX4:
        launch: ["bash", "-c", "echo hello > /tmp/test"]
      # Let `with_mark` also press a Shift key (useful for Emacs emulation)
      MOD1-KEY_XXX5: { set_mark: true } # use { set_mark: false } to disable it
      # Add Shift to output when `set_mark` has been set to `true`.
      MOD1-KEY_XXX6: { with_mark: MOD2-KEY_YYY }
      # Ignore the next key press when searching for remappings in keymap (modmap is unaffected)
      MOD1-KEY_XXX7: { escape_next_key: true }
      # Set mode to enable/disable remappings.
      MOD1-KEY_XXX8: { set_mode: default }
      # Illustrate a nested mapping that times out;
      # also useful for timing out double-key sequences if the second key is never pressed.
      space:  # Use timeout to fix a bouncy spacebar
        remap:
          space: null          # make space output nothing; null is equivalent to []
          timeout_key: space   # output space after timeout or a non-mapped key (only space is mapped above)
          timeout_millis: 150  # timeout duration in ms
    application: # Optional
      not: [Application, ...]
      # or
      only: [Application, ...]
    window: # Optional
      not: [/regex of window title/, ...]
      # or
      only: [/regex of window title/, ...]
    device: # Optional
      not: [Device, ...]
      # or
      only: [Device, ...]
    mode: default # Optional
    # or
    mode: [ default, my_mode ]
```

What to use for modifiers, the `MOD-` part, is described in [Key names](doc/reference_key_names.md).

### exact_match

`exact_match` controls how modifiers are matched.
A remapping, where modifiers match exactly will always be used. But when such a remapping
doesn't exist, the default is to try an inexact match, this can be disabled with
`exact_match=true`.

Example of inexact match: Given a mapping of `Ctrl-n: down`, and
you pressed <kbd>Ctrl-Shift-n</kbd>, it will automatically be remapped to
<kbd>Shift-down</kbd>. With exact matching, you would have to define a mapping for
<kbd>Ctrl-Shift-n</kbd>.

### application

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

```yml
keymap:
  - application:
      not: firefox
      #not: [firefox, ...]
      #only: firefox
      #only: [firefox, ...]
    remap:
      capslock: KEY_A
```

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

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

```
xremap --list-windows
```

It was added in `v0.15.5`. [See methods prior to that](https://github.com/xremap/xremap/tree/v0.15.4#application).
It doesn't work on GNOME Wayland or KDE Wayland, though. But there it's possible to do:

#### GNOME Wayland

Use the following command or check windows' WMClass by pressing Alt+F2 and running `lg` command in [LookingGlass](https://wiki.gnome.org/Projects/GnomeShell/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 and class in the following style:
`active window: caption: '<caption>', class: '<class>'`
The `class` property should be used for application matching, while the `caption` property should be used for window matching.

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

#### 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.

```yml
# 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.

### device

Much like [`application`](#application), you may specify `{keymap,modmap}.device.{not,only}` in your configuration for device-specific remapping. Consistent with the global `--device` flag, device-matching strings may be any of:

- The full path of the device (e.g. /dev/input/event0)
- The filename of the device (e.g. event0)
- The device name
- A substring of the device name
- The vendor and/or product id (e.g. ids:0x3f0:0x24)

To determine the names and paths of your devices, examine `xremap`'s log output at startup. To get
further info run: `xremap --list-devices` or even `xremap --device-details`.

```yml
keymap:
  - device:
      not: "/dev/input/event0"
      # not: "/dev/input/by-id/Cool_Device" # Symlink to device. Since v0.14.8
      # not: [event0, event1]
      # only: 'Some Cool Device Name'
      # only: ['Cool Device', 'Another Device']
      # only: [ids:0x3f0:0x24]
    remap:
      W: UP
```

Unlike for `application`, regexs are not supported for `device`.

If both `not` and `only` is specified, then `only` is used for matching, and `not` has no effect.

Vendor and product ids must be given in hexadecimal, with or without '0x' prefix. It's possible to only
match on vendor id with: `ids:0x3f0:0`, and only on product id with `ids:0:0x24`.

### mode

You can assign mode(s) to keymap and/or remap which effectively turns them on or off
when you set the mode.

```yml
modmap:
  - name: Up
    remap:
      W: UP
    mode: [Up, Up_And_Down] # Mode is optional

  - name: Down
    remap:
      S: DOWN
    mode: [Down, Up_And_Down]

  - name: Right_And_Left
    remap:
      D: RIGHT
      A: LEFT
    mode: Right_And_Left # Mode can be a string or vector of strings

  - name: Turn Off
    remap:
      L:
        press: { set_mode: Off } # Modmap can set mode via press and release
        release:
    # If mode is absent the keymap or modmap is always on

keymap:
  - name: SetMode
    remap:
      CTRL-U: { set_mode: Up }
      CTRL-I: { set_mode: Down }
      CTRL-O: { set_mode: Up_And_Down }
      CTRL-P: { set_mode: Right_And_Left }
    mode: [Up, Down, Right_And_Left, Up_And_Down, Off] # You can assign modes to keymap too!

default_mode: Up_And_Down # Optional, if absent default mode is "default"
```

## Commandline arguments

Usage for xremap is shown by running the following command:

```
xremap --help
```

The result is shown here:

```
Usage: xremap [OPTIONS] [CONFIGS]...

Arguments:
  [CONFIGS]...
          Config file(s)

          When more than one file is given, then will modmap, keymap and virtual_modifiers
          from the subsequent files be merged into the first configuration file.

Options:
      --device <DEVICE>
          Limit input devices to the given names or paths. Default is all keyboards

      --ignore <IGNORE>
          Ignore input devices with the given names or paths

      --mouse
          Listen to mouse devices. Default is false.
          Trackpads, tablets and other absolute devices are not supported.

      --watch[=<WATCH>...]
          Watch for new devices or changing configuration files.
          Default is not watching for either.
          Examples
          - xremap --watch config.yml               # watch devices
          - xremap --watch=config config.yml        # watch configuration files
          - xremap --watch=config,device config.yml # watch both

          Possible values:
          - device: add new devices automatically
          - config: reload the config automatically

      --output-device-name <OUTPUT_DEVICE_NAME>
          Choose the name of the created output device. Default is 'xremap' or 'xremap pid=xx'

      --vendor <VENDOR>
          Choose the vendor value of the created output device.
          Must be given in hexadecimal with or without a prefix '0x'.
          Default is: 0x1234

      --product <PRODUCT>
          Choose the product value of the created output device.
          Must be given in hexadecimal with or without a prefix '0x'.
          Default is: 0x5678

      --list-devices
          List info about devices

      --device-details
          Show device details

      --list-windows
          List open windows. Use this to get app_class and title.
          Since v0.15.5. Not supported for GNOME Wayland or KDE Wayland.

      --no-window-logging
          Suppress logging of window title and application changes.
          Default is false. Since v0.14.10.

      --allow-launch <ALLOW_LAUNCH>
          Allow remappings to execute programs. Default is ambiguous. Since v0.15.1

          [possible values: true, false]

      --bridge
          Open a bridge from the desktop environment to the xremap system service.
          Since v0.15.1

      --completions <SHELL>
          Generate shell completions

          You can use them by storing in your shells completion file or by running
          - in bash: eval "$(xremap --completions bash)"
          - in fish: xremap --completions fish | source

          [possible values: bash, elvish, fish, powershell, zsh]

  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version
```

### Device/ignore

The arguments to `--device` and `--ignore` are described [here](#device). When using
`--device`, only the devices you specify will be used. To select more than one device separate them
by `,` or use `--device` for each:

```sh
xremap --device "first device,second device" config.yml
```

or:

```sh
xremap --device "first device" --device "second device" config.yml
```

## Maintainers

- @k0kubun
- @N4tus (KDE client)
- @jixiuf (wlroots client)
- @saurabhsharan (Niri client)
- @hpccc53 (COSMIC, Pantheon client)

## Releasing

First, bump the xremap version at Cargo.toml and Cargo.lock, and Update CHANGELOG.md. Then:

```
git add .
git commit -m "Version 0.X.Y"
git push origin master
git tag v0.X.Y
git push origin --tags
```

## License

`xremap` is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).