Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

lecture au vol du clavier, c et ubuntu

9 réponses
Avatar
Alex
Bonsoir à tous,

je débute en c, et j'utilise anjuta avec une distrib ubuntu.

je cherche dans un thread à récupérer la frappe de n'importe quel
caractère au clavier, au début je pensai utiliser getc, mais cette
fonction n'est pas implémenté sous linux.

ce que je veux obtenir c'est que la frappe d'une seule touche, la lettre
D par exemple, me rende de suite la main.

En attendant de vous lire, bonne nuit à tous et A+

Alex

9 réponses

Avatar
Vivien MOREAU
On 2010-02-06, Alex wrote:

je cherche dans un thread à récupérer la frappe de n'importe quel
caractère au clavier, au début je pensai utiliser getc, mais cette
fonction n'est pas implémenté sous linux.



Tu te trompes, getc() fait partie de la bibliothèque standard et ton
système l'implémente au travers de la glibc. Tape donc man getc dans un
terminal.

[ snip le reste sur lequel je n'ai pas encore assez de recul... ]



--
Vivien MOREAU / vpm

« Unix is simple. It just takes a genius to understand its simplicity »
Dennis M. Ritchie
Avatar
Samuel Devulder
Alex a écrit :
Bonsoir à tous,

je débute en c, et j'utilise anjuta avec une distrib ubuntu.

je cherche dans un thread à récupérer la frappe de n'importe quel
caractère au clavier, au début je pensai utiliser getc, mais cette
fonction n'est pas implémenté sous linux.

ce que je veux obtenir c'est que la frappe d'une seule touche, la lettre
D par exemple, me rende de suite la main.

En attendant de vous lire, bonne nuit à tous et A+



C'est pas vraiment un problème de C, mais un problème d'API. Est-ce que
tu fais du X11 ou du terminal texte? Si c'est du texte, il faut utiliser
changer les paramètres du terminal pour le faire passer en mode raw
(i.e. il n'interprète pas les séquences), non bloquant, et sans echo, et
enfin lire les caractères.

Il y a plusieurs façon de faire cela:

1/ utiliser termios

#include <termios.h>

int l_getch (void) {
static struct termios term, back;
int ret = -1;

tcgetattr (0, &term); //get term info
memcpy (&back, &term, sizeof(term));

term.c_lflag &= ~(ICANON|ECHO); //change term attr
term.c_cc[VTIME] = 1; //latency
term.c_cc[VMIN] = 1; //nb char

tcsetattr(0, TCSANOW, &term); //change stdin attr
ret = getchar();
tcsetattr(0, TCSANOW, &back); //restore attr

return ret;
}

2/ passer par ioctl
On peut aussi faire la même chose ne remplacant tcgetattr() par un appel
direct à ioctl():

#include <sys/ioctl.h>

ioctl(fd, TIOCGETA, &t);
t.c_lflag &= ~(ICANON|ECHO);

t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 1;
ioctl(fd, TIOCSETA, &t);


3/ utiliser curses
Une autre possibilité, utiliser getch() de l'API curses/ncurses.

Dans tous les cas il faut se référer à la doc de l'api:
1/ man termios
2/ man ioctl, man ioctl_list
3/ man ncurses

Maintenant tu parles de thread.. et olà il faut faire gaffe à la
ré-entrance (en gros qu'un seul thread accède au clavier à la fois).

sam (use the "man", man!)
Avatar
espie
In article <4b6df1ce$0$673$,
Samuel Devulder <samuel-dot-devulder-at-geensoft-dot-com> wrote:

3/ utiliser curses
Une autre possibilité, utiliser getch() de l'API curses/ncurses.



A peu pres le seul conseil raisonnable que tu donnes... ;-)

Deja, eviter les ioctl direct si on peut, parce que c'est generalement
tres peu portable, c'est pour ca qu'on a pondu termios.

MAIS l'utilisation directe de termios n'est pas simple: ca necessite de
comprendre une bonne partie du systeme, a savoir les terminaux, mais aussi
la notion de terminal de controle et les interactions avec les signaux.
Vois-tu, tu n'as aucune garantie que le shell, lorsqu'il reprend la main,
va remettre le terminal en bon etat (meme si c'est souvent ce qui se passe) ->
du coup, jouer avec termios sans intercepter TOUS les signaux qui peuvent
interrompre ton programme, de facon temporaire ou definitive, c'est le
bordel.

Globalement, curses ou assimile est un bon compromis...
Avatar
Alex
Samuel Devulder a écrit :
Alex a écrit :
Bonsoir à tous,

je débute en c, et j'utilise anjuta avec une distrib ubuntu.

je cherche dans un thread à récupérer la frappe de n'importe quel
caractère au clavier, au début je pensai utiliser getc, mais cette
fonction n'est pas implémenté sous linux.

ce que je veux obtenir c'est que la frappe d'une seule touche, la lettre
D par exemple, me rende de suite la main.

En attendant de vous lire, bonne nuit à tous et A+



C'est pas vraiment un problème de C, mais un problème d'API. Est-ce que
tu fais du X11 ou du terminal texte? Si c'est du texte, il faut utiliser
changer les paramètres du terminal pour le faire passer en mode raw
(i.e. il n'interprète pas les séquences), non bloquant, et sans echo, et
enfin lire les caractères.

Il y a plusieurs façon de faire cela:

1/ utiliser termios

#include <termios.h>

int l_getch (void) {
static struct termios term, back;
int ret = -1;

tcgetattr (0, &term); //get term info
memcpy (&back, &term, sizeof(term));

term.c_lflag &= ~(ICANON|ECHO); //change term attr
term.c_cc[VTIME] = 1; //latency
term.c_cc[VMIN] = 1; //nb char

tcsetattr(0, TCSANOW, &term); //change stdin attr
ret = getchar();
tcsetattr(0, TCSANOW, &back); //restore attr

return ret;
}

2/ passer par ioctl
On peut aussi faire la même chose ne remplacant tcgetattr() par un appel
direct à ioctl():

#include <sys/ioctl.h>

ioctl(fd, TIOCGETA, &t);
t.c_lflag &= ~(ICANON|ECHO);
t.c_cc[VMIN] = 1;
t.c_cc[VTIME] = 1;
ioctl(fd, TIOCSETA, &t);


3/ utiliser curses
Une autre possibilité, utiliser getch() de l'API curses/ncurses.

Dans tous les cas il faut se référer à la doc de l'api:
1/ man termios
2/ man ioctl, man ioctl_list
3/ man ncurses

Maintenant tu parles de thread.. et olà il faut faire gaffe à la
ré-entrance (en gros qu'un seul thread accède au clavier à la fois).

sam (use the "man", man!)



Bonjour,

Merci pour la qualité de ta réponse, c'est en plus exactement celle que
j'attendai, j'ai parcouru temio.h et sys/termio.h, je commence un peu à
comprendre comment cela fonctionne.

L'objectif est de concevoir un bout de programme qui lit des commandes
qui arrivent dans un fichier texte, et qui les envoie sur un port série
vers un dispositif électronique d'asservissement.
Le thread devrait servir à pouvoir interrompre le traitement si on appui
sur une touche particulière du clavier.

En tout cas merci encore, je vais lire avec plus d'attention tous tes posts.

Cordialement
Alex.
Avatar
Alex
Vivien MOREAU a écrit :
On 2010-02-06, Alex wrote:

je cherche dans un thread à récupérer la frappe de n'importe quel
caractère au clavier, au début je pensai utiliser getc, mais cette
fonction n'est pas implémenté sous linux.



Tu te trompes, getc() fait partie de la bibliothèque standard et ton
système l'implémente au travers de la glibc. Tape donc man getc dans un
terminal.

[ snip le reste sur lequel je n'ai pas encore assez de recul... ]






Bonjour Vivien,

Meci pour ta réponse, en effet tu as raison, j'avai oublié de mettre à
jour le fichier MAKE avec -lncurses

AM_CFLAGS =
-Wall
-g
-lncurses
-pthread

Merci encore, cordialement;
Alex
Avatar
-ed-
On 6 fév, 23:23, Alex wrote:
je débute en c, et j'utilise anjuta avec une distrib ubuntu.

je cherche dans un thread à récupérer la frappe de n'importe quel
caractère au clavier, au début je pensai utiliser getc, mais cette
fonction n'est pas implémenté sous linux.



getc() est bel et bien implémentée sous Linux ! (c'est une fonction
standard identique à getchar()). Par contre, je suppose que tu parles
de getch(), comme sous DOS/Windows/conio qui permet d'extraire un
caractère du tampon du clavier sans attendre qu'on frappe <ENTER> (ce
qui oblige à gérer la correction de frappe 'à la main').

Dans ce cas, il faut utiliser des fonctions de termios qui permettent
de faire une entrée 'raw' qui se comporte de la sorte. Cest une
question de système et non de langage.

Si je me souviens bien, j'ai dû écrire un portage de getch() sour
Linux il y a quelques années :

http://delahaye.emmanuel.free.fr/clib/conio/
Avatar
-ed-
On 7 fév, 10:09, (Marc Espie) wrote:
Globalement, curses ou assimile est un bon compromis...



Oui exact, je n'y pensais plus ...

au P.O. : oublie ma proposition avec termios et renseigne toi plutôt
sur [n]curses.
Avatar
Samuel Devulder
Alex a écrit :

L'objectif est de concevoir un bout de programme qui lit des commandes
qui arrivent dans un fichier texte, et qui les envoie sur un port série
vers un dispositif électronique d'asservissement.
Le thread devrait servir à pouvoir interrompre le traitement si on appui
sur une touche particulière du clavier.



En gros tu veux faire en sorte qu'un équivalent de ctrl-c stoppe
proprement ton programme. Il y a un truc plus simple que les threads et
la lecture clavier dans ce cas. L'idée est de mettre un handler qui
serait appelé quand ton prog reçoit un signal du clavier. Le plus
indiqué me semble de trapper le ctrl-c (SIGINT) de ton prog. A la louche
sans filets ca donnerait un truc comme ca:

#include <stdio.h>
#include <signal.h>

volatile int running = 0;

void ctrl_c_handler(int signum_ignored) {
running = 0;
/* pas besoin de re-armer le handler ici */
}

int main(int ac, char **av) {
void (*old_handler)(int);

/* on récupère l'ancien handler, et on place le notre */
old_handler = signal(SIGINT, ctrl_c_handler);
if(old_handler==SIG_ERR) {perror("signal"); exit(EXIT_FAILURE);}

printf("Running...n");
for(running = 1; running; ) {
.. ta boucle de traitement ..
}
printf("Exiting...n");

/* on remet tout dans l'ordre */
signal(SIGINT, old_handler);
}

L'idée est que lorsque ton prog recoit un SIGINT (i.e. ctrl-c), la
fonction ctrl_c_handler() est appelée, et baisse le drapeau "running". A
partir de là tu sais que tu dois avorter ton traitement.

Tout cela sans aucun thread. C'est beaucoup mieux à mon avis.

sam.
Avatar
Antoine Leca
Alex écrivit :
Vivien MOREAU a écrit :
On 2010-02-06, Alex wrote:

au début je pensai utiliser getc, mais cette
fonction n'est pas implémenté sous linux.


Tu te trompes, getc() fait partie de la bibliothèque standard et ton
système l'implémente au travers de la glibc. Tape donc man getc dans un
terminal.



Meci pour ta réponse, en effet tu as raison, j'avai oublié de mettre à
jour le fichier MAKE avec -lncurses



Euh non non non, il y a un gros souci ici.

Soit tu cherches à utiliser getc() et c'est toujours disponible, cela
fait partie de la bibliothèque standard (libc) et c'est lié dans tous
les cas (pas besoin de rajouter -lc)

Soit tu cherches à utiliser getch() et effectivement sur ton système
cela demande [n]curses qui est optionnel donc -lncurses


Antoine