[PATCH libevdev 1/6] Add support for uinput device creation

Benjamin Tissoires benjamin.tissoires at gmail.com
Wed Aug 14 05:45:31 PDT 2013


On Tue, Aug 13, 2013 at 12:39 PM, Peter Hutterer
<peter.hutterer at who-t.net> wrote:
> This lets libevdev provide a relatively generic interface for the
> creation of uinput devices so we don't need to duplicate this across
> multiple projects.
>
> Most of this is lifted from the current test implementation, with a
> couple of minor changes.
>
> EV_REP needs special handling:
> Kernel allows to set the EV_REP bit, it doesn't set REP_* bits (which we
> wrap anyway) but it will also set the default values (500, 33).
>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>  doc/libevdev.doxygen.in        |   3 +-
>  libevdev/Makefile.am           |   5 +-
>  libevdev/libevdev-uinput-int.h |  29 +++++
>  libevdev/libevdev-uinput.c     | 285 +++++++++++++++++++++++++++++++++++++++++
>  libevdev/libevdev-uinput.h     | 232 +++++++++++++++++++++++++++++++++
>  libevdev/libevdev.c            |   1 -
>  test/Makefile.am               |   3 +
>  7 files changed, 555 insertions(+), 3 deletions(-)
>  create mode 100644 libevdev/libevdev-uinput-int.h
>  create mode 100644 libevdev/libevdev-uinput.c
>  create mode 100644 libevdev/libevdev-uinput.h
>
> diff --git a/doc/libevdev.doxygen.in b/doc/libevdev.doxygen.in
> index 4511ae8..855b317 100644
> --- a/doc/libevdev.doxygen.in
> +++ b/doc/libevdev.doxygen.in
> @@ -668,7 +668,8 @@ WARN_LOGFILE           =
>  # directories like "/usr/src/myproject". Separate the files or directories
>  # with spaces.
>
> -INPUT                  = @top_srcdir@/libevdev/libevdev.h
> +INPUT                  = @top_srcdir@/libevdev/libevdev.h \
> +                        @top_srcdir@/libevdev/libevdev-uinput.h
>
>  # This tag can be used to specify the character encoding of the source files
>  # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
> diff --git a/libevdev/Makefile.am b/libevdev/Makefile.am
> index 9879c0e..2e99c2a 100644
> --- a/libevdev/Makefile.am
> +++ b/libevdev/Makefile.am
> @@ -6,12 +6,15 @@ libevdev_la_SOURCES = \
>                     libevdev.h \
>                     libevdev-int.h \
>                     libevdev-util.h \
> +                   libevdev-uinput.c \
> +                   libevdev-uinput.h \
> +                   libevdev-uinput-int.h \
>                     libevdev.c
>
>  libevdev_la_LDFLAGS = -version-info $(LIBEVDEV_LT_VERSION) -export-symbols-regex '^libevdev_' $(GCOV_LDFLAGS)
>
>  libevdevincludedir = $(includedir)/libevdev-1.0/libevdev
> -libevdevinclude_HEADERS = libevdev.h
> +libevdevinclude_HEADERS = libevdev.h libevdev-uinput.h
>
>  event-names.h: Makefile make-event-names.py
>                 $(srcdir)/make-event-names.py --output=c > $@
> diff --git a/libevdev/libevdev-uinput-int.h b/libevdev/libevdev-uinput-int.h
> new file mode 100644
> index 0000000..70fa1e1
> --- /dev/null
> +++ b/libevdev/libevdev-uinput-int.h
> @@ -0,0 +1,29 @@
> +/*
> + * Copyright © 2013 Red Hat, Inc.
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +
> +struct libevdev_uinput {
> +       int fd; /**< file descriptor to uinput */
> +       char *name; /**< device name */
> +       char *syspath; /**< /sys path */
> +       time_t ctime[2]; /**< before/after UI_DEV_CREATE */
> +};
> diff --git a/libevdev/libevdev-uinput.c b/libevdev/libevdev-uinput.c
> new file mode 100644
> index 0000000..3009fba
> --- /dev/null
> +++ b/libevdev/libevdev-uinput.c
> @@ -0,0 +1,285 @@
> +/*
> + * Copyright © 2013 Red Hat, Inc.
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +#define _GNU_SOURCE
> +#include <config.h>
> +#include <fcntl.h>
> +#include <poll.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <dirent.h>
> +#include <sys/stat.h>
> +#include <time.h>
> +#include <linux/uinput.h>
> +
> +#include "libevdev.h"
> +#include "libevdev-int.h"
> +#include "libevdev-uinput.h"
> +#include "libevdev-uinput-int.h"
> +#include "libevdev-util.h"
> +
> +#define SYS_INPUT_DIR "/sys/devices/virtual/input/"
> +
> +static struct libevdev_uinput *
> +alloc_uinput_device(const char *name)
> +{
> +       struct libevdev_uinput *uinput_dev;
> +
> +       uinput_dev = calloc(1, sizeof(struct libevdev_uinput));
> +       if (uinput_dev)
> +               uinput_dev->name = strdup(name);
> +
> +       return uinput_dev;
> +}
> +
> +int set_evbits(const struct libevdev *dev, int fd, struct uinput_user_dev *uidev)

hmm, it looks like either this function should be prefixed with
libevdev_uinput, or it should be static.

> +{
> +       int rc = 0;
> +       unsigned int type;
> +
> +       for (type = 0; type < EV_MAX; type++) {
> +               unsigned int code;
> +               int max;
> +               int uinput_bit;
> +               const unsigned long *mask;
> +
> +               if (!libevdev_has_event_type(dev, type))
> +                       continue;
> +
> +               rc = ioctl(fd, UI_SET_EVBIT, type);
> +               if (rc == -1)
> +                       break;
> +
> +               /* uinput can't set EV_REP */
> +               if (type == EV_REP)
> +                       continue;
> +
> +               max = type_to_mask_const(dev, type, &mask);
> +               if (max == -1)
> +                       continue;
> +
> +               switch(type) {
> +                       case EV_KEY: uinput_bit = UI_SET_KEYBIT; break;
> +                       case EV_REL: uinput_bit = UI_SET_RELBIT; break;
> +                       case EV_ABS: uinput_bit = UI_SET_ABSBIT; break;
> +                       case EV_MSC: uinput_bit = UI_SET_MSCBIT; break;
> +                       case EV_LED: uinput_bit = UI_SET_LEDBIT; break;
> +                       case EV_SND: uinput_bit = UI_SET_SNDBIT; break;
> +                       case EV_FF: uinput_bit = UI_SET_FFBIT; break;
> +                       case EV_SW: uinput_bit = UI_SET_SWBIT; break;
> +                       default:
> +                                   rc = -1;
> +                                   errno = EINVAL;
> +                                   goto out;
> +               }
> +
> +               for (code = 0; code < max; code++) {
> +                       if (!libevdev_has_event_code(dev, type, code))
> +                               continue;
> +
> +                       rc = ioctl(fd, uinput_bit, code);
> +                       if (rc == -1)
> +                               goto out;
> +
> +                       if (type == EV_ABS) {
> +                               const struct input_absinfo *abs = libevdev_get_abs_info(dev, code);
> +                               uidev->absmin[code] = abs->minimum;
> +                               uidev->absmax[code] = abs->maximum;
> +                               uidev->absfuzz[code] = abs->fuzz;
> +                               uidev->absflat[code] = abs->flat;
> +                               /* uinput has no resolution in the device struct, this needs
> +                                * to be fixed in the kernel */
> +                       }
> +               }
> +
> +       }
> +
> +out:
> +       return rc;
> +}
> +
> +int set_props(const struct libevdev *dev, int fd, struct uinput_user_dev *uidev)

