Pourquoi `ioctl (fd, EVIOCGRAB, 1)` provoque-t-il parfois du spam par clé?

J’essaie d’écrire mon propre “pilote de clavier” (sans écrire réellement un module du kernel), en saisissant le clavier à ce que je suppose être le niveau d’abstraction le plus bas du monde utilisateur: /dev/input/event* .

Le code suivant effectue la saisie, à condition que vous modifiiez la première occurrence de ioctl(fd, EVIOCGRAB, UNGRAB) en ioctl(fd, EVIOCGRAB, GRAB) .

 // gcc main.c -o main #include  #include  #include  #include  #include  #include  #define EXIT_KEY KEY_ESC #define UNGRAB 0 #define GRAB 1 const char* kbd_device = "/dev/input/event4"; // ------------------------------------------------------------------------------------------------ int main(void){ int fd = open(kbd_device, O_RDONLY); if(fd == -1){ printf("Cannot open %s. %s.\n", kbd_device, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGRAB, UNGRAB)) printf("Couldn't grab %s. %s.\n", kbd_device, strerror(errno)); else printf("Grabbed %s!\n", kbd_device); while(1){ struct input_event event; read(fd, &event, sizeof(event)); if (event.type == EV_KEY && event.value >= 0 && event.value <= 2){ printf("%d %3d\n", event.value, event.code); if(event.code == EXIT_KEY){ ioctl(fd, EVIOCGRAB, UNGRAB); close(fd); return 0; } } } } 

Problème

  • Si je lance gcc main.c -o main && sudo ./main , tout fonctionne comme prévu.
  • Si je comstack d’abord et que je lance ensuite sudo ./main , le terminal défile sans arrêt, comme si la touche RETURN était enfoncée.

Pourquoi ça arrive?

Remarques

  • J’utilise Ubuntu 14.04
  • Sur ma plate-forme, /dev/input/event4 se trouve être le clavier

Motivation

J’essaie d’écrire un “pilote” de clavier qui fonctionne à la fois sur X et non sur X (par exemple, un ATS).

Je comprends que la bibliothèque / extension du clavier de X11 est XKB. Je pense que la bibliothèque de clavier du téléscripteur est linux/divers/tty/vt/keyboard.c ( source ), la carte de clavier initiale qu’il utilise est sous linux/drivers/tty/vt/defkeymap.map ( source ), et elle peut être modifiée en utilisant loadkeys (source ici ). Corrigez-moi si je me trompe.

    Quand vous tapez

     gcc main.c -o main && sudo ./main ↵ 

    GCC prend du temps, la clé a été relâchée au moment où ./main s’exécute.

    Quand vous tapez

     sudo ./main ↵ 

    le terminal envoie une nouvelle ligne au shell dès que vous appuyez sur , et commence à exécuter ./main . Ensuite, l’événement publié est vu par votre programme, mais pas par votre terminal, car votre programme a saisi le périphérique d’entrée. Ainsi, au terminal, il semble que est bloqué, il continue donc à produire de nouvelles lignes.