Насколько переносимо использование режима getch outside curses? - PullRequest
0 голосов
/ 13 января 2019

Я работаю над программой терминала для распознавания отдельных нажатий клавиш, включая клавиши клавиатуры, но я бы не стал делать это в режиме проклятий / программы, если это возможно. Вместо того, чтобы заново изобретать колесо с помощью terminfo и какого-либо отображения или древовидной структуры для быстрого сопоставления клавиш клавиатуры, я подумал, что мог бы просто использовать проклятия и использовать tcgetattr() и tcsetattr(), чтобы делать то, что я хочу, вне режима проклятий, все еще используя проклятия 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;
}

Однако, учитывая, что я вышел из режима проклятий, действительно ли безопасно / переносимо все еще использовать getch() указанным способом?

Или мне нужно выбрать более сложный путь использования setupterm() для загрузки БД terminfo и перебрать массив strnames, вызывая tigetstr() для каждого, плюс вручную установить свои собственные флаги termios и заняться чтением Сама клавиша?

Ничто в спецификации XSI Curses, по-видимому, не запрещает этого, при условии, что stdscr остается действительным, что, по-видимому, либо до выхода из программы, либо до вызова delwin(), я могу продолжать использовать его, и поскольку подключено stdscr к моему ttyf файлу, который является терминалом, я могу использовать его для нажатия клавиш, не прибегая к самостоятельной обработке.

1 Ответ

0 голосов
/ 13 января 2019

Вы инициализировали проклятия, используя newterm, и не имеет значения , которые вы называли endwin: проклятия будут возобновите полноэкранный режим, если он вызывает refresh как побочный эффект вызова getch.

Это не просто ncurses, а любая реализация curses (за исключением давно устаревших версий BSD 1980-х). X / Открытые проклятия Примечания

Если текущее или указанное окно не является пэдом, и оно было перемещено или изменено с момента последней операции обновления, то оно будет обновлено до прочтения другого символа.

В вашем примере ничего не было "перемещено или изменено". Но getch проверяет. (Вероятно, ничего не получится с помощью endwin / termios, так как newterm не делает четкий экран до первого refresh).

...