94 votes

C non-blocage de l'entrée de clavier

Je suis en train d'écrire un programme en C (sous linux) qui boucle jusqu'à ce que l'utilisateur appuie sur une touche, mais ne devrait pas exiger une touche pour continuer chaque boucle.

Est-il un moyen simple de faire cela? Je me dis que je pourrais peut-être faire ça avec select (), mais cela ressemble à beaucoup de travail.

Sinon, est-il un moyen de rattraper un control-c pression de touche pour effectuer le nettoyage avant que le programme se ferme au lieu de non-blocage io?

74voto

Alnitak Points 143355

Comme déjà indiqué, vous pouvez utiliser sigaction de piège ctrl-c ou select pour intercepter toute entrée standard.

À noter toutefois qu'avec la deuxième méthode, vous devez également définir le terminal de sorte qu'il est de caractère-à-un-temps plutôt que de ligne-à-un-temps. Le second est la valeur par défaut - si vous entrez une ligne de texte, il n'est pas envoyé à l'exécution du programme stdin jusqu'à ce que vous appuyez sur entrée.

Vous auriez besoin d'utiliser l' tcsetattr() fonction pour désactiver ICANON mode, et probablement aussi de désactiver l'ÉCHO aussi. À partir de la mémoire, vous devez également définir le terminal de retour dans ICANON mode lorsque le programme se termine!

Juste pour être complet, voici un code que j'ai juste frappé vers le haut (nb: pas de vérification d'erreur!) qui met en place un Unix ATS et émule le DOS <conio.h> fonctions kbhit() et getch():

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>

struct termios orig_termios;

void reset_terminal_mode()
{
    tcsetattr(0, TCSANOW, &orig_termios);
}

void set_conio_terminal_mode()
{
    struct termios new_termios;

    /* take two copies - one for now, one for later */
    tcgetattr(0, &orig_termios);
    memcpy(&new_termios, &orig_termios, sizeof(new_termios));

    /* register cleanup handler, and set the new terminal mode */
    atexit(reset_terminal_mode);
    cfmakeraw(&new_termios);
    tcsetattr(0, TCSANOW, &new_termios);
}

int kbhit()
{
    struct timeval tv = { 0L, 0L };
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(0, &fds);
    return select(1, &fds, NULL, NULL, &tv);
}

int getch()
{
    int r;
    unsigned char c;
    if ((r = read(0, &c, sizeof(c))) < 0) {
        return r;
    } else {
        return c;
    }
}

int main(int argc, char *argv[])
{
    set_conio_terminal_mode();

    while (!kbhit()) {
        /* do some work */
    }
    (void)getch(); /* consume the character */
}

16voto

Norman Ramsey Points 115730

select() est un peu trop bas niveau pour plus de commodité. Je vous suggère d'utiliser l' ncurses bibliothèque pour mettre le terminal en cbreak mode et mode de retard, puis appelez getch(), qui sera de retour ERR si aucun personnage est prêt:

WINDOW *w = initscr();
cbreak();
nodelay(w, TRUE);

À ce stade, vous pouvez appeler getch sans blocage.

11voto

Mehrdad Afshari Points 204872

Sur les systèmes UNIX, vous pouvez utiliser sigaction appel à enregistrer un gestionnaire de signal pour SIGINT signal qui représente le Contrôle+touche C de la séquence. Le gestionnaire de signal peut définir un indicateur qui sera vérifié dans la fabrication de la boucle à la briser de manière appropriée.

6voto

Jon Clegg Points 661

Vous voulez probablement, kbhit();

//Example will loop until a key is pressed
#include <conio.h>
#include <iostream>

using namespace std;

int main()
{
    while(1)
    {
        if(kbhit())
        {
            break;
        }
    }
}

cela peut ne pas fonctionner sur tous les environnements. Un portable moyen serait de créer un thread de surveillance et définir un drapeau sur getch();

3voto

PolyThinker Points 3473

La bibliothèque curses peut être utilisé à cette fin. Bien sûr, select() et les gestionnaires de signaux peuvent être utilisés aussi dans une certaine mesure.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X