Распознавание специальных клавиш без захвата экрана
В программе, которая использует curses
или же ncurses
библиотека, getch()
функция может распознать либо обычный символ (например, 'x'
) или escape-последовательность, отправленная стрелкой и функциональными клавишами. Например, нажатие клавиши со стрелкой вверх может отправить последовательность (Escape, '[', 'A'), но getch()
вернет int
значение KEY_UP
, Он даже использует информацию о времени, чтобы различать отправленный отдельно символ Escape и символ Escape, являющийся частью последовательности.
Использовать getch()
успешно, сначала нужно позвонить initscr()
, который очищает экран, так что проклятия могут контролировать то, что отображается.
Есть ли удобный способ распознать специальные клавиши без захвата экрана? В идеале я хотел бы позвонить getch()
без первого звонка initscr()
и он вернул бы то же значение, которое он возвратил бы, если бы я позвонил initscr()
, но эксперимент показывает, что не работает.
Вот нерабочий пример того, что я пытаюсь сделать. Программа предлагает пользователю ввести Вверх, Вниз, Выход, Влево, Вправо и подтверждает, что были введены правильные клавиши.
Запуск программы с -c
Запускает initscr()
и позволяет ему работать правильно. Запуск без -c
звонки getch()
без первого звонка initscr()
; все getch()
звонки не выполняются без ожидания ввода и возврата ERR
(-1
).
// gcc arrows.c -o arrows -lncurses
#include <term.h>
#include <stdio.h>
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int use_curses = 0;
if (argc == 2 && strcmp(argv[1], "-c") == 0) {
use_curses = 1;
}
else if (argc != 1) {
fprintf(stderr, "Usage: %s [-c]\n", argv[0]);
exit(EXIT_FAILURE);
}
WINDOW *win;
if (use_curses) {
win = initscr();
cbreak();
noecho();
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
mvaddstr(0, 0, "Press UP, DOWN, Escape, LEFT, RIGHT");
}
else {
puts("Press UP, DOWN, Escape, LEFT, RIGHT");
}
int keys[5];
for (int i = 0; i < 5; i ++) {
keys[i] = getch();
}
int ok;
if (keys[0] == KEY_UP &&
keys[1] == KEY_DOWN &&
keys[2] == '\x1b' &&
keys[3] == KEY_LEFT &&
keys[4] == KEY_RIGHT)
{
ok = 1;
if (use_curses) {
mvaddstr(2, 0, "OK");
}
else {
puts("OK");
}
}
else {
ok = 0;
char message[100];
sprintf(message,
"Incorrect input: (%d, %d, %d, %d, %d)",
keys[0], keys[1], keys[2], keys[3], keys[4]);
if (use_curses) {
mvaddstr(2, 0, message);
}
else {
puts(message);
}
}
if (use_curses) {
mvaddstr(4, 0, "Press any key to quit ");
(void)getch();
endwin();
}
exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
Выход без -c
опция (в Ubuntu 17.04 x86_64):
Press UP, DOWN, Escape, LEFT, RIGHT
Incorrect input: (-1, -1, -1, -1, -1)
ОБНОВЛЕНИЕ: решение, использующее что-то кроме проклятий, было бы хорошо. Для того чтобы узнать, какие входные последовательности искать, пришлось бы использовать terminfo, прямо или косвенно. (Мне кажется, что распознавание специальных клавиш должно быть простым и не должно быть тесно связано с захватом всего экрана.)
1 ответ
filter
функция, вызываемая ранее initscr
, говорит проклятиям использовать одну строку (а не весь экран). В ncurses-examples есть пример его использования (с именем "filter"), который состоит из командной строки.
getch
обновляет по крайней мере часть экрана, например, когда он повторяет ввод. Это обновление может повлиять на одну строку (используя filter
) или весь экран. Если вы умны, вы можете отключить эхо, и (так как filter
подавляет стирание экрана), делайте вид, что он вообще ничего не обновляет. Например, вы можете перенаправить вывод на /dev/null
инициализируя проклятия с newterm
,
Повторение ввода - только часть истории: curses действительно инициализирует экран, и связанный с ним refresh
сделано getch
сделает это трудно избежать портативным способом. В программе-примере есть специфичная для ncurses опция, которая устраняет нежелательное переключение между обычными / альтернативными экранами, которое может произойти во время инициализации экрана.
Вот скриншот "фильтра", демонстрирующий, что он не занимает весь экран. Обратное видео происходит из-за ncurses, инициализирующих цвета (белый на черном), но, как указывает справочное сообщение, это настраивается. Без создания фильма трудно доказать, что он обрабатывает специальные ключи, но чтения исходного кода должно быть достаточно.