本文介绍了C 非阻塞键盘输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用 C 语言(在 Linux 上)编写一个程序,该程序会循环直到用户按下某个键,但不需要按键来继续每个循环.

I'm trying to write a program in C (on Linux) that loops until the user presses a key, but shouldn't require a keypress to continue each loop.

有没有简单的方法可以做到这一点?我想我可以用 select() 做到这一点,但这似乎需要做很多工作.

Is there a simple way to do this? I figure I could possibly do it with select() but that seems like a lot of work.

或者,有没有办法在程序关闭而不是非阻塞 io 之前捕获 - 按键进行清理?

Alternatively, is there a way to catch a - keypress to do cleanup before the program closes instead of non-blocking io?

推荐答案

如前所述,您可以使用 sigaction 捕获 ctrl-c,或使用 select 捕获任何标准输入.

As already stated, you can use sigaction to trap ctrl-c, or select to trap any standard input.

但是请注意,使用后一种方法,您还需要设置 TTY,使其处于一次字符而不是一次行模式.后者是默认设置——如果你输入一行文本,它不会被发送到正在运行的程序的标准输入中,直到你按下回车键.

Note however that with the latter method you also need to set the TTY so that it's in character-at-a-time rather than line-at-a-time mode. The latter is the default - if you type in a line of text it doesn't get sent to the running program's stdin until you press enter.

您需要使用 tcsetattr() 函数来关闭 ICANON 模式,并且可能也禁用 ECHO.根据记忆,您还必须在程序退出时将终端设置回 ICANON 模式!

You'd need to use the tcsetattr() function to turn off ICANON mode, and probably also disable ECHO too. From memory, you also have to set the terminal back into ICANON mode when the program exits!

为了完整起见,这里有一些我刚刚编写的代码(注意:没有错误检查!)它设置了一个 Unix TTY 并模拟了 DOS <conio.h> 函数 kbhit()getch():

Just for completeness, here's some code I've just knocked up (nb: no error checking!) which sets up a Unix TTY and emulates the DOS <conio.h> functions kbhit() and getch():

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <termios.h>

struct termios orig_termios;

void reset_terminal_mode()
{
    tcsetattr(0, TCSANOW, &orig_termios);
}

void set_conio_terminal_mode()
{
    struct termios new_termios;

    /* take two copies - one for now, one for later */
    tcgetattr(0, &orig_termios);
    memcpy(&new_termios, &orig_termios, sizeof(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) > 0;
}

int getch()
{
    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 (!kbhit()) {
        /* do some work */
    }
    (void)getch(); /* consume the character */
}

这篇关于C 非阻塞键盘输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 19:30