在curses模式之外使用getch的便携性如何?

时间:2019-01-12 23:52:09

标签: c ncurses portability curses

我正在开发一种终端程序,以识别各个按键,包括小键盘按键,但我宁愿不要以curses / program模式进行操作。我认为,与其使用terminfo和某种映射或树结构来快速进行键盘按键匹配来重新发明轮子,不如说我可能只是利用curses并使用tcgetattr()tcsetattr()来执行我想在curses模式之外执行的操作仍然使用curses I / O功能为我完成键盘按键的翻译。令我惊讶的是,这行得通(Linux,ncurses 6.1.20180127):

/**
 * Most error checking elided for brevity.
 */
#include <stdio.h>     // printf
#include <string.h>    // memcpy

#include <curses.h>
#include <termios.h>   // tcgetattr, tcsetattr

int main(void)
{
    struct termios curr, new_shell_mode;
    int c, fd;
    SCREEN *sp;
    FILE *ttyf;

    /*
     * Initialize desired abilities in curses.
     * This unfortunately clears the screen, so
     * a refresh() is required, followed by
     * endwin().
     */
    ttyf = fopen("/dev/tty", "r+b");
    fd = fileno(ttyf);
    sp = newterm(NULL, ttyf, ttyf);
    raw();
    noecho();
    nonl();
    keypad(stdscr, TRUE);
    refresh();
    // Save the current curses mode TTY attributes for later use.
    tcgetattr(fd, &curr);
    endwin();

    /*
     * Set the shell/non-curses mode TTY attributes to
     * match those of program/curses mode (3 attempts).
     */
    memcpy(&new_shell_mode, &curr, sizeof curr);
    for (c = 0; c < 3; c++) {
        tcsetattr(fd, TCSADRAIN, &new_shell_mode);
        tcgetattr(fd, &curr);
        if (0 == memcmp(&new_shell_mode, &curr, sizeof curr))
            break;
    }
    // If new shell mode could fully be set, get a key press.
    if (c != 3)
        c = getch();
    reset_shell_mode();
    delscreen(sp);
    fclose(ttyf);
    printf("%02X\n", c);
    return 0;
}

但是,考虑到我已经退出了curses模式,以所示方式仍然使用getch()真的安全/便携式吗?

还是我需要采取更困难的路径来使用setupterm()来加载terminfo数据库并遍历strnames数组,为每个数组调用tigetstr(),并设置自己的termios手动标记并自己处理读按键?

如果stdscr仍然有效,那么XSI Curses规范中的任何内容似乎都不禁止这样做,这似乎一直存在,直到程序退出或调用delwin()为止,我可以继续使用它,并且由于{ {1}}已连接到我的stdscr文件(该文件为终端文件),我可以使用它来获取按键,而无需自己处理所有事情。

1 个答案:

答案 0 :(得分:1)

您使用 newterm 初始化了诅咒,并且您未将 称为 {{1} } :如果curses进行 endwin 作为 refresh 的副作用,它将恢复全屏模式。< / p>

这不仅是ncurses,而且是任何curses实现(除了1980年代早已过时的BSD版本)。 X/Open Curses笔记

  

如果当前或指定的窗口不是填充板,并且自上次刷新操作以来已被移动或修改,则将在读取另一个字符之前对其进行刷新。

在您的示例中,没有任何内容被“移动或修改”。但是getch检查。 ( getch / termios东西可能无法获得任何东西,因为 endwin 直到第一个< strong> newterm )。