如何在Linux上使用系统调用等待击键中断?

时间:2014-12-08 19:38:08

标签: linux assembly kernel nasm system-calls

我希望在用户按下我的程序中的F1-12特殊击键时收到一个中断,这是用nasm编写的。我只需要在主函数的开头等待一个函数击键。我知道这可以通过BIOS int 16h来实现,它会返回一个扫描码。我怎么能在Linux下做到这一点?

1 个答案:

答案 0 :(得分:3)

这方面的必要代码相当复杂;我最终想出了如何使用原始ioctl,读取和写入来检查C中的F1。如果您熟悉汇编和Linux系统调用,那么对nasm的翻译应该是直截了当的。

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

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

在原始模式的终端上,read()将获得用户键入的任何字符,而不像" cooked"模式,其中内核使用backspace和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,这非常有用。