IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

[linux] petit soucis avec la saisie d'un caractère en mode non bloquant


Sujet :

C

  1. #1
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut [linux] petit soucis avec la saisie d'un caractère en mode non bloquant
    Greetings !!

    Je pensais avoir trouvé une solution pour pouvoir saisir un caractère sans devoir:

    + appuyer sur entrée (c'est un peu idiot de devoir appuyer sur entrée pour saisir un caractère)
    + au niveau des processus, attendre que le caractère ait été saisi avant de passer à l'instruction suivante
    + ne pas faire l'écho (afficher) le caractère en question (notamment en mode console quand il s'agit de "touches spéciales" comme les touches de direction, de fonction, etc...)

    Voici la fonction bloquante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #ifdef LINUX
    int getch() 
    {
      struct termios oldt, newt;
    	struct sigaction Detournement;
     
    	Detournement.sa_handler=SIG_IGN;
    	// On ne peut pas interrompre le getch...
    	sigaction(SIGINT,&Detournement,NULL);
     
        int ch;
        tcgetattr(STDIN_FILENO, &oldt);
        newt = oldt;
    		newt.c_lflag &= ~(ICANON | ECHO ); // works !!
        //newt.c_lflag &= ~(ICANON | ECHO | NOFLSH); // 22 aug 2014
        tcsetattr(STDIN_FILENO, TCSANOW, &newt);
        ch = getchar();
        tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
     
    		Detournement.sa_handler=SIG_DFL;
    		Detournement.sa_flags=0;
    		sigaction(SIGINT,&Detournement,NULL);
     
        return ch;
    }
    #endif

    Voici la fonction non-bloquante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #ifdef LINUX
    int nbgetch(void)
    {
    	char							Buffer;
    	struct termios		oldt;
    	struct termios		newt;
     
    	tcgetattr(STDIN_FILENO, &oldt);
      newt = oldt;
     
    	newt.c_lflag &= ~(ICANON | ECHO ); 			// affiche le caractère alors que je dis de ne pas faire l'écho... 
     
    	// mode non bloquant...
     
    	newt.c_cc[VMIN] = 0;
    	newt.c_cc[VTIME] = 0;
    	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
     
    	Buffer=getchar();	// retourne EOF (-1) si il y a rien dans le buffer
     
    	// on restitue "l'ancienne configuration"
    	tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 
    	return Buffer;
    }
    #endif
    Ces deux fonctions me permettent de faire un gestionnaire de saisie clavier. Le principe est de boucler indéfiniment (dans un thread) et dés qu'il y a quelque chose dans le buffer, essayer de déterminer ce
    qu'il faut faire en fonction des codes (ANSI) présents dans le buffer. Le traitement sera différent pour la touche de direction "HAUT" (SEQUENCE: 27 91 65) que la touche "DROITE" (SEQUENCE: 27 91 66)
    ça je suis bon, mais ce que je ne comprends pas c'est pourquoi "^[[A" est affiché à l'écran alors que j'ai mis à 0 le bit pour "faire écho" du caractère

    Est-ce que quelqu'un pourrait m'expliquer à quoi cela est-ce dû ? Et quelles modifications apporter pour permettre à cette fonction non bloquante de continuer à l'être et en plus à ne pas afficher les caractères saisis au clavier ?

    Merci d'avance...

  2. #2
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 451
    Points : 43 097
    Points
    43 097
    Par défaut
    Regardes ce post :
    http://www.developpez.net/forums/d15...ation-getchar/

    Les réponses d'Obsidian te fera comprendre à quoi correspond [[A" : les séquences CSI.

    Depuis je passe entièrement par ncurses.

    Attention ncurses t'obligera à utiliser wprint à la place de printf etc...

    Pour gérer les touches spéciales aucun problème :

    tu peux intercepter les touches spéciales avec la fonction ncurses :
    ne pas afficher les caractères saisies :
    tu dois pouvoir t"en sortir avec termios mais c'est plus compliqué (du moins je trouve)
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  3. #3
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut
    Merci beaucoup chrstophe ^^

    Je sais à quoi correspond la séquence "^[[A", j'ai mal formulé mes observations, normalement l'écho ne devait pas se faire vu que je pensais avoir mis le bit ECHO à 0...

    En fait ma sous question est la suivante:

    Quand j'utilise la fonction non bloquante "getch" ça fonctionne, le caractère ne s'affiche pas et je suis tout content j'utilise cette fonction depuis des années, je n'ai jamais eu de soucis particuliers.
    Ici, pour les besoins de futures démonstrations pour les cours que je donne, j'ai eu besoin d'une fonction non bloquante, or, ici, il semble que SOIT je puisse rendre la fonction non bloquante OU ALORS je puisse faire en sorte que l'écho ne se fasse pas; MAIS les deux ensembles
    je n'y arrive pas :{

    Concernant "ncurses" j'ai décidé de laisser tomber, je n'aime pas du tout utiliser cette librairie, elle me semble un peu trop opaque. Même si quelque part elle propose exactement les mêmes fonctionalités que la mienne et qu'elle est "portable", je pense que sous Windows ou Mac elle peut fonctionner; ma "librairie", elle, ne "tourne" que sous Linux, mais je m'en f*** je n'utilise que Linux dans mon labo et si les élèves veulent bosser chez eux, ce qui est TRES rare, ils ont des machines virtuelles ou un dual-boot.

    De plus dans mes observations j'ai remarqué quelque chose de méga étrange:

    Quand je saisis CTRL-A ma fonction retourne 1 --> content
    Quand je saisis CTRL-B ma fonction retourne 2 --> content
    ...CTRL-C je ne l'utilise que pour stopper mon programme...
    Quand je saisis CTRL-D (qui normalement termine mon programme comme dans showkey de linux) --> ma fonction retourne 0 !!! (pas content)
    Quand je saisis CTRL-E ma fonction retourne 5 --> content
    Quand je saisis CTRL-F ma fonction retourne 6 --> content

    Je pense que il y a "quelque chose" que je n'ai pas bien saisi... avec la version bloquante ça fonctionne parfaitement sauf qu'elle est bloquante :{

    Je viens juste de modifier les lignes en italique dans le code du thread et maintenant ça marche !! je n'ai vraiment pas compris grand chose...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    void thread_clavier(void)
    {
    	long avant;
    	long apres;
    	
    	fprintf(stderr,"[DEBUG] Thread lancé...\n",iGlobal_clavier);
    	while(bEnMarche)
    	{
    		avant=clock();
    		iGlobal_clavier=nbgetch();
    		apres=clock();
    		
    		
    		fprintf(stderr,"[DEBUG] %d (%08ld)\n",iGlobal_clavier,apres-avant);
    		fflush(stderr);
    
    		switch(iGlobal_clavier)
    		{
    			case 4:	fprintf(stderr,"CTRL-D appuyé...\n");
    							bEnMarche=false;
    							break;
    			
    			case 27:	if(nbgetch()!=-1) 
    								{
    									fprintf(stderr,"Une touche spéciale a été activée...\n");
    								}
    								else fprintf(stderr,"ESC a été appuyée...\n");
    								break;
    		}
    		nanosleep(&latence,NULL);
    	}
    	fprintf(stderr,"Arrêt du thread...\n");
    	pthread_exit(NULL);
    }

  4. #4
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut
    Bon bin... comme la fonction nbgetch() (non blocking getch) est censée uniquement être non bloquante j'ai extrait le code (en italique) de la fonction et l'ai directement insérée dans le thread.

    Il y a eu des comportements très bizarres un coup ça fonctionnait, je modifie le code autre part dans le programme et poum ! de nouveau l'écho des caractères et le CTRL-D qui est interprété comme étant 0 au lieu de 4 (???)

    Maintenant ça à l'air d'être parfait...

    http://paste.opensuse.org/45493926
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    void thread_clavier(void)
    {
    	long avant;
    	long apres;
    	
    	struct termios		oldt;
    	struct termios		newt;
    	
    	tcgetattr(STDIN_FILENO, &oldt);
      newt = oldt;
    	
    	newt.c_lflag &= ~(ICANON | ECHO | ECHONL | ECHOCTL);
    	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    	
    	printf("[DEBUG] Thread lancé...\n",iGlobal_clavier);
    	while(bEnMarche)
    	{
    		avant=clock();
    		iGlobal_clavier=nbgetch();
    		apres=clock();
    		
    		//fprintf(stderr,"[DEBUG] %d (%08ld)\n",iGlobal_clavier,apres-avant);
    		//fflush(stderr);
    
    		switch(iGlobal_clavier)
    		{
    			case 4:	fprintf(stderr,"CTRL-D appuyé...\n");
    							bEnMarche=false;
    							break;
    			
    			case 27:	if(nbgetch()!=-1) 
    								{
    									fprintf(stderr,"Une touche spéciale a été activée...\n");
    								}
    								else fprintf(stderr,"ESC a été appuyée...\n");
    								break;
    		}
    		nanosleep(&latence,NULL);
    	}
    	fprintf(stderr,"Arrêt du thread...\n");
    	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    	pthread_exit(NULL);
    }

Discussions similaires

  1. petit soucis avec mon graveur
    Par Vador dans le forum Périphériques
    Réponses: 8
    Dernier message: 02/11/2005, 14h58
  2. petit soucis avec les listes
    Par Death83 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 03/09/2005, 10h08
  3. Petit souci avec clause where
    Par ybruant dans le forum SQL
    Réponses: 1
    Dernier message: 21/07/2005, 22h10
  4. petit souci avec des variables avec des fonctions psql
    Par dust62 dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 02/04/2005, 13h45
  5. [DEBUTANT] petits soucis avec un prgm de chat
    Par LechucK dans le forum MFC
    Réponses: 8
    Dernier message: 19/01/2004, 16h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo