Come gestire il tasto premuto in una console Linux in C?

Sto usando la console Linux e mi piacerebbe fare un programma che emette caratteri casuali fino a quando non viene premuto ESC. Come posso creare un gestore di tastiera del genere?

getch () dalla libreria Curses forse? Inoltre, dovrai usare notimeout () per dire a getch () di non aspettare la prossima pressione del tasto.

La disciplina di linea per un dispositivo terminale spesso funziona in modalità canonica di default. In questa modalità, il driver del terminale non presenta il buffer nello spazio utente finché non viene visualizzato il newline (viene premuto il tasto Invio ).

È ansible impostare il terminale in modalità raw (non canonica) utilizzando tcsetattr() per manipolare la struttura del termios . Cancellando i flag ECHO e ICANON rispettivamente, si disabilita l’eco dei caratteri mentre vengono digitati e le richieste di lettura vengono soddisfatte direttamente dalla coda di input. Impostando i valori di VTIME e VMIN a zero nell’array c_cc , la richiesta di lettura ( fgetc() ) viene restituita immediatamente anziché fgetc() ; efficacemente polling stdin. La chiamata a fgetc() restituirà EOF se un carattere non è disponibile nello stream.

 #define _XOPEN_SOURCE 700 #include  #include  #include  #include  #include  int getkey() { int character; struct termios orig_term_attr; struct termios new_term_attr; /* set the terminal to raw mode */ tcgetattr(fileno(stdin), &orig_term_attr); memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios)); new_term_attr.c_lflag &= ~(ECHO|ICANON); new_term_attr.c_cc[VTIME] = 0; new_term_attr.c_cc[VMIN] = 0; tcsetattr(fileno(stdin), TCSANOW, &new_term_attr); /* read a character from the stdin stream without blocking */ /* returns EOF (-1) if no character is available */ character = fgetc(stdin); /* restore the original terminal attributes */ tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr); return character; } int main() { int key; /* initialize the random number generator */ srand(time(NULL)); for (;;) { key = getkey(); /* terminate loop on ESC (0x1B) or Ctrl-D (0x04) on STDIN */ if (key == 0x1B || key == 0x04) { break; } else { /* print random ASCII character between 0x20 - 0x7F */ key = (rand() % 0x7F); printf("%c", ((key < 0x20) ? (key + 0x20) : key)); } } return 0; } 

Nota: questo codice omette la verifica degli errori per semplicità.

modificare le impostazioni tty per una pressione di un tasto:

 int getch(void) { int c=0; struct termios org_opts, new_opts; int res=0; //----- store old settings ----------- res=tcgetattr(STDIN_FILENO, &org_opts); assert(res==0); //---- set new terminal parms -------- memcpy(&new_opts, &org_opts, sizeof(new_opts)); new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL); tcsetattr(STDIN_FILENO, TCSANOW, &new_opts); c=getchar(); //------ restore old settings --------- res=tcsetattr(STDIN_FILENO, TCSANOW, &org_opts); assert(res==0); return(c); } 
 #include  #include  #include  #include  char * me = "Parent"; void sigkill(int signum) { //printf("=== %s EXIT SIGNAL %d ===\n", me, signum); exit(0); } main() { int pid = fork(); signal(SIGINT, sigkill); signal(SIGQUIT, sigkill); signal(SIGTERM, sigkill); if(pid == 0) //IF CHILD { int ch; me = "Child"; while(1) { ch = (rand() % 26) + 'A'; // limit range to ascii AZ printf("%c",ch); fflush(stdout); // flush output buffer sleep(2); // don't overwhelm if (1 == getppid()) { printf("=== CHILD EXIT SINCE PARENT DIED ===\n"); exit(0); } } printf("==CHILD EXIT NORMAL==\n"); } else //PARENT PROCESS { int ch; if((ch = getchar())==27) kill(pid, SIGINT); //printf("==PARENT EXIT NORMAL (ch=%d)==\n", ch); } return(0); } 

In questo programma dovrai solo premere enter dopo esc char, perché getchar() è una funzione di blocco. Inoltre è ansible rimuovere o ridurre il tempo di sonno per il processo figlio secondo necessità.