Scancodes, keycodes, evdev, X

Опубликовано 1 Августа, 2022 под тегами X, evdev, keyboards

Если вы вдруг захотите собрать себе кастомную клавиатуру (например на QMK), добавить к ней нестандартных клавиш и использовать эти клавиши в иксах, то надо понимать некоторые взаимосвязанные термины. Увы, материалов, внятно их объясняющих, не так уж и много. Поэтому себе для памяти и вдруг кому пригодится, пишу эту заметку.

Клавиатура, скорее всего, подключается через USB. USB-клавиатуры используют протокол HID для передачи сигнала о нажатии клавиши. Какая клавиша нажата – определяется так называемым scancode-ом.

Оговорка по поводу QMK – scancode-ы не прямо соответствуют кодам клавиш в QMK, это верно только для идентификаторов, объявленных в перечислении hid_keyboard_keypad_usage в quantum/keycode.h, прочие обрабатываются особым образом. Следует отметить, что scancode-ы могут быть как 8-битными, так и 16-битными. 8-битные считаются “стандартными”, хотя не все scancode-ы распознаются во всех ОС, а 16-битные – “vendor-specific”.

Scancode-ы затем драйвер клавиатуры преобразует в keycode-ы. Keycode – это внутреннее представление кода клавиши в ядре. Список всех keycode-ов можно найти в исходниках ядра.

Нестандартные сопоставления определяются через hwdb в udev, см. /lib/udev/hwdb.d/60-keyboard.hwdb. Найти табличку стандартных мне сходу не удалось, но всегда можно выяснить методом тыка, используя скажем showkey или evtest.

UPD: В исходниках qemu нашлась табличка сопоставлений между scancode-ами, keycode-ами и keysym-ами для разных драйверов: https://github.com/qemu/keycodemapdb/blob/master/data/keymaps.csv. Если вдруг файл переместится куда-то, то вот форк

Подробности добавления своих записей в hwdb есть в Arch Wiki.

Когда keycode попадает в иксы, видимо чтобы нам не было скучно, к нему прибавляется 8. Поэтому showkey будет показывать keycode на 8 меньше, чем скажем xev.

В иксах, keycode-ы преобразуются в keysym-ы. Происходит это через xkb. Собственно, подробное обсуждение xkb выходит за рамки этой заметки, но посмотреть таблицу сопоставлений можно используя xmodmap -pke. Каждому keycode-у может быть сопоставлено до 8 keysym-ов (потенциально до 10, но я не видел примеров), нужный выберется в зависимости от активных модификаторов (shift, level3, mode_switch, level5). Сами по себе модификаторы тоже назначаются на клавиши, но эту тему мы пока оставим (посмотреть можно сделав xmodmap -pm).

Наконец, keysym-ы получает собственно что там их должно получать (например, менеджер окон или приложение).

Если вдруг хочется странного – можно это самое “странное” добавить на любом этапе. Увы, для действительно странного – на практике это часто выливается в “добавить на каждом этапе”.

Пример: я хочу использовать какую-нибудь бесполезную клавишу как модификатор для управления менеджером окон (xmonad). Теоретически, достаточно назначить соответствующий scancode для qmk и вперёд? Но нет, не тут то было.

Допустим, я выбрал scancode 143 (в спецификации HID это “international 9”, и насколько мне известно, он не используется нигде). Но не тут-то было! evdev не знает про такую клавишу. Придётся добавить преобразование в keycode руками.

Какой keycode выбрать? Навскидку кажется что тоже какой-нибудь бесполезный, но вот беда, бесполезных-то не так уж и много. Зато есть пропущенные, например keycode 84 никак нельзя выдать из evdev (что неудачно, поскольку в иксах это 92 = ISO_Level3_Shift, и с ним дальше было бы всё проще). Если не патчить ядро, приходится использовать какой-нибудь теоретически полезный, но не используемый лично в моей раскладке keycode.

Но в X11 этот keycode уже имеет какой-то мистический смысл, а мне надо назначить его на модификатор. Приходится ко всему прочему ковырять раскладку xkb чтобы переназначить.

Конечно, проще взять scancode, сопоставленный с каким-нибудь неиспользуемым keysym-ом, и перебить только раскладку в xkb. Например, переключатель хираганы/катаканы с японской клавиатуры (если, конечно, клавиатура не японская).

Использованные материалы: