2. La Tastiera

Indice di questa sezione

Cerchiamo di chiarire in breve come funziona la tastiera in Linux.

A questo scopo è molto utile il programma showkey(1), che permette di controllare il buon funzionamento della tastiera. Si può trovare in ``Il pacchetto kbd'' , assieme ai programmi per la gestione della tabella dei caratteri, loadkeys(1), dumpkeys(1) e una bellissima FAQ che consiglio di leggere. Viene comunque installata di default dalla maggior parte delle distribuzioni, slackware inclusa.

Quando premete un tasto sulla vostra tastiera, il controller interno della stessa spedisce una serie di valori (ScanCodes) al kernel. Esistono in commercio delle tastiere programmabili, ovvero delle tastiere con cui è possibile modificare gli scancodes generati.

Vedremo anche che ci sono molti altri modi meno dispendiosi, oltre che cambiare tastiera, per poter associare effetti diversi ai tasti.

ScanCode (Raw) Mode

Quando il kernel viene posto in questa modalità da un programma, non fa altro che passare, tali e quali, gli scancodes al programma che ne ha fatto richiesta.

Programmi che hanno questo comportamento sono, per esempio, X e DOOM.

Potete vedere gli scancode della vostra tastiera semplicemente facendo un showkey -s.

KeyCode (Medium Raw) Mode

Altrimenti il kernel converte gli scancode in eventi detti KeyCode composti da un flag, che indica se è un evento di tasto premuto o di tasto rilasciato, e da un numero identificativo del tasto stesso, tra l'altro seguendo l'ordine logico della tastiera, ovvero [ESC]=1, [F1]=2, ... Non esistono combinazioni. Anche il premere il tasto [ALT] o [CTRL] genera un KeyCode, mentre premere in contemporanea più tasti genera semplicemente più KeyCode di pressione corrispondenti.

Questi caratteri possono essere passati direttamente all'applicazione che ne fa richiesta in KeyCode mode. Non è molto usuale, infatti l'unica applicazione a me nota è showkey(1) che senza l'opzione -s serve proprio a fare vedere i KeyCode.

KeySim Mode

I KeyCode vengono filtrati dal kernel attraverso la KeyMap, ovvero una tabella di conversione. Non è un eufemismo, si tratta di una particolare tabella, un file di testo, che contiene tutte le conversioni KeyCode->KeySim. Questa conversione genera in uscita caratteri o stringhe (dette sequenze di escape) seguendo lo standard VT100, ovvero lo standard di terminale testo che Linux adotta per i suoi terminali virtuali, o virtual consoles.

Fanno parte di questa categoria la stragrande maggioranza degli applicativi, a partire da shells, editors e programmi vari.

2.1 Caso generale - Linux Console

Come abbiamo visto, possiamo agire al livello 3, modificando la KeyMap, per poter ottenere tutto quello che vogliamo.

E' sufficiente impartire il comando loadkeys /usr/lib/kbd/keytables/it.map per riconfigurare la tastiera. Il file it.map è ormai presente in tutte le distribuzioni, correttamente installato e configurato. Inoltre supporta alcune aggiunte molto comode per i programmatori, come le parentesi graffe e il carattere tilde ottenuti premendo [AltGr+8], [AltGr+9] e [AltGr+0] rispettivamente.

Ovviamente la modifica della tabella interessa tutto il sistema, anche se solitamente anche un utente comune può compiere questa operazione. Si consiglia quindi, quando comporti problemi di sicurezza, di impedire l'esecuzione dei programmi citati a utenti diversi da root, agendo sui permessi di esecuzione dei file.

Di solito conviene aggiungere questo comando nel file /etc/rc.d/rc.local, in modo che venga eseguito ad ogni avvio del SO.

Altro programma utile oltre al già citato showkey(1) è dumpkey(1) che produce in output la tabella di conversione corrente. Si considerano utili letture le manpages di questi programmi.

2.2 Programmi ``buoni''..

Fano parte di questa categoria tutti quei programmi che lavorano con i KeySim generati dal kernel nella maniera descritta prima.

Il problema maggiore, in questi casi, è quello di completare la dotazione di comandi del programma, di modo che il suo uso ne sia semplificato.

Shells (interpreti di comandi)

tcsh

tcsh(1) è dotata di un comando che serve ad assegnare delle macro a dei KeySym, ovvero bindkey.

