【问题标题】:Recognizing special keys without taking over the screen在不占用屏幕的情况下识别特殊键
【发布时间】:2018-02-09 23:58:04
【问题描述】:

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

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

有没有一种方便的方法来识别特殊键而不占据屏幕?理想情况下,我想在不先调用initscr() 的情况下调用getch(),并让它返回与调用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)

更新:使用除诅咒以外的解决方案就可以了。它必须直接或间接地使用 terminfo 来了解要查找的输入序列。 (在我看来,识别特殊键输入应该很简单,并且与接管整个屏幕密切相关。)

【问题讨论】:

  • 没时间回答,但也许man 3 termcap与你想要的有关
  • curses 库不提供这样的代码,AFAIK。您必须自己使用终端属性。您可能会发现(部分)How to distinguish between escape and escape sequence 中的讨论很有用。问题的一部分是为键序列定义代码。另一部分是识别关键序列。其余大部分或多或少是机械编码。

标签: c unix ncurses terminfo


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 2014-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多