【问题标题】:How do I wait for a keystroke interrupt with a syscall on Linux?如何在 Linux 上通过系统调用等待击键中断?
【发布时间】:2015-02-06 13:16:41
【问题描述】:

我想在用户按下我的程序中的 F1-12 之类的特殊按键时接收中断,该程序是用 nasm 编写的。我只需要在我的主要功能开始时等待功能按键。我知道这可以通过 BIOS 的int 16h 来实现,它返回一个扫描码。如何在 Linux 下做到这一点?

【问题讨论】:

标签: linux assembly kernel nasm system-calls


【解决方案1】:

为此所需的代码相当复杂;我最终想出了如何在 C 中使用原始 ioctl、读取和写入来检查 F1。如果您熟悉汇编和 Linux 系统调用,那么转换为 nasm 应该很简单。

这并不完全是您想要的,因为它只检查 F1,而不检查其余部分。 F1的序列是0x1b、0x4f、0x50。您可以使用od -t x1 并按 键找到其他序列。例如,F2 为 0x1b、0x4f、0x51。

基本思想是我们获取当前终端属性,将它们更新为原始(cfmakeraw),然后将它们设置回来。为此使用 ioctl 系统调用。

在原始模式下的终端上,read() 将获取用户输入的任何字符,这与内核使用退格键和 control-u 进行行编辑的“熟”模式不同,直到用户提交该行通过按 enter 或 control-d (EOF)。

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

struct ktermios {
    tcflag_t c_iflag;
    tcflag_t c_oflag;
    tcflag_t c_cflag;
    tcflag_t c_lflag;
    cc_t c_line;
    cc_t c_cc[19];
};

int getch() {
    unsigned char c;
    read(0, &c, sizeof(c));
    return c;
}

int main(int argc, char *argv[]) {
    struct ktermios orig, new;
    ioctl(0, TCGETS, &orig);
    ioctl(0, TCGETS, &new);   // or more simply  new = orig;

    // from cfmakeraw documentation
    new.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
    new.c_oflag &= ~OPOST;
    new.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    new.c_cflag &= ~(CSIZE | PARENB);
    new.c_cflag |= CS8;

    ioctl(0, TCSETS, &new);

    while (1) {
        if (getch() == 0x1b && getch() == 0x4f && getch() == 0x50) {
            break;
        }
    }

    write(1, "Got F1!\n", 8);
    ioctl(0, TCSETS, &orig);    // restore original settings before exiting!
    return 0;
}

我根据this answer 做了这个,这很有帮助。

【讨论】:

  • 你不需要非阻塞;如果您只是想在read() 上旋转,请使用阻塞read!这里只有原始部分是个好主意。如果您有一个游戏循环,您希望每帧或模拟步骤检查一次击键,那么是的,您需要非阻塞(或使用select),但这只是无缘无故地浪费大量 CPU 时间. (和your asm version of this answer一样,你不需要2个ioctl系统调用,只需做new = orig然后修改它。)
  • 事实上,这段代码没有使用fcntl(0, F_SETFL, O_NONBLOCK) 使stdin 非阻塞,所以read(2) 会阻塞直到按键,编辑以从答案文本中删除这个坏建议。
猜你喜欢
  • 1970-01-01
  • 2019-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 2015-08-17
相关资源
最近更新 更多