How to Capture Raw Hid Input on Linux

How can I capture raw HID input on Linux?

You'll want uinput. You'll listen on your /dev/usb/hiddev0 and then create new events that you'll send out on /dev/input/uinput.

This explains it and gives a little tutorial:
Using uinput driver in Linux- 2.6.x to send user input {This is the EInfochips' "Dashboard" publication issue January 2007 "Tip of the Month" article mentioned on this archived page}.

How to capture an input device and prevent it's default behavior

You could open the raw input device for reading (basically ioctl with parameter EVIOCGRAB for Linux and RegisterRawInputDevices() for Windows as discussed here and here). However, the mechanisms are quite different for Windows and Linux, so you will end up implementing all the low-level logic twice.

It should also be possible to read the input data stream from the standard input just like you would read an input from the keyboard (e.g. scanf() or fgets() in C) with some logic that recognizes when a data set (= tag ID) is complete - the reader device might for example terminate an input with a newline '\n' or null character '\0'.

You should probably do this in a separate thread and have some kind of producer-consumer mechanism or event model for communication with your main application.

Capture HID keyboard event

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;
}

Can you get Windows raw input data immediately without WM_INPUT messages?

You can use (possibly overlapped - for async reads) ReadFile on a HID device file handle.
See Obtaining HID Reports article and HClient sample application that is doing both - enumerating devices and reads from them. It is doing that without WM_INPUT/Raw Input API.

Interacting with raw HID devices using Python?

Under the hood, your python application uses hidapi C library, which as of this moment doesn't support getting usage/usage_page-es on Linux.

So, answering your direct question: currently there is no way to get usage/usage_page directly from Python, specifically, using hid library.

There is an active discussion to add such support of-the-box:
https://github.com/libusb/hidapi/pull/139



Related Topics



Leave a reply



Submit