J’utilise un clavier typematrix bépo, comme ce n’est pas très répendu j’ai déjà eu plusieurs fois besoins de configurer certains soft ou device pour les rendre compatible. J’ai donc du manipulé les notions de scancode, keycode… et le moins qu’on puisse dire c’est que ce n’est pas claire !
Dans cet article je détaille ce que j’ai compris de ces notions.
Sources général :
- xmodmap – Université Paris Diderot.
- descrition du fonctionnement des claviers sur le wiki FreeRDP
scancode
Souces :
- notes de Andries Brouwer
- l’excellent article A summary of scan code & key codes sets used in the PC virtualization stack
Un scancode est référence une position de touche sur le clavier, indépendamment de ce qu’il y a écrit sur la touche. Par exemple, 0x14 est le scancode USB qui représente la première touche sur la ligne des touches de lettre, qu’il y ai un « q » (qwerty), un « a » (azerty) ou un « b » (bépo) écrit dessus.
Lors de l’appui sur une touche deux scancodes sont généré, un pour l’appui et un pour la relache.
Il existe plusieurs type de scancode, mais seuls deux nous intéresse aujourd’hui.
scancode PS/2
Les scancode PS/2, que j’appelerais par la suite scancode console, sont les scancode qui apparaisse dans /dev/console.
Leurs nom viens de la norme utilisé pour les anciens connecteur clavier PS/2 (enfin je crois).
Lorsque vous entendez parler de scancode il s’agit généralement de ceux là.
On peut obtenir le scancode console des touches tapées au clavier via la commande showkey.
max@laptop % sudo showkey -s
kb mode was ?UNKNOWN?
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]
press any key (program terminates 10s after last keypress)...
0x9c
b0x10 0x90
é0x11 0x91
p0x12 0x92
o0x13 0x93
Ici j’ai tapé sur les quatre première touche de lettre de mon clavier bépo.
0x10 est le scancode console correspondant à l’appuie sur la seconde touche de la deuxième ligne (la touche « b » sur mon clavier).
0x90 correspond au relachement de cette touche.
scancode USB
Les scancode PS/2 ne sont pas les même que les scancode USB.
Généralement lorsqu’on parle de scancode, il ne s’agit pas de ceux là.
Ce pdf donne le mapping entre les scancode USB (HID Usage ID) et PS/2 (PS/2 Set 1 Make=appui, Break=relache).
On peut obtenir le scancode USB des touches tapées au clavier via la commande l’outil evtest. Par exemple lorsque je tape « bépo » sur mon clavier bépo.
max@laptop % sudo evtest /dev/input/by-id/usb-TypeMatrix.com_USB_Keyboard-event-kbd | grep -B1 'value 1'
Event: time 1445026894.642484, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70014
Event: time 1445026894.642484, type 1 (EV_KEY), code 16 (KEY_Q), value 1
b--
Event: time 1445026894.898453, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7001a
Event: time 1445026894.898453, type 1 (EV_KEY), code 17 (KEY_W), value 1
é--
Event: time 1445026895.250487, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70008
Event: time 1445026895.250487, type 1 (EV_KEY), code 18 (KEY_E), value 1
p--
Event: time 1445026895.978447, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70015
Event: time 1445026895.978447, type 1 (EV_KEY), code 19 (KEY_R), value 1
o
- « b » correspond au scancode USB 0x14 (fin de 70014)
- « é » correspond au scancode USB 0x1a (fin de 7001a)
- « p » correspond au scancode USB 0x08
- « o » correspond au scancode USB 0x15
Les « KEY_x » sont détaillé dans la section keycode console.
scancode evdev
« scancode evdev » est un autre nom pour les keycode X.
keycode
Tous les clavier n’utilise pas les même scancodes pour les même touches et il existe une multitude de type de clavier. Déjà on a vue que les scancodes sont différent en PS/2 et en USB.
Le noyau présente donc à l’espace utilisateur un autre élément, le keycode. Comme le scancode celui-ci est indépendant du layout ; une même touche (position sur le clavier) donnera toujours le même keycode, quelque soit le layout dans lequel on se trouve. Cependant il ne dépendant pas de la disposition du clavier, de la marque, etc.
Lors de l’appui et la relache d’une touche touche possède le même keycodes mais sont accompagné d’un « marqueur » différent (qui ne nous intéresse pas ici).
Nous nous intéresserons ici au keycode console et au keycode X (qui sont très similaire… comme on va le voir).
keycode console
On peut obtenir le keycode console des touches tapées au clavier via les commandes showkey ou showkey.
max@laptop % sudo showkey -k
kb mode was ?UNKNOWN?
[ if you are trying this under X, it might not work
since the X server is also reading /dev/console ]
press any key (program terminates 10s after last keypress)...
bkeycode 16 press
keycode 16 release
ékeycode 17 press
keycode 17 release
pkeycode 18 press
keycode 18 release
okeycode 19 press
keycode 19 release
max@laptop % sudo evtest /dev/input/by-id/usb-TypeMatrix.com_USB_Keyboard-event-kbd | grep 'EV_KEY.*value 1'
…
Event: time 1459100766.987735, type 1 (EV_KEY), code 16 (KEY_Q), value 1
Event: time 1459100767.419710, type 1 (EV_KEY), code 17 (KEY_W), value 1
Event: time 1459100768.235743, type 1 (EV_KEY), code 18 (KEY_E), value 1
Event: time 1459100768.691725, type 1 (EV_KEY), code 19 (KEY_R), value 1
…
Même si vous êtres dans un autre layout le « KEY_x » correspondra toujours au layout qwerty us. Il s’agit juste d’un nom associé au keycode, les concepteurs on choisi d’utiliser les noms des touches correspondant à ce layout.
Par exemple ici, je suis en layout « bépo » et j’ai tapé bépo sur mon clavier. Les keycode apparue sont KEY_Q, KEY_W, KEY_R et KEY_R. Ceux-ci ont respectivement pour valeurs numérique 16, 17, 18 et 19.
evtest indique au démarrage quels sont les keycode console supporté par le device séléctionné.
max@laptop % sudo evtest /dev/input/by-id/usb-TypeMatrix.com_USB_Keyboard-event-kbd
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x1e54 product 0x2030 version 0x110
Input device name: "TypeMatrix.com 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 16 (KEY_Q)
Event code 17 (KEY_W)
Event code 18 (KEY_E)
Event code 19 (KEY_R)
…
On peut aussi utiliser libinput-debug-events pour afficher les keycode console :
max@laptop % sudo libinput-list-devices | grep -A 16 TypeMatrix
Device: TypeMatrix.com USB Keyboard
Kernel: /dev/input/event3
Group: 9
Seat: seat0, default
Capabilities: keyboard
Tap-to-click: n/a
Tap-and-drag: n/a
Tap drag lock: n/a
Left-handed: n/a
Nat.scrolling: n/a
Middle emulation: n/a
Calibration: n/a
Scroll methods: none
Click methods: none
Disable-w-typing: n/a
Accel profiles: n/a
Rotation: n/a
--
Device: TypeMatrix.com USB Keyboard
Kernel: /dev/input/event4
Group: 9
Seat: seat0, default
Capabilities: keyboard pointer
Tap-to-click: n/a
Tap-and-drag: n/a
Tap drag lock: n/a
Left-handed: n/a
Nat.scrolling: disabled
Middle emulation: n/a
Calibration: n/a
Scroll methods: none
Click methods: none
Disable-w-typing: n/a
Accel profiles: n/a
Rotation: n/a
max@laptop % sudo libinput-debug-events --show-keycodes --device /dev/input/event3
-event3 DEVICE_ADDED TypeMatrix.com USB Keyboard seat0 default group1 cap:k
event3 KEYBOARD_KEY +1.53s KEY_Q (16) pressed
b event3 KEYBOARD_KEY +1.61s KEY_Q (16) released
event3 KEYBOARD_KEY +2.11s KEY_W (17) pressed
é event3 KEYBOARD_KEY +2.18s KEY_W (17) released
event3 KEYBOARD_KEY +3.33s KEY_E (18) pressed
p event3 KEYBOARD_KEY +3.41s KEY_E (18) released
event3 KEYBOARD_KEY +4.33s KEY_R (19) pressed
o event3 KEYBOARD_KEY +4.39s KEY_R (19) released
scancode console → keycode console
getkeycodes permet d’afficher le mapping actuelle du noyau entre scancode console et keycode console.
max@laptop % sudo getkeycodes
Plain scancodes xx (hex) versus keycodes (dec)
for 1-83 (0x01-0x53) scancode equals keycode
0x50: 80 81 82 83 99 0 86 87
0x58: 88 117 0 0 95 183 184 185
0x60: 0 0 0 0 0 0 0 0
0x68: 0 0 0 0 0 0 0 0
0x70: 93 0 0 89 0 0 85 91
0x78: 90 92 0 94 0 124 121 0
Escaped scancodes e0 xx (hex)
e0 00: 0 0 0 0 0 0 0 0
e0 08: 0 0 0 0 0 0 0 0
e0 10: 165 0 0 0 0 0 0 0
e0 18: 0 163 0 0 96 97 0 0
e0 20: 113 140 164 0 166 0 0 0
e0 28: 0 0 255 0 0 0 114 0
e0 30: 115 0 172 0 0 98 255 99
e0 38: 100 0 0 0 0 0 0 0
e0 40: 0 0 0 0 0 119 119 102
e0 48: 103 104 0 105 112 106 118 107
e0 50: 108 109 110 111 0 0 0 0
e0 58: 0 0 0 125 126 127 116 142
e0 60: 0 0 0 143 0 217 156 173
e0 68: 128 159 158 157 155 226 0 112
e0 70: 0 0 0 0 0 0 0 0
e0 78: 0 0 0 0 0 0 0 0
Par exemple avec la touche « PageUp ».
max@laptop % sudo showkey -s
…
^[[5~0xe0 0x49 0xe0 0xc9
max@laptop % sudo getkeycodes | grep 104
e0 48: 103 104 0 105 112 106 118 107
Ce qui veut dire :
- le scancode console ‘0xe0 0x48’ correspond au keycode console 103
- le scancode console ‘0xe0 0x49’ correspond au keycode console 104 (PageUp)
- le scancode console ‘0xe0 0x50’ n’est pas mappé
- le scancode console ‘0xe0 0x51’ correspond au keycode console 105
- le scancode console ‘0xe0 0x52’ correspond au keycode console 112
- …
scancode USB → keycode console
evtest permet d’afficher à la fois les scancode USB et les keycode console.
max@laptop % sudo evtest /dev/input/by-id/usb-TypeMatrix.com_USB_Keyboard-event-kbd | grep -B1 'value 1'
Event: time 1445026894.642484, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70014
Event: time 1445026894.642484, type 1 (EV_KEY), code 16 (KEY_Q), value 1
b--
Event: time 1445026894.898453, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7001a
Event: time 1445026894.898453, type 1 (EV_KEY), code 17 (KEY_W), value 1
é--
Event: time 1445026895.250487, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70008
Event: time 1445026895.250487, type 1 (EV_KEY), code 18 (KEY_E), value 1
p--
Event: time 1445026895.978447, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70015
Event: time 1445026895.978447, type 1 (EV_KEY), code 19 (KEY_R), value 1
o
Pour reprendre l’exemple de tout à l’heure, avec « PageUp ».
max@laptop % sudo evtest /dev/input/by-id/usb-TypeMatrix.com_USB_Keyboard-event-kbd | grep -B1 'value 1'
Event: time 1459112181.688010, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7004b
Event: time 1459112181.688010, type 1 (EV_KEY), code 104 (KEY_PAGEUP), value 1
^[[5~
Ce qui signifie que le scancode USB 0x4b est mappé sur le keycode console 104.
Le mapping complet (scancode USB → keycode console) se trouve dans les notes de Andries Brouwer.
keycode X
Les keycode X (evdev driver) sont exactement les même que les keycode console, majoré de 8.
On peut obtenir les keycode X via la command xev.
max@laptop % xev | awk -F'[ )]+' '/^KeyPress/ { a[NR+2] } NR in a { printf "%-3s %s\n", $5, $8 }'
24 b
25 eacute
26 p
27 o
On voit que ces valeurs sont les même que les keycode console auquelle on a ajouté 8.
max@laptop % sudo evtest /dev/input/by-id/usb-TypeMatrix.com_USB_Keyboard-event-kbd | grep 'EV_KEY.*value 1'
…
Event: time 1459100766.987735, type 1 (EV_KEY), code 16 (KEY_Q), value 1
Event: time 1459100767.419710, type 1 (EV_KEY), code 17 (KEY_W), value 1
Event: time 1459100768.235743, type 1 (EV_KEY), code 18 (KEY_E), value 1
Event: time 1459100768.691725, type 1 (EV_KEY), code 19 (KEY_R), value 1
…
keycode symbolique
Pour faire le mapping entre keycode X et keysym, XKeyboardConfig utilise un autre niveau d’abstraction, le keycode symbolique.
Le mapping entre keycode X (evdev driver) et keysym indiqué dans le fichier /usr/share/X11/xkb/keycodes/evdev.
…
// translation from evdev scancodes to something resembling xfree86 keycodes.
default xkb_keycodes "evdev" {
minimum = 8;
maximum = 255;
…
<AD01> = 24;
<AD02> = 25;
<AD03> = 26;
<AD04> = 27;
…
Le keycode symbolique AD01 est associé au keycode X 24, AD02 à 25, etc.
keysym
Un keysym est une référence à un symbole, un caractère. Par exemple « b » et « B » sont des keysym généralement assigné au keycode X 24 (b) et 24 (b) avec modifieur 50 (Shift) sur mon clavier bépo. On peut avoir la liste des keysym (valeur numérique et nom) via la commande dumpkeys.
max@laptop % sudo dumpkeys -l
…
Symbols recognized by dumpkeys:
(numeric value, symbol)
0x0000 nul
0x0001 Control_a
0x0002 Control_b
0x0003 Control_c
0x0004 Control_d
0x0005 Control_e
0x0006 Control_f
0x0007 Control_g
0x0008 BackSpace
0x0009 Tab
…
keycode symbolique → keysym
Il s’agit du layout (sous X). XKeyboardConfig maintient une base de données des différent mapping/layout dans le dossier /usr/share/X11/xkb/symbols.
Par exemple le layout bépo est détaillé dans le fichier /usr/share/X11/xkb/symbols/fr.
// ┌─────┐
// │ S A │ S = Shift, A = AltGr + Shift
// │ s a │ s = normal, a = AltGr
// └─────┘
//
// ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┲━━━━━━━━━┓
// │ # ¶ │ 1 „ │ 2 “ │ 3 ” │ 4 ≤ │ 5 ≥ │ 6 │ 7 ¬ │ 8 ¼ │ 9 ½ │ 0 ¾ │ ° ′ │ ` ″ ┃ ⌫ Retour┃
// │ $ – │ " — │ « < │ » > │ ( [ │ ) ] │ @ ^ │ + ± │ - − │ / ÷ │ * × │ = ≠ │ % ‰ ┃ arrière┃
// ┢━━━━━┷━┱───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┴─┬───┺━┳━━━━━━━┫
// ┃ ┃ B ¦ │ É ˝ │ P § │ O Œ │ È ` │ ! │ V │ D Ð │ L │ J IJ │ Z Ə │ W ┃Entrée ┃
// ┃Tab ↹ ┃ b | │ é ˊ │ p & │ o œ │ è ` │ ˆ ¡ │ v ˇ │ d ð │ l / │ j ij │ z ə │ w ̆ ┃ ⏎ ┃
// ┣━━━━━━━┻┱────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┴┬────┺┓ ┃
// ┃ ┃ A Æ │ U Ù │ I ˙ │ E ¤ │ ; ̛ │ C ſ │ T Þ │ S ẞ │ R ™ │ N │ M º │ Ç , ┃ ┃
// ┃Maj ⇬ ┃ a æ │ u ù │ i ̈ │ e € │ , ’ │ c © │ t þ │ s ß │ r ® │ n ˜ │ m ¯ │ ç ¸ ┃ ┃
// ┣━━━━━━━┳┹────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┬┴────┲┷━━━━━┻━━━━━━┫
// ┃ ┃ Ê │ À │ Y ‘ │ X ’ │ : · │ K │ ? ̉ │ Q ̣ │ G │ H ‡ │ F ª ┃ ┃
// ┃Shift ⇧┃ ê / │ à \ │ y { │ x } │ . … │ k ~ │ ' ¿ │ q ˚ │ g µ │ h † │ f ˛ ┃Shift ⇧ ┃
// ┣━━━━━━━╋━━━━━┷━┳━━━┷━━━┱─┴─────┴─────┴─────┴─────┴─────┴───┲━┷━━━━━╈━━━━━┻━┳━━━━━━━┳━━━┛
// ┃ ┃ ┃ ┃ Espace inséc. Espace inséc. fin ┃ ┃ ┃ ┃
// ┃Ctrl ┃Meta ┃Alt ┃ ␣ (Espace) _ ␣ ┃AltGr ⇮┃Menu ┃Ctrl ┃
// ┗━━━━━━━┻━━━━━━━┻━━━━━━━┹───────────────────────────────────┺━━━━━━━┻━━━━━━━┻━━━━━━━┛
partial alphanumeric_keys
xkb_symbols "bepo" {
…
// Second row
key <AD01> { [ b, B, bar, brokenbar ] }; // b B | ¦
key <AD02> { [ eacute, Eacute, dead_acute, dead_doubleacute ] }; // é É ˊ ˝
key <AD03> { [ p, P, ampersand, section ] }; // p P & §
key <AD04> { [ o, O, oe, OE ] }; // o O œ Œ
…
Le keycode symbolique AD01 est associé au keysym b, au keysym B si le modifier Shift est présent, etc.
layout
Un layout permet de faire le mapping entre un keycode et un keysym. Sous X, voir section keycode symbolique → keysym.
notes
numlock sans touche numlock
On enregistre n’importe quel sequence de touches avec libinput record (c’est juste pour avoir le début du fichier de record).
sudo libinput record --show-keycodes --output-file libinput-numlock.yaml /dev/input/by-id/usb-Keyboardio_Model_01_Ckbio01-if03-event-kbd
On remplace la section events du fichier de record par le contenu suivant (correspondant à un appuis sur la touche numlock) :
events:
- evdev:
- [ 0, 5911, 4, 4, 458835] # EV_MSC / MSC_SCAN 458835
- [ 0, 5911, 1, 69, 1] # EV_KEY / KEY_NUMLOCK 1
- [ 0, 5911, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +1ms
- evdev:
- [ 0, 6764, 4, 4, 458835] # EV_MSC / MSC_SCAN 458835
- [ 0, 6764, 1, 69, 0] # EV_KEY / KEY_NUMLOCK 0
- [ 0, 6764, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +1ms
On execute le fichier de record :
sudo libinput replay libinput-numlock.yaml