Erik Figueiredo Erik Figueiredo - 6 months ago 26
Linux Question

Capture HID keyboard event

The code below works fine for only one input device. Unfortunately I need to capture about 12 different HID devices (RFID readers), so I would like to know if does anyone know how to adapt the code to work with 12 different inputs?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <termios.h>
#include <signal.h>

int main(int argc, char* argv[])
{
struct input_event ev[64];
int fevdev = -1;
int result = 0;
int size = sizeof(struct input_event);
int rd;
int value;
char name[256] = "Unknown";
char *device = "/dev/input/event3";


fevdev = open(device, O_RDONLY);
if (fevdev == -1) {
printf("Failed to open event device.\n");
exit(1);
}

result = ioctl(fevdev, EVIOCGNAME(sizeof(name)), name);
printf ("Reading From : %s (%s)\n", device, name);

printf("Getting exclusive access: ");
result = ioctl(fevdev, EVIOCGRAB, 1);
printf("%s\n", (result == 0) ? "SUCCESS" : "FAILURE");

while (1)
{
if ((rd = read(fevdev, ev, size * 64)) < size) {
break;
}

value = ev[0].value;

if (value != ' ' && ev[1].value == 1 && ev[1].type == 1) {
printf ("Code[%d]\n", (ev[1].code));
}
}

printf("Exiting.\n");
result = ioctl(fevdev, EVIOCGRAB, 1);
close(fevdev);
return 0;
}

Answer

Call open() for each device, and then use select() (or (e)poll()) to monitor all of the file descriptors together so you can detect which devices have data available to then be read() from at any given moment.

Update: For example:

struct event_device
{
    char *device;
    int fd;
};

int main(int argc, char* argv[])
{
    struct input_event ev[64];
    int numevents;
    int result = 0;
    int size = sizeof(struct input_event);
    int rd;
    char name[256];
    char* device[12];
    event_device evdevs[12], *evdev;
    int numevdevs = 0;
    fd_set fds;
    int maxfd;

    device[0] = "/dev/input/event3";
    device[1] = "/dev/input/event4";
    // and so on...

    for (int i = 0; i < 12; ++i) {
        evdev = &evdevs[numevdevs];

        evdev->device = device[i];
        evdev->fd = open(evdev->device, O_RDONLY);
        if (evdev->fd == -1) {
            printf("Failed to open event device: %s.\n", evdev->device);
            continue;
        }
        ++numevdevs;

        memset(name, 0, sizeof(name));
        result = ioctl(evdev->fd, EVIOCGNAME(sizeof(name)), name);
        printf ("Reading From : %s (%s)\n", evdev->device, name);

        printf("Getting exclusive access: ");
        result = ioctl(evdev->fd, EVIOCGRAB, 1);
        printf("%s\n", (result == 0) ? "SUCCESS" : "FAILURE");
    }

    if (numevdevs == 0) {
        exit(1);
    }

    while (1)
    {
        FD_ZERO(&fds);
        maxfd = -1;

        for (int i = 0; i < numevdevs; ++i) {
            evdev = &evdevs[i];
            FD_SET(evdev->fd, &fds);
            if (maxfd < evdev->fd) maxfd = evdev->fd;
        }

        result = select(maxfd+1, &fds, NULL, NULL, NULL);
        if (result == -1) {
            break;        
        }

        for (int i = 0; i < numevdevs; ++i) {
            evdev = &evdevs[i];

            if (!FD_ISSET(evdev->fd, &fds)) {
                continue;
            }

            if ((rd = read(evdev->fd, ev, size * 64)) < size) {
                continue;
            }

            numevents = rd / size;
            for (int j = 0; j < numevents; ++j) {
                printf ("%s: Type[%d] Code[%d] Value[%d]\n", evdev->device, ev[j].type, ev[j].code, ev[j].value);
            }
        }
    }

    printf("Exiting.\n");

    for (int i = 0; i < numevdevs; ++i) {
        evdev = &evdevs[i];
        result = ioctl(evdev->fd, EVIOCGRAB, 0);
        close(evdev->);
    }

    return 0;
}
Comments