Вопрос по c, multithreading, keypress – Реализация события KeyPress в C

1

У меня есть бесконечный цикл, подобный следующему, и в этом цикле я хочу постоянно проверять клавиатуру, чтобы увидеть, была ли нажата клавиша ESC (ESC) или нет. Если она нажата, то петля должна быть разорвана. Как я могу сделать это в C? (Я использую gcc, и делаю доступ к pthreads также в случае, если это должно быть сделано через потоки)

 while(1){
        //do something
        //check for the ESC key
 }
Пытатьсяwhile((ch = getchar()) != ESC_ASCCI_CODE) Maroun
Постоянно проверяйте клавиатуру, пока выпостоянно занимаешься чем-то другим? @ ᴍ SzG
Что это за система? Linux? Пожалуйста, обновите теги. Lundin
arounᴍСпасибо, но, используя этот подход, каждый раз, когда цикл останавливается, чтобы получить символ. Я неНе хочу останавливаться и проверять клавиатуру. Blue Sky
@SzG Мне действительно нужно событие нажатия клавиши. Похоже, мне нужен обработчик прерываний. Blue Sky

Ваш Ответ

2   ответа
0

Если основная работа у васЭто может быть сделано в этом основном цикле, вы можете использовать STDIN в неблокирующем режиме. У вас все еще есть проблема с терминалом, который обычно выполняет буферизацию строки. Вы также должны перевести терминал в режим raw.

Как насчет использования Ctrl-C (прерывание)?

Неблокирующая означает, чтоread() Системный вызов всегда возвращается немедленно, даже если в файле нет новых байтов. В Linux / Unix STDIN можно разблокировать следующим образом:

#include 
#include 
fcntl(0, F_SETFL, O_NONBLOCK); /* 0 is the stdin file decriptor */
Спасибо! На самом деле, я хочу использовать что-то вроде Ctrl-C, но с другой клавишей, например ESC. Не могли бы вы подробнее рассказать о STDIN в неблокирующем режиме? Blue Sky
6

Это сильно зависит от системы. В системах Unix / Linux обработчик терминала по умолчанию собирает строки и уведомляет программу только тогда, когда доступна полная строка (послеВойти ударил.) Если вы вместо этого хотите немедленное нажатие клавиш, вам нужно перевести терминал в неканонический режим:

#include 

struct termios info;
tcgetattr(0, &info);          /* get current terminal attirbutes; 0 is the file descriptor for stdin */
info.c_lflag &= ~ICANON;      /* disable canonical mode */
info.c_cc[VMIN] = 1;          /* wait until at least one keystroke available */
info.c_cc[VTIME] = 0;         /* no timeout */
tcsetattr(0, TCSANOW, &info); /* set immediately */

Однажды ты'Сделав это, вы можете использовать любые вызовы, которые читают из stdin, и они будут возвращать ключи, не дожидаясь конца строки. Вы можете дополнительно установитьc_cc[VMIN] = 0 заставить его вообще не ждать нажатия клавиш при чтении со стандартного ввода.

Если, однако, вычитая stdin с помощью вызовов stdio FILE (getchar и т. д.), установка VMIN = 0 заставит вас думать, чтомы достигли EOF, когда нет доступных ключей, поэтому выпридется позвонитьclearerr после этого случается попытаться прочитать больше символов. Вы можете использовать цикл как:

int ch;
while((ch = getchar()) != 27 /* ascii ESC */) {
    if (ch < 0) {
        if (ferror(stdin)) { /* there was an error... */ }
        clearerr(stdin);
        /* do other stuff */
    } else {
        /* some key OTHER than ESC was hit, do something about it? */
    }
}

После Вас'После этого вы, вероятно, захотите снова установить терминал в канонический режим, чтобы другие программы (например, ваша оболочка) не запутались:

tcgetattr(0, &info);
info.c_lflag |= ICANON;
tcsetattr(0, TCSANOW, &info);

Есть также и другие вещи, которые вы можете сделать с помощью tcsetattr - см. Подробности на странице руководства. Одной вещи, которая может быть достаточной для ваших целей, является установка альтернативного символа EOL.

Похожие вопросы