First, let's see how a key press is processed (taken from this answer):
/keyboard/ → scancode
→ /input driver/ → keycode
→ /X server XKB/ → keysym
The scancode
is a device specific code that is bound to a specific key and can differ between different vendors/products. keycode
and keysym
are propagated to applications. The keycode
serves as an abstraction layer as it is device agnostic and locale agnostic. The same keycode
can produce different keysym
s, depending on the locale and the state of modifier keys. That is the reason why some applications only look for the keycode
, especially when dealing with keyboard shortcuts.
So our goal is to map the scancode
of your CapsLock key to the keycode
of the BackSpace key. Applications will then see the same keycode
and keysym
regardless whether you press BackSpace or CapsLock.
This mapping is done by udev using the hardwaredatabase file (hwdb.bin) which is compiled from .hwdb files in both /lib/udev/hwdb.d/
and /etc/udev/hwdb.d/
.
How to change scancode
->keycode
mapping
Gather required information
First you have to determine the bustype
, vendor
, product
and version
of your input device (keyboard), as well as the scancode
of the key you want to remap and the key code identifier
you want to map it to.
Run evtest
(you may have to install it first) and identify your keyboard in the list of devices. On keyboards with additional keys like Play/Pause, WWW, etc. these keys are often exposed as a different input device. If you don't get any output when pressing a key, hit Control+C and try a different device. Once you have identified your keyboard, remember the first column (/dev/input/eventX
) and press the key you want to remap. The value after (MSC_SCAN)
is the scancode
. On my keyboard:
$ evtest
Available devices:
/dev/input/event0: Power Button
/dev/input/event1: Power Button
/dev/input/event2: G19 Gaming Keyboard
/dev/input/event3: G19 Gaming Keyboard
...
Select the device event number [0-18]:2
...
Event: time 1522111203.117945, -------------- SYN_REPORT ------------
Event: time 1522111220.778787, type 4 (EV_MSC), code 4 (MSC_SCAN),value 70039
Event: time 1522111220.778787, type 1 (EV_KEY), code 14 (KEY_BACKSPACE), value 1
... the scancode
is 70039.
Now run the following command, where eventX
is the one you chose before:
$ grep "" /sys/class/input/eventX/device/id/*
The output for my keyboard is
/sys/class/input/event2/device/id/bustype:0003
/sys/class/input/event2/device/id/product:c228
/sys/class/input/event2/device/id/vendor:046d
/sys/class/input/event2/device/id/version:0110
To get the key code identifier
, either use the output of evtest
or look at the Keys and buttons section in /usr/include/linux/input-event-codes.h
for a complete list. The identifier is the part after KEY_
converted to lowercase, e.g. KEY_BACKSPACE
becomes backspace.
Configure udev
Take a look at /lib/udev/hwdb.d/
. We will create a text file in /etc/udev/hwdb.d/
with a filename beginning with a number greater than the file corresponding to our device type. For a keyboard, this can be any number greater than 60, while for a pointing stick it should be greater than 70. For example 65-keyboard-custom.hwdb
.
Use your favorite text editor, but keep in mind that you have to start it as root
, e.g.
$ sudo gedit /etc/udev/hwdb.d/65-keyboard-custom.hwdb
Add the following content
evdev:input:b[bustype]v[vendor]p[product]e[version]*
KEYBOARD_KEY_[scancode]=[key code identifier]
...where
- [bustype], [vendor], [product] and [version] have exactly 4 characters (pad with zeros if needed) and letters need to be uppercase
- [scancode] does not need padding but letters have to be lowercase
- the
evdev:...
line has no preceding space
- the
KEYBOARD_KEY...
line has exactly one preceding space
In my example, the file looks like this:
evdev:input:b0003v046DpC228e0110*
KEYBOARD_KEY_70039=backspace # map CapsLock to BackSpace
The first line will be matched to your device. You can specify additional evdev:
lines and you can use more than one wildcard (*
) to match additional devices, but keep in mind that scancodes are device specific. You can also add more than one scancode mapping. Have a look at /lib/udev/hwdb.d/60-keyboard.hwdb
for inspiration. A more detailed and up-to-date version of that file can be found in the online repository.
Apply new configuration
Compile the new configuration to the hardware database:
$ sudo systemd-hwdb update
If you want to apply the changes immediately, inform udev:
$ sudo udevadm trigger
Please note that configuration values can only be added or changed while the system is running. If you remove a configuration (e.g. scancode mapping), you have to reboot for the changes to take effect.
Remember to also revert the remapping you did before (using /etc/default/keyboard
), because that will still be applied to all keyboards.