按下键时如何准备stdin文件描述符?

时间:2019-05-31 08:55:06

标签: c linux select stdin

我有一个自定义_kbhit()函数,用于非阻塞字符输入。 _kbhit()函数使用select()来检查stdin是否已准备好读取。 但是最后,只要按回车键,我就已经准备好标准输入。 当我按任意键时如何使其工作?

void set_conio_terminal_mode()
{
    struct termios new_termios;

    /* take two copies - one for now, one for later */
    tcgetattr(0, &new_termios);

    /* register cleanup handler, and set the new terminal mode */
    atexit(reset_terminal_mode);
    cfmakeraw(&new_termios);
    tcsetattr(0, TCSANOW, &new_termios);
}

int _kbhit()
{
    struct timeval tv = { 0L, 0L };
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(0, &fds);
    return select(1, &fds, NULL, NULL, &tv);
}

static char _getch(void) {
    int r;
    unsigned char c;
    if ((r = read(0, &c, sizeof(c))) < 0) {
        return r;
    } else {
        return c;
    }
}

int main( int argc, char *argv[] )
{
    set_conio_terminal_mode();
    while (1) {
        if (_kbhit()) {
            inputbuffer[inputlen] = _getch();
            if (inputbuffer[inputlen] >= 0x20 && inputbuffer[inputlen] < 0x7F) {
                putchar(inputbuffer[inputlen]);
                inputlen++;
            }
        }
    }
}

我希望这段代码将输出echo,但是在我按RETURN键后它会输出整个字符串。

1 个答案:

答案 0 :(得分:1)

我认为问题在于-尽管您使用cfmakeraw()初始化了终端属性-stdout仍处于行缓冲模式。

尝试将标准输出设置为非缓冲模式。

setbuf(stdout, NULL);

等效于

setvbuf(stdout, NULL, _IONBF, 0);

这样可以避免在每个fflush(stdout);之后都需要调用putchar(inputbuffer[inputlen]);

有一种方法可以使用tcsetattr()而不是setvbuf()来完成此操作,但是我不熟悉。