Erroneous group assignment leads to incorrect Caps Lock behavior with certain xkeyboard-configs
xkeyboard-config provides a standardized tool to remap the Caps Lock key to another Backspace. However, due to a glitch in either xkbcomp or somewhere deeper inside xkb (depending on how you look at it), X11-based applications cannot use this remapping correctly. Instead of the Caps Lock key repeating backspace entries when held down, the key only inputs once, so that one must press the key five times to delete five characters.
STEPS TO REPRODUCE
- Be using an X11-based desktop environment, or, in Wayland-based desktop environments, use an XWayland or Electron-based application. As examples, I could reproduce in KDE Plasma 6 with an X11 session, and KDE Plasma 6 and GNOME 46 with the Signal application, which is Electron. (Note that native Wayland applications are NOT affected.)
- Use the "gnome-tweaks" tool, KDE Plasmas "Keyboard" settings menu, or
setxkbmap
to enable the "Make Caps Lock an Additional Backspace" option. (setxkbmap -option caps:backspace
) - Attempt to press the Caps Lock key to delete characters.
- Observe how only one character is deleted instead of repeating multiple times.
PREVIOUS SOLUTIONS
This bug has been known about for at least 13 years now. 12 years ago, a bug was opened in xkeyboard-config that described the issue.
Previously, running the command xmodmap -e "clear Lock"
temporarily paused the issue, until the Caps Lock key started "sticking" again. However, with Wayland-based desktop environments, this solution no longer works.
This drove me so far up the wall over the last few years that I spent the day trying to hunt down the root cause of the issue.
WHAT IS GOING ON?
The graphical settings menus I suggested earlier call into setxkbmap
with the option I described above. setxkbmap
submits this option verbatim to the Xorg server, which will look up the option in the xkeyboard-config settings. Xorg finds that it should transform this option into +caps(backspace)
, which means:
-
- overrides previous descriptions
- The "caps" key should be mapped to
- Backspace. (source documentation here)
Xorg then makes other decisions, and passes the final description on to xkbcomp
. This is the input file and means of execution I saw, derived from strace:
/usr/bin/xkbcomp -w 1 "-R/usr/share/X11/xkb" -xkm "-" -em1 "The XKEYBOARD keymap compiler (xkbcomp) reports:" -emp "> " -eml "Errors from xkbcomp are not fatal to the X server" /tmp/server-0.xkm
xkb_keymap "default" {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compatibility { include "complete" };
xkb_symbols { include "pc+us+inet(evdev)+capslock(backspace)" };
xkb_geometry { include "pc(pc104)" };
};
xkbcomp
produces this xkb file as output (Note that the original provides an xkm, this is the decompiled version):
xkb_keymap {
.......
xkb_symbols "pc+us+inet(evdev)+capslock(backspace)" {
.......
key <BKSP> { [ BackSpace, BackSpace ] };
.......
key <CAPS> {
type= "ONE_LEVEL",
symbols[Group1]= [ BackSpace ]
};
The produced description for CAPS differs from the BKSP description. Whether or not this is technically "wrong" I leave to someone more experienced than me (though does it really make sense to assign a "Group" to this binding implicitly, especially if I made multiple Groups?), but it definitely breaks the desired Backspace behavior. Removing the description that binds the Backspace binding to Group1, like so:
key <CAPS> {
type= "ONE_LEVEL",
[ BackSpace ]
};
Then uploading the patched .xkb file via xkbcomp fixed.xkb $DISPLAY
restores the desired behavior.
NOW WHAT?
I'm not really sure what to do to fix this issue. Compilers aren't my forte, and I've only spelunked into the depths of Xorg for this one day, not long enough to see the whole picture. I'm opening this issue in the hopes that someone who understands this better than I do sees a clear solution to this problem.