Linux – How do I use system calls on Linux to wait for keystrokes to interrupt?

How do I use system calls on Linux to wait for keystrokes to interrupt?… here is a solution to the problem.

How do I use system calls on Linux to wait for keystrokes to interrupt?

I want in my program to receive an interrupt when the user presses a special key like F1-12, which is written in nasm. I just have to wait for the feature keystrokes at the beginning of my main feature. I know this can be achieved with int 16h of the BIOS, which returns a scan code. How do I do this under Linux?

Solution

The code required for this is quite complex; I eventually figured out how to check F1 in C using raw ioctl, read, and write. If you are familiar with assembly and Linux system calls, then converting to NASM should be simple.

This is not what you want, as it only checks F1 and not the rest. The order of F1 is 0x1b, 0x4f, 0x50. You can use od -t x1 and press the key to find other sequences. For example, F2 is 0x1b, 0x4f, 0x51.

The basic idea is that we take the current terminal properties, update them to the original (cfmakeraw), and set them back. The ioctl system call is used for this purpose.

On a terminal in raw mode, read() will fetch any character typed by the user, unlike the “cooked” mode in which the kernel uses the backspace key and the control key for row editing until the user submits the line by pressing enter or 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;
}

I based this answer on which is very helpful.

Related Problems and Solutions