Linux input

Some notes on using /dev/input/* device driver files.

mouseX / mice

These device files are created by the mousedev driver.

  • /dev/input/mouseX represents the input stream for a SINGLE mouse device.
  • /dev/input/mice represents the merged input stream for ALL mouse devices.

The data stream consists of 3 bytes per event. An event is encoded as (BTN, X, Y).

  • BTN button pressed
  • X movement in x-direction -1 -> left and 1 -> right
  • Y movement in y-direction -1 -> down and 1 -> up

The raw data stream can be inspected as follows.

sudo cat /dev/input/mice | od -tx1 -w3 -v

eventX

These device files are created by the evdev driver.

  • /dev/input/eventX represents the generic input event interface a SINGLE input device.

Input events are encoded as given by the input_event struct below. Reading from the eventX device file will always yield whole number of input events.

struct input_event {
    struct timeval time;
    unsigned short type;
    unsigned short code;
    unsigned int value;
};

On most 64bit machines the raw data stream can be inspected as follows.

sudo cat /dev/input/event4 | od -tx1 -w24 -v

Identifying device files.

To find out which device file is assigned to which input device the following file /proc/bus/input/devices in the proc filesystem can be consulted.

This yields entries as follows and shows which Handlers are assigned to which Name.

I: Bus=0018 Vendor=04f3 Product=0033 Version=0000
N: Name="Elan Touchpad"
...
H: Handlers=event15 mouse0
...

Example: Toying with /dev/input/eventX

Once compiled, the example should be run as sudo ./event /dev/input/eventX.

#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <time.h>

#include <sys/time.h>
#include <linux/input-event-codes.h>

struct input_event {
    struct timeval time;
    unsigned short type;
    unsigned short code;
    unsigned int value;
};

const char* type(unsigned short t) {
    static char buf[32];
    const char* fmt = "0x%x";
    switch (t) {
#define FMT(TYPE) case TYPE: fmt = #TYPE"(0x%x)"; break
        FMT(EV_SYN);
        FMT(EV_KEY);
        FMT(EV_REL);
        FMT(EV_ABS);
#undef FMT
    }
    snprintf(buf, sizeof(buf), fmt, t);
    return buf;
}

const char* code(unsigned short c) {
    static char buf[32];
    const char* fmt = "0x%x";
    switch (c) {
#define FMT(CODE) case CODE: fmt = #CODE"(0x%x)"; break
        FMT(BTN_LEFT);
        FMT(BTN_RIGHT);
        FMT(BTN_MIDDLE);
        FMT(REL_X);
        FMT(REL_Y);
#undef FMT
    }
    snprintf(buf, sizeof(buf), fmt, c);
    return buf;
}

const char* timefmt(const struct timeval* t) {
    assert(t);
    struct tm* lt = localtime(&t->tv_sec); // Returns pointer to static tm object.
    static char buf[64];
    strftime(buf, sizeof(buf), "%H:%M:%S", lt);
    return buf;
}

int main(int argc, char* argv[]) {
    assert(argc == 2);

    int fd = open(argv[1], O_RDONLY);
    assert(fd != -1);

    struct input_event inp;
    while (1) {
        int ret = read(fd, &inp, sizeof(inp));
        assert(ret == sizeof(inp));
        printf("time: %s type: %s code: %s value: 0x%x\n",
               timefmt(&inp.time), type(inp.type), code(inp.code), inp.value);
    }
}