当前位置:  开发笔记 > 运维 > 正文

C非阻塞键盘输入

如何解决《C非阻塞键盘输入》经验,为你挑选了4个好方法。

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

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

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



1> Alnitak..:

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

但请注意,对于后一种方法,您还需要设置TTY,使其一次一个字符而不是一次一行模式.后者是默认值 - 如果您键入一行文本,则在按Enter键之前不会将其发送到正在运行的程序的stdin.

您需要使用该tcsetattr()功能关闭ICANON模式,也可能还禁用ECHO.从内存中,您还必须在程序退出时将终端设置回ICANON模式!

为了完整性,这里有一些代码我刚刚敲了(nb:没有错误检查!),它设置了一个Unix TTY并模拟了DOS 函数,kbhit()并且getch():

#include 
#include 
#include 
#include 
#include 

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);
}

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 */
}



2> Norman Ramse..:

select()为方便起见有点太低级了.我建议您使用该ncurses库将终端设置为cbreak模式和延迟模式,然后调用getch(),ERR如果没有字符准备就会返回:

WINDOW *w = initscr();
cbreak();
nodelay(w, TRUE);

那时你可以getch不受阻塞地打电话.


是的,诅咒是全有或全无.

3> Mehrdad Afsh..:

在UNIX系统上,您可以使用sigactioncall为SIGINT信号注册信号处理程序,该信号处理程序代表Control + C键序列.信号处理程序可以设置一个标志,该标志将在循环中检查,使其适当地中断.



4> Jon Clegg..:

你可能想要 kbhit();

//Example will loop until a key is pressed
#include 
#include 

using namespace std;

int main()
{
    while(1)
    {
        if(kbhit())
        {
            break;
        }
    }
}

这可能不适用于所有环境.一种可移植的方法是创建一个监视线程并设置一些标志getch();


绝对不便携.kbhit()是DOS/Windows控制台的IO功能.
Alnitak:我不知道它暗示了一个平台 - 什么是等效的Windows术语?
@Alnitak:我的意思是我在接触任何*nix之前很久就熟悉"非阻塞呼叫"一词......所以就像Zxaos一样,我永远不会意识到它会暗示一个平台.
@Alnitak为什么会将"非阻塞"作为一种编程概念,在Unix环境中更为熟悉?
推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有