Remapowanie niedziałających klawiszy
Kategoria: Artykuły, etykiety: evtest, keycode, keymap, keysym, klawiatura, klawisze multimedialne, scancode, showkey, udev, xev
Dodany: 2014-04-05 19:16
(zmodyfikowany: 2015-01-21 17:54)
Przez: morfik
Wyświetleń: 15918
Na sieci znalazłem sporo nieaktualnych już informacji na temat tego jak powinno się przemapować klawisze, które nie do końca są wykrywane w systemie. Zwykle są to klawisze multimedialne lub inne niestandardowe przyciski, które nie pasują do układu 104 klawiszy. Większość z tego co znalazłem można, co prawda, wdrożyć z większym lub mniejszym powodzeniem, jednak zaleca się nie stosować tamtych rozwiązań, poza tym istnieją nowsze i lepsze alternatywy, które nieco upraszczają cały proces zmiany układu klawiatury.
1. Konfiguracja klawiatury
Klawiaturę można konfigurować w kilku miejscach, w debianie można tego dokonać, albo w plikach konfiguracyjnych Xorga, albo przez dpkg-reconfigure keyboard-configuration . I tak dla przykładu, plik Xorga z konfiguracją klawiatury może wyglądać tak:
Section "InputClass"
Identifier "Logitech Media Keyboard Elite"
MatchIsKeyboard "on"
MatchDevicePath "/dev/input/event*"
Driver "evdev"
Option "XkbModel" "logimel"
Option "XkbLayout" "pl"
#Option "XkbVariant" ""
Option "XkbOptions" "lv3:ralt_switch,compose:rctrl,terminate:ctrl_alt_bksp"
EndSection
Powyższą zawartość trzeba umieścić np. w /etc/X11/xorg.conf.d/10-keyboard.conf . Jeśli mamy inną klawiaturę, musimy dowiedzieć się jakie wartości powpisywać do powyższego pliku.
XkbModel można wyciągnąć z pliku /usr/share/X11/xkb/rules/xorg.lst znając oczywiście model klawiatury , zaś XkbLayout można odszukać w /usr/share/X11/xkb/symbols/ , w przypadku polskiego układu, jest to pl .
Jeśli chodzi o debianowy sposób, ten z konfiguracją pakietu keyboard-configuration , to w przeciwieństwie do tego powyżej nie musimy ręcznie uzupełniać pliku. Po wydaniu polecenia:
# dpkg-reconfigure keyboard-configuration
zostaniemy po prostu poproszeni o wybranie szeregu parametrów dla naszej klawiatury i tu już raczej nie powinno być problemów co do tego jaki model klawiatury należy wybrać, bo prawdopodobnie jego nazwa widnieje na liście.
2. Błędy Xservera
Samo wybranie modelu powinno rozwiązać większość problemów. Jednak bywają przypadki kiedy nie wszystkie klawisze działają tak jakbyśmy tego chcieli, a niektóre nawet wcale nie są wykrywane. Zanim jednak przejdziemy do ich przemapowania, w moim przypadku Xserver wyrzucił mi kilka błędów, niby nie są to jakieś krytyczne sprawy ale przydało by się je wyeliminować.
Błędy można zaobserwować albo w logach Xservera, w pliku /var/log/Xorg.0.log albo w pliku błędów sesji zlokalizowanym w katalogu domowym -- plik /home/morfik/.xsession-errors . Nie wszędzie i nie zawsze te błędy będą widoczne, np. w przypadku posiadania graficznego menadżera logowania, część z tych błędów może, albo zostać wyeliminowana, albo ukryta, dokładnie nie wiem, w każdym razie mogą nie być widoczne. Ja podnoszę Xserver przez zwykłe startx i u mnie w logu sesji mam poniższe komunikaty:
The XKEYBOARD keymap compiler (xkbcomp) reports:
> Error: Meta_L added to symbol map for multiple modifiers
> Using Mod4, ignoring Mod1.
> Error: Key <META> added to map for multiple modifiers
> Using Mod4, ignoring Mod1.
> Warning: Type "ONE_LEVEL" has 1 levels, but <RALT> has 2 symbols
> Ignoring extra symbols
Errors from xkbcomp are not fatal to the X server
The XKEYBOARD keymap compiler (xkbcomp) reports:
> Warning: Compat map for group 2 redefined
> Using new definition
> Warning: Compat map for group 3 redefined
> Using new definition
> Warning: Compat map for group 4 redefined
> Using new definition
Errors from xkbcomp are not fatal to the X server
By poprawić te błędy, trzeba wyedytować plik /usr/share/X11/xkb/symbols/level3 i wykomentować poniższe dwie linijki:
// type[Group1]="ONE_LEVEL",
// symbols[Group1] = [ ISO_Level3_Shift ]
Pod nimi trzeba dopisać poniższe dwie:
type[Group1]="TWO_LEVEL",
symbols[Group1] = [ ISO_Level3_Shift, ISO_Level3_Shift ]
W ten sposób pozbędziemy się błędu z RALT, który służy do wstawiania polskich znaków.
By pozbyć się pozostałych błędów, trzeba wykomentować 3 linijki w pliku /usr/share/X11/xkb/compat/basic :
// group 2 = AltGr;
// group 3 = AltGr;
// group 4 = AltGr;
Po powyższych operacjach, te błędy, które zostały zalogowane w pliku błędów sesji, powinny zniknąć.
3. SCANCODE, KEYCODE oraz KEYSYM
Ja posiadam klawiaturę Logitech Media Keyboard Elite i w jej przypadku połowa klawiszy dodatkowych zwyczajnie nie działa. By móc ustalić przyczynę, trzeba wiedzieć co się tak naprawdę dzieje po tym jak wciskamy klawisz na klawiaturze. Są generalnie trzy terminy, z którymi można się spotkać: SCANCODE, KEYCODE oraz KEYSYM.
SCANCODE jest to kod klawisza, który klawiatura przesyła do kernela po przyciśnięciu czegoś na klawiaturze. KEYCODE jest to przemapowany przez kernel SCANCODE -- każdy kernel posiada tablicę z parami KEYCODE-SCANCODE. Jeśli kernel jest w stanie odczytać SCANCODE, powinien wypluć KEYCODE. Z kolei KEYSYM jest tym co my rozpoznajemy jako literki i cyferki lub też inne znaki jakie mamy zwykle nadrukowane na klawiszach naszej klawiatury.
4. Problemy z showkey i xev
Jest szereg narzędzi, które potrafią odczytać SCANCODE lub/i KEYCODE. Zwykle ludzie używają do tego celu showkey . Jednak jest bardzo duże prawdopodobieństwo, że znajdziemy się w takiej sytuacji gdzie klawisz będzie miał KEYCODE, a nie będzie miał przy tym SCANCODE. Czyli to by było tak jakby klawiatura nie wysłała żadnego sygnału do kernela, a ten jakimś cudem potrafił go zidentyfikować. Tak było z klawiszami na mojej klawiaturze.
Innym narzędzie szeroko rozpowszechnionym i też przy tym dość często używanym jest xev . Podobnie jak poprzednik, nie jest pozbawiony wad, a ma ich dość sporo. Przede wszystkim wypluwa złe kody. Dla przykładu, jeśli wklepiemy poniższą linijkę do terminala:
$ xev | grep -A2 --line-buffered '^KeyRelease' | sed -n '/keycode /s/^.*keycode \([0-9]*\).* (.*, \(.*\)).*$/\1 \2/p'
po wciśnięciu klawisza a dostaniemy:
38 a
Co w tym dziwnego? Mamy KEYCODE oraz odpowiadający mu znak. No nie do końca. Jeśli byśmy skorzystali z showkey:
# showkey --keycode
akeycode 30 press
keycode 30 release
mamy inny KEYCODE. Komu wierzyć? Xserver potrafi obsłużyć niezbyt wygórowaną liczbę KEYCODE -- wynosi ona 255. Z jakichś powodów pierwsze 8 kodów (0-7) jest zarezerwowanych. Tak więc do dyspozycji mamy znaki od 8 do 255 włącznie i to co xev rozumie pod znakiem 38, w rzeczywistości nie ma kodu 38, a 30. Dodatkowo kod 8 i 255 również są zarezerwowane, czyniąc tym samym kod 9 pierwszym możliwym, który możemy przypisać -- domyślnie jest on przeznaczony dla klawisza ESC. I tak w showkey ESC jest widziany jako 1, w xev zaś jako 9. Jeśli ktoś chce korzystać z xev, musi pamiętać by odjąć 8 od wartości KEYCODE zwracanej przez ten program.
Problem z podbijaniem numerków przez xev to nie jedyna z jego wad -- inną jest to, że czasami nie podaje on zupełnie żadnego KEYCODE i tak było też w moim przypadku. Nawet po przemapowaniu klawiszy, xev nie zwraca żadnego KEYCODE po przyciśnięciu tych klawiszy. Jednym słowem xev ssie.
5. Błędne wartości SCANCODE
Szukając czegoś na temat SCANCODE, natknąłem się na informację, że czasami kernel może zwracać złe wartości SCANCODE oraz iż można dopisać do linijki kernela w extlinux czy grubie odpowiedni parametr by to przekłamanie kernela naprawić.
atkbd.softraw=0
6. Narzędzie evtest
Jak nie showkey i nie xev to jaka pozostaje nam alternatywa? Na szczęście nie jest tak źle jakby mogło się wydawać. Mamy jeszcze w zanadrzu pakiet evtest . Zainstalujmy i odpalmy go:
# evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0: Logitech Logitech USB Keyboard
/dev/input/event1: Logitech Logitech USB Keyboard
/dev/input/event2: Power Button
/dev/input/event3: Power Button
/dev/input/event4: PC Speaker
/dev/input/event5: A4Tech USB Mouse
/dev/input/event6: ACPI Virtual Keyboard Device
Select the device event number [0-6]:
Jak widzimy, zostały przeskanowane wszystkie urządzenia w katalogu /dev/input i jak możemy również zauważyć event0 oraz event1 są od mojej klawiatury. Pytanie się nasuwa: czemu są dwa, a nie jeden, przecie klawiatura jest tylko jedna. Do końca nie wiem jak to wygląda na innych klawiaturach ale w przypadku tej, pierwsza pozycja (event0) odpowiada za zwykłe klawisze, druga zaś (event1) za klawisze multimedialne. Jako, że mi nie działa tylko połowa klawiszy multimedialnych, będę korzystał z urządzenia event1.
Poniżej jest przedstawione przykładowe wyjście programu evtest:
# evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0: Logitech Logitech USB Keyboard
/dev/input/event1: Logitech Logitech USB Keyboard
/dev/input/event2: Power Button
/dev/input/event3: Power Button
/dev/input/event4: PC Speaker
/dev/input/event5: A4Tech USB Mouse
/dev/input/event6: ACPI Virtual Keyboard Device
Select the device event number [0-6]: 0
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x46d product 0xc30f version 0x110
Input device name: "Logitech Logitech USB Keyboard"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 1 (KEY_ESC)
Event code 2 (KEY_1)
Event code 3 (KEY_2)
Event code 4 (KEY_3)
Event code 5 (KEY_4)
Event code 6 (KEY_5)
Event code 7 (KEY_6)
Event code 8 (KEY_7)
Event code 9 (KEY_8)
Event code 10 (KEY_9)
Event code 11 (KEY_0)
Event code 12 (KEY_MINUS)
Event code 13 (KEY_EQUAL)
Event code 14 (KEY_BACKSPACE)
Event code 15 (KEY_TAB)
Event code 16 (KEY_Q)
Event code 17 (KEY_W)
Event code 18 (KEY_E)
Event code 19 (KEY_R)
Event code 20 (KEY_T)
Event code 21 (KEY_Y)
Event code 22 (KEY_U)
Event code 23 (KEY_I)
Event code 24 (KEY_O)
Event code 25 (KEY_P)
Event code 26 (KEY_LEFTBRACE)
Event code 27 (KEY_RIGHTBRACE)
Event code 28 (KEY_ENTER)
Event code 29 (KEY_LEFTCTRL)
Event code 30 (KEY_A)
Event code 31 (KEY_S)
Event code 32 (KEY_D)
Event code 33 (KEY_F)
Event code 34 (KEY_G)
Event code 35 (KEY_H)
Event code 36 (KEY_J)
Event code 37 (KEY_K)
Event code 38 (KEY_L)
Event code 39 (KEY_SEMICOLON)
Event code 40 (KEY_APOSTROPHE)
Event code 41 (KEY_GRAVE)
Event code 42 (KEY_LEFTSHIFT)
Event code 43 (KEY_BACKSLASH)
Event code 44 (KEY_Z)
Event code 45 (KEY_X)
Event code 46 (KEY_C)
Event code 47 (KEY_V)
Event code 48 (KEY_B)
Event code 49 (KEY_N)
Event code 50 (KEY_M)
Event code 51 (KEY_COMMA)
Event code 52 (KEY_DOT)
Event code 53 (KEY_SLASH)
Event code 54 (KEY_RIGHTSHIFT)
Event code 55 (KEY_KPASTERISK)
Event code 56 (KEY_LEFTALT)
Event code 57 (KEY_SPACE)
Event code 58 (KEY_CAPSLOCK)
Event code 59 (KEY_F1)
Event code 60 (KEY_F2)
Event code 61 (KEY_F3)
Event code 62 (KEY_F4)
Event code 63 (KEY_F5)
Event code 64 (KEY_F6)
Event code 65 (KEY_F7)
Event code 66 (KEY_F8)
Event code 67 (KEY_F9)
Event code 68 (KEY_F10)
Event code 69 (KEY_NUMLOCK)
Event code 70 (KEY_SCROLLLOCK)
Event code 71 (KEY_KP7)
Event code 72 (KEY_KP8)
Event code 73 (KEY_KP9)
Event code 74 (KEY_KPMINUS)
Event code 75 (KEY_KP4)
Event code 76 (KEY_KP5)
Event code 77 (KEY_KP6)
Event code 78 (KEY_KPPLUS)
Event code 79 (KEY_KP1)
Event code 80 (KEY_KP2)
Event code 81 (KEY_KP3)
Event code 82 (KEY_KP0)
Event code 83 (KEY_KPDOT)
Event code 85 (KEY_ZENKAKUHANKAKU)
Event code 86 (KEY_102ND)
Event code 87 (KEY_F11)
Event code 88 (KEY_F12)
Event code 89 (KEY_RO)
Event code 90 (KEY_KATAKANA)
Event code 91 (KEY_HIRAGANA)
Event code 92 (KEY_HENKAN)
Event code 93 (KEY_KATAKANAHIRAGANA)
Event code 94 (KEY_MUHENKAN)
Event code 95 (KEY_KPJPCOMMA)
Event code 96 (KEY_KPENTER)
Event code 97 (KEY_RIGHTCTRL)
Event code 98 (KEY_KPSLASH)
Event code 99 (KEY_SYSRQ)
Event code 100 (KEY_RIGHTALT)
Event code 102 (KEY_HOME)
Event code 103 (KEY_UP)
Event code 104 (KEY_PAGEUP)
Event code 105 (KEY_LEFT)
Event code 106 (KEY_RIGHT)
Event code 107 (KEY_END)
Event code 108 (KEY_DOWN)
Event code 109 (KEY_PAGEDOWN)
Event code 110 (KEY_INSERT)
Event code 111 (KEY_DELETE)
Event code 113 (KEY_MUTE)
Event code 114 (KEY_VOLUMEDOWN)
Event code 115 (KEY_VOLUMEUP)
Event code 116 (KEY_POWER)
Event code 117 (KEY_KPEQUAL)
Event code 119 (KEY_PAUSE)
Event code 121 (KEY_KPCOMMA)
Event code 122 (KEY_HANGUEL)
Event code 123 (KEY_HANJA)
Event code 124 (KEY_YEN)
Event code 125 (KEY_LEFTMETA)
Event code 126 (KEY_RIGHTMETA)
Event code 127 (KEY_COMPOSE)
Event code 128 (KEY_STOP)
Event code 129 (KEY_AGAIN)
Event code 130 (KEY_PROPS)
Event code 131 (KEY_UNDO)
Event code 132 (KEY_FRONT)
Event code 133 (KEY_COPY)
Event code 134 (KEY_OPEN)
Event code 135 (KEY_PASTE)
Event code 136 (KEY_FIND)
Event code 137 (KEY_CUT)
Event code 138 (KEY_HELP)
Event code 183 (KEY_F13)
Event code 184 (KEY_F14)
Event code 185 (KEY_F15)
Event code 186 (KEY_F16)
Event code 187 (KEY_F17)
Event code 188 (KEY_F18)
Event code 189 (KEY_F19)
Event code 190 (KEY_F20)
Event code 191 (KEY_F21)
Event code 192 (KEY_F22)
Event code 193 (KEY_F23)
Event code 194 (KEY_F24)
Event code 240 (KEY_UNKNOWN)
Event type 4 (EV_MSC)
Event code 4 (MSC_SCAN)
Event type 17 (EV_LED)
Event code 0 (LED_NUML)
Event code 1 (LED_CAPSL)
Event code 2 (LED_SCROLLL)
Event code 3 (LED_COMPOSE)
Event code 4 (LED_KANA)
Properties:
Property type 20 (EV_REP)
Property code 0 (REP_DELAY)
Value 250
Property code 1 (REP_PERIOD)
Value 33
Testing ... (interrupt to exit)
Event: time 1396640460.310836, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70028
Event: time 1396640460.310836, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0
Event: time 1396640460.310836, -------------- SYN_REPORT ------------
Event: time 1396640461.998826, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1396640461.998826, type 1 (EV_KEY), code 30 (KEY_A), value 1
Event: time 1396640461.998826, -------------- SYN_REPORT ------------
aEvent: time 1396640462.102821, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1396640462.102821, type 1 (EV_KEY), code 30 (KEY_A), value 0
Event: time 1396640462.102821, -------------- SYN_REPORT ------------
Jak widzimy, spora część logu to klawisze, które aktualnie są przypisane, czyli zwykła mapa klawiatury. Na samym dole mamy wciśnięty klawisz a. Mamy trochę info, w tym też code 30 . Zatem program zdaje się wypisywać aktualnie przypisane klawisze oraz zwraca poprawne kody. Pamiętać trzeba, że drugi event może mieć również przypisane pewne klawisze. Jeśli poddamy testowi drugie urządzenie, zobaczymy, że KEYCODE niektórych klawiszy mają dość spore wartości:
# evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0: Logitech Logitech USB Keyboard
/dev/input/event1: Logitech Logitech USB Keyboard
/dev/input/event2: Power Button
/dev/input/event3: Power Button
/dev/input/event4: PC Speaker
/dev/input/event5: A4Tech USB Mouse
/dev/input/event6: ACPI Virtual Keyboard Device
Select the device event number [0-6]: 1
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x46d product 0xc30f version 0x110
Input device name: "Logitech Logitech USB Keyboard"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 113 (KEY_MUTE)
Event code 114 (KEY_VOLUMEDOWN)
Event code 115 (KEY_VOLUMEUP)
Event code 116 (KEY_POWER)
Event code 131 (KEY_UNDO)
Event code 138 (KEY_HELP)
Event code 140 (KEY_CALC)
Event code 142 (KEY_SLEEP)
Event code 143 (KEY_WAKEUP)
Event code 155 (KEY_MAIL)
Event code 156 (KEY_BOOKMARKS)
Event code 158 (KEY_BACK)
Event code 159 (KEY_FORWARD)
Event code 163 (KEY_NEXTSONG)
Event code 164 (KEY_PLAYPAUSE)
Event code 165 (KEY_PREVIOUSSONG)
Event code 166 (KEY_STOPCD)
Event code 168 (KEY_REWIND)
Event code 171 (KEY_CONFIG)
Event code 172 (KEY_HOMEPAGE)
Event code 182 (KEY_REDO)
Event code 208 (KEY_FASTFORWARD)
Event code 210 (KEY_PRINT)
Event code 217 (KEY_SEARCH)
Event code 234 (KEY_SAVE)
Event code 319 (?)
Event code 328 (BTN_TOOL_QUINTTAP)
Event code 329 (?)
Event code 330 (BTN_TOUCH)
Event code 331 (BTN_STYLUS)
Event code 418 (KEY_ZOOMIN)
Event code 419 (KEY_ZOOMOUT)
Event code 420 (KEY_ZOOMRESET)
Event code 421 (KEY_WORDPROCESSOR)
Event code 423 (KEY_SPREADSHEET)
Event code 425 (KEY_PRESENTATION)
Event code 430 (KEY_MESSENGER)
Event type 4 (EV_MSC)
Event code 4 (MSC_SCAN)
Properties:
Testing ... (interrupt to exit)
Event: time 1396640828.951618, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022d
Event: time 1396640828.951618, type 1 (EV_KEY), code 418 (KEY_ZOOMIN), value 1
Event: time 1396640828.951618, -------------- SYN_REPORT ------------
Event: time 1396640829.143618, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022d
Event: time 1396640829.143618, type 1 (EV_KEY), code 418 (KEY_ZOOMIN), value 0
Event: time 1396640829.143618, -------------- SYN_REPORT ------------
Event: time 1396640830.231616, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022e
Event: time 1396640830.231616, type 1 (EV_KEY), code 419 (KEY_ZOOMOUT), value 1
Event: time 1396640830.231616, -------------- SYN_REPORT ------------
Event: time 1396640830.359616, type 4 (EV_MSC), code 4 (MSC_SCAN), value c022e
Event: time 1396640830.359616, type 1 (EV_KEY), code 419 (KEY_ZOOMOUT), value 0
Event: time 1396640830.359616, -------------- SYN_REPORT ------------
Jak widzimy, część z klawiszy ma kod > 255, dlatego one nie działają. Problem w tym, że by przemapować kernelowskie KEYCODE, czyli zmienić ich numerki na niższe (te < 255), musimy znać SCANCODE klawisza na klawiaturze.
W uzyskaniu SCANCODE pomoże nam /lib/udev/keymap . By ustalić jakie urządzenie chcemy monitorować, możemy albo wyciągnąć jedno z evtest albo skorzystać z /lib/udev/findkeyboards . Choć to narzędzie też trochę ssie i nie zawsze potrafi wskazać to czego szukamy. Dla przykładu, u mnie nie wykrył urządzenia event1 :
# /lib/udev/findkeyboards
USB keyboard: input/event0
Unknown type: input/event6
W każdym razie, w tym przypadku musimy zbadać urządzenie input/event1 :
# /lib/udev/keymap -i input/event1
Press ESC to finish, or Control-C if this device is not your primary keyboard
scan code: 0xC022D key code: zoomin
scan code: 0xC022E key code: zoomout
Bingo! Mamy SCANCODE niedziałających klawiszy -- tych co mają KEYCODE > 255.
Teraz musimy przemapować te klawisze. Do tego celu wykorzystamy udev oraz narzędzie keymap. Musimy napisać regułkę dla naszej klawiatury. Jeśli ktoś jeszcze nie czytał mojego artykułu na temat udeva, znajdzie go pod tym linkiem.
Zanim jednak się weźmiemy do pisania reguły dla udeva, stwórzmy plik, którego zawartość składać się będzie z dwóch kolumn, w jednej będzie SCANCODE, a w drugiej nowy KEYCODE. W moim przypadku to wygląda tak:
# /usr/include/linux/input.h
0xC01BC CHAT
0xC022D PROG3
0xC022E PROG4
0x90040 FINANCE
0xC0184 SPORT
0xC0186 SHOP
0xC0188 F14
0x90049 F15
0x9004A F16
0x9004B F17
0x9004C F18
Uzupełnienie pierwszej kolumny raczej nie powinno stanowić problemu. Dane, które trzeba wpisać do drugiej kolumny musimy odczytać z pliku /usr/include/linux/input.h . Dla przykładu:
#define KEY_PROG3 202
#define KEY_PROG4 203
KEYCODE dla PROG3 oraz PROG4, które zostały wykorzystane powyżej, posiadają numerki 202 oraz 203. Trzeba teraz wrócić do evtest i sprawdzić, które KEYCODE nie są zajęte. Z reguły te powyżej 200 są wolne.
W moim przypadku, kernel przypisał KEYCODE do paru nieistniejących klawiszy, także jeśli nie jesteśmy pewni jakie numerki wybrać, to najlepiej powciskać wszystkich klawisze na klawiaturze i pospisywać każdy KEYCODE.
Jeśli już wypełniliśmy plik z nowym mapowaniem, tworzymy regułę dla udeva w /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules :
KERNEL=="event*", ACTION=="add", SUBSYSTEM=="input", SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="c30f", RUN+="/lib/udev/keymap $name /lib/udev/keymaps/logitech-media-keyboard-elite"
Większość opcji będzie taka sama, za wyjątkiem ścieżki do pliku z mapowaniem oraz zmiennych ENV{ID_VENDOR_ID} i ENV{ID_MODEL_ID} . By uzyskać wartości dla tych zmiennych, odpalamy udevadm :
# udevadm info /dev/input/event0
P: /devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/input/input10/event0
N: input/event0
S: input/by-id/usb-Logitech_Logitech_USB_Keyboard-event-kbd
S: input/by-path/pci-0000:00:1d.1-usb-0:1:1.0-event-kbd
E: BACKSPACE=guess
E: DEVLINKS=/dev/input/by-id/usb-Logitech_Logitech_USB_Keyboard-event-kbd /dev/input/by-path/pci-0000:00:1d.1-usb-0:1:1.0-event-kbd
E: DEVNAME=/dev/input/event0
E: DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/input/input10/event0
E: ID_BUS=usb
E: ID_INPUT=1
E: ID_INPUT_KEY=1
E: ID_INPUT_KEYBOARD=1
E: ID_MODEL=Logitech_USB_Keyboard
E: ID_MODEL_ENC=Logitech\x20USB\x20Keyboard
E: ID_MODEL_ID=c30f
E: ID_PATH=pci-0000:00:1d.1-usb-0:1:1.0
E: ID_PATH_TAG=pci-0000_00_1d_1-usb-0_1_1_0
E: ID_REVISION=2300
E: ID_SERIAL=Logitech_Logitech_USB_Keyboard
E: ID_TYPE=hid
E: ID_USB_DRIVER=usbhid
E: ID_USB_INTERFACES=:030101:030000:
E: ID_USB_INTERFACE_NUM=00
E: ID_VENDOR=Logitech
E: ID_VENDOR_ENC=Logitech
E: ID_VENDOR_ID=046d
E: MAJOR=13
E: MINOR=64
E: SUBSYSTEM=input
E: USEC_INITIALIZED=350329788
E: XKBLAYOUT=pl
E: XKBMODEL=logimel
E: XKBOPTIONS=lv3:ralt_switch,compose:rctrl,terminate:ctrl_alt_bksp
Zapisujemy regułę i testujemy ją:
# udevadm test /devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1:1.0/input/input10/event0
...
read rules file: /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules
...
RUN '/lib/udev/keymap $name /lib/udev/keymaps/logitech-media-keyboard-elite' /etc/udev/rules.d/95-keymap-media-keyboard-elite.rules:1
...
run: '/lib/udev/keymap input/event0 /lib/udev/keymaps/logitech-media-keyboard-elite'
Jeśli z jakichś powodów coś nie działa jak należy, można spróbować posłużyć się udevd z opcją --debug . U mnie niby wszystko działa jak należy ale keymap zwraca szereg błędów:
# /lib/udev/keymap /dev/input/by-id/usb-Logitech_Logitech_USB_Keyboard-event-kbd /lib/udev/keymaps/logitech-media-keyboard-elite
EVIOCGKEYCODE for scan code 0xc01bc: Invalid argument
EVIOCGKEYCODE for scan code 0xc022d: Invalid argument
EVIOCGKEYCODE for scan code 0xc022e: Invalid argument
EVIOCGKEYCODE for scan code 0x90040: Invalid argument
EVIOCGKEYCODE for scan code 0xc0184: Invalid argument
EVIOCGKEYCODE for scan code 0xc0186: Invalid argument
EVIOCGKEYCODE for scan code 0xc0188: Invalid argument
EVIOCGKEYCODE for scan code 0x90049: Invalid argument
EVIOCGKEYCODE for scan code 0x9004a: Invalid argument
EVIOCGKEYCODE for scan code 0x9004b: Invalid argument
EVIOCGKEYCODE for scan code 0x9004c: Invalid argument
KEYCODE precyzowane w /lib/udev/keymaps/logitech-media-keyboard-elite mogą mieć postać nazwy -- CHAT , mogą być także zapisane, albo w systemie dziesiętnym -- 216, albo szesnastkowym -- 0xD8 . Nie ważne co tam wpiszę i tak wyrzuca ten sam komunikat.
7. Problemy z nowszą wersją udeva
Natknąłem się na informację, że w nowszych wersjach udeva, prawdopodobnie > 206 , /lib/udev/keymap nie będzie używany. Od teraz mapowanie klawiatury będzie trzymane w bazie danych udeva. Jeśli posiadamy udeva w wersji 206 lub nowszej, trzeba stworzyć plik /etc/udev/hwdb.d/65-keyboard.hwdb o treści podobnej do tej poniżej:
keyboard:usb:v046dpc30f*
KEYBOARD_KEY_c01bc=chat
KEYBOARD_KEY_c022d=prog3
KEYBOARD_KEY_c022e=prog4
KEYBOARD_KEY_90040=finance
KEYBOARD_KEY_c0184=sport
KEYBOARD_KEY_c0186=shop
KEYBOARD_KEY_c0188=f14
KEYBOARD_KEY_90049=f15
KEYBOARD_KEY_9004a=f16
KEYBOARD_KEY_9004b=f17
KEYBOARD_KEY_9004c=f18
W pierwszej linijce zawsze występuje keyboard:usb: . Potem mamy dwa numerki zaczynające się od v oraz p czyli v046d oraz pc30f i na końcu * . Te dwa numerki są to: idVendor=046d oraz idProduct=c30f , które wyciągnęliśmy wcześniej. Mapowanie klawiszy sprowadza się do podania SCANCODE bez 0x , czyli zamiast 0xc01bc należy podać c01bc oraz KEYCODE, w tym przypadku jest to nazwa zapisana z małych liter -- chat .
Następnie trzeba zaktualizować bazę danych udeva (plik /lib/udev/hwdb.bin) przy pomocy:
# udevadm hwdb --update
Klawisze powinny być widoczne po ponownym podłączeniu klawiatury.
Jeśli nasza klawiatura jest wykrywana w postaci kilku eventów, np:
# evtest
...
/dev/input/event6: Logitech Logitech USB Keyboard
/dev/input/event13: Logitech Logitech USB Keyboard
...
Wtedy musimy określić bardziej precyzyjne dopasowanie, bo w przeciwnym wypadku, reguła zostanie zaaplikowana w stosunku do tych dwóch urządzeń i jedno z nich zwróci poniższy błąd:
Jan 21 17:00:50 morfikownia systemd-udevd[88118]: keyboard: mapping scan code 786820 (0xc0184) to key code 220 (0xdc)
Jan 21 17:00:50 morfikownia systemd-udevd[88118]: Error calling EVIOCSKEYCODE on device node '/dev/input/event6' (scan code 0xc0184, key code 220): Invalid argument
By odnaleźć dokładny numerek identyfikacyjny urządzenia z klawiszami multimedialnymi, możemy posłużyć się poniższą linijką:
# find /sys -name modalias -print0 | xargs -0 cat | sort -u | grep usb
usb:v046DpC30Fd2300dc00dsc00dp00ic03isc00ip00in01
usb:v046DpC30Fd2300dc00dsc00dp00ic03isc01ip01in00
...
Vendor i product ID tej klawiatury to odpowiednio 046D oraz C30F , zatem interesują nas tylko dwa wpisy -- po jednym na event. Wystarczy tylko odszukać odpowiednie ID, a to można wyciągnąć z bazy udeva:
# udevadm info --export-db > plik
Przeszukujemy tak utworzony plik pod kątem eventu z mapowanymi klawiszami, w tym przypadku jest to event13 (sprawdzić via evtest):
P: /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3.4/2-1.3.4:1.1/0003:046D:C30F.0018/input/input52/event13
N: input/event13
...
E: ID_USB_INTERFACE_NUM=01
...
Zatem dopasowanie w pliku udeva będzie wyglądać następująco:
keyboard:usb:v046DpC30Fd2300dc00dsc00dp00ic03isc00ip00in01
KEYBOARD_KEY_c01bc=chat
KEYBOARD_KEY_c022d=prog3
KEYBOARD_KEY_c022e=prog4
KEYBOARD_KEY_90040=finance
KEYBOARD_KEY_c0184=sport
KEYBOARD_KEY_c0186=shop
KEYBOARD_KEY_c0188=f14
KEYBOARD_KEY_90049=f15
KEYBOARD_KEY_9004a=f16
KEYBOARD_KEY_9004b=f17
KEYBOARD_KEY_9004c=f18