Ad esempio, aggiungendo questo nel proprio $(HOME)/.cshrc (oppure per rendere valida la modifica per tutti gli utenti in /etc/csh.cshrc come root) si ottiene la possibilita' di usare i tasti [Home],[End] e [Canc] con i loro corretti siglificati:


        if ($term == "xterm" || $term == "vt100" \
                || $term == "vt102" || $term !~ "con*") then
                # bind keypad keys for console, vt100, vt102, xterm
                bindkey "\e[1~" beginning-of-line  # Home
                bindkey "\e[2~" overwrite-mode     # Ins
                bindkey "\e[3~" delete-char        # Delete
                bindkey "\e[4~" end-of-line        # End
        endif

Comunque sempre meglio riguardarsi la man page di tcsh(1) per ulteriori chiarimenti e approfondimenti.

bash

Similmente a quanto fatto per tcsh, aggiungendo nel file $(HOME)/.inputrc le seguenti righe:


        "\e[1~": beginning-of-line
        "\e[3~": delete-char
        "\e[4~": end-of-line

ci si ritrova con i tasti [Home], [Canc], e [Fine] correttamente rispondenti alle funzioni che uno si aspetta.

Anche qui la man page di bash(1) è lettura caldamente consigliata.

Editors

Emacs 19

Emacs soffre di una grossa problematica. Il tasto [BackSpace] genera in linux il carattere ascii Ctrl-H (o 0x08), che sfortunatamente, da quando esiste emacs sulla terra, è anche il caratere con il quale viene richiamato l'help, e che, per rendere le cose ancora piu' semplici, e' lo stesso che viene generato comunque premendo [Ctrl+H].

Insomma, le scelte sono due. O si rimappa BS su qualche altro tasto, o su qualche combianzione di tasti, oppure si sposta il tasto di help da qualche altra parte.

Ho scelto di seguire la seconda via. I cultori di Emacs non se l'abbiano a a male, questo non vuole essere un golpe...

Emacs 19 ha una funzione del linguaggio interno elisp define-key che serve proprio ad assegnare i tasti.

In questo modo vedremo di sistemate le cose, ovvero assegnamo al tasto BS il suo vero significato, spostando il tasto per richiamare l'help su qualche altro tasto

Piazzando questo nel proprio $(HOME)/.emacs:


        ;; map function keys on PC keyboard
        (setq term (getenv "TERM"))
        (if (or 
                (string= "xterm" term)
                (string= "con" (substring term 0 3)) ; linux consoles
                (string= "vt100" term)
                (string= "vt102" term))
                (progn
                (defun my-setkey-hook ()
                (define-key function-key-map "\e[1~" [home])
                (define-key function-key-map "\e[2~" [insert])
                (define-key function-key-map "\e[3~" [delete])
                (define-key function-key-map "\e[4~" [end])
                ;; these are just my own sequences
                ;; so I can use the keys under Emacs
                (define-key function-key-map "\e[40~" [C-prior])
                (define-key function-key-map "\e[41~" [C-next])
                ;; function keys: use same mapping as xterm
                (define-key function-key-map "\e[11~" [f1])
                (define-key function-key-map "\e[12~" [f2]) 
                ;; ...
                (define-key function-key-map "\e[24~" [f12])
                (define-key function-key-map "\e[25~" [S-f1])
                (define-key function-key-map "\e[26~" [S-f2])
                ;; ...
                (define-key function-key-map "\e[39~" [S-f12])
                )
                (add-hook 'term-setup-hook 'my-setkey-hook)
                )
        ()
        )

Ovviamente tutto deve essere così com'è, ovvero emacs fa molta differenza tra maiuscolo e minuscolo.

