3

Basically, what I am trying to do is capture keyboard input from the user, using files in "/dev/input/". However, a problem I have come across is that the file which handles keyboard input is different on event files. What do I mean by this? Well, on my specific machine, "/dev/input/event5" works with this program, but I've seen that, on some people's machines, the file might be event4, event0, event3, or even event17.

Is there a way that I can programmatically figure out which file handles keyboard input?

If you want to test the code, make sure you run with root privileges. You need them to open any files in "/dev/input/".

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/input.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
 
#define UK "UNKNOWN"
#define ESCAPE(key) (key == KEY_ESC)
#define SHIFT(key)  ((key == KEY_LEFTSHIFT) || (key == KEY_RIGHTSHIFT))
 
static const char *keycodes[] =
{
    "RESERVED", "ESC", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
    "-", "=", "BACKSPACE", "TAB", "q", "w", "e", "r", "t", "y", "u", "i",
    "o", "p", "[", "]", "ENTER", "L_CTRL", "a", "s", "d", "f", "g", "h",
    "j", "k", "l", ";", "'", "`", "L_SHIFT", "\\", "z", "x", "c", "v", "b",
    "n", "m", ",", ".", "/", "R_SHIFT", "*", "L_ALT", "SPACE", "CAPS_LOCK", 
    "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "NUM_LOCK",
    "SCROLL_LOCK", "NL_7", "NL_8", "NL_9", "-", "NL_4", "NL5",
    "NL_6", "+", "NL_1", "NL_2", "NL_3", "INS", "DEL", UK, UK, UK,
    "F11", "F12", UK, UK,   UK, UK, UK, UK, UK, "R_ENTER", "R_CTRL", "/", 
    "PRT_SCR", "R_ALT", UK, "HOME", "UP", "PAGE_UP", "LEFT", "RIGHT", "END", 
    "DOWN", "PAGE_DOWN", "INSERT", "DELETE", UK, UK, UK, UK,UK, UK, UK, 
    "PAUSE"
};
 
static const char *shifted_keycodes[] =
{
    "RESERVED", "ESC", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", 
    "_", "+", "BACKSPACE", "TAB", "Q", "W", "E", "R", "T", "Y", "U", "I", 
    "O", "P", "{", "}", "ENTER", "L_CTRL", "A", "S", "D", "F", "G", "H", 
    "J", "K", "L", ":", "\"", "~", "L_SHIFT", "|", "Z", "X", "C", "V", "B", 
    "N", "M", "<", ">", "?", "R_SHIFT", "*", "L_ALT", "SPACE", "CAPS_LOCK", 
    "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "NUM_LOCK", 
    "SCROLL_LOCK", "HOME", "UP", "PGUP", "-", "LEFT", "NL_5", 
    "R_ARROW", "+", "END", "DOWN", "PGDN", "INS", "DEL", UK, UK, UK, 
    "F11", "F12", UK, UK,   UK, UK, UK, UK, UK, "R_ENTER", "R_CTRL", "/", 
    "PRT_SCR", "R_ALT", UK, "HOME", "UP", "PAGE_UP", "LEFT", "RIGHT", "END", 
    "DOWN", "PAGE_DOWN", "INSERT", "DELETE", UK, UK, UK, UK,UK, UK, UK, 
    "PAUSE"
};
 
static int running;
static int keyboard_fd;
 
static void sig_handler(int signo)
{
    running = 0;
}
 
void input_demo_init(char *keyboard_eventfile)
{
    signal(SIGINT, sig_handler);
 
    running = 1;
 
    if ((keyboard_fd = open(keyboard_eventfile, O_RDONLY)) < 0) {
        fprintf(stderr, "\nUnable to read from the device\n");
        exit(EXIT_FAILURE);
    }
}
 
void input_demo_exit(void)
{
    close(keyboard_fd);
}
 
void input_demo_run(void)
{
    int shift_flag = 0;
    struct input_event event;
 
    while (running) {
        read(keyboard_fd, &event, sizeof(event));
 
        /* If a key from the keyboard is pressed */
        if (event.type == EV_KEY && event.value == 1) {
            if (ESCAPE(event.code))
                return;
 
            if (SHIFT(event.code))
                shift_flag = event.code;
 
            if (shift_flag && !SHIFT(event.code))
                printf("%s\n", shifted_keycodes[event.code]);
            
            else if (!shift_flag && !SHIFT(event.code))
                printf("%s\n", keycodes[event.code]);
        }
        else {
            /* If a key from the keyboard is released */
            if (event.type == EV_KEY && event.value == 0)
                if (SHIFT(event.code))
                    shift_flag = 0;
        }
    }
}
 
int main(int argc, char **argv) {
 
    input_demo_init("/dev/input/event5");
    input_demo_run();
    input_demo_exit();
 
    return 0;
}
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Reddington
  • 31
  • 1

2 Answers2

2

You can try

cat /proc/bus/input/devices
I: Bus=001e Vendor=0000 Product=0000 Version=0001
N: Name="vc4"
P: Phys=vc4/input0
S: Sysfs=/devices/platform/soc/fef00700.hdmi/rc/rc0/input1
U: Uniq=
H: Handlers=kbd event0
B: PROP=20
B: EV=100017
B: KEY=ffffc000000000 3ff 0 400000320fc200 40830c900000000 0 210300 49d2c040ec00 1e378000000000 8010000010000000
B: REL=3
B: MSC=10

I: Bus=001e Vendor=0000 Product=0000 Version=0001
N: Name="vc4"
P: Phys=vc4/input0
S: Sysfs=/devices/platform/soc/fef05700.hdmi/rc/rc1/input2
U: Uniq=
H: Handlers=kbd event1
B: PROP=20
B: EV=100017
B: KEY=ffffc000000000 3ff 0 400000320fc200 40830c900000000 0 210300 49d2c040ec00 1e378000000000 8010000010000000
B: REL=3
B: MSC=10

hope that can help you.

Jiahao
  • 76
  • 1
  • 7
1

This answer is based on the answer on Edit2 here: https://unix.stackexchange.com/a/94329/28489. This also might help: https://github.com/torvalds/linux/blob/02de58b24d2e1b2cf947d57205bd2221d897193c/include/linux/input.h#L45

The Keyboard usually sends those three event types: EV_SYN, EV_KEY, and EV_MSC.

To read what events get published in "/dev/input/event5":

    if(ioctl(keyboard_fd, EVIOCGRAB, 1) < 0) print("error");
    unsigned long evbits;
    int request = EVIOCGBIT(0, sizeof(unsigned long));
    if(ioctl(keyboard_fd, EVIOCGBIT(0, sizeof(unsigned long)), & evbits) <0) print("error") // to get what type of events that this device broadcast.
    keyboardEventsMask = 0x13 // this corresponds to 0001 0011 The three on flags correspond to EV_MSC, EV_KEY, and EV_SYN respectivaly.
    var result = keyboardEventsMask & evbits;
    if(result == keyboardEventsMask) // Yes, /dev/input/event5 is a keyboard.

Note: The link above also suggests to check the keys that the device broadcasts using ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), &keybit);