jeudi 11 avril 2019

Chapitre 57 : saisie d'une seule touche


Une chaine de caractères peut être lue sur l’entrée standard du terminal par l’appel système Linux READ mais il est aussi intéressant d’avoir une fonction permettant l’attente et la saisie d’une seule touche. Hélas, il n’y a pas d’appel système qui effectue cette tâche et j’avais déjà cherché une solution il y a plus d’un an pour résoudre ce problème. J’avais été rebuté car des exemples en C montrait qu’il fallait utiliser la fonction tcgetattr et je n’avais pas trouver la correspondance avec un appel système.
Mais récemment j’ai trouvé un post sur stackoverflow qui donnait une solution en C et qui expliquait que la fonction tcgetattr pouvait être remplacée par l’appel système IOCTL que nous avons déjà utilisé.
J’ai donc traduit le programme C donné en exemple en assembleur ARM et cela fonctionne bien.
Dans ce programme, nous commençons à décrire les constantes nécessaires puis les structures TERMIOS, SIGATION et POLL qui permettent de gérer l’état du terminal, le traitement des signaux et la lecture du terminal puis dans la partie code, nous récupérons l’état initial du terminal avec l’appel système IOCTL et le code action TCGETS qui donc effectue la même action que tcgetaatr.
Ensuite à l’aide de l’appel système SIGACTION, nous déroutons les signaux SIGINT,SIGQUIT et SIGTERM vers une routine qui positionnera la variable iEnd à 1 pour terminer la boucle de lecture. Si nous n’avions pas fait cela, l’appui sur les touches ctrl-c terminerait le programme alors qu’il faut sortir de la boucle pour effectuer éventuellemnt des tâches.
Toujours à l’aide de SIGACTION, nous positionnons la non prise en compte du signal SIGTOUT qui concerne si j’ai bien compris les signaux provenant de process tournant à l’arrière-plan.
Puis nous récupérons à nouveau l’état du terminal et nous modifions les flags de la structure TERMIOS pour ne plus afficher la touche à l’écran (flag ECHO) et n’autoriser la saisie que d’une seule touche (flag ICANON).
Enfin, nous entrons dans une boucle qui va tester la variable iEnd pour se terminer puis préparer ‘appel système SYS_POOL qui va prendre en compte l’évènement appui sur une touche de la console standard d’entrée (STDIN). Si le code retour est supérieur à zéro, une touche a été appuyée et nous utilisons l’appel système READ pour lire le contenu dans un buffer. Ce buffer doit être d’une taille supérieure à un octet car certaines touches peuvent être codées sur 4 octets (flèches de direction par exemple). Nous affichons le contenu du buffer pour vérifier les frappes et nous testons aussi les codes q et Q pour terminer la boucle.
Enfin le programme se termine en restaurant le terminal à son état du début.
Il ne reste plus qu’à améliorer ce programme pour le transformer en fonction et ajouter dans la boucle lle ou les traitements appropriés.