识别特殊键而不占用屏幕

时间:2018-02-09 23:58:04

标签: c unix ncurses terminfo

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

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

有没有方便的方法来识别特殊键而不用接管屏幕?理想情况下,我想在没有先调用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来知道要查找的输入序列。 (在我看来,识别特殊键输入应该是直截了当的,并且与接管整个屏幕密切相关。)

1 个答案:

答案 0 :(得分:1)

filter之前调用的initscr函数告诉curses使用单行(而不是整个屏幕)。在ncurses-examples中有一个使用它的例子(名为&#34; filter&#34;),它包含一个命令提示符。

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

回应输入只是故事的一部分:curses会初始化屏幕,refresh完成的相关getch会以便携的方式避免这种情况。示例程序中有一个特定于ncurses的选项,它可以在正常/备用屏幕之间进行不需要的切换,这可能在屏幕初始化期间发生。

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

example of filter program