I have remapped my caps lock to backspace.
/etc/default/keyboard
XKBLAYOUT="us"
XKBVARIANT="altgr-intl"
BACKSPACE="guess"
XKBOPTIONS="caps:backspace"
This works pretty great, except that it doesn’t work for some specific tools. I used xev
to find out what’s going on.
Backspace pressed
KeyPress event, serial 38, synthetic NO, window 0x2400001,
root 0x159, subw 0x0, time 1028211, (335,635), root:(452,749),
state 0x10, keycode 22 (keysym 0xff08, BackSpace), same_screen YES,
XLookupString gives 1 bytes: (08) "
XmbLookupString gives 1 bytes: (08) "
XFilterEvent returns: False
KeyRelease event, serial 38, synthetic NO, window 0x2400001,
root 0x159, subw 0x0, time 1028272, (335,635), root:(452,749),
state 0x10, keycode 22 (keysym 0xff08, BackSpace), same_screen YES,
XLookupString gives 1 bytes: (08) "
XFilterEvent returns: False
Caps lock pressed
KeyPress event, serial 38, synthetic NO, window 0x2400001,
root 0x159, subw 0x0, time 859789, (391,558), root:(508,672),
state 0x10, keycode 66 (keysym 0xff08, BackSpace), same_screen YES,
XKeysymToKeycode returns keycode: 22
XLookupString gives 1 bytes: (08) "
XmbLookupString gives 1 bytes: (08) "
XFilterEvent returns: False
KeyRelease event, serial 38, synthetic NO, window 0x2400001,
root 0x159, subw 0x0, time 859875, (391,558), root:(508,672),
state 0x10, keycode 66 (keysym 0xff08, BackSpace), same_screen YES,
XKeysymToKeycode returns keycode: 22
XLookupString gives 1 bytes: (08) "
XFilterEvent returns: False
I also tried it in the browser using
addEventListener('keyup', event => {
console.log(event.keyCode, event.key, event.code)
})
This logs the following when I press backspace and caps lock
8 "Backspace" "Backspace"
8 "Backspace" "CapsLock"
So basically my caps lock is remapped to backspace, but it only works if tools and websites use proper checks. I don’s want to file a bug report for every tool or website I ever use that implements this incorrectly.
Is it possible to map caps lock in such a way that it fully emulates a backspace instead of acting like a remapped caps lock?
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
andkeysym
are propagated to applications. Thekeycode
serves as an abstraction layer as it is device agnostic and locale agnostic. The samekeycode
can produce differentkeysym
s, depending on the locale and the state of modifier keys. That is the reason why some applications only look for thekeycode
, especially when dealing with keyboard shortcuts.So our goal is to map the
scancode
of your CapsLock key to thekeycode
of the BackSpace key. Applications will then see the samekeycode
andkeysym
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
mappingGather required information
First you have to determine the
bustype
,vendor
,product
andversion
of your input device (keyboard), as well as thescancode
of the key you want to remap and thekey 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 thescancode
. On my keyboard:... the
scancode
is 70039.Now run the following command, where
eventX
is the one you chose before:The output for my keyboard is
To get the
key code identifier
, either use the output ofevtest
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 afterKEY_
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 example65-keyboard-custom.hwdb
. Use your favorite text editor, but keep in mind that you have to start it asroot
, e.g.Add the following content
...where
evdev:...
line has no preceding spaceKEYBOARD_KEY...
line has exactly one preceding spaceIn my example, the file looks like this:
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:
If you want to apply the changes immediately, inform udev:
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.