Linux, клавиатура и udev hwdb
Решил я обновить свою рабочую лошадку Lenovo на почти такую же, только чуть свежее. Все супер, но инженеры Lenovo, зачем-то решили вместо клавиши Ins впихнуть End, а Ins вовсе перенести на функциональную клавишу. Инженеры Lenovo, вы в курсе, что в Linux, сочетание Ctrl+Ins и Shift+Ins - это аналог Ctrl+c/Ctrl+v? Зачем вы перенесли Ins? Зачем там End? Я даже не помню, когда последний раз пользовался клавишей End!
Это все риторические вопросы, на которые я вряд ли узнаю логичные ответы. Но с этим нужно что-то делать.
Я уже делал заметку, как с помощью xmodmap в Xorg отключать клавиши (еще один пламенный привет Lenovo и инженерному гению, который разместил PgUp и PgDown над стрелками). Таким же способом, можно и переназначать клавиши. Но иногда этот метод не работает. Например, если у вас Wayland. В таком случае мы воспользуемся более низкоуровневым решением с помощью udev.
Udev предоставляет встроенную функцию, которая называется hwdb и служит для обслуживания базы данных оборудования. База данных собирается из разных файлов *.hwdb. Более подробно о hwdb можно почитать в официальной документации.
Нас же интересует файл /usr/lib/udev/hwdb.d/60-keyboard.hwdb, в котором описывается соответствие сканкодов к кейкодам по умолчанию.
Формат этого файла простой - строка, которая начинается с префикса evdev: содержащая идентификатор устройства (или ряда устройств) и последующего блока соответствий. Каждая строка блока выглядит как KEYBOARD_KEY_<scancode>=<keycode>, где scancode - это шестнадцатеричное значение, а keycode - строка из /usr/include/linux/input-event-codes.h без KEY_, строчными буквами, например insert или tab. C кейкодом все понятно, осталось найти сканкод.
Для начала найдем нашу клавиатуру. Для этого выполним команду cat /proc/bus/input/devices и поищем там нашу клаву. Вывод команды для моей клавиатуры следующий:
I: Bus=0011 Vendor=0001 Product=0001 Version=ab83
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/devices/platform/i8042/serio0/input/input2
U: Uniq=
H: Handlers=sysrq kbd leds event2
B: PROP=0
B: EV=120013
B: KEY=402000000 3803078f800d001 feffd6dfffefffff fffffffffffffffe
B: MSC=10
B: LED=7
Запоминаем хендлер - event2. Теперь нам понадобиться утилита evtest, которая есть в репозиториях популярных дистрибутивов.
Запускаем ее командой sudo evtest /dev/input/event2, подставляя хендлер. Затем жмем нужную клавишу. У меня вывод такой:
Event: time 1710420949.452477, -------------- SYN_REPORT ------------
Event: time 1710420956.404526, type 4 (EV_MSC), code 4 (MSC_SCAN), value cf
Event: time 1710420956.404526, type 1 (EV_KEY), code 109 (KEY_END), value 1
Нам нужно значение MSC_SCAN - cf.
Если мы не хотим сильно вдаваться в подробности, то можем переназначить клавиши для всех устройств типа клавиатура. В моем случае файл hwdb выглядит так:
cat /etc/udev/hwdb.d/61-keyboard-local.hwdb
evdev:atkbd:*
KEYBOARD_KEY_cf=insert
KEYBOARD_KEY_c9=reserved
KEYBOARD_KEY_d1=reserved
Здесь видно, что я, используя найденный сканкод cf, переназначаю Ins на клавишу End. А так же отключаю PgUp и PgDown с помощью ключевого слова reserved. Их сканкоды я нашел уже вышеупомянутым путем.
После того, как мы создали конфиг, нужно обновить базу
sudo systemd-hwdb update
и применить изменения
sudo udevadm trigger /dev/input/event2
Если же мы хотим переназначить клавиши только для определенной клавиатуры, то нам необходимо найти ее идентификатор. Это может быть идентификатор общих устройств ввода, который имеет формат
evdev:input:b<bus_id>v<vendor_id>p<product_id>e<version_id>-<input_modalias>
Всю информацию можно найти в выводе команды cat /proc/bus/input/devices или cat /sys/class/input/<handler>/device/modalias. Все, после <version_id> можно опустить, заменив на * и тогда строка идентификатора, в моем случае, будет выглядеть следующим образом:
evdev:input:b0011v0001p0001eAB83*
Так же это может быть идентификатор с именем устройства и DMI данными, следующего формата:
evdev:name:<input device name>:dmi:bvn*:bvr*:bd*:svn<vendor>:pn*
Для того, чтобы найти эти данные, вы можете воспользоваться утилитой evemu-describe, которая является частью пакета evemu или evemu-tools, в зависимости от вашего дистрибутива.