Appunti su Gentoo Linux.
La tastiera

Esamineremo ora come avviene la gestione della tastiera a un livello abbastanza dettagliato. Seguiremo cosa accade durante la pressione di 4 tasti o combinazioni di tasti: A, Shift+A, Del, ←. Da ricordare che nella tastiera italiana Del è quasi sempre tradotto in Canc.

Dal tasto fisico agli scancode

La tastiera fisica e il suo driver inviano, quando si preme un tasto, degli scancode al kernel. Tali scancode in pratica sono dei numeri che identificano univocamente i tasti della tastiera.

tasto fisico -> scancodes

Per osservare gli scancode bisogna dare il comando

showkey -s

Non funziona da remoto! Sotto X funziona solo da root ma non sempre perfettamente. Meglio farlo funzionare sempre da console.

Ecco i nostri famosi 4 tasti

Tasto fisico     Press    Release
A                1e       92
Shift            2a       aa
Del              e0 53    e0 d3
←                0e       8e

Nella tabella è presente solo Shift e non Shift+A perché a questo livello è ovvio cosa succede combinando la pressione dei tasti.

Se si tiene premuto un tasto viene generato ripetutamente lo scancode di pressione. Invece quello di rilascio viene generato solo alla fine, quando si rilascia il tasto.

Ecco la voce di Wikipedia. Lo standard per gli scancode normalmente usato da quasi tutte le tastiere è l'IBM PC XT.

Dagli scancode ai keycode

Il kernel provvede poi a tradurre gli scancode in keycode. Immaginate che esista una tastiera virtuale. Un singolo tasto della tastiera fisica può corrispondere a un singolo tasto di questa tastiera virtuale. Oppure una combinazione di tasti della tastiera fisica può corrispondere a un singolo tasto della tastiera virtuale. Come gli scancode sono gli identificatori univoci dei tasti della tastiera fisica, i keycode sono gli identificatori univoci della tastiera virtuale.

Per osservare i keycode bisogna dare il comando

showkey

Non funziona da remoto! Sotto X funziona solo da root ma non sempre perfettamente. Meglio farlo funzionare sempre da console.

Tasto     Scancode           Keycode
--------------------------------------
A         1e / 92              30
Shift     2a / aa              42
Del       e0 53 / e0 d3       111
←         0e / 8e              14

Nella tabella qua sopra ho omesso di indicare press e release. "30 press" e "30 release" ovviamente sono comprensibilissimi.

Dai keycode ai keysym

Ora il sistema traduce i keycode in keysym (Key Symbols) tramite una tabella di corrispondenza tra keycode e keysym. I keysym sono in pratica i simboli che è possibile usare. Questi "nomi" sono solo a livello descrittivo e servono per rendere chiaro il significato che si vuole dare a un tasto o una combinazione di tasti. Però questi "nomi" non sono capiti dalle applicazioni della console, e quindi vedremo che servono dei passi in più. L'associazione tra keycode e keysym non è 1 a 1. Anzi solitamente si tende ad associare molti keysym a diverse combinazioni di keycode. Per esempio prendiamo i nostri soliti 4 tasti come vengono descritti nella mappa italiana di corrispondenza:

        keycode  30 = a

        keycode 111 = Remove

        keycode  14 = Delete Delete
control keycode  14 = Control_underscore
alt     keycode  14 = Meta_Delete

Le prima riga dice che il keycode 30 corrisponde al keysym "a" e sottointende che quando si preme la combinazione di keycode 42+30 cioè Shift+a si ottiene la "a maiuscola", cioè A. Se questa cosa non era sottointesa si doveva scrivere

keycode  30 = a A

La seconda riga dice che il keycode 111 corrisponde al keysym "Remove".

Infine le ultime 3 righe ci dicono che il keycode 14 corrisponde al keysym "Delete". Anche la combinazione 42+14 corrisponde a "Delete". Invece la combinazione Control + ← (tasti fisici), cioè ... (scancode), cioè ... (keycode) corrisponde al keysym "Control_underscore" e analogamente per Alt + ← (tasti fisici).

Dai keysym alle sequenze ASCII/UNICODE

Le applicazioni per la console non capiscono queste stringhe, questi "nomi" che abbiamo dato ai simboli, chiamate keysym. Possono solo capire sequenze di bit in una particolare codifica di caratteri. Di questo passaggio se ne occupa la console stessa che prende i keysym e li traduce in sequenze di bit da passare poi alle applicazioni che vengono lanciate da dentro di essa.

