LEdoian's Blog

Creating own XKB tweaks

Debugging this took me a bit too long, so I want to write about the caveat.

My problem: My laptop does not have PageUp and PageDown keys, and many other keyboards I use have similar deficiencies. And I use various environments and various systems, some of which are shared with other people who don't need/want my tweaks. IOW: I want something generic, but it must be confined to my user – no system-wide daemon, no udev remapping. (I mostly ended up with these solutions when I searched for a way to remap keys on Wayland.)

Requirements: xkbcommon implementation of XKB with utilities. It is quite common these days (duh…), but you could probably just compile this yourself if you don't have it.

The tweaking

The xkbcommon guide tells us that we can inspect the files in [1] /usr/share/X11/xkb for the source files and just write our bits to ~/.config/xkb/symbols/ledoian. In particular, I added this snippet to remap keyboard brightness controls to PageUp/Down:

partial
xkb_symbols "qs" {
    key <I238> {[ Prior ]};
    key <I237> {[ Next ]};
};

The key identifiers are taken e.g. from xkbcli interactive-wayland. However, this is KcCGST [2] description, but layouts are configured using RMLVO, so I need to define an option and tell what it should do. The guide wants me to create ~/.config/xkb/rules/evdev with:

! option = symbols
  ledoian:qs    = +ledoian(qs)
! include %S/evdev

Now I just add ledoian:qs [3] to my keyboard configuration and… it does not work. For this, at all, but if I remap e.g. the L key, that gets applied. The problem? That included file says that the default keyboard model always includes inet(evdev) symbols. Those symbols set the default meaning of the keys, but since that got applied later, it overrides my tweak.

Solution: first include, then add my option.

How to debug: read stuff that xkbcli compile-keymap --verbose tells you (pass your config as --layout, --variant, --options, …). At the top it says what it does:

xkbcommon: DEBUG: Include path added: /home/ledoian/.config/xkb
xkbcommon: DEBUG: Include path added: /usr/share/X11/xkb
xkbcommon: DEBUG: Compiling from RMLVO: rules 'evdev', model 'pc105', layout 'us', variant '(null)', options '(null)'
xkbcommon: DEBUG: Compiling from KcCGST: keycodes 'evdev+aliases(qwerty)', types 'complete', compat 'complete', symbols 'pc+us+inet(evdev)'

My option would appear before the inet(evdev) part.

A note about X11

X11 uses a separate implementation of XKB (the original one, in fact), which does _not_ look into the user directory, just the system ones. However, you can compile the keymap yourself using xkbcli compile-keymap [KEYMAP OPTIONS] > my_layout.xkb and load it into the X server with xkbcomp my_layout.xkb $DISPLAY.


[1]This is not technically accurate, really the paths reference $XDG_something variables. I am lazy and just copied my system, so YMMV (probably won't, though).
[2]There are two levels of describing the keymap: the lowlevel one is called KcCGST (short for keycodes, compat, geometry, symbols, types) and is considered to be an implementation detail; the user-facing one is RMLVO (rules, model, layout, variant, options) and that is what you use in the configs, with setxkbmap &c.
[3]While both this example and the upstream layouts name the symbols and options similarly, I think they don't need to be related – you should be able to put whatever you want in your options to the left of =, the right hand side is the name of the symbol file and if a non-default layout from that file is used, its name is put in the parentheses.