Терминал продолжает буферизовать нажатые клавиши - PullRequest
0 голосов
/ 27 июня 2019

Я пишу терминальный движок VT100, но обработка ввода несколько сложна. Сначала я инициализирую свой tty без эха.

static void init_tty() {
    if (tcgetattr(STDIN_FILENO, &ctty) != 0)
        throw std::runtime_error("can not get tty attribute");

    ctty.c_lflag &= ~(FLAG(ICANON) | FLAG(ECHO) | FLAG(ISIG));

    if (tcsetattr(STDIN_FILENO, TCSANOW, &ctty) != 0)
        throw std::runtime_error("can not set tty attribute");
}

Далее я инициализирую неблокирующий дескриптор файла клавиатуры.

static void init_keyboard(const char *device) {
    if ((kfd = open(device, FLAG(O_RDONLY) | FLAG(O_SYNC))) == -1)
        throw std::runtime_error("can not open keyboard fd");

    unsigned flags = fcntl(kfd, F_GETFL, 0);

    flags |= FLAG(O_NONBLOCK);

    if (fcntl(kfd, F_SETFL, flags) == -1)
        throw std::runtime_error("can not set keyboard fd flags");
}

Пока все хорошо. Основной цикл - это просто опрос событий, который прервется при нажатии ESC.

int main() {
    while (true) {
        read(kfd, evt, sizeof(input_event));

        if (evt->type == EV_KEY && evt->value == 1 && evt->code == KEY_ESC)
            break;
    }
}

Итак, я набираю несколько символов. Тем временем мой терминал буферизует все символы, которые я набираю. После выхода из программы все символы отображаются.

Итак, вот мой вопрос: как я могу отключить буферизацию выходного потока терминала во время работы моей программы?

Вот GIF, чтобы проиллюстрировать проблему.

Шаги:

  • sudo ./clac
  • двигатель работает, но не эхом; набрав несколько символов
  • нажатие ESC
  • введенные символы отображаются; выход из программы

enter image description here

Ответы [ 2 ]

0 голосов
/ 27 июня 2019

Я только что решил свою проблему. (https://unix.stackexchange.com/questions/126974/where-do-i-find-ioctl-eviocgrab-documented)

Итак, я получаю все события сразу после запуска моей программы, включая ENTER

Пример: sudo ./clac ENTER

Решением было добавить задержку в 1000 миллисекунд при запуске, а затем перехватить события fd с помощью

std::this_thread::sleep_for(std::chrono::seconds(1));

if (ioctl(kfd, EVIOCGRAB, FD_GRAB) == -1)
    throw std::runtime_error("can not set keyboard fd grab");

И когда программа выходит из UNGRAB, нажмите

.
if (ioctl(kfd, EVIOCGRAB, FD_UNGRAB) == -1)
    throw std::runtime_error("can not set keyboard fd ungrab");
0 голосов
/ 27 июня 2019

Программа не должна отображать типизированные клавиши, поэтому я отключился, но на заднем плане клавиши буферизуются. и когда программа выходит, эти символы были напечатаны. как я должен очистить некоторые буферы перед выходом.

Это можно сделать, позвонив по номеру

    tcflush(STDIN_FILENO, TCIFLUSH);

перед выходом; см. tcflush (3) - справочная страница Linux .

...