在Linux上测试按键是否被按下而不阻塞的方法

3

我正在寻找如何测试按键是否被按下,测试不应该阻塞程序。如果没有太多依赖,我可以使用一个小型库,但不幸的是ncurses太重了。


这是不相关的话题,因为您正在要求我们提供代码/教程。 - Irrational Person
"我不能使用ncurse。"为什么?无论如何,你可以看一下它们的源代码,了解它们实际上是如何做到的。 - πάντα ῥεῖ
@πάνταῥεῖ 可能是因为它太重了吧?从问题中可以看出:“如果它们不太重,我可以使用一些小型库”。 - Borgleader
2
这不是离题。这种类型的问题正是大多数人使用此网站的原因。(虽然我想象不出它不是重复的...) - indiv
相关的内容请参考https://dev59.com/wobca4cB1Zd3GeqPY7C9#27827955(该示例是关于鼠标的,但Linux内核统一了输入设备,所以键盘也差不多)。 - sehe
6
这个问题并不是离题的。目前来看,它只是一个懒惰提出的问题,不符合一个好问题的准则。 - Rapptz
2个回答

4
我找到了一个解决方案:
int khbit() const
{
    struct timeval tv;
    fd_set fds;
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    FD_ZERO(&fds);
    FD_SET(STDIN_FILENO, &fds);
    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
    return FD_ISSET(STDIN_FILENO, &fds);
}

void nonblock(int state) const
{
    struct termios ttystate;
    tcgetattr(STDIN_FILENO, &ttystate);

    if ( state == 1)
    {
        ttystate.c_lflag &= (~ICANON & ~ECHO); //Not display character
        ttystate.c_cc[VMIN] = 1;
    }
    else if (state == 0)
    {
        ttystate.c_lflag |= ICANON;
    }
    tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
}

bool keyState(int key) const //Use ASCII table
{
    bool pressed;
    int i = khbit(); //Alow to read from terminal
    if (i != 0)
    {
        char c = fgetc(stdin);
        if (c == (char) key)
        {
            pressed = true;
        }
        else
        {
            pressed = false;
        }
    }

    return pressed;
}

int main()
{
    nonblock(1);
    int i = 0;
    while (!i)
    {
        if (cmd.keyState(32)) //32 in ASCII table correspond to Space Bar
        {
            i = 1;
        }
    }
    nonblock(0);

    return 0;
}

它运行良好。感谢你的帮助。我希望它能帮助到其他人 :)


2
它适用于非root用户,谢谢!只是不要忘记在等待按键时稍微使用usleep()(这不是我的情况,所以我没有必要),并且在使用后不要忘记恢复回显状态:在nonblock()中使用ttystate.c_lflag |= ICANON | ECHO; - Shlublu
太棒了!非常感谢。Shiublu关于重新启用回显是正确的。我想补充一下,你需要这些包含文件 #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <termios.h> - Algoman
我还要补充一点,这些函数不能是const的,因为它们会修改环境(g++ 5.4在此方面失败)。而且我更喜欢这个修改后的keystate函数,它只告诉你哪个键被按下了,而不是测试是否按下了特定的键:bool keystate(int& key) { if(khbit() == 0) return false; key = fgetc(stdin); return true; } - Algoman

0

我不知道你具体在寻找什么。

  • 我最近在这里从“原始”输入设备节点进行了概念验证阅读:boost::asio read from /dev/input/event0。示例是使用鼠标,但Linux内核统一了输入设备,因此键盘也差不多。

    你所需要的只是UNIX权限来打开/读取设备文件(如果这对你的部署方式更方便,你可以将它们创建在/etc-tree之外)。

    该示例显示了完整的事件异步处理

  • 我已经使用XTest绑定(libxtst)(实际上是发送按键),我想这可能包含你需要的功能

  • 然后还有XInput,它(据我所知)构成了XOrg抽象“原始”输入设备流的方式,我在第一个选项中描述了它们


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接