Gestion du clavier sous GNU/Linux

Published: 27-03-2016

Updated: 29-05-2017

By: Maxime de Roucy

tags: keyboard keycode layout scancode

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 :

scancode

Souces :

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

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 :

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.