如何检查Linux中是否按下了某个键? [英] How to check if a key was pressed in Linux?

查看:111
本文介绍了如何检查Linux中是否按下了某个键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

解决方案

我假设您希望在终端仿真器(而不是X客户端)上使用它,并且您不关心密钥的释放. /p>

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抽象是关于 terminals 的,它可以是物理控制台,串行端口上的终端(或终端仿真器),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).

I need to know which interrupt in Linux checks if any key was pressed?

解决方案

I'm assuming that you want this on a terminal emulator (and not on an X client), and that you don't care about key release.

The Linux way to do this would be to use termios(3) to set the terminal to non-canonical or to raw mode, then read stdin using the usual libc functions.

System call numbers on Linux are on /usr/include/asm/unistd.h (or unistd_64.h), but the termios functions end up getting converted to ioctl()'s. So, if you can't call libc for some strange and unusual reason, you'll have to lookup the syscall number for ioctl, and the ioctl's corresponding to termios functions.

Edit:

Apparently, you're assuming that Linux uses the same model as DOS, in which the console input is an abstraction of a keyboard (with functions like KEYPRESSED, GETC, ...) and the console output is an abstraction of a character-oriented display.

Unix/Linux abstraction is about terminals, which can be the physical console, a terminal (or terminal emulator) on a serial port, an xterm, ... An important point here is that by default, input lines are not made available to programs until the terminal (or terminal emulator) sees a line delimiter.

On POSIX, these terminals are controlled by the termios(3) functions. Linux ends up translating those to ioctl() calls, as follows (see 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)
  • ...

So, a C program to do what you asked for, using termios(3) and poll(2) (error checking stripped for brevity and clarity):

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

Now, ioctl and poll are syscalls, and you can find their numbers on /usr/include/asm/unistd.h (54 and 168 on x86), and /usr/include/asm/ioctls.h has the ioctl constants you need (on x86: TCGETS=0x5401, TCSETS=0x5402, TCSETSW=0x5403, TCSETSF=0x5404).

这篇关于如何检查Linux中是否按下了某个键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