[英]Recognizing special keys without taking over the screen
在使用curses
或ncurses
庫的程序中, getch()
函數可以識別普通字符(如'x'
)或由箭頭鍵和功能鍵發送的轉義序列。 例如,鍵入向上箭頭鍵可能會發送序列 (Escape, '[', 'A'),但getch()
將返回int
值KEY_UP
。 它甚至使用時間信息來區分自己發送的轉義字符和作為序列一部分的轉義字符。
要成功使用getch()
,您首先必須調用initscr()
,它會清除屏幕,以便initscr()
可以控制顯示的內容。
有沒有一種方便的方法來識別特殊鍵而不占用屏幕? 理想情況下,我想調用getch()
沒有先調用initscr()
並使其返回,如果我曾呼吁它會返回的值相同initscr()
但實驗表明,不起作用。
這是我正在嘗試做的一個非工作示例。 程序提示用戶輸入 Up、Down、Escape、Left、Right,並確認輸入了正確的鍵。
使用-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)
更新:使用除curses 以外的其他方法的解決方案會很好。 它必須直接或間接使用 terminfo 來了解要查找的輸入序列。 (在我看來,識別特殊鍵輸入應該很簡單,而不是與接管整個屏幕密切相關。)
在initscr
之前調用的filter
函數告訴curses 使用單行(而不是整個屏幕)。 在ncurses-examples 中有一個使用示例(名為“過濾器”),它由命令提示符組成。
getch
至少更新屏幕的一部分,例如,當它回顯輸入時。 該更新可以只影響一行(使用filter
),也可以影響整個屏幕。 如果你很聰明,你可以關閉回聲,並且(因為filter
抑制屏幕擦除),假裝它根本不更新。 例如,您可以通過使用newterm
初始化 curses 來將輸出重定向到/dev/null
。
回顯輸入只是故事的一部分:curses 確實初始化了屏幕,並且由getch
完成的相關refresh
將很難以可移植的方式避免。 示例程序中有一個特定於 ncurses 的選項,可以解決正常/備用屏幕之間不需要的切換,這可能在屏幕初始化期間發生。
這是“過濾器”的屏幕截圖,表明它不會接管整個屏幕。 反向視頻是由於 ncurses 初始化顏色(黑底白字),但正如幫助消息所示,這是可配置的。 不制作電影,很難證明它處理特殊鍵,但閱讀源代碼應該足夠了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.