2010-10-18 10 views
2

J'ai besoin de savoir quelle interruption sous Linux vérifie si une touche a été enfoncée?Comment vérifier si une touche a été enfoncée sous Linux?

+0

Ne devriez-vous pas faire un appel système pour faire cela? –

+0

Les appels système sous Linux sont des interruptions. –

+0

Vote pour fermer aussi peu clair. Dans quelle langue? Pour faire quoi? Version C: http://stackoverflow.com/questions/2984307/c-key-pressed-in-linux-console –

Répondre

5

Je suppose que vous voulez cela sur un émulateur de terminal (et non sur un client X), et que vous ne vous souciez pas de la libération de la clé. La manière Linux de le faire serait d'utiliser termios (3) pour mettre le terminal en mode non-canonique ou brut, puis de lire stdin en utilisant les fonctions habituelles de la libc.

Les numéros d'appel système sous Linux sont sur /usr/include/asm/unistd.h (ou unistd_64.h), mais les fonctions termios sont converties en ioctl(). Donc, si vous ne pouvez pas appeler libc pour une raison étrange et inhabituelle, vous devrez rechercher le numéro de syscall pour ioctl, et le ioctl correspondant aux fonctions termios.

Edit:

Apparemment, vous êtes en supposant que Linux utilise le même modèle que DOS, dans lequel l'entrée de la console est une abstraction d'un clavier (avec des fonctions comme keyPressed, GETC, ...) et la sortie de la console est une abstraction d'un affichage orienté sur les caractères.

L'abstraction d'Unix/Linux est d'environ les terminaux, qui peuvent être la console physique, un terminal (ou émulateur de terminal) sur un port série, un xterm, ... Un point important ici est que par défaut, les lignes d'entrée ne sont pas mis à la disposition des programmes tant que le terminal (ou l'émulateur de terminal) ne voit pas de délimiteur de ligne.

Sur POSIX, ces terminaux sont contrôlés par les fonctions termios(3). Linux finit par traduire ceux appels ioctl(), comme suit (voir tty_ioctl(4)):

  • tcgetattr (fd, arg) => ioctl (fd, TCGETS, arg)
  • tcsetattr (fd, TCSANOW, arg) => ioctl (fd, TCSETS, arg)
  • tcsetattr (fd, TCSADRAIN, arg) => ioctl (fd, TCSETSW, arg)
  • tcsetattr (fd, TCSAFLUSH, arg) => ioctl (fd, TCSETSF , arg)
  • ...

Ainsi, un programme C pour faire ce que vous avez demandé, à l'aide termios(3) et poll(2) (vérification d'erreurs dépouillé par souci de concision et de clarté):

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <unistd.h> 
#include <poll.h> 
#include <signal.h> 
#include <termios.h> 
#include <sys/ioctl.h> 

static sig_atomic_t end = 0; 

static void sighandler(int signo) 
{ 
    end = 1; 
} 

int main() 
{ 
    struct termios oldtio, curtio; 
    struct sigaction sa; 

    /* Save stdin terminal attributes */ 
    tcgetattr(0, &oldtio); 

    /* Make sure we exit cleanly */ 
    memset(&sa, 0, sizeof(struct sigaction)); 
    sa.sa_handler = sighandler; 
    sigaction(SIGINT, &sa, NULL); 
    sigaction(SIGQUIT, &sa, NULL); 
    sigaction(SIGTERM, &sa, NULL); 

    /* This is needed to be able to tcsetattr() after a hangup (Ctrl-C) 
    * see tcsetattr() on POSIX 
    */ 
    memset(&sa, 0, sizeof(struct sigaction)); 
    sa.sa_handler = SIG_IGN; 
    sigaction(SIGTTOU, &sa, NULL); 

    /* Set non-canonical no-echo for stdin */ 
    tcgetattr(0, &curtio); 
    curtio.c_lflag &= ~(ICANON | ECHO); 
    tcsetattr(0, TCSANOW, &curtio); 

    /* main loop */ 
    while (!end) { 
      struct pollfd pfds[1]; 
      int ret; 
      char c; 

      /* See if there is data available */ 
      pfds[0].fd = 0; 
      pfds[0].events = POLLIN; 
      ret = poll(pfds, 1, 0); 

      /* Consume data */ 
      if (ret > 0) { 
        printf("Data available\n"); 
        read(0, &c, 1); 
      } 
    } 

    /* restore terminal attributes */ 
    tcsetattr(0, TCSANOW, &oldtio); 

    return 0; 
} 

Maintenant, ioctl et poll sont syscalls, et vous pouvez trouver leurs numéros sur/usr/include/asm/unistd.h (54 et 168 sur x86), et /usr/include/asm/ioctls.h a les constantes ioctl dont vous avez besoin (sur x86: TCGETS = 0x5401, TCSETS = 0x5402, TCSETSW = 0x5403, TCSETSF = 0x5404).

+0

Je souhaite utiliser un service d'interruption. Je sais qu'il y a un tel service pour les interruptions DOS, donc je me suis dit qu'il y avait aussi pour Linux ... – Sason

+1

Non, ninjalj a décrit ce dont vous avez besoin. Sous Linux (architecture i386), vous pouvez effectuer des appels système en utilisant int 0x80 avec le numéro de service dans eax. Cependant, contrairement à DOS, il n'y a pas d'appel direct pour "vérifier si une touche est enfoncée". Pour les raisons voir http://en.wikipedia.org/wiki/Ring_%28computer_security%29 et http: //en.wikipedia.org/wiki/Espace utilisateur. Les systèmes de type Unix utilisent l'abstraction du terminal et vous devez suivre les instructions de ninjalj sauf si vous voulez modifier Linux lui-même. –

Questions connexes