Книга: Основы программирования в Linux
Обнаружение нажатий клавиш
Пользователи, программировавшие в ОС MS-DOS, часто ищут в ОС Linux эквивалент функции kbhit
, которая определяет, была ли нажата клавиша, без реального ее считывания. К сожалению, их поиски оказываются безуспешными, поскольку прямого аналога нет. Программисты в среде UNIX не ощущают этого отсутствия, т.к. UNIX запрограммирована так, что программы очень редко (если когда-либо вообще) озабочены ожиданием события. Поскольку это обычный способ применения kbhit
, ее нехватка редко ощущается в системах UNIX и Linux.
Однако, когда вы переносите программы из MS-DOS, часто удобно эмулировать функцию kbhit
, которую можно применять на деле в неканоническом режиме ввода (упражнение 5.7).
Упражнение 5.7. Исключительно ваша собственная kbhit
1. Начните со стандартной заголовочной информации и пары структур для установки параметров терминала. peek_character
применяется для проверки нажатия клавиши. Далее описываются функции, которые будут использоваться позже:
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <term.h>
#include <curses.h>
#include <unistd.h>
static struct termios initial_settings, new_settings;
static int peek_character = -1;
void init_keyboard();
void close_keyboard();
int kbhit();
int readch();
2. Функция main вызывает функцию init_keyboard
для настройки терминала, затем выполняет цикл один раз в секунду, каждый раз вызывая в нем функцию kbhit
. Если нажата клавиша <q>, функция close_keyboard
восстанавливает нормальный режим и программа завершается:
int main() {
int ch = 0;
init_keyboard();
while (ch != 'q') {
printf("loopingn");
sleep(1);
if (kbhit()) {
ch = readch();
printf("you hit %cn", ch);
}
}
close_keyboard();
exit(0);
}
3. Функции init_keyboard
и close_keyboard
настраивают терминал в начале и конце программы:
void init_keyboard() {
tcgetattr(0, &initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
new_settings.c_lflag &= ~ISIG;
new_settings.c_cc[VMIN] = 1;
new_settings.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &new_settings);
}
void close_keyboard() {
tcsetattr(0, TCSANOW, &initial_settings);
}
4. Теперь функция, проверяющая нажатие клавиши:
int kbhit() {
char ch;
int nread;
if (peek_character != -1) return 1;
new_settings.c_cc[VMIN] = 0;
tcsetattr(0, TCSANOW, &new_settings);
nread = read(0, sch, 1);
newrsettings.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &new_settings);
if (nread == 1) {
peek_character = ch;
return 1;
}
return 0;
}
5. Нажатый символ считывается следующей функцией readch
, которая затем восстанавливает значение -1 переменной peek_character
для выполнения следующего цикла:
int readch() {
char ch;
if (peek_character != -1) {
ch = peek_character;
peek_character = -1;
return ch;
}
read(0, &ch, 1);
return ch;
}
Когда вы выполните программу (kbhit.c), то получите следующий вывод:
$ ./kbhit
looping
looping
looping
you hit h
looping
looping
looping
you hit d
looping
you hit q
$
Как это работает
Терминал настраивается в функции init_keyboard
на считывание одного символа (MIN=1, TIME=0
). Функция kbhit
изменяет это поведение на проверку ввода и его немедленный возврат (MIN=0, TIME=0
) и затем восстанавливает исходные установки перед завершением.
Обратите внимание на то, что вы должны считать символ нажатой клавиши, но сохраняете его локально, готовые вернуть символ в вызывающую программу по ее требованию.
- 10.5. Обнаружение жестов-нажатий
- 10.6. Обнаружение щипка
- 18.2. Обнаружение доступности гироскопа
- 18.1. Обнаружение доступности акселерометра
- Глава 2 Обнаружение адреса
- 16.2. Комбинации клавиш
- Где находится клавиша Windows?
- Нужно набрать специальные символы, а на клавиатуре нет таких клавиш
- Как избежать случайного нажатия клавиши Caps Lock?
- Горячие клавиши Windows
- 12.7.4. Переназначение клавиш на клавиатуре
- Можно ли при помощи горячих клавиш переводить компьютер в спящий режим?