Ora che abbiamo assegnato dei codici ai tasti, dobbiamo assegnare delle funziondi da eseguire! Anche qui emacs ci viene in aiuto con il comando interno global-set-key. Al solito, aggiungendo questo nel file $(HOME)/.emacs:


        (global-set-key [delete] 'delete-char)
        (global-set-key [home] 'beginning-of-line)      ; you might not want this
        (global-set-key [end] 'end-of-line)             ; nor this
        (global-set-key [C-prior] 'beginning-of-buffer)
        (global-set-key [C-next] 'end-of-buffer)
    
        (global-set-key [f1] 'help-for-help)
        ;; ...
        (global-set-key [S-f12] 'info)

Le cose dovrebbero andare a posto.

Come sempre la lettura della man page di emacs, o meglio del suo help ipertestuale in formato info e' consigliata per saperne di piu'. Si ottiene con emacs -f info.

Altri Programmi

less

Il comando lesskey(1) premette di rimappare i tasti per less(1), che è il pager, ovvero il visualizzatore di file testo che viene implicitamente usato da man (e da qualche altro centinaio di programmi...). Aggiungendo le seguenti cose nel proprio $(HOME)/.lessrc:


        # aggiunge la gestione dei tasti cursore a less
        \e[A   back-line     
        \e[B   forw-line      
        \e[C   next-file
        \e[D   prev-file
        \eOA   back-line     
        \eOB   forw-line      
        \eOC   next-file
        \eOD   prev-file
        \e[6~  forw-scroll
        \e[5~  back-scroll 
        \e[1~  goto-line
        \e[4~  goto-end

Eseguendo lesskey il file genererà automaticamente il file .less con le impostazioni corrette.

Come sempre, la lettura delle man pages di less(1) e lesskey(1) sono letture consigliate.

2.3 Configurazione di XFree86

Come abbiamo già accennato in precedenza, X(1) si riporta in modalità ScanCode, ovvero và ad interagire direttamente con l'hardware, il controller della tastiera.

X inoltre utilizza le sue convenzioni per la gestione dei tasti, ovviamente diversa da quella di Linux.

X associa ad ogni tasto un codice (e fin qui niente di diverso), assieme a dei Modifiers, ovvero dei modificatori, ovvero dei flags che indicano la contemporanea pressione dei tasti CTRL, ALT, SHIFT, META, SUPER, HYPER.

Tutti i codici associati ai tasti possono essere visti nel file /usr/lib/X11/XKeysymDB. Occhio che non è un file di gestione della tastiera, ma solo un database di nomi di tasti!!! Insomma, non picchignate...

Tutte quese cose possono essere anche viste utilizzando il programma xev, che monitorizza e visualizza tutti gli eventi di X.

Ovviamente X fa il possibile per rendere indolore il passaggio dalla console al modo grafico. Cerca di ricavare da linux tutto quello che gli serve per inizializzare il suo driver di tastiera.

Il problema è che sbaglia miseramente, ovviamente sul solito, sfortunato, tasto di [BackSpace].

Bisogna aggiustare le cose a mano, con il programma xmodmap(1), ma vedremo che questo di solito non basta.

X server

Come prima cosa bisogna avvisare X che abbiamo intenzione di usare [AltGr] come modificatore META. (Non vi ricordate? era una di quelle imbarazzanti domande che vi ha posto xf86config(1)...)

A tal fine è bene che ci sia una riga come questa nel vostro XF86Config(1)


        Section "Keyboard"

        [...]

        LeftAlt     Meta
        RightAlt    ModeShift

        EndSection

Ora non resta che modificare i KeySym associati a BS e DEL.

Ovviamente xmodmap(1) non fa altro che associare KeySym a X KeyCodes, come il buon vecchio loadkeys.

Qui, a meno di volersi lanciare in una completa personalizzazione della tastiera, basta correggere la scorretta impostazione dei tasti BS e DEL.

I metodi sono 2:

O si crea un file $(HOME)/.Xmodmap così fatto:


        keycode 22 = BackSpace
        keycode 107 = Delete

e si fa in modo che il proprio $(HOME)/.xinitrc o il generale /var/X11R6/lib/xinit/xinitrc abbia una riga del tipo


        usermodmap=$HOME/.Xmodmap

        if [ -f $usermodmap ]; then
                xmodmap $usermodmap
        fi

Oppure inserire direttamente in $(HOME)/.xinitrc o /var/X11R6/lib/xinit/xinitrc le righe:


        # map the <BackSpace> key to the [BackSpace] keysym.
        xmodmap -e "keycode 22 = BackSpace"
        # map the <Delete> key to the [Delete] keysym.
        xmodmap -e "keycode 107 = Delete"

che eseguono direttamente la reinizializzazione.

ATTENZIONE che /var/X11R6/lib/xinit/xinitrc o $(HOME)/.xinitrc devono avere sempre come ultima riga eseguibile il nome del window manager, di solito fvwm(1), altrimenti X esce appena eseguito la lista di elementi nei suddetti file.

Consiglio caldamente, se si vuole fare il proprio $(HOME)/.xinitrc, di copiarlo da quello generale e fare SOLO AGGIUNTE!!!

X applications

Le X applications di solito vengono configurate via risorse. Le risorse sono dei file che vengono caricati da X (/var/X11R6/lib/xinit/.Xresources, e poi $HOME/.Xresources) nel momento dell'avvio, e poi dei file, che hanno però la stessa sitassi, che vengono caricati da ogni applicazione e che si trovano tutti in /var/X11R6/lib/app-defaults.

Queste impostazioni vengono gestite da un resource manager, ovvero un programma che si accolla la responsabilità di inserire, modificare, aggiornare dei valori in un database.

Questo accade nel solito /var/X11R6/lib/xinit/xinitrc o $(HOME)/.xinitrc, precisamente alle righe:


        userresources=$HOME/.Xresources
        sysresources=/var/X11R6/lib/xinit/.Xresources

        if [ -f $sysresources ]; then
                xrdb -load $sysresources
        fi

        if [ -f $userresources ]; then
                xrdb -load $userresources
        fi

Anche qui una lettura delle man page di X(1) e xrdb sono consigliate per chiarirsi le idee.

Programmi di emulazione terminale

In questo caso dobbiamo cercare di convertire la pressione dei tasti in X in codici VT100 compatibili, che ormai sappiamo essere lo standard di Linux, da mandare attraverso il programma di emulazione terminale.

Tutto questo NON si applica a rxvt(1), che per adesso resta un caso patologico a parte.

Famiglia degli xterm (xterm, color_xterm, ...)

Aggiungendo queste righe nel proprio $(HOME)/.Xresources:


        *VT100.Translations: #override <Key>BackSpace: string(0x7F)\n\
                <Key>Delete:    string(0x1b) string("[3~")\n\
                <Key>Home:      string(0x1b) string("[1~")\n\
                <Key>End:       string(0x1b) string("[4~")\n\
                Ctrl<Key>Prior: string(0x1b) string("[40~")\n\
                Ctrl<Key>Next:  string(0x1b) string("[41~")

tutti i programmi, shell e cose varie che girano nell'xterm si dovrebbero comportare tali quali che in console.

Ma a me non funge niente. Funziona solo la shell (che mi fa end, home e cose varie, ma gli editor non fungono una tega...)

Editors

Emacs 19

In teoria le cose dovrebbero essere già a posto.

Il problema è che emacs è un programma tasto-dipendente, ovvero fa un uso smodato di combinazioni di tasti.

Il consiglio che vi do è che, se vi trovate con combinazioni di tasti non mappati o con comportamenti stani, provate a vedere, in un buffer vuoto, che cosa genera la pressione del tasto usando il comando view-lossage (di solito [Ctrl+h] [l]) per vedere che cosa e' stato generato.

Poi non vi resta che aggiungere una riga al vostro file $HOME/.emacs visto sopra.

Altro

Applicazioni OpenWindows e OpenWindows stesso

Non funge assolutamente niente. Provare con TextEdit, se ne strafrega delle impostazioni. Continua a generare BS quando si preme DEL.

Mi viene da piangere...

Applicazioni Motif

Anche in Motif il tasto [Delete] da molti problemi. Un esempio di queste applicazioni è Mosaic o Netscape. Su consiglio di Ted Stern , basta aggiungere queste righe nel proprio $HOME/.Xdefaults:


        !
        !  To make Backspace delete-previous-character and Delete
        !  delete-next-character in Motif applications generally ...
        !
        *XmText.translations:      #override \n\
                ~a <Key>osfBackSpace: delete-previous-character() \n\
                ~a <Key>osfDelete: delete-next-character() \n\
                a <Key>osfDelete: delete-previous-word() \n\
                c <Key>d: delete-next-character() \n\
                a <Key>d: delete-next-word() \n\
                c <Key>a: beginning-of-line() \n\
                c <Key>e: end-of-line() \n\
                c <Key>k: delete-to-end-of-line() \n\
                a <Key>Left: backward-word() \n\
                a <Key>Right: forward-word()
    
        *XmTextField.translations:      #override \n\
                ~a <Key>osfBackSpace: delete-previous-character() \n\
                ~a <Key>osfDelete: delete-next-character() \n\
                a <Key>osfDelete: delete-previous-word() \n\
                c <Key>d: delete-next-character() \n\
                a <Key>d: delete-next-word() \n\
                c <Key>a: beginning-of-line() \n\
                c <Key>e: end-of-line() \n\
                c <Key>k: delete-to-end-of-line() \n\
                a <Key>Left: backward-word() \n\
                a <Key>Right: forward-word()

Ovviamente questo richiede comunque che i tasti [BackSpace] e [Delete] generino i corretti KeySyms.


Capitolo Successivo, Capitolo Precedente

Indice di questo capitolo, Indice generale

Inizio del documento, Inizio di questo Capitolo