Queste sequenze di bit possono essere viste con il comando showkey -a.

Keysym         Decimal sequence
a                97 (a in ASCII)
A                65 (A in ASCII)
Remove           27 91 51 126 (ESC [ 3 ~ in ASCII)
Delete          127 (DEL in ASCII)

Dalle sequenze ASCII/UNICODE alle capabilities

Alcune applicazioni sono scritte con delle librerie particolari (ncurses) che permettono di "capire" e gestire lo spazio del terminale. Queste librerie hanno un componente, chiamato terminfo, che si occupa di alcune operazioni da fare sul terminale. Ad alcuni caratteri speciali devono essere assegnate quindi delle capabilities, cioè delle capacità secondo le convenzioni di terminfo. In sostanza si tratta di operazioni vere e proprie. Terminfo usa un "terminal database" dove ci sono scritte le associazioni tra sequenze ASCII/UNICODE e capabilities.

Per controllare cosa contengono i vari database usare

infocmp  (per il database attuale)
infocmp ... (per il database ...)

La modalità della tastiera

Usando il comando kbd_mode si può conoscere in che modalità il kernel sta inviando i segnali della tastiera al terminale attualmente in esecuzione. Nella console di Linux la modalità solitamente è Unicode (UTF-8) mode. In X la modalità è solitamente raw (scancode) mode.

Per cambiare mappa per esempio per adattarla a una tastiera non US, si può creare un'altra mappa predefinita per il kernel (assurdo) oppure si può caricare con il programma loadkeys una nuova mappa (creata con una sintassi particolare). Le mappe si trovano in /usr/share/keymaps/piattaforma/.

Ricordiamo che tale mappa di conversione serve solo se si usa la modalità ASCII o UNICODE, cioè in pratica solo quando si usa la console. Quando ci si trova nel sistema X, la modalità è quella RAW (cioè il server grafico prende in input direttamente i keycode e li gestisce a modo suo). Quindi per cambiare mappa di tastiera in X, il modo è completamente diverso.

Il programma dumpkeys serve per avere informazioni sull'attuale mappa per la tastiera utilizzata e per avere una lista di sequenza ASCII o UNICODE da associare ai keycode desiderati.

dumpkeys -l
dumpkeys -f

La tabella di conversione

Per passare dai keysym alle sequenze ASCII o UNICODE (modalità ASCII o UNICODE) c'è bisogno di una tabella di conversione. La tabella di default è sorgenti_linux/driver/char/defkeymap.c.

I livelli della tastiera

I livelli della tastiera sono (solitamente) al massimo 4. Il primo corrisponde alla normale pressione dei tasti, il secondo livello viene attivato dalla pressione del tasto Shift, il terzo dalla pressione del tasto AltGr (alternative group) e infine il quarto dalla pressione di Shift e AltGr.

Cosa accade in X?

Il problema dei tasti Del e ←

Il tasto Delete (Del) (Cancel (Canc) sulle tastiere italiane) cancella il carattere su cui si trova il cursore.

Il tasto ← cancella il carattere precedente rispetto a quello dove si trova il cursore e poi sposta il cursore a sinistra di un carattere. Questo tasto viene spesso chiamato Backspace ma, come dice il nome stesso, significa semplicemente che il cursore deve tornare indietro di una posizione (funzione molto utile nelle macchine da scrivere per sovrapporre dei simboli, per esempio accenti). Tecnicamente il carattere ASCII che bisognerebbe associare al vero Backspace è l'8 (decimale) cioè, non a caso, Backspace.

Per quanto riguarda il carattere associato a ← quindi, non deve essere l'8 (cioè backspace). Solitamente gli si associa il carattere 127 cioè DEL (da non confondere con il tasto Del).

Quindi prima di tutto bisogna chiedersi qual è il vero significato dei caratteri di controllo ASCII. L'ultima revisione dello standard ASCII è del 1986 (US ASCII, ANSI X3.4-1986 (ISO 646 International Reference Version)). Secondo questo documento i caratteri di controllo hanno il seguente significato:

Si capisce quindi che i caratteri ASCII utili ai nostri scopi sono solo BS e DEL. In linea di principio ← dovrebbe produrre BS + DEL mentre Del dovrebbe produrre solo DEL. Cioè il tasto ← arretrerebbe il cursore di una posizione e cancellerebbe il carattere sotto di esso. Il tasto Del invece cancellerebbe solo il carattere sotto il cursore.

Tasto fisico      ASCII
---------------------------
←                 BS DEL
Del               DEL

In pratica però si fa tutt'altro. Queste sono le direttive di Debian per quanto riguarda i tasti ← e Del: http://www.debian.org/doc/debian-policy/ch-opersys.html#s9.8. E infatti è quello che si ha anche nel nostro sistema Gentoo. Ecco qua sotto un quadro riassuntivo.

Tasto   Scanc   Keyc   Keysym   ASCII            terminfo  terminal
-------------------------------------------------------------------
Del     e0 53    111   Remove   ESC[3~ (^[[3~)    kdch1     
←       0e        14   Delete   DEL (^? o \177)   kbs       erase

CTRL+?  ?          ?   Delete   DEL (^? o \177)   kbs       erase
CTRL+H  ?          ?        ?   BS (^H)           
                                CAN (^X)           

Nella colonna ASCII abbiamo riportato anche i caratteri di controllo BS e CAN per completezza e per far vedere che non sono associati ad alcun tasto fisico. Infine nell'ultima colonna abbiamo riportato le impostazioni per la funzione erase dei terminali (alcuni terminali non usano terminfo per cancellare i caratteri ma si basano direttamente sul codice ASCII ricevuto).

In terminfo (ncurses) le capabilities che ci interessano sono kdch1 (delete character key), kbs (backspace key), key_sdc (shifted delete-character key). Ignoriamo l'ultima possibilità. kbs corrisponderebbe al nostro ← mentre kdch1 al nostro Del. In realtà dal nome kbs era meglio se corrispondesse solo al movimento del cursore verso sinistra di una posizione.

Se tutto funziona il programma ne deve funzionare dentro la console.

Manca da capire cosa accade sotto X. In questo caso i keycode vengono tradotti in keysym specifici per X. E poi la trafila prosegue come al solito nel caso degli emulatori di terminali. Per le applicazioni invece X passa direttamente i keysym.

In Gentoo, almeno nel mio caso, sotto X kbs non è più associato al carattere ASCII DEL bensì al carattere ASCII BS! Per controllare i caratteri generati da X usare xev. Il problema è dovuto al fatto che sotto X la variabile TERM è settata a xterm mentre nella console è settata a linux. Il terminal database linux è corretto. Il terminal database xterm no!!!! Ecco spiegato l'arcano! Per vedere la differenza tra questi terminal database basta dare il comando

infocmp linux xterm gnome
infocmp linux xterm gnome | grep kbs

La variabile TERM viene settata dal programma che lancia il terminale. Nel caso siate fisicamente davanti al PC e accedete in maniera testuale, il programma che lancia la console è agetty, cioè il programma che vi permette di fare il login. Questo programma è lanciato da init il cui file di configurazione è /etc/inittab. Ci saranno delle righe del tipo

c1:2345:respawn:/sbin/agetty 38400 tty1 linux

linux significa che il terminale è lanciato con la variabile TERM settata a linux.

Per quanto riguarda X non ho capito se esiste un posto unico dove settare la variabile TERM e che verrà usata poi dai vari emulatori di terminali (terminal in XFCE, ecc...). Nonostante questo potete cambiare la variabile TERM dentro le impostazioni dell'emulatore di terminale. Per esempio in Terminal, il terminale solitamente usato sotto XFCE, usa di default TERM=xterm. Cambiatelo a linux o gnome ecc... e il problema del tasto ← che non funziona nel programme ne verrà risolto. Attualmente in Terminal c'è un bug che non permette di settare la variabile TERM che rimane sempre al valore xterm. Per il momento per ovviare potete mettere export TERM=linux nel file di configurazione di bash.

Se usate PuTTY dovete aprire PuTTY (senza collegarvi ad alcuna macchina!), andate su Connection -> Data e nel riquadro Terminal details potete cambiare la casella Terminal-type string a ciò che desiderate. Quello sarà il valore assegnato alla variabile TERM. Usare linux o gnome va benissimo.

Se vi connettete da remoto usando ssh, la variabile TERM settata sul computer remoto è uguale alla variabile TERM del terminale da cui ci si connette.