在C中实现KeyPress事件

时间:2014-01-13 12:21:22

标签: c multithreading keypress

我有一个像下面这样的无限循环,在这个循环中,我想连续检查键盘,看看是否按下了退出键(ESC)。如果按下,则应该打破循环。我怎么能用C做到这一点? (我正在使用gcc,并且在必须通过线程完成的情况下也可以访问pthreads)

 while(1){
        //do something
        //check for the ESC key
 }

3 个答案:

答案 0 :(得分:6)

这严重依赖于系统。在Unix / Linux系统中,默认终端处理程序收集行,仅在完整行可用时通知程序(在 Enter 命中后)。如果您想立即按键,则需要放置终端进入非规范模式:

#include <termios.h>

struct termios info;
tcgetattr(0, &info);          /* get current terminal attirbutes; 0 is the file descriptor for stdin */
info.c_lflag &= ~ICANON;      /* disable canonical mode */
info.c_cc[VMIN] = 1;          /* wait until at least one keystroke available */
info.c_cc[VTIME] = 0;         /* no timeout */
tcsetattr(0, TCSANOW, &info); /* set immediately */

完成后,您可以使用从stdin读取的任何调用,它们将返回键而无需等待行尾。您还可以设置c_cc[VMIN] = 0,使其在从标准输入读取时根本不等待击键。

但是,如果您正在使用stdio FILE相关调用(getchar等)读取stdin,则设置VMIN = 0会使您认为只要没有可用键就已达到EOF,因此您必须调用clearerr之后恰好尝试阅读更多字符。您可以使用如下循环:

int ch;
while((ch = getchar()) != 27 /* ascii ESC */) {
    if (ch < 0) {
        if (ferror(stdin)) { /* there was an error... */ }
        clearerr(stdin);
        /* do other stuff */
    } else {
        /* some key OTHER than ESC was hit, do something about it? */
    }
}

完成后,您可能希望确保将终端设置回规范模式,以免其他程序(例如您的shell)混淆:

tcgetattr(0, &info);
info.c_lflag |= ICANON;
tcsetattr(0, TCSANOW, &info);

您还可以使用tcsetattr执行其他操作 - 有关详细信息,请参阅手册页。可能满足您的目的的一件事是设置另一个EOL角色。

答案 1 :(得分:0)

如果你正在做的主要工作可以放在这个主循环中,你可以在非阻塞模式下使用STDIN。您仍然遇到正常进行线路缓冲的终端问题。您也应将终端设置为原始模式。

使用Ctrl-C(中断)怎么样?

非阻塞意味着即使文件中没有新字节,read()系统调用也会立即返回。在Linux / Unix上,您可以通过这种方式使STDIN无阻塞:

#include <unistd.h>
#include <fcntl.h>
fcntl(0, F_SETFL, O_NONBLOCK); /* 0 is the stdin file decriptor */

答案 2 :(得分:0)

这就是您想要的:

#include <stdio.h>
#include <conio.h>

void main() {

   int c;

   while((c = getch()) != EOF )
      if(c == 27)   break;
/* 27 is the ASCII code for Esc */

}