1

在使用cursesorncurses库的程序中,该getch()函数可以识别普通字符(如'x')或箭头和功能键发送的转义序列。例如,键入向上箭头键可能会发送序列 (Escape, '[', 'A'),但getch()会返回intKEY_UP。它甚至使用时间信息来区分自己发送的转义字符和序列中的转义字符。

getch()成功使用,您首先必须调用initscr(),它会清除屏幕,以便curses 可以控制显示的内容。

有没有一种方便的方法可以在占用屏幕的情况下识别特殊键?理想情况下,我想在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 来了解要查找的输入序列。(在我看来,识别特殊键输入应该很简单,而不是与接管整个屏幕密切相关。)

4

1 回答 1

2

filter之前调用的函数initscr告诉curses 使用单行(而不是整个屏幕)。在ncurses-examples中有一个使用示例(名为“过滤器”),其中包含一个命令提示符。

getch至少更新屏幕的一部分,例如,当它回显输入时。该更新可能仅影响一行(使用filter)或整个屏幕。如果你很聪明,你可以关闭回声,并且(因为filter抑制屏幕擦除),假装它根本没有更新。例如,您可以/dev/null通过初始化 curses将输出重定向到newterm.

回显输入只是故事的一部分:curses 确实会初始化屏幕,而相关联refresh的操作getch会使这种情况难以以可移植的方式避免。示例程序中有一个特定于 ncurses 的选项,可以解决在屏幕初始化期间可能发生的正常/备用屏幕之间不必要的切换。

这是“过滤器”的屏幕截图,表明它不会占据整个屏幕。反向视频是由于 ncurses 初始化颜色(黑底白字),但正如帮助消息所示,这是可配置的。如果不制作电影,很难证明它处理特殊键,但阅读源代码应该足够了。

过滤程序示例

于 2018-02-10T00:52:43.573 回答