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
, в зависимости от вашего дистрибутива.