Libsuinput

Thin userspace library on top of Linux uinput kernel module.

License: GPLv3+
Version: 0.6.1

Uinput is Linux kernel module which allows attaching userspace device drivers into the Linux kernel. However, its ioctl-interface is pretty low level from an application developer's perspective. This library provides a set of helper functions for making the usage of uinput easier. Libsuinput can be considered thin, because file descriptors it operates on can be passed to uinput's own ioctl requests and vice versa.

For example, one could open and initialize an uinput device via the standard ioctl API, but actually emit events using suinput API.

Usage examples

Note

You need to have uinput kernel module loaded to be able to emit input events. If it is not yet loaded in your system, load it by running:

modprobe uinput

To load it automatically on every boot, add uinput to /etc/modules.

Note

For the sake of presentational simplicty, error handling is omitted from the following examples.

Move mouse cursor

Create a virtual mouse and move it towards bottom-right.

#include <string.h>

#include <suinput.h>

int main(void)
{
        int uinput_fd;
        int rel_axes[] = {REL_X, REL_Y, REL_WHEEL};
        struct uinput_user_dev user_dev;
        int i;

        memset(&user_dev, 0, sizeof(struct uinput_user_dev));
        strcpy(user_dev.name, "libsuinput-example-mouse");

        uinput_fd = suinput_open();

        for (i = 0; i < 3; ++i) {
                suinput_enable_event(uinput_fd, EV_REL, rel_axes[i]);
        }

        suinput_create(uinput_fd, &user_dev);

        for (i = 0; i < 20; ++i) {
                suinput_emit(uinput_fd, EV_REL, REL_X, 5);
                suinput_emit(uinput_fd, EV_REL, REL_Y, 5);
                suinput_syn(uinput_fd);
        }

        suinput_destroy(uinput_fd);

        return 0;
}

Generate keyboard clicks

Create a virtual 4-key keyboard and write "hello" with it.

#include <string.h>

#include <suinput.h>

int main(void)
{
        int i;
        int uinput_fd;
        int keys[] = {KEY_E, KEY_H, KEY_L, KEY_O};
        struct uinput_user_dev user_dev;

        memset(&user_dev, 0, sizeof(struct uinput_user_dev));
        strcpy(user_dev.name, "libsuinput-example-keyboard");

        uinput_fd = suinput_open();

        for (i = 0; i < 4; ++i) {
                suinput_enable_event(uinput_fd, EV_KEY, keys[i]);
        }

        suinput_create(uinput_fd, &user_dev);

        suinput_emit_click(uinput_fd, KEY_H);
        suinput_syn(uinput_fd);

        suinput_emit_click(uinput_fd, KEY_E);
        suinput_syn(uinput_fd);

        suinput_emit_click(uinput_fd, KEY_L);
        suinput_syn(uinput_fd);

        suinput_emit_click(uinput_fd, KEY_L);
        suinput_syn(uinput_fd);

        suinput_emit_click(uinput_fd, KEY_O);
        suinput_syn(uinput_fd);

        suinput_destroy(uinput_fd);

        return 0;
}

Download and install

To get the source code, fetch the source code release tarball from releases and unpack it.

Then building and installing libsuinput is just a matter of running:

./configure
make
make install

Note

Alternatively, you can clone the git repository:

git clone https://github.com/tuomasjjrasanen/libsuinput.git
cd libsuinput

Then prepare the GNU Build System and build:

./autogen.sh
./configure
make
make install

API

The API of libsuinput consists solely of functions declared in suinput.h:

int suinput_open(void);
int suinput_destroy(int uinput_fd);

int suinput_enable_event(int uinput_fd, uint16_t ev_type, uint16_t ev_code);
int suinput_create(int uinput_fd, const struct uinput_user_dev *user_dev);

int suinput_write_event(int uinput_fd, const struct input_event *event);
int suinput_emit(int uinput_fd, uint16_t ev_type, uint16_t ev_code, int32_t ev_value);
int suinput_emit_click(int uinput_fd, uint16_t key_code);
int suinput_emit_combo(int uinput_fd, const uint16_t *key_codes, size_t len);
int suinput_syn(int uinput_fd);

The suinput_open() queries sysfs for the filepath of uinput device node, opens the device and returns its file descriptor. For each succesful call of suinput_open(), the user must call suinput_destroy() which unsurprisingly destroys the device and closes its file descriptor.

The suinput_enable_event() enables an event capability which is defined by the event type and code passed as arguments to the function. This function must be called before the device is created. Enabling new events after creating the device results in undefined behavior. After events have been enabled, the device must be created and initialized by calling suinput_create() which accepts a structure describing device-dependent information. The struct uinput_user_dev is defined in /usr/include/linux/uinput.h.

The suinput_write_event() is a low-level function which just writes the given event to the event device. The structure of the event is defined in /usr/include/linux/input.h. The suinput_emit() emits the given event timestamped with current system clock time. The suinput_emit_click() emits the given key event twice (press and release) with different values (1 and 0 respectively). The suinput_emit_combo() emits the given key combination by first emitting press events for each key and then release events in reversed order. Finally, to make the kernel to flush all events, suinput_syn() emits SYN_REPORT event.

Because libsuinput acts as a thin wrapper for several system calls, error handling of all functions follows the underlying system call error scheme: on error -1 is returned and errno is set accordingly.

Comments

Comments powered by Disqus