mirror of
https://gitlab.freedesktop.org/libevdev/libevdev.git
synced 2025-12-20 08:00:09 +01:00
Add support for uinput device creation
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). Device node is guessed based on the sysfs path: The sysfs path contains a eventN file, that corresponds to our /dev/input/eventN number. Use it so clients can quickly get the device node, without a libudev dependency. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
1b7c46b2f1
commit
1acbfb3579
6 changed files with 632 additions and 3 deletions
|
|
@ -652,7 +652,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
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
lib_LTLIBRARIES=libevdev.la
|
||||
|
||||
AM_CPPFLAGS = $(GCC_CFLAGS) $(GCOV_CFLAGS)
|
||||
AM_CPPFLAGS = $(GCC_CFLAGS) $(GCOV_CFLAGS) -I$(top_srcdir)
|
||||
|
||||
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 > $@
|
||||
|
|
|
|||
31
libevdev/libevdev-uinput-int.h
Normal file
31
libevdev/libevdev-uinput-int.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 */
|
||||
int fd_is_managed; /**< do we need to close it? */
|
||||
char *name; /**< device name */
|
||||
char *syspath; /**< /sys path */
|
||||
char *devnode; /**< device node */
|
||||
time_t ctime[2]; /**< before/after UI_DEV_CREATE */
|
||||
};
|
||||
361
libevdev/libevdev-uinput.c
Normal file
361
libevdev/libevdev-uinput.c
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* 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);
|
||||
uinput_dev->fd = -1;
|
||||
}
|
||||
|
||||
return uinput_dev;
|
||||
}
|
||||
|
||||
static int
|
||||
set_evbits(const struct libevdev *dev, int fd, struct uinput_user_dev *uidev)
|
||||
{
|
||||
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 < (unsigned int)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;
|
||||
}
|
||||
|
||||
static int
|
||||
set_props(const struct libevdev *dev, int fd, struct uinput_user_dev *uidev)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
open_uinput(void)
|
||||
{
|
||||
int fd = open("/dev/uinput", O_RDWR|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
LIBEVDEV_EXPORT int
|
||||
libevdev_uinput_get_fd(const struct libevdev_uinput *uinput_dev)
|
||||
{
|
||||
return uinput_dev->fd;
|
||||
}
|
||||
|
||||
static int is_event_device(const struct dirent *dent) {
|
||||
return strncmp("event", dent->d_name, 5) == 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
fetch_device_node(const char *path)
|
||||
{
|
||||
char *devnode = NULL;
|
||||
struct dirent **namelist;
|
||||
int ndev, i;
|
||||
|
||||
ndev = scandir(path, &namelist, is_event_device, alphasort);
|
||||
if (ndev <= 0)
|
||||
return NULL;
|
||||
|
||||
/* ndev should only ever be 1 */
|
||||
|
||||
for (i = 0; i < ndev; i++) {
|
||||
asprintf(&devnode, "/dev/input/%s", namelist[i]->d_name);
|
||||
free(namelist[i]);
|
||||
}
|
||||
|
||||
free(namelist);
|
||||
|
||||
return devnode;
|
||||
}
|
||||
|
||||
static int is_input_device(const struct dirent *dent) {
|
||||
return strncmp("input", dent->d_name, 5) == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
int ndev, i;
|
||||
|
||||
/* FIXME: use new ioctl() here once kernel supports it */
|
||||
|
||||
ndev = scandir(SYS_INPUT_DIR, &namelist, is_input_device, alphasort);
|
||||
if (ndev <= 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < ndev; i++) {
|
||||
int fd, len;
|
||||
char buf[sizeof(SYS_INPUT_DIR) + 64];
|
||||
struct stat st;
|
||||
|
||||
strcpy(buf, SYS_INPUT_DIR);
|
||||
strcat(buf, namelist[i]->d_name);
|
||||
|
||||
if (stat(buf, &st) == -1)
|
||||
continue;
|
||||
|
||||
/* created before UI_DEV_CREATE, or after it finished */
|
||||
if (st.st_ctime < uinput_dev->ctime[0] ||
|
||||
st.st_ctime > uinput_dev->ctime[1])
|
||||
continue;
|
||||
|
||||
/* created within time frame */
|
||||
strcat(buf, "/name");
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0)
|
||||
continue;
|
||||
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (len <= 0)
|
||||
continue;
|
||||
|
||||
buf[len - 1] = '\0'; /* file contains \n */
|
||||
if (strcmp(buf, uinput_dev->name) == 0) {
|
||||
strcpy(buf, SYS_INPUT_DIR);
|
||||
strcat(buf, namelist[i]->d_name);
|
||||
uinput_dev->syspath = strdup(buf);
|
||||
uinput_dev->devnode = fetch_device_node(buf);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ndev; i++)
|
||||
free(namelist[i]);
|
||||
free(namelist);
|
||||
|
||||
return uinput_dev->devnode ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LIBEVDEV_EXPORT int
|
||||
libevdev_uinput_create_from_device(const struct libevdev *dev, int fd, struct libevdev_uinput** uinput_dev)
|
||||
{
|
||||
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;
|
||||
|
||||
if (fd == LIBEVDEV_UINPUT_OPEN_MANAGED) {
|
||||
fd = open_uinput();
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
new_device->fd_is_managed = 1;
|
||||
} else if (fd < 0)
|
||||
return -EBADF;
|
||||
|
||||
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 ((size_t)rc < sizeof(uidev)) {
|
||||
errno = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* ctime notes time before/after ioctl to help us filter out devices
|
||||
when traversing /sys/devices/virtual/input to find the device
|
||||
node.
|
||||
|
||||
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;
|
||||
|
||||
if (fetch_syspath_and_devnode(new_device) == -1) {
|
||||
errno = ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*uinput_dev = new_device;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
libevdev_uinput_destroy(new_device);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
LIBEVDEV_EXPORT void
|
||||
libevdev_uinput_destroy(struct libevdev_uinput *uinput_dev)
|
||||
{
|
||||
ioctl(uinput_dev->fd, UI_DEV_DESTROY, NULL);
|
||||
if (uinput_dev->fd_is_managed)
|
||||
close(uinput_dev->fd);
|
||||
free(uinput_dev->syspath);
|
||||
free(uinput_dev->devnode);
|
||||
free(uinput_dev->name);
|
||||
free(uinput_dev);
|
||||
}
|
||||
|
||||
LIBEVDEV_EXPORT const char*
|
||||
libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev)
|
||||
{
|
||||
return uinput_dev->syspath;
|
||||
}
|
||||
|
||||
LIBEVDEV_EXPORT const char*
|
||||
libevdev_uinput_get_devnode(struct libevdev_uinput *uinput_dev)
|
||||
{
|
||||
return uinput_dev->devnode;
|
||||
}
|
||||
|
||||
LIBEVDEV_EXPORT 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, max;
|
||||
|
||||
if (type > EV_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
max = libevdev_get_event_type_max(type);
|
||||
if (max == -1 || code > (unsigned int)max)
|
||||
return -EINVAL;
|
||||
|
||||
rc = write(fd, &ev, sizeof(ev));
|
||||
|
||||
return rc < 0 ? -errno : 0;
|
||||
}
|
||||
230
libevdev/libevdev-uinput.h
Normal file
230
libevdev/libevdev-uinput.h
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* 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);
|
||||
*
|
||||
* err = libevdev_uinput_create_from_device(dev,
|
||||
* LIBEVDEV_UINPUT_OPEN_MANAGED,
|
||||
* &uidev);
|
||||
* if (err != 0)
|
||||
* return err;
|
||||
*
|
||||
* // ... do something ...
|
||||
*
|
||||
* libevdev_uinput_destroy(uidev);
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
enum libevdev_uinput_open_mode {
|
||||
/* intentionally -2 to avoid to avoid code like the below from accidentally working:
|
||||
fd = open("/dev/uinput", O_RDWR); // fails, fd is -1
|
||||
libevdev_uinput_create_from_device(dev, fd, &uidev); // may hide the error */
|
||||
LIBEVDEV_UINPUT_OPEN_MANAGED = -2, /**< let libevdev open and close @c /dev/uinput */
|
||||
};
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* If uinput_fd is LIBEVDEV_UINPUT_OPEN_MANAGED, libevdev_uinput_create_from_device()
|
||||
* will open @c /dev/uinput in read/write mode and manage the file descriptor.
|
||||
* Otherwise, uinput_fd must be opened by the caller and opened with the
|
||||
* appropriate permissions.
|
||||
*
|
||||
* 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 LIBEVDEV_UINPUT_OPEN_MANAGED or a file descriptor to @c /dev/uinput,
|
||||
* @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.
|
||||
*
|
||||
* If the device was opened with LIBEVDEV_UINPUT_OPEN_MANAGED, libevdev_uinput_destroy()
|
||||
* also closes the file descriptor. Otherwise, the fd is left as-is and
|
||||
* must be closed by the caller.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @see libevdev_uinput_get_devnode
|
||||
*/
|
||||
const char*libevdev_uinput_get_syspath(struct libevdev_uinput *uinput_dev);
|
||||
|
||||
/**
|
||||
* @ingroup uinput
|
||||
*
|
||||
* Return the device node representing this uinput device.
|
||||
*
|
||||
* This relies on libevdev_uinput_get_syspath() to provide a valid syspath.
|
||||
* See libevdev_uinput_get_syspath() for more details.
|
||||
*
|
||||
* @note This function may return NULL. libevdev currently has to guess the
|
||||
* syspath and the device node. See libevdev_uinput_get_syspath() for details.
|
||||
* @param uinput_dev A previously created uinput device.
|
||||
* @return The device node for this device, in the form of /dev/input/eventN
|
||||
*
|
||||
* @see libevdev_uinput_get_syspath
|
||||
*/
|
||||
const char* libevdev_uinput_get_devnode(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 */
|
||||
|
|
@ -5,6 +5,9 @@ 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-uinput-int.h \
|
||||
$(top_srcdir)/libevdev/libevdev-util.h \
|
||||
$(top_srcdir)/libevdev/libevdev-int.h
|
||||
common_sources = $(libevdev_sources) \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue