Krei.se
XKB Input Flow ❡
You can use xkb with just 5 concepts thus reducing the complexity from ~20 to 5:
scancodes (evdev) -> keycodes
keycodes --(keytype)--> keysymbol (actual character).
modifiers actions -> keytypes
Useful but not needed: Keycode-aliases, indicators
Scrapped: All .lst, .xml, Rules, Models, Layouts, Variants, Options, virtual modifiers, explicit, implicit, indirect.
It's possible to write a full X11 compatible map with 8 modifiers, 4 groups, 8 levels getting (108) 4 8 = 3456 characters. Then you only send this map and actually know whats going on - never needing strange overrides, etc. - which feels great.
It took me 4 days, you can likely do it in 1-2.
Just start ❡
apt install libxkbcommon-tools for xkbcli
wayland only, although X11 compatible map is done here and doable (i have 108 keys, up to: 4 groups, 8 levels => 3456 keysymbols!)
Read this, do not read blogs: https://xkbcommon.org/doc/current/keymap-text-format-v1-v2.html
0 Hardware stage (output USB HID) ❡
A key is pressed on a keyboard.
The keyboard translates this key press to a RAW keycode and sends it to the operating system.
QMK firmware does this. See: https://github.com/qmk/qmk_firmware/blob/master/quantum/keycodes.h
1 Kernel-stage (input USB HID - output Kernel keycode, Kernel key) ❡
The operating system uses its input system to read the RAW keycode.
The operating system uses its EVent DEVice (evdev) framework to translate the keycode into a key of event type EV_KEY.
Debug as root: evtest - sometimes keyboards expose multiple events like:
/dev/input/event1: BFO-9000 BFO-9000:
type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004<br>type 1 (EV_KEY), code 30 (KEY_A), value 1
/dev/input/event4: BFO-9000 BFO-9000 Consumer Control:
type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e9<br>type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 1
Notice the 70000 / c0000 - "USB HID Usage Page" 7 - keyboard (normal keys), c - consumer device (multimedia keys)
value 0 - released key. value 1 - pressed key. value 2 - key repeat
HID Usage Pages:
https://github.com/torvalds/linux/blob/075b74841bd0065a3bda3440873c747938e69b68/include/linux/hid.h
#define HID_UP_KEYBOARD 0x00070000<br>#define HID_UP_CONSUMER 0x000c0000<br>Mapping of USB HID Input to kernel keycode is done via: https://github.com/torvalds/linux/blob/master/drivers/hid/hid-input.c
# line 27<br>static const unsigned char hid_keyboard[256] = {<br>0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, # 0x0004 USB == KEY_A 30<br>50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,<br>4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, # 0x0029 USB == KEY_ESC 1<br>27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,<br>65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,<br>105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,<br>72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,<br>191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,<br>115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,<br>122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,<br>unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,<br>unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,<br>unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,<br>unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,<br>29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,<br>150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk<br>};
# line 772<br>case HID_UP_KEYBOARD:<br>set_bit(EV_REP, input->evbit);
if ((usage->hid & HID_USAGE) hid & HID_USAGE]) goto ignore;<br>map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);<br>} else<br>map_key(KEY_UNKNOWN);
break;
# line 1116
case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */<br>switch (usage->hid & HID_USAGE) {<br>case 0x000: goto ignore;<br>case 0x030: map_key_clear(KEY_POWER); break;<br>case 0x031: map_key_clear(KEY_RESTART); break;
...
case 0x22e: map_key_clear(KEY_ZOOMOUT); break;<br>case 0x22f: map_key_clear(KEY_ZOOMRESET); break;<br>case 0x232: map_key_clear(KEY_FULL_SCREEN); break;
So you get: The USB Page + hidinput code mapped to a kernel keycode and kernel key
for 256 lookup-table is used (hid_keyboard)
>= 256 KEY_ constants (from kernel key - kernel keycode map - see below)
kernel key - kernel keycode map: ❡
https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
or
/usr/include/linux/input.h
#define KEY_RESERVED 0<br>#define KEY_ESC 1<br>#define KEY_1 2<br>#define KEY_2 3<br>#define KEY_3 4<br>#define KEY_4 5<br>#define KEY_5 6<br>#define KEY_6 7<br>2 libinput-stage (wayland) ❡
https://en.wikipedia.org/wiki/Wayland_(protocol)#libinput
This is the userspace library used by your compositor (Wayland) to talk to evdev devices. So if you set your input devices in sway et. here is the interface.
Small History Lesson ❡
Bits 0-7 in X11 are reserved. See: https://tronche.com/gui/x/xlib/input/keyboard-encoding.html
In the X11 Protocol Specification, a keycode was defined...