如何检查Linux中是否按下了某个键?

时间:2010-10-18 18:40:44

标签: linux

我需要知道Linux中的哪个中断检查是否按下了任何键?

1 个答案:

答案 0 :(得分:5)

我假设你想在终端模拟器上(而不是在X客户端上),并且你不关心密钥释放。

Linux的方法是使用termios(3)将终端设置为非规范或原始模式,然后使用常用的libc函数读取stdin。

Linux上的系统调用号在/usr/include/asm/unistd.h(或unistd_64.h)上,但是termios函数最终转换为ioctl()。所以,如果你因为一些奇怪和不寻常的原因不能调用libc,你必须查找ioctl的系统调用号,以及与termios函数相对应的ioctl。

修改

显然,你假设Linux使用与DOS相同的模型,其中控制台输入是键盘的抽象(具有类似KEYPRESSED,GETC等的函数),控制台输出是一个抽象的面向字符的显示。

Unix / Linux抽象是关于终端,它可以是物理控制台,串口上的终端(或终端仿真器),xterm,......这里重点是通过默认情况下,在终端(或终端仿真器)看到行分隔符之前,输入行不可用于程序。

在POSIX上,这些终端由termios(3)功能控制。 Linux最终将这些调用转换为ioctl()调用,如下所示(请参阅tty_ioctl(4)):

  • tcgetattr(fd,arg)=> ioctl(fd,TCGETS,arg)
  • tcsetattr(fd,TCSANOW,arg)=> ioctl(fd,TCSETS,arg)
  • tcsetattr(fd,TCSADRAIN,arg)=> ioctl(fd,TCSETSW,arg)
  • tcsetattr(fd,TCSAFLUSH,arg)=> ioctl(fd,TCSETSF,arg)
  • ...

所以,一个C程序使用termios(3)poll(2)执行您要求的操作(为了简洁和清晰起见,错误检查被删除):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <poll.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>

static sig_atomic_t end = 0;

static void sighandler(int signo)
{
    end = 1;
}

int main()
{
    struct termios oldtio, curtio;
    struct sigaction sa;

    /* Save stdin terminal attributes */
    tcgetattr(0, &oldtio);

    /* Make sure we exit cleanly */
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = sighandler;
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGQUIT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);

    /* This is needed to be able to tcsetattr() after a hangup (Ctrl-C)
     * see tcsetattr() on POSIX
     */
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = SIG_IGN;
    sigaction(SIGTTOU, &sa, NULL);

    /* Set non-canonical no-echo for stdin */
    tcgetattr(0, &curtio);
    curtio.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(0, TCSANOW, &curtio);

    /* main loop */
    while (!end) {
            struct pollfd pfds[1];
            int ret;
            char c;

            /* See if there is data available */
            pfds[0].fd = 0;
            pfds[0].events = POLLIN;
            ret = poll(pfds, 1, 0);

            /* Consume data */
            if (ret > 0) {
                    printf("Data available\n");
                    read(0, &c, 1);
            }
    }

    /* restore terminal attributes */
    tcsetattr(0, TCSANOW, &oldtio);

    return 0;
}

现在,ioctlpoll是系统调用,您可以在/usr/include/asm/unistd.h(x86上的54和168)和/ usr / include /上找到它们的编号asm / ioctls.h具有您需要的ioctl常量(在x86上:TCGETS = 0x5401,TCSETS = 0x5402,TCSETSW = 0x5403,TCSETSF = 0x5404)。