ditto

> +{
> +       unsigned int prop;
> +       int rc = 0;
> +
> +       for (prop = 0; prop < INPUT_PROP_MAX; prop++) {
> +               if (!libevdev_has_property(dev, prop))
> +                       continue;
> +
> +               rc = ioctl(fd, UI_SET_PROPBIT, prop);
> +               if (rc == -1)
> +                       break;
> +       }
> +       return rc;
> +}
> +
> +int
> +libevdev_uinput_create_from_device(const struct libevdev *dev, int fd, struct libevdev_uinput** uinput_dev)

The code looks good, but I don't really like the parameter "fd". To
me, it looks like this parameter can only be a fresh open of
/dev/uinput node, with the right permissions and parameters. Besides,
having this as a parameter, would allow a user to use it twice for two
different uinput devices.

To my mind, the parameter should be omitted and the open called in
libevdev_uinput_create_from_device(). If the user wants to have a
handle to it, it can call libevdev_uinput_get_fd(), and it will also
allows us to close the fd in libevdev_uinput_destroy().

Cheers,
Benjamin

> +{
> +       int rc;
> +       struct uinput_user_dev uidev;
> +       struct libevdev_uinput *new_device;
> +
> +       new_device = alloc_uinput_device(libevdev_get_name(dev));
> +       if (!new_device)
> +               return -ENOMEM;
> +
> +       memset(&uidev, 0, sizeof(uidev));
> +
> +       strncpy(uidev.name, libevdev_get_name(dev), UINPUT_MAX_NAME_SIZE - 1);
> +       uidev.id.vendor = libevdev_get_id_vendor(dev);
> +       uidev.id.product = libevdev_get_id_product(dev);
> +       uidev.id.bustype = libevdev_get_id_bustype(dev);
> +       uidev.id.version = libevdev_get_id_version(dev);
> +
> +       if (set_evbits(dev, fd, &uidev) != 0)
> +               goto error;
> +       if (set_props(dev, fd, &uidev) != 0)
> +               goto error;
> +
> +       rc = write(fd, &uidev, sizeof(uidev));
> +       if (rc < 0)
> +               goto error;
> +       else if (rc < sizeof(uidev)) {
> +               errno = EINVAL;
> +               goto error;
> +       }
> +
> +       /* ctime notes before/after ioctl to help us filter out devices
> +          when traversing /sys/devices/virtual/input inl
> +          libevdev_uinput_get_syspath.
> +
> +          this is in seconds, so ctime[0]/[1] will almost always be
> +          identical but /sys doesn't give us sub-second ctime so...
> +        */
> +       new_device->ctime[0] = time(NULL);
> +
> +       rc = ioctl(fd, UI_DEV_CREATE, NULL);
> +       if (rc == -1)
> +               goto error;
> +
> +       new_device->ctime[1] = time(NULL);
> +       new_device->fd = fd;
> +
> +       *uinput_dev = new_device;
> +
> +       return 0;
> +
> +error:
> +       return -errno;
> +}
> +
> +void libevdev_uinput_destroy(struct libevdev_uinput *uinput_dev)
> +{
> +       ioctl(uinput_dev->fd, UI_DEV_DESTROY, NULL);
> +       free(uinput_dev->name);
> +       free(uinput_dev);
> +}
> +
> +int libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev)
> +{
> +       return uinput_dev->fd;
> +}
> +
> +const char* libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev)
> +{
> +       DIR *dir;
> +       struct dirent *dent;
> +
> +       if (uinput_dev->syspath != NULL)
> +               return uinput_dev->syspath;
> +
> +       /* FIXME: use new ioctl() here once kernel supports it */
> +
> +       dir = opendir(SYS_INPUT_DIR);
> +       if (!dir)
> +               return NULL;
> +
> +       while((dent = readdir(dir))) {
> +               struct stat st;
> +               int fd;
> +               char path[sizeof(SYS_INPUT_DIR) + 64];
> +               char buf[256];
> +               int len;
> +
> +               if (strncmp("input", dent->d_name, 5) != 0)
> +                       continue;
> +
> +               strcpy(path, SYS_INPUT_DIR);
> +               strcat(path, dent->d_name);
> +
> +               if (stat(path, &st) == -1)
> +                       continue;
> +
> +               /* created before/after UI_DEV_CREATE */
> +               if (st.st_ctime < uinput_dev->ctime[0] ||
> +                   st.st_ctime > uinput_dev->ctime[1])
> +                       continue;
> +
> +               /* created after UI_DEV_CREATE */
> +               strcat(path, "/name");
> +               fd = open(path, O_RDONLY);
> +               if (fd < 0)
> +                       continue;
> +
> +               len = read(fd, buf, sizeof(buf));
> +               if (len > 1) {
> +                       buf[len - 1] = '\0'; /* file contains \n */
> +                       if (strcmp(buf, uinput_dev->name) == 0) {
> +                               strcpy(path, SYS_INPUT_DIR);
> +                               strcat(path, dent->d_name);
> +                               uinput_dev->syspath = strdup(path);
> +                               close(fd);
> +                               break;
> +                       }
> +               }
> +
> +               close(fd);
> +       }
> +
> +       closedir(dir);
> +
> +       return uinput_dev->syspath;
> +}
> +
> +int libevdev_uinput_write_event(const struct libevdev_uinput *uinput_dev,
> +                               unsigned int type,
> +                               unsigned int code,
> +                               int value)
> +{
> +       struct input_event ev = { {0,0}, type, code, value };
> +       int fd = libevdev_uinput_get_fd(uinput_dev);
> +       int rc;
> +
> +       if (type > EV_MAX)
> +               return -EINVAL;
> +
> +       if (code > libevdev_get_event_type_max(type))
> +               return -EINVAL;
> +
> +       rc = write(fd, &ev, sizeof(ev));
> +
> +       return rc < 0 ? -errno : 0;
> +}
> diff --git a/libevdev/libevdev-uinput.h b/libevdev/libevdev-uinput.h
> new file mode 100644
> index 0000000..9e19ad2
> --- /dev/null
> +++ b/libevdev/libevdev-uinput.h
> @@ -0,0 +1,232 @@
> +/*
> + * Copyright © 2013 Red Hat, Inc.
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and its
> + * documentation for any purpose is hereby granted without fee, provided that
> + * the above copyright notice appear in all copies and that both that copyright
> + * notice and this permission notice appear in supporting documentation, and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no representations
> + * about the suitability of this software for any purpose.  It is provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +#ifndef libevdev_uinput_H
> +#define libevdev_uinput_H
> +
> +#include <libevdev/libevdev.h>
> +
> +struct libevdev_uinput;
> +
> +/**
> + * @defgroup uinput uinput device creation
> + *
> + * Creation of uinput devices based on existing libevdev devices. These functions
> + * help to create uinput devices that emulate libevdev devices. In the simplest
> + * form it serves to duplicate an existing device:
> + *
> + * @code
> + * int err;
> + * int new_fd;
> + * struct libevdev *dev;
> + * struct libevdev_uinput *uidev;
> + * struct input_event ev[2];
> + *
> + * err = libevdev_new_from_fd(&dev, fd);
> + * if (err != 0)
> + *     return err;
> + *
> + * uifd = open("/dev/uinput", O_RDWR);
> + * if (uidev < 0)
> + *     return -errno;
> + *
> + * err = libevdev_uinput_create_from_device(dev, uifd, &uidev);
> + * if (err != 0)
> + *     return err;
> + *
> + * // post a REL_X event
> + * err = libevdev_uinput_write(event(uidev, EV_REL, REL_X, -1);
> + * if (err != 0)
> + *     return err;
> + * libevdev_uinput_write(event(uidev, EV_SYN, SYN_REPORT, 0);
> + * if (err != 0)
> + *     return err;
> + *
> + * libevdev_uinput_destroy(uidev);
> + * close(uifd);
> + *
> + * @endcode
> + *
> + * Alternatively, a device can be constructed from scratch:
> + *
> + * @code
> + * int err;
> + * struct libevdev *dev;
> + * struct libevdev_uinput *uidev;
> + *
> + * dev = libevdev_new();
> + * libevdev_set_name(dev, "test device");
> + * libevdev_enable_event_type(dev, EV_REL);
> + * libevdev_enable_event_code(dev, EV_REL, REL_X);
> + * libevdev_enable_event_code(dev, EV_REL, REL_Y);
> + * libevdev_enable_event_type(dev, EV_KEY);
> + * libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT);
> + * libevdev_enable_event_code(dev, EV_KEY, BTN_MIDDLE);
> + * libevdev_enable_event_code(dev, EV_KEY, BTN_RIGHT);
> + *
> + * uifd = open("/dev/uinput", O_RDWR);
> + * if (uidev < 0)
> + *     return -errno;
> + *
> + * err = libevdev_uinput_create_from_device(dev, uifd, &uidev);
> + * if (err != 0)
> + *     return err;
> + *
> + * // ... do something ...
> + *
> + * libevdev_uinput_destroy(uidev);
> + * close(uifd);
> + *
> + * @endcode
> + */
> +
> +/**
> + * @ingroup uinput
> + *
> + * Create a uinput device based on the libevdev device given. The uinput device
> + * will be an exact copy of the libevdev device, minus the bits that uinput doesn't
> + * allow to be set.
> + *
> + * The device's lifetime is tied to the uinput file descriptor, closing it will
> + * destroy the uinput device. You should call libevdev_uinput_destroy() before
> + * closing the file descriptor to free allocated resources.
> + * A file descriptor can only create one uinput device at a time; the second device
> + * will fail with -EINVAL.
> + *
> + * You don't need to keep the file descriptor variable around,
> + * libevdev_uinput_get_fd() will return it when needed.
> + *
> + * @note Due to limitations in the uinput kernel module, REP_DELAY and
> + * REP_PERIOD will default to the kernel defaults, not to the ones set in the
> + * source device.
> + *
> + * @param dev The device to duplicate
> + * @param uinput_fd A file descriptor to @c /dev/uinput, opened with the required
> + * permissions to create a device. This fd may only be used once to create a
> + * uinput device.
> + * @param[out] uinput_dev The newly created libevdev device.
> + *
> + * @return 0 on success or a negative errno on failure. On failure, the value of
> + * uinput_dev is unmodified.
> + *
> + * @see libevdev_uinput_destroy
> + */
> +int libevdev_uinput_create_from_device(const struct libevdev *dev,
> +                                      int uinput_fd,
> +                                      struct libevdev_uinput **uinput_dev);
> +
> +/**
> + * @ingroup uinput
> + *
> + * Destroy a previously created uinput device and free associated memory.
> + *
> + * @note libevdev_uinput_destroy() does not close the fd.
> + *
> + * @param uinput_dev A previously created uinput device.
> + *
> + * @return 0 on success or a negative errno on failure
> + */
> +void libevdev_uinput_destroy(struct libevdev_uinput *uinput_dev);
> +
> +/**
> + * @ingroup uinput
> + *
> + * Return the file descriptor used to create this uinput device. This is the
> + * fd pointing to <strong>/dev/uinput</strong>. This file descriptor may be used to write
> + * events that are emitted by the uinput device.
> + * Closing this file descriptor will destroy the uinput device, you should
> + * call libevdev_uinput_destroy() first to free allocated resources.
> + *
> + * @param uinput_dev A previously created uinput device.
> + *
> + * @return The file descriptor used to create this device
> + */
> +int libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev);
> +
> +/**
> + * @ingroup uinput
> + *
> + * Return the syspath representing this uinput device.
> + * As of 3.11, the uinput kernel device does not
> + * provide a way to get the syspath directly through uinput so libevdev must guess.
> + * In some cases libevdev is unable to derive the syspath. If the running kernel
> + * supports the UI_GET_SYSPATH ioctl, the syspath is retrieved through that and will
> + * be reliable and not be NULL.
> + *
> + * To obtain a /dev/input/eventX device node from this path use the following code:
> + *
> + * @code
> + * DIR *dir;
> + * const char *syspath;
> + * struct dirent *dp;
> + * struct udev *udev;
> + * struct udev_device *udev_device;
> + *
> + * syspath = libevdev_uinput_get_syspath(uidev);
> + * udev = udev_new();
> + * dir = opendir(syspath);
> + * while ((dp = readdir(dir))) {
> + *      char *path;
> + *
> + *      if (strncmp(dp->d_name, "event", 5) != 0)
> + *          continue;
> + *
> + *      asprintf(&path, "%s/%s", syspath, dp->d_name);
> + *      udev_device = udev_device_new_from_syspath(udev, path);
> + *      printf("device node: %s\n", udev_device_get_devnode(udev_device));
> + *      udev_device_unref(udev_device);
> + *      free(path);
> + * }
> + *
> + * closedir(dir);
> + * udev_unref(udev);
> + * @endcode
> + *
> + *
> + * @note This function may return NULL. libevdev currently uses ctime and
> + * the device name to guess devices. To avoid false positives, wait at least
> + * wait at least 1.5s between creating devices that have the same name.
> + * @param uinput_dev A previously created uinput device.
> + * @return The syspath for this device, including preceding /sys.
> + */
> +const char*libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev);
> +
> +/**
> + * @ingroup uinput
> + *
> + * Post an event through the uinput device. It is the caller's responsibility
> + * that any event sequence is terminated with an EV_SYN/SYN_REPORT/0 event.
> + * Otherwise, listeners on the device node will not see the events until the
> + * next EV_SYN event is posted.
> + *
> + * @param uinput_dev A previously created uinput device.
> + * @param type Event type (EV_ABS, EV_REL, etc.)
> + * @param code Event code (ABS_X, REL_Y, etc.)
> + * @param value The event value
> + * @return 0 on success or a negative errno on error
> + */
> +int libevdev_uinput_write_event(const struct libevdev_uinput *uinput_dev,
> +                               unsigned int type,
> +                               unsigned int code,
> +                               int value);
> +
> +#endif /* libevdev_uinput_H */
> diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
> index 5883447..9448f1c 100644
> --- a/libevdev/libevdev.c
> +++ b/libevdev/libevdev.c
> @@ -27,7 +27,6 @@
>  #include <string.h>
>  #include <unistd.h>
>  #include <stdarg.h>
> -#include <linux/uinput.h>
>
>  #include "libevdev.h"
>  #include "libevdev-int.h"
> diff --git a/test/Makefile.am b/test/Makefile.am
> index 12f7176..8cad6c7 100644
> --- a/test/Makefile.am
> +++ b/test/Makefile.am
> @@ -5,8 +5,11 @@ TESTS = $(noinst_PROGRAMS)
>
>  libevdev_sources = $(top_srcdir)/libevdev/libevdev.c \
>                    $(top_srcdir)/libevdev/libevdev.h \
> +                  $(top_srcdir)/libevdev/libevdev-uinput.h \
> +                  $(top_srcdir)/libevdev/libevdev-uinput.c \
>                    $(top_srcdir)/libevdev/libevdev-util.h \
>                    $(top_srcdir)/libevdev/libevdev-int.h
> +                  $(top_srcdir)/libevdev/libevdev-uinput-int.h
>  common_sources = $(libevdev_sources) \
>                  test-common-uinput.c \
>                  test-common-uinput.h \
> --
> 1.8.2.1
>
> _______________________________________________
> Input-tools mailing list
> Input-tools at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/input-tools


More information about the Input-tools mailing list