2010-06-06 2 views
14

Я использую консоль Linux, и я хотел бы сделать программу, которая выводит случайные символы до нажатия ESC. Как я могу сделать такой обработчик клавиатуры?Как справиться с нажатием клавиши на консоли Linux в C?

+0

аналогичный и/или родственный - [C неблокирующий ввод клавиатуры] (http://stackoverflow.com/q/448944/203667) – jschmier

ответ

2

getch() из библиотеки Curses возможно? Кроме того, вам нужно будет использовать notimeout(), чтобы сообщить getch(), чтобы не ждать следующего нажатия клавиши.

+0

Вы должны прямо указать, что вы говорите о библиотеке (N) curses. –

+0

Да, конечно. Обновлено. Благодарю. –

+2

примечание: getch() из ncurses нуждается в правильном ncurses «screen», который будет инициализирован, или он не будет работать. – ShinTakezou

-3
#include <stdio.h> 

#include <stdlib.h> 

#include <unistd.h> 

#include <signal.h> 

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 A-Z 
      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); 
} 

В этой программе и будет необходимо только нажать enter после esc полукокса, потому что getchar() является функцией блокировки. Также вы можете удалить или уменьшить время сна для дочернего процесса, как ур.

+1

За исключением 'getchar' ждет ввода, поэтому никакие случайные символы не будут выводиться, а' getchar' ждет, когда пользователь нажмет [enter]. –

4

изменить настройки TTY для одного нажатия клавиши:

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); 
} 
+0

Разве 'ICRNL' не входит в поле' c_iflag', а не поле 'c_lflag'? –

20

Линия дисциплина для терминального устройства часто работает в каноническом режиме по умолчанию. В этом режиме драйвер терминала не представляет буфер для пользовательского пространства до появления новой строки (Enter нажата клавиша).

Вы можете установить терминал в необработанный (неканонический) режим, используя tcsetattr() для управления структурой termios. Очистка флагов ECHO и ICANON соответственно отключает эхо-символы символов при их вводе и вызывает запросы на чтение, которые должны выполняться непосредственно из входной очереди. Установка значений VTIME и VMIN в ноль в массиве c_cc вызывает запрос на чтение (fgetc()) для немедленного возврата, а не для блокировки; эффективно опрос stdin. Вызов fgetc() вернет EOF, если символ недоступен в потоке.

#define _XOPEN_SOURCE 700 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <termios.h> 
#include <time.h> 

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; 
}

Примечание: этот код пропускает проверку ошибок для простоты.

+1

Кажется, что это работает, но он также каждый раз обеспечивает весь буфер. Так что, если я нажимаю a тогда b, то c, после нажатия c, он отображает aababc – Jackie

+0

@Jackie может сделать 'while (getchar()! = EOF);' after 'character = fgetc (stdin);' –

Смежные вопросы