Comment faire en sorte que les touches fléchées et le retour arrière fonctionnent correctement lorsque vous demandez une entrée à un utilisateur du programme C à l’aide de termios.h?

J’ai donc le code suivant qui lit simplement les caractères saisis par l’utilisateur et les affiche jusqu’à ce que ‘q’ soit entré.

#include #include #include #include int main(void) { char c; static struct termios oldtio, newtio; tcgetattr(0, &oldtio); newtio = oldtio; newtio.c_lflag &= ~ICANON; newtio.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &newtio); printf("Give text: "); fflush(stdout); while (1) { read(0, &c, 1); printf("%c", c); fflush(stdout); if (c == 'q') { break; } } printf("\n"); tcsetattr(0, TCSANOW, &oldtio); return 0; } 

Au début de la fonction principale, je désactive le mode canonique pour permettre à l’utilisateur de voir son entrée lorsqu’il le donne. Je désactive également l’écho pour que des choses comme “^ [[A” “] n’apparaissent pas lorsque vous appuyez sur la flèche vers le haut, par exemple. Cela fonctionne, mais je peux également déplacer le curseur vers les lignes supérieures de la fenêtre d’un terminal, ce qui n’est pas bon. Existe-t-il un moyen de résoudre ce problème afin que l’utilisateur ne puisse se déplacer que dans la ligne en cours?

Un autre problème est le backspace. Lorsque j’appuie dessus, le programme imprime un symbole étrange (ce qui, je suppose, est 0x7f) au lieu d’effacer le caractère laissé à l’emplacement actuel du curseur. Je devrais probablement gérer la sortie de la touche de retour arrière dans le programme, mais je ne sais pas comment le faire car il s’agit de ce nombre hexadécimal étrange. Des conseils pour cela?

Une option à laquelle je pensais aussi pour rendre ce travail efficace consiste à utiliser le mode canonique afin que les fonctionnalités des touches de direction et de retour arrière soient automatiquement utilisées. Cependant, le mode canonique fonctionne ligne par ligne et le texte n’apparaît donc pas tant que l’utilisateur n’a pas appuyé sur “Entrée”. Jusqu’à présent, je n’ai trouvé aucun moyen de faire en sorte que l’utilisateur voie ses commentaires lors de la frappe. Est-ce seulement possible?

Et s’il vous plaît, pas de suggestions ncurses ou readline. Je veux faire cela en utilisant termios.h.

avez-vous regardé dans les pages de manuel? (devrait être man termios ou regarder quelque part en ligne )

Là j’ai trouvé le drapeau ECHOE qui aurait l’effet suivant:

Si ICANON est également défini, le caractère ERASE efface le caractère saisi précédemment et WERASE efface le mot précédent.

Cela devrait résoudre votre problème de retour arrière?

Je suggère également que vous examiniez les exemples de la page de manuel. Par exemple, vous pouvez faire ce qui suit:

 newtio.c_lflag &= ~(ECHO | ECHOE | ICANON); 

… pour définir plus d’un drapeau à la fois sur une seule ligne. Je sais que les pages de manuel sont difficiles à lire pour les débutants, mais vous vous y habituerez et plus vous les utiliserez, plus elles deviendront efficaces pour la recherche de fonctions C / POSIX, etc. (juste au cas où vous ne les utiliseriez pas). en tous cas).

Le problème de la touche flèche : Peut être pourriez-vous essayer la fonction cfmakeraw() ; sa description semble prometteuse. Je n’ai pas eu le temps d’enquêter davantage sur les touches de direction. Cependant, vous trouverez peut-être quelque chose d’autre d’utile dans la page de manuel.

BTW: termios semble intéressant, je me suis toujours demandé quelles fonctions certains programmes en ligne de commande utilisent; appris quelque chose par votre question, merci!

MODIFIER

J’ai fait d’autres recherches ce week-end. Le symbole “étrange” imprimé lorsque vous appuyez sur la touche Retour arrière est assez facile à masquer. C’est la valeur ASCII 0x7f . Alors ajoutez un simple

 if (c == 0x7f) { continue; } 

… simplement ignorer la touche de retour arrière. Ou manipulez-le de manière à supprimer le dernier caractère (voir l’exemple de code ci-dessous).

Cette solution de contournement simple ne fonctionne pas pour les touches de direction, car il ne s’agit pas de caractères ASCII: / Cependant, ces deux sujets m’ont aidé à gérer également ce problème: sujet 1 et sujet 2 . En gros, en appuyant sur les touches fléchées, une série de caractères est envoyée à stdin (voir le deuxième lien pour plus d’informations).

Voici mon code complet qui (je pense) fonctionne comme vous le souhaitez:

 #include  #include  #include  #include  int main(void) { char c; static struct termios oldtio, newtio; tcgetattr(0, &oldtio); newtio = oldtio; newtio.c_lflag &= ~ICANON; newtio.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &newtio); printf("Give text:\n"); fflush(stdout); while (1) { c = getchar(); // is this an escape sequence? if (c == 27) { // "throw away" next two characters which specify escape sequence c = getchar(); c = getchar(); continue; } // if backspace if (c == 0x7f) { // go one char left printf("\b"); // overwrite the char with whitespace printf(" "); // go back to "now removed char position" printf("\b"); continue; } if (c == 'q') { break; } printf("%c", c); } printf("\n"); tcsetattr(0, TCSANOW, &oldtio); return 0; } 

En passant, vous pouvez obtenir les séquences d’échappement complètes à l’aide du code suivant:

 int main(void) { char c; while (1) { c = getchar(); printf("%d", c); } return 0; } 

Je pense que je n’ai pas à dire que cette chose complète est un sale coup et qu’il est facile d’oublier de manipuler des clés spéciales. Par exemple, dans mon code, je ne gère pas les touches de page-up/down … -> le code ci-dessus est loin d’être complet, mais vous donne un sharepoint départ. Vous devriez également jeter un coup d’œil à terminfo qui peut vous fournir beaucoup d’informations nécessaires; cela devrait également aider avec une solution plus portable. Comme vous le voyez, cette chose “simple” peut devenir assez complexe. Vous pourriez donc repenser votre décision contre ncurses 🙂

En fait, pour manipuler les touches fléchées, vous devez implémenter un bloc de bonne taille de ncurses. Il y a des avantages / inconvénients: le principal inconvénient de l’utilisation de ncurses dans une application en ligne de commande peut être qu’elle efface généralement l’écran. Cependant, (n) curses fournit un filtre de fonction. Il existe un exemple de programme “test / filter.c” dans la source ncurses qui illustre cela en utilisant la touche flèche gauche comme caractère d’effacement et en passant la ligne résultante à system () pour exécuter des commandes simples. L’échantillon comporte moins de 100 lignes de code, ce qui semble plus simple et plus complet que les exemples ci-dessus.