C - как опросить () ввод без буферизации? - PullRequest
0 голосов
/ 25 января 2019

Я пытаюсь обнаружить любой символ, введенный в stdin (без символа новой строки).

Я пытался:

setvbuf(stdin, NULL, _IONBF); //This returns 0
struct pollfd pfd = {STDIN_FILENO, POLLIN};

while (!poll(pfd, 1, ms)) {
  /* do some thing, e.g. printf("n\n"); */
}

По-видимому, печать не прекращается, когда я набираю q , но останавливается после нажатия , ввода .Система, над которой я работаю, это arch-linux, компилятор gcc.

Ответы [ 2 ]

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

Это работает для меня, но это может зависеть от вашей системы / терминала

#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>

int main() {
    int i = 0;
    struct termios ts;
    tcgetattr(0, &ts);
    ts.c_lflag &= ~ICANON;
    tcsetattr(0, TCSANOW, &ts);
    while (!ioctl(0, FIONREAD, &i) && !i) {
        printf("x");
        fflush(stdout);
        sync();
        usleep(100);
    }
    printf("\n");
    return 0;
}

Крейг действительно ответил за вас.Мне было просто любопытно найти реализацию.Ioctl (0, FIONREAD, & i) получает количество символов в буфере и помещает его в i.Страницы руководства для termios и ioctl_tty содержали все детали, необходимые для разработки этого решения.

Честно говоря, если вы хотите сделать что-то интерактивное, ncurses делает его несколько проще.

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

q задерживается в драйвере / буфере слоя TTY ядра , потому что он находится в режиме "готово".

В этом режиме приложение будет возвращать что-либо в приложение только тогда, когда драйвер увидит новую строку. Затем он возвращает: q\n (т.е. q<newline>).

Чтобы он немедленно возвращался на любом символе, вам придется использовать вызовы ioctl, чтобы перевести слой TTY в «сырой» режим.

Вам нужно будет использовать [рекомендуемые] вызовы termios: tcgetattr и tcsetattr

.

UPDATE:

Будет ли работать только ioctl? Какая команда соответствует для перевода терминала в режим raw?

Посмотрите на man termios. В нем есть полная документация о том, как установить необработанный режим (так называемый неканонический режим на странице руководства).

Прошло много времени с тех пор, как я это сделал, но вот функция скелета.

Хотя функция восстанавливает исходное состояние в конце, вы можете установить неканонический режим один раз при запуске программы.

Но тогда вам придется обрабатывать все свои собственные редактирование строк (например, поддержку возврата и т. Д.) Для других разделов вашей программы, которые хотят нормального канонического редактирования строк.

#include <termios.h>
#include <unistd.h>

void
change_tty(int fd)
{
    struct termios orig;
    struct termios raw;

    // get original cooked/canonical mode values
    tcgetattr(fd,&orig);

    // set options for raw mode
    raw = orig;
#if 0
    raw.c_lflag &= ~ICANON;
    raw.c_cc[VMIN] = ...
    raw.c_cc[VTIME] = ...
#else
    cfmakeraw(&raw);
#endif

    // put unit into raw mode ...
    tcsetattr(fd,TCSANOW,&raw);

    // do stuff in raw mode ...

    // restore original mode
    tcsetattr(fd,TCSANOW,&orig);
}
...