Un OSD de capture clavier en bash

Impossible de trouver un outil OSD de capture clavier qui puisse fonctionner convenablement avec un tilling desktop... car évidemment tous les outils que j'ai trouvé me place la capture dans la mosaïque... Comme je suis en vacance, je me suis pris 25 minutes à coder un truc qui marche en bash, et qui fasse du vrai OSD (On Screen Display), c'est à dire "sans fenêtre". Et comme je suis gentil, je vous montre :)

Je cherchais sur le net un outil qui afficherait ce que je tape au clavier sur l'écran. Histoire de faire des captures pour des didacticiels vidéo. J'ai cherché un peu partout, rien ne me plaisait vraiment... je me suis alors penché sur une solution à coder. Deux outils sont utilisés: xosd et xinput. OSD voulant dire: On Screen Display, c'est à dire "Affichage sur l'écran"

Je suis d'abord parti en Python... puis en quelques minutes je me suis dit que "finalement, en bash, ce sera tout aussi simple à gérer"... vous me pensez fou, c'est pas faux...

Pourquoi utiliser un vrai OSD ? tout simplement parce que ça m'énervait d'avoir une fenêtre qui affiche les contrôles... je bosse sur Xmonad, et par conséquent le mode "tilling" en fait baver les outils que j'ai trouvé...

Avant de pouvoir utiliser mon script il vous faudra installer 3 paquets (je ne sais pas lesquels sont là par défaut):

yum install util-linux xosd xorg-x11-apps

Cela vous donne quelques commandes que mon script utilise:

  • xinput qui va capter ce que vous tapez
  • osd_cat qui affiche des choses sur l'écran
  • script qui va capturer une sortie terminal

Le script que vous allez voir par la suite fait quelques manipulations:

  • trouve le clavier par défaut: je cherche un clavier qui a "AT" dans "xinput --list"
  • lance la capture des touches via "xinput test ID" où ID est l'identifiant du clavier trouvé ci-dessus
  • faire tourner ça dans "script" qui écrit le typescript dans /dev/null, mais dont la sortie sera captée dans un FIFO
  • cherche la correspondance de clef clavier dans "xmodmap -pke" et écrit ça dans un autre FIFO
  • et enfin, en boucle, on lit le FIFO de sortie clavier qu'on inject dans "osd_cat" avec des options de couleur, de placement, de fontes...

Je me suis amusé à savoir si on pressait une touche de modification (Maj, Ctrl, Super...) pour concaténer les chaines.

Le script est loin d'être parfait, il affiche mal la touche "AltGr" et vous ne pouvez pas non plus faire des maintiens de touches trop complexe en séquence. Par exemple il est impossible de presser:

Ctrl+shift+a puis relacher shift et a en gardant Ctrl pessé et frapper une autre touche sans relacher Ctrl

Bref, le but était de faire un truc fonctionnel, rapidement, et qui me permette de faire à peu près ce que je veux... Je ferai évoluer le script et je le mettrai à jour ici.

Attention les yeux, voici le script:

#!/bin/bash
#author Patrice Ferlet
#Licence BSD
 
 
#some conf vars
COLOR="Purple"
FONT='-*-terminus-*-*-*-*-32-*-*-*-*-*-*-*'
DELAY="5"
XPOS="center"
YPOS="bottom"
OFFSET="15"
INDENT="80"
MAXLINE=3
 
#FIFOS
_tmp_opt=""
if [[ -d /dev/shm ]]; then
    #some unix can use shared memory instead of /tmp
    _tmp_opt=" --tmpdir=/dev/shm"
fi
 
OSDPID=""
TMP=$(mktemp -u $_tmp_opt)
OSD=$(mktemp -u $_tmp_opt)
mkfifo $TMP
mkfifo $OSD
 
 
#when script is closed, remove fifos
onexit(){
    echo "close..."
    kill $OSDPID
    rm -f $TMP
    rm -f $OSD
    exit 0
}
trap onexit INT TERM
 
#get valid keyboard input
kb=$(xinput --list | grep "keyboard" | grep "AT" | grep -Po "id=\d+" | cut -d"=" -f2)
 
#launch "script" to capture xinput, this is a trick !
script -c "xinput test $kb" -f /dev/null > $TMP &
 
#lauch osd command that read OSD fifo
tail -f $OSD | osd_cat -a -d $DELAY -l $MAXLINE -f $FONT -A $XPOS -o $OFFSET -i $INDENT -p $YPOS -c $COLOR &
OSDPID=$!
 
#be sure everything is launched
sleep 0.2
 
#now, read lines from xinput output to do the job
MOD=""
while read line; do
    #reading code, state (press, release) and get keyboard value
    #from xmodmap
    code=$(echo "$line" | awk '{print $3}')
    state=$(echo "$line" | awk '{print $2}')
    key=$(xmodmap -pke | awk "/keycode\s*$code\s+/ {print \$4}")
 
    if [[ $(echo "$key" | grep -Pi "Control|Shift|Alt|Super") ]]; then
        #this case should not be displayed, we only record mod key
        MOD="$MOD$key + "
        if [[ "$state" == "release" ]]; then
            #mod released, remove mod
            MOD=""
        fi
    elif [[ $state == "press" ]]; then
        if [[ $( echo "$MOD" | grep "Shift") ]]; then
            #shift pressed, we should read 5th column
            key=$(xmodmap -pke | awk "/keycode\s*$code\s+/ {print \$5}")
        fi
        echo "$MOD$key" > $OSD
    fi
done < $TMP
exit 1

Vous lancez ce script dans un terminal, puis n'importe où vous pressez des touches... Cela les affiches en OSD. Voilà, c'est ce que je voulais... rien de plus.

OSD keys Bash

Pour arrêter le script, retournez sur le terminal et pessez CTRL+c, cela coupe le script, en supprimant les FIFO en passant.

Voilà, si vous avez des questions, des remarques... je suis preneur !

UPDATE: et oui, il manque un truc... je coupe pas osd_cat à la fermeture, je corrige le script de suite... désolé UPDATE: Voilà, corrigé