在C中实现KeyPress事件

 可以吸的果冻Ci 发布于 2023-02-03 11:49

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

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

Chris Dodd.. 6

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

#include 

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为在从stdin读取时根本不等待键击.

但是,如果您正在使用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 个回答
  • 这严重依赖于系统.在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为在从stdin读取时根本不等待键击.

    但是,如果您正在使用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角色.

    2023-02-03 11:51 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有