libevdev is a library to handle evdev devices

Two main goals of this library:
- 'transparently' handle SYN_DROPPED events
- avoid errors in ioctl handling by providing a simpler interface.

Keeps a cached copy of the device for quick querying.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2013-05-27 14:59:41 +10:00
commit a3255d3ec7
15 changed files with 2434 additions and 0 deletions

45
.gitignore vendored Normal file
View file

@ -0,0 +1,45 @@
aclocal.m4
autom4te.cache/
autoscan.log
ChangeLog
compile
config.guess
config.h
config.h.in
config.log
config-ml.in
config.py
config.status
config.status.lineno
config.sub
configure
configure.scan
depcomp
.deps/
INSTALL
install-sh
.libs/
libtool
libtool.m4
ltmain.sh
lt~obsolete.m4
ltoptions.m4
ltsugar.m4
ltversion.m4
Makefile
Makefile.in
mdate-sh
missing
mkinstalldirs
*.pc
py-compile
stamp-h?
symlink-tree
texinfo.tex
ylwrap
*.la
*.lo
*.o
*~
*.swp
.vimdir

19
COPYING Normal file
View file

@ -0,0 +1,19 @@
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.

6
Makefile.am Normal file
View file

@ -0,0 +1,6 @@
SUBDIRS = libevdev test
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libevdev.pc
EXTRA_DIST = libevdev.pc.in

33
README.md Normal file
View file

@ -0,0 +1,33 @@
libevemu - wrapper library for evdev input devices
==================================================
libevdevdev is a wrapper library for evdev devices. it moves the common
tasks when dealing with evdev devices into a library and provides a library
interface to the callers, thus avoiding erroneous ioctls, etc.
http://github.com/whot/libevdev
**libevdev is currently in early stages of development. Use at your own risk**
Device capabilities
-------------------
libevdev provides interfaces to query a device's capabilities. These
interfaces are type-safe (as opposed to the ioctl bits) and protect against
invalid codes, etc.
SYN_DROPPED handling
--------------------
SYN_DROPPED is sent by the kernel if userspace cannot keep up with the
reporting rate of the device. Once the kernel's buffer is full, it will
issue a SYN_DROPPED event signalling dropped event. The userspace process
must re-sync the device.
libevdevdev semi-transparently handles SYN_DROPPED events, providing an
interface to the caller to sync up device state without having to manually
compare bitfields. Instead, libevdev sends the 'missing' events to the
caller, allowing it to use the same event processing paths as it would
otherwise.
Changing devices
----------------
libevdev provides interfaces to **modify** the kernel device.

47
configure.ac Normal file
View file

@ -0,0 +1,47 @@
AC_PREREQ([2.64])
AC_INIT([libevdev],
[0.1],
[],
[libevdev],
[])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
# Before making a release, the LIBEVDEV_LT_VERSION string should be
# modified.
# The string is of the form C:R:A.
# - If interfaces have been changed or added, but binary compatibility has
# been preserved, change to C+1:0:A+1
# - If binary compatibility has been broken (eg removed or changed interfaces)
# change to C+1:0:0
# - If the interface is the same as the previous version, change to C:R+1:A
LIBEVDEV_LT_VERSION=1:0:0
AC_SUBST(LIBEVDEV_LT_VERSION)
AM_SILENT_RULES([yes])
# Check for programs
AC_PROG_CC
# Initialize libtool
LT_PREREQ([2.2])
LT_INIT
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(FFI, [libffi])
if test "x$GCC" = "xyes"; then
GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
fi
AC_SUBST(GCC_CFLAGS)
AC_CONFIG_FILES([Makefile
libevdev/Makefile
test/Makefile
libevdev.pc])
AC_OUTPUT

10
libevdev.pc.in Normal file
View file

@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: evdev_read
Description: Handler library for evdev events
Version: @EVDEV_READ_VERSION@
Cflags: -I${includedir}/libevdev-1.0/
Libs: -L${libdir} -levdev

11
libevdev/Makefile.am Normal file
View file

@ -0,0 +1,11 @@
lib_LTLIBRARIES=libevdev.la
libevdev_la_SOURCES = \
libevdev.h \
libevdev-int.h \
libevdev.c
libevdev_la_LDFLAGS = -version-info $(LIBEVDEV_LT_VERSION) -export-symbols-regex '^libevdev_'
libevdevincludedir = $(includedir)/libevdev-1.0/libevdev
libevdevinclude_HEADERS = libevdev.h

66
libevdev/libevdev-int.h Normal file
View file

@ -0,0 +1,66 @@
/*
* 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_INT_H
#define libevdev_INT_H
#include <config.h>
#include "libevdev.h"
#define LONG_BITS (sizeof(long) * 8)
#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
#define ARRAY_LENGTH(a) (sizeof(a) / (sizeof((a)[0])))
#define MAX_NAME 256
#define MAX_SLOTS 32
#define ABS_MT_MIN ABS_MT_SLOT
#define ABS_MT_MAX ABS_MT_TOOL_Y
#define ABS_MT_CNT (ABS_MT_MAX - ABS_MT_MIN + 1)
struct libevdev {
int fd;
libevdev_callback_proc callback;
libevdev_callback_proc sync_callback;
void *userdata;
char name[MAX_NAME];
struct input_id ids;
unsigned long bits[NLONGS(EV_CNT)];
unsigned long props[NLONGS(INPUT_PROP_CNT)];
unsigned long key_bits[NLONGS(KEY_CNT)];
unsigned long rel_bits[NLONGS(REL_CNT)];
unsigned long abs_bits[NLONGS(ABS_CNT)];
unsigned long led_bits[NLONGS(LED_CNT)];
unsigned long key_values[NLONGS(KEY_CNT)];
struct input_absinfo abs_info[ABS_CNT];
unsigned int mt_slot_vals[MAX_SLOTS][ABS_MT_CNT];
int num_slots; /**< valid slots in mt_slot_vals */
int need_sync;
int grabbed;
struct input_event *queue;
size_t queue_size; /**< size of queue in elements */
size_t queue_next; /**< next event index */
};
#endif

790
libevdev/libevdev.c Normal file
View file

@ -0,0 +1,790 @@
/*
* 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.
*/
#include <config.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libevdev.h"
#include "libevdev-int.h"
#define MAXEVENTS 64
static inline int
bit_is_set(const unsigned long *array, int bit)
{
return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
}
static inline void
set_bit(unsigned long *array, int bit)
{
array[bit / LONG_BITS] |= (1LL << (bit % LONG_BITS));
}
static inline void
clear_bit(unsigned long *array, int bit)
{
array[bit / LONG_BITS] &= ~(1LL << (bit % LONG_BITS));
}
static inline void
set_bit_state(unsigned long *array, int bit, int state)
{
if (state)
set_bit(array, bit);
else
clear_bit(array, bit);
}
static unsigned int
type_to_mask_const(const struct libevdev *dev, unsigned int type, const unsigned long **mask)
{
unsigned int max;
switch(type) {
case EV_ABS:
*mask = dev->abs_bits;
max = ABS_MAX;
break;
case EV_REL:
*mask = dev->rel_bits;
max = REL_MAX;
break;
case EV_KEY:
*mask = dev->key_bits;
max = KEY_MAX;
break;
case EV_LED:
*mask = dev->led_bits;
max = LED_MAX;
break;
default:
return 0;
}
return max;
}
static unsigned int
type_to_mask(struct libevdev *dev, unsigned int type, unsigned long **mask)
{
unsigned int max;
switch(type) {
case EV_ABS:
*mask = dev->abs_bits;
max = ABS_MAX;
break;
case EV_REL:
*mask = dev->rel_bits;
max = REL_MAX;
break;
case EV_KEY:
*mask = dev->key_bits;
max = KEY_MAX;
break;
case EV_LED:
*mask = dev->led_bits;
max = LED_MAX;
break;
default:
return 0;
}
return max;
}
static int
init_event_queue(struct libevdev *dev)
{
/* FIXME: count the number of axes, keys, etc. to get a better idea at how many events per
EV_SYN we could possibly get. Then multiply that by the actual buffer size we care about */
const int QUEUE_SIZE = 256;
dev->queue = calloc(QUEUE_SIZE, sizeof(struct input_event));
if (!dev->queue)
return -ENOSPC;
dev->queue_size = QUEUE_SIZE;
dev->queue_next = 0;
return 0;
}
struct libevdev*
libevdev_new(int fd)
{
struct libevdev *dev;
dev = calloc(1, sizeof(*dev));
dev->num_slots = -1;
if (fd >= 0)
libevdev_set_fd(dev, fd);
dev->fd = fd;
return dev;
}
void
libevdev_free(struct libevdev *dev)
{
free(dev);
}
int
libevdev_change_fd(struct libevdev *dev, int fd)
{
if (dev->fd == -1)
return -1;
dev->fd = fd;
return 0;
}
int
libevdev_set_fd(struct libevdev* dev, int fd)
{
int rc;
int i;
if (dev->fd == -1) {
libevdev_callback_proc cb, scb;
void *userdata;
/* these may be set before set_fd */
cb = dev->callback;
scb = dev->sync_callback;
userdata = dev->userdata;
memset(dev, 0, sizeof(*dev));
dev->fd = -1;
dev->callback = cb;
dev->sync_callback = scb;
dev->userdata = userdata;
}
rc = ioctl(fd, EVIOCGBIT(0, sizeof(dev->bits)), dev->bits);
if (rc < 0)
goto out;
rc = ioctl(fd, EVIOCGNAME(sizeof(dev->name) - 1), dev->name);
if (rc < 0)
goto out;
rc = ioctl(fd, EVIOCGID, &dev->ids);
if (rc < 0)
goto out;
rc = ioctl(fd, EVIOCGPROP(sizeof(dev->props)), dev->props);
if (rc < 0)
goto out;
rc = ioctl(fd, EVIOCGBIT(EV_REL, sizeof(dev->rel_bits)), dev->rel_bits);
if (rc < 0)
goto out;
rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(dev->abs_bits)), dev->abs_bits);
if (rc < 0)
goto out;
rc = ioctl(fd, EVIOCGBIT(EV_LED, sizeof(dev->led_bits)), dev->led_bits);
if (rc < 0)
goto out;
rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(dev->key_bits)), dev->key_bits);
if (rc < 0)
goto out;
for (i = ABS_X; i <= ABS_MAX; i++) {
if (bit_is_set(dev->abs_bits, i)) {
struct input_absinfo abs_info;
rc = ioctl(fd, EVIOCGABS(i), &dev->abs_info[i]);
if (rc < 0)
goto out;
if (i == ABS_MT_SLOT)
dev->num_slots = abs_info.maximum + 1; /* FIXME: non-zero min? */
}
}
rc = init_event_queue(dev);
if (rc < 0)
return -rc;
/* not copying key state because we won't know when we'll start to
* use this fd and key's are likely to change state by then.
* Same with the valuators, really, but they may not change.
*/
dev->fd = fd;
out:
return rc ? -errno : 0;
}
int
libevdev_get_fd(const struct libevdev* dev)
{
return dev->fd;
}
int
libevdev_set_callbacks(struct libevdev *dev,
libevdev_callback_proc callback,
libevdev_callback_proc sync_callback,
void *userdata)
{
dev->callback = callback;
dev->sync_callback = sync_callback;
dev->userdata = userdata;
return 0;
}
static inline void
init_event(struct input_event *ev, int type, int code, int value)
{
ev->time.tv_sec = 0; /* FIXME: blah! */
ev->time.tv_usec = 0; /* FIXME: blah! */
ev->type = type;
ev->code = code;
ev->value = value;
}
static int
sync_key_state(struct libevdev *dev)
{
int rc;
int i;
unsigned long keystate[NLONGS(KEY_MAX)];
struct input_event ev;
rc = ioctl(dev->fd, EVIOCGKEY(sizeof(keystate)), keystate);
if (rc < 0)
goto out;
for (i = 0; i < KEY_MAX; i++) {
int old, new;
old = bit_is_set(dev->key_values, i);
new = bit_is_set(keystate, i);
if (old ^ new) {
init_event(&ev, EV_KEY, i, new ? 1 : 0);
dev->sync_callback(dev, &ev, dev->userdata);
}
set_bit_state(dev->key_values, i, new);
}
rc = 0;
out:
return rc ? -errno : 0;
}
static int
sync_abs_state(struct libevdev *dev)
{
int rc;
int i;
struct input_event ev;
for (i = ABS_X; i <= ABS_MAX; i++) {
if (i >= ABS_MT_MIN && i <= ABS_MT_MAX)
continue;
if (bit_is_set(dev->abs_bits, i)) {
struct input_absinfo abs_info;
rc = ioctl(dev->fd, EVIOCGABS(i), &abs_info);
if (rc < 0)
goto out;
if (dev->abs_info[i].value != abs_info.value) {
init_event(&ev, EV_ABS, i, abs_info.value);
dev->sync_callback(dev, &ev, dev->userdata);
dev->abs_info[i].value = abs_info.value;
}
}
}
rc = 0;
out:
return rc ? -errno : 0;
}
static int
sync_mt_state(struct libevdev *dev)
{
int rc;
int i;
struct mt_state {
int code;
int val[MAX_SLOTS];
} mt_state[ABS_MT_CNT];
struct input_event ev;
for (i = ABS_MT_MIN; i < ABS_MT_MAX; i++) {
if (i == ABS_MT_SLOT)
continue;
mt_state[i].code = i;
rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(struct mt_state)), &mt_state[i]);
if (rc < 0)
goto out;
}
for (i = 0; i < dev->num_slots; i++) {
int j;
init_event(&ev, EV_ABS, ABS_MT_SLOT, i);
dev->sync_callback(dev, &ev, dev->userdata);
for (j = ABS_MT_MIN; j < ABS_MT_MAX; j++) {
if (dev->mt_slot_vals[i][j] != mt_state[j].val[i]) {
init_event(&ev, EV_ABS, j, mt_state[j].val[i]);
dev->sync_callback(dev, &ev, dev->userdata);
dev->mt_slot_vals[i][j] = mt_state[j].val[i];
}
}
}
rc = 0;
out:
return rc ? -errno : 0;
}
static int
sync_state(struct libevdev *dev, unsigned int flags)
{
int rc = 0;
struct input_event ev;
if (libevdev_has_event_type(dev, EV_KEY))
rc = sync_key_state(dev); /* FIXME: handle ER_SINGLE */
if (rc == 0 && libevdev_has_event_type(dev, EV_ABS))
rc = sync_abs_state(dev);
if (rc == 0 && libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT))
rc = sync_mt_state(dev);
init_event(&ev, EV_SYN, SYN_REPORT, 0);
dev->sync_callback(dev, &ev, dev->userdata);
dev->need_sync = 0;
return rc;
}
static int
update_key_state(struct libevdev *dev, const struct input_event *e)
{
if (!libevdev_has_event_type(dev, EV_KEY))
return 1;
if (e->code > KEY_MAX)
return 1;
if (e->value == 0)
clear_bit(dev->key_values, e->code);
else
set_bit(dev->key_values, e->code);
return 0;
}
static int
update_abs_state(struct libevdev *dev, const struct input_event *e)
{
if (!libevdev_has_event_type(dev, EV_ABS))
return 1;
if (e->code > ABS_MAX)
return 1;
dev->abs_info[e->code].value = e->value;
return 0;
}
static int
update_state(struct libevdev *dev, const struct input_event *e)
{
int rc = 0;
switch(e->type) {
case EV_SYN:
case EV_REL:
break;
case EV_KEY:
rc = update_key_state(dev, e);
break;
case EV_ABS:
rc = update_abs_state(dev, e);
break;
}
return rc;
}
static int
read_more_events(struct libevdev *dev)
{
int free_elem;
int len;
free_elem = dev->queue_size - dev->queue_next - 1;
if (free_elem <= 0)
return 0;
len = read(dev->fd, &dev->queue[dev->queue_next], free_elem * sizeof(struct input_event));
if (len < 0) {
if (errno != EAGAIN || dev->queue_next == 0)
return -errno;
} else if (len > 0 && len % sizeof(struct input_event) != 0)
return -EINVAL;
dev->queue_next += len/sizeof(struct input_event);
return 0;
}
int libevdev_read_events(struct libevdev *dev,
unsigned int flags)
{
int nevents, processed;
int i;
int rc = 0;
if (dev->fd < 0)
return -ENODEV;
if (flags & ER_SYNC) {
if (!dev->need_sync)
return 0;
return sync_state(dev, flags);
}
/* Always read in some more events. Best case this smoothes over a potential SYN_DROPPED,
worst case we don't read fast enough and end up with SYN_DROPPED anyway */
rc = read_more_events(dev);
if (rc < 0)
goto out;
nevents = dev->queue_next;
for (processed = 0; processed < nevents; processed++) {
struct input_event *e = &dev->queue[processed];
update_state(dev, e);
if (e->type == EV_SYN && e->code == SYN_DROPPED) {
dev->need_sync = 0;
rc = 1;
break;
} else if (libevdev_has_event_code(dev, e->type, e->code)) {
if (dev->callback(dev, e, dev->userdata) != 0) {
rc = -ECANCELED;
break;
}
}
}
for (i = 0; i < nevents - processed; i++) {
dev->queue[i] = dev->queue[i + processed];
}
dev->queue_next -= processed;
out:
return rc;
}
const char *
libevdev_get_name(const struct libevdev *dev)
{
return dev->name;
}
int libevdev_get_pid(const struct libevdev *dev)
{
return dev->ids.product;
}
int libevdev_get_vid(const struct libevdev *dev)
{
return dev->ids.vendor;
}
int libevdev_get_bustype(const struct libevdev *dev)
{
return dev->ids.bustype;
}
int
libevdev_has_property(const struct libevdev *dev, unsigned int prop)
{
return (prop <= INPUT_PROP_MAX) && bit_is_set(dev->props, prop);
}
int
libevdev_has_event_type(const struct libevdev *dev, unsigned int type)
{
return (type <= EV_MAX) && bit_is_set(dev->bits, type);
}
int
libevdev_has_event_code(const struct libevdev *dev, unsigned int type, unsigned int code)
{
const unsigned long *mask;
unsigned int max;
if (!libevdev_has_event_type(dev, type))
return 0;
if (type == EV_SYN)
return 1;
max = type_to_mask_const(dev, type, &mask);
if (code > max)
return 0;
return bit_is_set(mask, code);
}
int
libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned int code)
{
int value;
if (!libevdev_has_event_type(dev, type) || !libevdev_has_event_code(dev, type, code))
return 0;
switch (type) {
case EV_ABS: value = dev->abs_info[code].value; break;
case EV_KEY: value = bit_is_set(dev->key_values, code); break;
default:
value = 0;
break;
}
return value;
}
int
libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, unsigned int code, int *value)
{
if (libevdev_has_event_type(dev, type) &&
libevdev_has_event_code(dev, type, code)) {
*value = libevdev_get_event_value(dev, type, code);
return 1;
} else
return 0;
}
int
libevdev_get_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code)
{
if (!libevdev_has_event_type(dev, EV_ABS) || !libevdev_has_event_code(dev, EV_ABS, code))
return 0;
if (slot >= dev->num_slots || slot >= MAX_SLOTS)
return 0;
if (code > ABS_MT_MAX || code < ABS_MT_MIN)
return 0;
return dev->mt_slot_vals[slot][code - ABS_MT_MIN];
}
int
libevdev_fetch_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code, int *value)
{
if (libevdev_has_event_type(dev, EV_ABS) &&
libevdev_has_event_code(dev, EV_ABS, code) &&
slot < dev->num_slots && slot < MAX_SLOTS) {
*value = libevdev_get_slot_value(dev, slot, code);
return 1;
} else
return 0;
}
int
libevdev_get_num_slots(const struct libevdev *dev)
{
return dev->num_slots;
}
const struct input_absinfo*
libevdev_get_abs_info(const struct libevdev *dev, unsigned int code)
{
if (!libevdev_has_event_type(dev, EV_ABS) ||
!libevdev_has_event_code(dev, EV_ABS, code))
return NULL;
return &dev->abs_info[code];
}
int
libevdev_get_abs_min(const struct libevdev *dev, unsigned int code)
{
const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code);
return absinfo ? absinfo->minimum : 0;
}
int
libevdev_get_abs_max(const struct libevdev *dev, unsigned int code)
{
const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code);
return absinfo ? absinfo->maximum : 0;
}
int
libevdev_get_abs_fuzz(const struct libevdev *dev, unsigned int code)
{
const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code);
return absinfo ? absinfo->fuzz : 0;
}
int
libevdev_get_abs_flat(const struct libevdev *dev, unsigned int code)
{
const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code);
return absinfo ? absinfo->flat : 0;
}
int
libevdev_get_abs_resolution(const struct libevdev *dev, unsigned int code)
{
const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code);
return absinfo ? absinfo->resolution : 0;
}
int
libevdev_enable_event_type(struct libevdev *dev, unsigned int type)
{
if (type > EV_MAX)
return 1;
set_bit(dev->bits, type);
/* FIXME: pass through to kernel */
return 0;
}
int
libevdev_disable_event_type(struct libevdev *dev, unsigned int type)
{
if (type > EV_MAX)
return 1;
clear_bit(dev->bits, type);
/* FIXME: pass through to kernel */
return 0;
}
int
libevdev_enable_event_code(struct libevdev *dev, unsigned int type,
unsigned int code, const void *data)
{
unsigned int max;
unsigned long *mask;
if (libevdev_enable_event_type(dev, type))
return 1;
max = type_to_mask(dev, type, &mask);
if (code > max)
return 1;
set_bit(mask, code);
if (type == EV_ABS) {
const struct input_absinfo *abs = data;
dev->abs_info[code] = *abs;
}
/* FIXME: pass through to kernel */
return 0;
}
int
libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned int code)
{
unsigned int max;
unsigned long *mask;
if (type > EV_MAX)
return 1;
max = type_to_mask(dev, type, &mask);
if (code > max)
return 1;
clear_bit(mask, code);
/* FIXME: pass through to kernel */
return 0;
}
int
libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
{
int rc;
if (code > ABS_MAX)
return -EINVAL;
rc = ioctl(dev->fd, EVIOCSABS(code), *abs);
if (rc < 0)
rc = -errno;
else
rc = libevdev_enable_event_code(dev, EV_ABS, code, abs);
return rc;
}
int
libevdev_grab(struct libevdev *dev, int grab)
{
int rc = 0;
if (grab && !dev->grabbed)
rc = ioctl(dev->fd, EVIOCGRAB, (void *)1);
else if (!grab && dev->grabbed)
rc = ioctl(dev->fd, EVIOCGRAB, (void *)0);
if (rc == 0)
dev->grabbed = grab;
return rc < 0 ? -errno : 0;
}

427
libevdev/libevdev.h Normal file
View file

@ -0,0 +1,427 @@
/*
* 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_H
#define libevdev_H
#include <config.h>
#include <linux/input.h>
struct libevdev;
enum EvdevReadFlags {
ER_SINGLE = 1, /**< Read until including the first EV_SYN or EAGAIN */
ER_SYNC = 2, /**< Process data in sync mode */
ER_ALL = 4, /**< Read until EAGAIN */
};
/**
* Initialize a new libevdev struct.
*
* @param fd If fd >= 0, the device is initialised for the fd. Otherwise, a
* caller must call evdev_set_fd() before attempting to read events.
*
* @see libevdev_set_fd
*/
struct libevdev* libevdev_new(int fd);
/**
* Clean up and free the libevdev struct.
*
* @note This function may be called before libevdev_set_fd.
*/
void libevdev_free(struct libevdev *dev);
/**
* Grab or ungrab the device through a kernel EVIOCGRAB. This prevents other
* clients (including kernel-internal ones such as rfkill) from receiving
* events from this device.
*
* This is generally a bad idea. Don't do this.
*
* Grabbing an already grabbed device, or ungrabbing an ungrabbed device is
* a noop and always succeeds.
*
* @param grab If true, grab the device. Otherwise ungrab the device.
*
* @return 0 if the device was successfull grabbed or ungrabbed, or a
* negative errno in case of failure.
*/
int libevdev_grab(struct libevdev *dev, int grab);
/**
* Set the fd for this struct and initialize internal data.
* The fd must be open for reading and ioctl.
*
* This function may only be called once per device. If you need to re-read
* a device, use libevdev_free and libevdev_new. If you need to change the
* fd, use libevdev_change_fd.
*
* Unless otherwise specified, libevdev function behavior is undefined until
* a successfull call to libevdev_set_fd.
*
* @param fd The file descriptor for the device
*
* @return 0 on success, or a negative error code on failure
*
* @see libevdev_change_fd
* @see libevdev_new
* @see libevdev_free
*/
int libevdev_set_fd(struct libevdev* dev, int fd);
/**
* Change the fd for this device, without re-reading the actual device.
*
* It is an error to call this function before calling libevdev_set_fd.
*
* @param fd The new fd
*
* @return 0 on success, or -1 on failure.
*
* @see libevdev_set_fd
*/
int libevdev_change_fd(struct libevdev* dev, int fd);
/**
*
* @return The previously set fd, or -1 if none had been set previously.
* @note This function may be called before libevdev_set_fd.
*/
int libevdev_get_fd(const struct libevdev* dev);
/**
* Event callback used to report events back to the client.
*
* If this function returns -1, event processing is interrupted and returned
* to the caller of libevdev_read_events. A future call to
* libevdev_read_events will continue with the next event in the queue.
*
* @param dev The device this callback was invoked on
* @param ev The event read from the kernel
* @param userdata Previously assigned caller-specific data
*
* @return 0 on success, or -1 on failure.
*
* @see libevdev_read_events
*/
typedef int (*libevdev_callback_proc)(struct libevdev *dev, struct input_event *ev, void *userdata);
/**
* Set the callbacks to be used when reading events off the fd.
* Two callbacks are used, one for reporting events during normal operation, one for
* reporting events during an event sync. If either is NULL, no events are
* reported for that mode.
*
* @param callback Callback used for regular events when read off the fd
* @param sync_callback Callback used for events while re-syncing after a
* SYN_DROPPED event.
* @param userdata Caller-specific data, passed back through the callbacks.
*
* @return zero on success, -1 on failure
*
* @see libevdev_read_events
* @note This function may be called before libevdev_set_fd.
*/
int libevdev_set_callbacks(struct libevdev *dev,
libevdev_callback_proc callback,
libevdev_callback_proc sync_callback,
void *userdata);
/**
* Read events off the fd and call the matching callback.
*
* Depending on the flags, the behaviour changes as follows:
* - ER_SINGLE: read a single event off the fd (i.e. up to the next EV_SYN).
* This should only be used if the caller is time-sensitive and event
* processing of multiple events may prevent other computation.
* - ER_ALL: read all the events off the fd until a read would block or
* an SYN_DROPPED event is read.
* - ER_SYNC: switch to sync mode and report all events that are required to
* bring the device state back in sync with the kernel device state.
*
* @param fd The file descriptor previously set, open in non-blocking mode. If
* the file descriptor differs from the previous one, -EBADF is returned.
* @param flags The set of flags to decide how to handle events.
*
* @return On failure, a negative errno is returned.
* @retval 0 One or more events where read of the fd
* @retval -EAGAIN No events are currently on the fd
* @retval -ECANCELLED The callback returned non-zero
* @retval 1 A SYN_DROPPED event was received
*
* @see libevdev_set_callbacks
*
* @note This function is signal-safe.
*/
int libevdev_read_events(struct libevdev *dev, unsigned int flags);
/**
* @return The device name as read off the kernel device
*
* @note This function is signal-safe.
*/
const char* libevdev_get_name(const struct libevdev *dev);
/**
* @return The device's product ID
*
* @note This function is signal-safe.
*/
int libevdev_get_pid(const struct libevdev *dev);
/**
* @return The device's vendor ID
*
* @note This function is signal-safe.
*/
int libevdev_get_vid(const struct libevdev *dev);
/**
* @return The device's bus type
*
* @note This function is signal-safe.
*/
int libevdev_get_bustype(const struct libevdev *dev);
/**
* @return 1 if the device supports this event type, or 0 otherwise.
*
* @note This function is signal-safe
*/
int libevdev_has_property(const struct libevdev *dev, unsigned int prop);
/**
* @return 1 if the device supports this event type, or 0 otherwise.
*
* @note This function is signal-safe.
*/
int libevdev_has_event_type(const struct libevdev *dev, unsigned int type);
/**
* @return 1 if the device supports this event type, or 0 otherwise.
*
* @note This function is signal-safe.
*/
int libevdev_has_event_code(const struct libevdev *dev, unsigned int type, unsigned int code);
/**
* @return axis minimum for the given axis or 0 if the axis is invalid
*/
int libevdev_get_abs_min(const struct libevdev *dev, unsigned int code);
/**
* @return axis maximum for the given axis or 0 if the axis is invalid
*/
int libevdev_get_abs_max(const struct libevdev *dev, unsigned int code);
/**
* @return axis fuzz for the given axis or 0 if the axis is invalid
*/
int libevdev_get_abs_fuzz(const struct libevdev *dev, unsigned int code);
/**
* @return axis flat for the given axis or 0 if the axis is invalid
*/
int libevdev_get_abs_flat(const struct libevdev *dev, unsigned int code);
/**
* @return axis resolution for the given axis or 0 if the axis is invalid
*/
int libevdev_get_abs_resolution(const struct libevdev *dev, unsigned int code);
/**
* @return The input_absinfo for the given code, or NULL if the device does
* not support this event code.
*/
const struct input_absinfo* libevdev_get_abs_info(const struct libevdev *dev, unsigned int code);
/**
* Behaviour of this function is undefined if the device does not provide
* the event.
*
* @return The current value of the event.
*
* @note This function is signal-safe.
* @note The value for ABS_MT_ events is undefined, use
* libevdev_get_slot_value instead
*
* @see libevdev_get_slot_value
*/
int libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned int code);
/**
* Fetch the current value of the event type. This is a shortcut for
*
* <pre>
* if (libevdev_has_event_type(dev, t) && libevdev_has_event_code(dev, t, c))
* val = libevdev_get_event_value(dev, t, c);
* </pre>
*
* @return non-zero if the device supports this event code, or zero
* otherwise. On return of zero, value is unmodified.
*
* @note This function is signal-safe.
* @note The value for ABS_MT_ events is undefined, use
* libevdev_fetch_slot_value instead
*
* @see libevdev_fetch_slot_value
*/
int libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, unsigned int code, int *value);
/**
* Return the current value of the code for the given slot.
*
* The return value is undefined for a slot exceeding the available slots on
* the device, or for a device that does not have slots.
*
* @note This function is signal-safe.
* @note The value for events other than ABS_MT_ is undefined, use
* libevdev_fetch_value instead
*
* @see libevdev_get_value
*/
int libevdev_get_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code);
/**
* Fetch the current value of the code for the given slot. This is a shortcut for
*
* <pre>
* if (libevdev_has_event_type(dev, EV_ABS) &&
* libevdev_has_event_code(dev, EV_ABS, c) &&
* slot < device->number_of_slots)
* val = libevdev_get_slot_value(dev, slot, c);
* </pre>
*
* @return non-zero if the device supports this event code, or zero
* otherwise. On return of zero, value is unmodified.
*
* @note This function is signal-safe.
* @note The value for ABS_MT_ events is undefined, use
* libevdev_fetch_slot_value instead
*
* @see libevdev_fetch_slot_value
*/
int libevdev_fetch_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code, int *value);
/**
* Get the number of slots supported by this device.
*
* Note that the slot offset may be non-zero, use libevdev_get_abs_min() or
* libevdev_get_abs_info() to get the minimum slot number.
*
* @return The number of slots supported, or -1
*/
int libevdev_get_num_slots(const struct libevdev *dev);
/**
* Forcibly enable an event type on this device, even if the underlying
* device does not support it. While this cannot make the device actually
* report such events, it will now return true for libevdev_has_event_type.
*
* This is a local modification only affecting only this process and only
* this device.
*
* @param type The event type to enable (EV_ABS, EV_KEY, ...)
*
* @return 0 on success or -1 otherwise
*
* @see libevdev_has_event_type
*/
int libevdev_enable_event_type(struct libevdev *dev, unsigned int type);
/**
* Forcibly disable an event type on this device, even if the underlying
* device provides it, effectively muting all keys or axes. libevdev will
* filter any events matching this type and none will reach the caller.
* libevdev_has_event_type will return false for this type.
*
* In most cases, a caller likely only wants to disable a single code, not
* the whole type. Use libevdev_disable_event_code for that.
*
* This is a local modification only affecting only this process and only
* this device.
*
* @param type The event type to enable (EV_ABS, EV_KEY, ...)
*
* @return 0 on success or -1 otherwise
*
* @see libevdev_has_event_type
* @see libevdev_disable_event_type
*/
int libevdev_disable_event_type(struct libevdev *dev, unsigned int type);
/**
* Forcibly enable an event type on this device, even if the underlying
* device does not support it. While this cannot make the device actually
* report such events, it will now return true for libevdev_has_event_code.
*
* The last argument depends on the type and code:
* - If type is EV_ABS, the vararg must be a pointer to a struct input_absinfo
* containing the data for this axis.
* - For all other types, the argument is ignored.
*
* This function calls libevdev_enable_event_type if necessary.
*
* This is a local modification only affecting only this process and only
* this device.
*
* @param type The event type to enable (EV_ABS, EV_KEY, ...)
* @param code The event code to enable (ABS_X, REL_X, etc.)
* @param data Axis/key data, depending on type and code
*
* @return 0 on success or -1 otherwise
*
* @see libevdev_enable_event_type
*/
int libevdev_enable_event_code(struct libevdev *dev, unsigned int type, unsigned int code, const void *data);
/**
* Forcibly disable an event code on this device, even if the underlying
* device provides it, effectively muting this key or axis. libevdev will
* filter any events matching this type and code and none will reach the
* caller.
* libevdev_has_event_code will return false for this code combination.
*
* Disabling all event codes for a given type will not disable the event
* type. Use libevdev_disable_event_type for that.
*
* This is a local modification only affecting only this process and only
* this device.
*
* @param type The event type to enable (EV_ABS, EV_KEY, ...)
* @param code The event code to enable (ABS_X, REL_X, etc.)
*
* @return 0 on success or -1 otherwise
*
* @see libevdev_has_event_code
* @see libevdev_disable_event_type
*/
int libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned int code);
/**
* Set the device's EV_ABS/<code> axis to the value defined in the abs
* parameter. This will be written to the kernel.
*
* @return zero on success, or a negative errno on failure
*
* @see libevdev_enable_event_code
*/
int libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs);
#endif /* libevdev_H */

2
test/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
libevdev-print
libevdev-events

11
test/Makefile.am Normal file
View file

@ -0,0 +1,11 @@
noinst_PROGRAMS = libevdev-print libevdev-events
AM_CPPFLAGS = -I$(top_srcdir)/libevdev
libevdev_ldadd = $(top_builddir)/libevdev/libevdev.la
libevdev_print_SOURCES = libevdev-print.c event-names.h
libevdev_print_LDADD = $(libevdev_ldadd)
libevdev_events_SOURCES = libevdev-events.c event-names.h
libevdev_events_LDADD = $(libevdev_ldadd)

704
test/event-names.h Normal file
View file

@ -0,0 +1,704 @@
/* THIS FILE IS GENERATED, DO NOT EDIT */
/* to regenerate this file, get evemu from
git://git.freedesktop.org/git/evemu
*/
#ifndef EVENT_NAMES_H
#define EVENT_NAMES_H
#define SYN_MAX 3 /* linux/input.h doesn't define that */
static const char * const ev_map[EV_MAX + 1] = {
[0 ... EV_MAX] = NULL,
[EV_SYN] = "EV_SYN",
[EV_KEY] = "EV_KEY",
[EV_REL] = "EV_REL",
[EV_ABS] = "EV_ABS",
[EV_MSC] = "EV_MSC",
[EV_SW] = "EV_SW",
[EV_LED] = "EV_LED",
[EV_SND] = "EV_SND",
[EV_REP] = "EV_REP",
[EV_FF] = "EV_FF",
[EV_PWR] = "EV_PWR",
[EV_FF_STATUS] = "EV_FF_STATUS",
[EV_MAX] = "EV_MAX",
};
static const char * const rel_map[REL_MAX + 1] = {
[0 ... REL_MAX] = NULL,
[REL_X] = "REL_X",
[REL_Y] = "REL_Y",
[REL_Z] = "REL_Z",
[REL_RX] = "REL_RX",
[REL_RY] = "REL_RY",
[REL_RZ] = "REL_RZ",
[REL_HWHEEL] = "REL_HWHEEL",
[REL_DIAL] = "REL_DIAL",
[REL_WHEEL] = "REL_WHEEL",
[REL_MISC] = "REL_MISC",
[REL_MAX] = "REL_MAX",
};
static const char * const abs_map[ABS_MAX + 1] = {
[0 ... ABS_MAX] = NULL,
[ABS_X] = "ABS_X",
[ABS_Y] = "ABS_Y",
[ABS_Z] = "ABS_Z",
[ABS_RX] = "ABS_RX",
[ABS_RY] = "ABS_RY",
[ABS_RZ] = "ABS_RZ",
[ABS_THROTTLE] = "ABS_THROTTLE",
[ABS_RUDDER] = "ABS_RUDDER",
[ABS_WHEEL] = "ABS_WHEEL",
[ABS_GAS] = "ABS_GAS",
[ABS_BRAKE] = "ABS_BRAKE",
[ABS_HAT0X] = "ABS_HAT0X",
[ABS_HAT0Y] = "ABS_HAT0Y",
[ABS_HAT1X] = "ABS_HAT1X",
[ABS_HAT1Y] = "ABS_HAT1Y",
[ABS_HAT2X] = "ABS_HAT2X",
[ABS_HAT2Y] = "ABS_HAT2Y",
[ABS_HAT3X] = "ABS_HAT3X",
[ABS_HAT3Y] = "ABS_HAT3Y",
[ABS_PRESSURE] = "ABS_PRESSURE",
[ABS_DISTANCE] = "ABS_DISTANCE",
[ABS_TILT_X] = "ABS_TILT_X",
[ABS_TILT_Y] = "ABS_TILT_Y",
[ABS_TOOL_WIDTH] = "ABS_TOOL_WIDTH",
[ABS_VOLUME] = "ABS_VOLUME",
[ABS_MISC] = "ABS_MISC",
[ABS_MT_SLOT] = "ABS_MT_SLOT",
[ABS_MT_TOUCH_MAJOR] = "ABS_MT_TOUCH_MAJOR",
[ABS_MT_TOUCH_MINOR] = "ABS_MT_TOUCH_MINOR",
[ABS_MT_WIDTH_MAJOR] = "ABS_MT_WIDTH_MAJOR",
[ABS_MT_WIDTH_MINOR] = "ABS_MT_WIDTH_MINOR",
[ABS_MT_ORIENTATION] = "ABS_MT_ORIENTATION",
[ABS_MT_POSITION_X] = "ABS_MT_POSITION_X",
[ABS_MT_POSITION_Y] = "ABS_MT_POSITION_Y",
[ABS_MT_TOOL_TYPE] = "ABS_MT_TOOL_TYPE",
[ABS_MT_BLOB_ID] = "ABS_MT_BLOB_ID",
[ABS_MT_TRACKING_ID] = "ABS_MT_TRACKING_ID",
[ABS_MT_PRESSURE] = "ABS_MT_PRESSURE",
[ABS_MT_DISTANCE] = "ABS_MT_DISTANCE",
[ABS_MT_TOOL_X] = "ABS_MT_TOOL_X",
[ABS_MT_TOOL_Y] = "ABS_MT_TOOL_Y",
[ABS_MAX] = "ABS_MAX",
};
static const char * const key_map[KEY_MAX + 1] = {
[0 ... KEY_MAX] = NULL,
[KEY_RESERVED] = "KEY_RESERVED",
[KEY_ESC] = "KEY_ESC",
[KEY_1] = "KEY_1",
[KEY_2] = "KEY_2",
[KEY_3] = "KEY_3",
[KEY_4] = "KEY_4",
[KEY_5] = "KEY_5",
[KEY_6] = "KEY_6",
[KEY_7] = "KEY_7",
[KEY_8] = "KEY_8",
[KEY_9] = "KEY_9",
[KEY_0] = "KEY_0",
[KEY_MINUS] = "KEY_MINUS",
[KEY_EQUAL] = "KEY_EQUAL",
[KEY_BACKSPACE] = "KEY_BACKSPACE",
[KEY_TAB] = "KEY_TAB",
[KEY_Q] = "KEY_Q",
[KEY_W] = "KEY_W",
[KEY_E] = "KEY_E",
[KEY_R] = "KEY_R",
[KEY_T] = "KEY_T",
[KEY_Y] = "KEY_Y",
[KEY_U] = "KEY_U",
[KEY_I] = "KEY_I",
[KEY_O] = "KEY_O",
[KEY_P] = "KEY_P",
[KEY_LEFTBRACE] = "KEY_LEFTBRACE",
[KEY_RIGHTBRACE] = "KEY_RIGHTBRACE",
[KEY_ENTER] = "KEY_ENTER",
[KEY_LEFTCTRL] = "KEY_LEFTCTRL",
[KEY_A] = "KEY_A",
[KEY_S] = "KEY_S",
[KEY_D] = "KEY_D",
[KEY_F] = "KEY_F",
[KEY_G] = "KEY_G",
[KEY_H] = "KEY_H",
[KEY_J] = "KEY_J",
[KEY_K] = "KEY_K",
[KEY_L] = "KEY_L",
[KEY_SEMICOLON] = "KEY_SEMICOLON",
[KEY_APOSTROPHE] = "KEY_APOSTROPHE",
[KEY_GRAVE] = "KEY_GRAVE",
[KEY_LEFTSHIFT] = "KEY_LEFTSHIFT",
[KEY_BACKSLASH] = "KEY_BACKSLASH",
[KEY_Z] = "KEY_Z",
[KEY_X] = "KEY_X",
[KEY_C] = "KEY_C",
[KEY_V] = "KEY_V",
[KEY_B] = "KEY_B",
[KEY_N] = "KEY_N",
[KEY_M] = "KEY_M",
[KEY_COMMA] = "KEY_COMMA",
[KEY_DOT] = "KEY_DOT",
[KEY_SLASH] = "KEY_SLASH",
[KEY_RIGHTSHIFT] = "KEY_RIGHTSHIFT",
[KEY_KPASTERISK] = "KEY_KPASTERISK",
[KEY_LEFTALT] = "KEY_LEFTALT",
[KEY_SPACE] = "KEY_SPACE",
[KEY_CAPSLOCK] = "KEY_CAPSLOCK",
[KEY_F1] = "KEY_F1",
[KEY_F2] = "KEY_F2",
[KEY_F3] = "KEY_F3",
[KEY_F4] = "KEY_F4",
[KEY_F5] = "KEY_F5",
[KEY_F6] = "KEY_F6",
[KEY_F7] = "KEY_F7",
[KEY_F8] = "KEY_F8",
[KEY_F9] = "KEY_F9",
[KEY_F10] = "KEY_F10",
[KEY_NUMLOCK] = "KEY_NUMLOCK",
[KEY_SCROLLLOCK] = "KEY_SCROLLLOCK",
[KEY_KP7] = "KEY_KP7",
[KEY_KP8] = "KEY_KP8",
[KEY_KP9] = "KEY_KP9",
[KEY_KPMINUS] = "KEY_KPMINUS",
[KEY_KP4] = "KEY_KP4",
[KEY_KP5] = "KEY_KP5",
[KEY_KP6] = "KEY_KP6",
[KEY_KPPLUS] = "KEY_KPPLUS",
[KEY_KP1] = "KEY_KP1",
[KEY_KP2] = "KEY_KP2",
[KEY_KP3] = "KEY_KP3",
[KEY_KP0] = "KEY_KP0",
[KEY_KPDOT] = "KEY_KPDOT",
[KEY_ZENKAKUHANKAKU] = "KEY_ZENKAKUHANKAKU",
[KEY_102ND] = "KEY_102ND",
[KEY_F11] = "KEY_F11",
[KEY_F12] = "KEY_F12",
[KEY_RO] = "KEY_RO",
[KEY_KATAKANA] = "KEY_KATAKANA",
[KEY_HIRAGANA] = "KEY_HIRAGANA",
[KEY_HENKAN] = "KEY_HENKAN",
[KEY_KATAKANAHIRAGANA] = "KEY_KATAKANAHIRAGANA",
[KEY_MUHENKAN] = "KEY_MUHENKAN",
[KEY_KPJPCOMMA] = "KEY_KPJPCOMMA",
[KEY_KPENTER] = "KEY_KPENTER",
[KEY_RIGHTCTRL] = "KEY_RIGHTCTRL",
[KEY_KPSLASH] = "KEY_KPSLASH",
[KEY_SYSRQ] = "KEY_SYSRQ",
[KEY_RIGHTALT] = "KEY_RIGHTALT",
[KEY_LINEFEED] = "KEY_LINEFEED",
[KEY_HOME] = "KEY_HOME",
[KEY_UP] = "KEY_UP",
[KEY_PAGEUP] = "KEY_PAGEUP",
[KEY_LEFT] = "KEY_LEFT",
[KEY_RIGHT] = "KEY_RIGHT",
[KEY_END] = "KEY_END",
[KEY_DOWN] = "KEY_DOWN",
[KEY_PAGEDOWN] = "KEY_PAGEDOWN",
[KEY_INSERT] = "KEY_INSERT",
[KEY_DELETE] = "KEY_DELETE",
[KEY_MACRO] = "KEY_MACRO",
[KEY_MUTE] = "KEY_MUTE",
[KEY_VOLUMEDOWN] = "KEY_VOLUMEDOWN",
[KEY_VOLUMEUP] = "KEY_VOLUMEUP",
[KEY_POWER] = "KEY_POWER",
[KEY_KPEQUAL] = "KEY_KPEQUAL",
[KEY_KPPLUSMINUS] = "KEY_KPPLUSMINUS",
[KEY_PAUSE] = "KEY_PAUSE",
[KEY_SCALE] = "KEY_SCALE",
[KEY_KPCOMMA] = "KEY_KPCOMMA",
[KEY_HANGEUL] = "KEY_HANGEUL",
[KEY_HANJA] = "KEY_HANJA",
[KEY_YEN] = "KEY_YEN",
[KEY_LEFTMETA] = "KEY_LEFTMETA",
[KEY_RIGHTMETA] = "KEY_RIGHTMETA",
[KEY_COMPOSE] = "KEY_COMPOSE",
[KEY_STOP] = "KEY_STOP",
[KEY_AGAIN] = "KEY_AGAIN",
[KEY_PROPS] = "KEY_PROPS",
[KEY_UNDO] = "KEY_UNDO",
[KEY_FRONT] = "KEY_FRONT",
[KEY_COPY] = "KEY_COPY",
[KEY_OPEN] = "KEY_OPEN",
[KEY_PASTE] = "KEY_PASTE",
[KEY_FIND] = "KEY_FIND",
[KEY_CUT] = "KEY_CUT",
[KEY_HELP] = "KEY_HELP",
[KEY_MENU] = "KEY_MENU",
[KEY_CALC] = "KEY_CALC",
[KEY_SETUP] = "KEY_SETUP",
[KEY_SLEEP] = "KEY_SLEEP",
[KEY_WAKEUP] = "KEY_WAKEUP",
[KEY_FILE] = "KEY_FILE",
[KEY_SENDFILE] = "KEY_SENDFILE",
[KEY_DELETEFILE] = "KEY_DELETEFILE",
[KEY_XFER] = "KEY_XFER",
[KEY_PROG1] = "KEY_PROG1",
[KEY_PROG2] = "KEY_PROG2",
[KEY_WWW] = "KEY_WWW",
[KEY_MSDOS] = "KEY_MSDOS",
[KEY_COFFEE] = "KEY_COFFEE",
[KEY_DIRECTION] = "KEY_DIRECTION",
[KEY_CYCLEWINDOWS] = "KEY_CYCLEWINDOWS",
[KEY_MAIL] = "KEY_MAIL",
[KEY_BOOKMARKS] = "KEY_BOOKMARKS",
[KEY_COMPUTER] = "KEY_COMPUTER",
[KEY_BACK] = "KEY_BACK",
[KEY_FORWARD] = "KEY_FORWARD",
[KEY_CLOSECD] = "KEY_CLOSECD",
[KEY_EJECTCD] = "KEY_EJECTCD",
[KEY_EJECTCLOSECD] = "KEY_EJECTCLOSECD",
[KEY_NEXTSONG] = "KEY_NEXTSONG",
[KEY_PLAYPAUSE] = "KEY_PLAYPAUSE",
[KEY_PREVIOUSSONG] = "KEY_PREVIOUSSONG",
[KEY_STOPCD] = "KEY_STOPCD",
[KEY_RECORD] = "KEY_RECORD",
[KEY_REWIND] = "KEY_REWIND",
[KEY_PHONE] = "KEY_PHONE",
[KEY_ISO] = "KEY_ISO",
[KEY_CONFIG] = "KEY_CONFIG",
[KEY_HOMEPAGE] = "KEY_HOMEPAGE",
[KEY_REFRESH] = "KEY_REFRESH",
[KEY_EXIT] = "KEY_EXIT",
[KEY_MOVE] = "KEY_MOVE",
[KEY_EDIT] = "KEY_EDIT",
[KEY_SCROLLUP] = "KEY_SCROLLUP",
[KEY_SCROLLDOWN] = "KEY_SCROLLDOWN",
[KEY_KPLEFTPAREN] = "KEY_KPLEFTPAREN",
[KEY_KPRIGHTPAREN] = "KEY_KPRIGHTPAREN",
[KEY_NEW] = "KEY_NEW",
[KEY_REDO] = "KEY_REDO",
[KEY_F13] = "KEY_F13",
[KEY_F14] = "KEY_F14",
[KEY_F15] = "KEY_F15",
[KEY_F16] = "KEY_F16",
[KEY_F17] = "KEY_F17",
[KEY_F18] = "KEY_F18",
[KEY_F19] = "KEY_F19",
[KEY_F20] = "KEY_F20",
[KEY_F21] = "KEY_F21",
[KEY_F22] = "KEY_F22",
[KEY_F23] = "KEY_F23",
[KEY_F24] = "KEY_F24",
[KEY_PLAYCD] = "KEY_PLAYCD",
[KEY_PAUSECD] = "KEY_PAUSECD",
[KEY_PROG3] = "KEY_PROG3",
[KEY_PROG4] = "KEY_PROG4",
[KEY_DASHBOARD] = "KEY_DASHBOARD",
[KEY_SUSPEND] = "KEY_SUSPEND",
[KEY_CLOSE] = "KEY_CLOSE",
[KEY_PLAY] = "KEY_PLAY",
[KEY_FASTFORWARD] = "KEY_FASTFORWARD",
[KEY_BASSBOOST] = "KEY_BASSBOOST",
[KEY_PRINT] = "KEY_PRINT",
[KEY_HP] = "KEY_HP",
[KEY_CAMERA] = "KEY_CAMERA",
[KEY_SOUND] = "KEY_SOUND",
[KEY_QUESTION] = "KEY_QUESTION",
[KEY_EMAIL] = "KEY_EMAIL",
[KEY_CHAT] = "KEY_CHAT",
[KEY_SEARCH] = "KEY_SEARCH",
[KEY_CONNECT] = "KEY_CONNECT",
[KEY_FINANCE] = "KEY_FINANCE",
[KEY_SPORT] = "KEY_SPORT",
[KEY_SHOP] = "KEY_SHOP",
[KEY_ALTERASE] = "KEY_ALTERASE",
[KEY_CANCEL] = "KEY_CANCEL",
[KEY_BRIGHTNESSDOWN] = "KEY_BRIGHTNESSDOWN",
[KEY_BRIGHTNESSUP] = "KEY_BRIGHTNESSUP",
[KEY_MEDIA] = "KEY_MEDIA",
[KEY_SWITCHVIDEOMODE] = "KEY_SWITCHVIDEOMODE",
[KEY_KBDILLUMTOGGLE] = "KEY_KBDILLUMTOGGLE",
[KEY_KBDILLUMDOWN] = "KEY_KBDILLUMDOWN",
[KEY_KBDILLUMUP] = "KEY_KBDILLUMUP",
[KEY_SEND] = "KEY_SEND",
[KEY_REPLY] = "KEY_REPLY",
[KEY_FORWARDMAIL] = "KEY_FORWARDMAIL",
[KEY_SAVE] = "KEY_SAVE",
[KEY_DOCUMENTS] = "KEY_DOCUMENTS",
[KEY_BATTERY] = "KEY_BATTERY",
[KEY_BLUETOOTH] = "KEY_BLUETOOTH",
[KEY_WLAN] = "KEY_WLAN",
[KEY_UWB] = "KEY_UWB",
[KEY_UNKNOWN] = "KEY_UNKNOWN",
[KEY_VIDEO_NEXT] = "KEY_VIDEO_NEXT",
[KEY_VIDEO_PREV] = "KEY_VIDEO_PREV",
[KEY_BRIGHTNESS_CYCLE] = "KEY_BRIGHTNESS_CYCLE",
[KEY_BRIGHTNESS_ZERO] = "KEY_BRIGHTNESS_ZERO",
[KEY_DISPLAY_OFF] = "KEY_DISPLAY_OFF",
[KEY_WIMAX] = "KEY_WIMAX",
[KEY_RFKILL] = "KEY_RFKILL",
[KEY_MICMUTE] = "KEY_MICMUTE",
[BTN_0] = "BTN_0",
[BTN_1] = "BTN_1",
[BTN_2] = "BTN_2",
[BTN_3] = "BTN_3",
[BTN_4] = "BTN_4",
[BTN_5] = "BTN_5",
[BTN_6] = "BTN_6",
[BTN_7] = "BTN_7",
[BTN_8] = "BTN_8",
[BTN_9] = "BTN_9",
[BTN_LEFT] = "BTN_LEFT",
[BTN_RIGHT] = "BTN_RIGHT",
[BTN_MIDDLE] = "BTN_MIDDLE",
[BTN_SIDE] = "BTN_SIDE",
[BTN_EXTRA] = "BTN_EXTRA",
[BTN_FORWARD] = "BTN_FORWARD",
[BTN_BACK] = "BTN_BACK",
[BTN_TASK] = "BTN_TASK",
[BTN_TRIGGER] = "BTN_TRIGGER",
[BTN_THUMB] = "BTN_THUMB",
[BTN_THUMB2] = "BTN_THUMB2",
[BTN_TOP] = "BTN_TOP",
[BTN_TOP2] = "BTN_TOP2",
[BTN_PINKIE] = "BTN_PINKIE",
[BTN_BASE] = "BTN_BASE",
[BTN_BASE2] = "BTN_BASE2",
[BTN_BASE3] = "BTN_BASE3",
[BTN_BASE4] = "BTN_BASE4",
[BTN_BASE5] = "BTN_BASE5",
[BTN_BASE6] = "BTN_BASE6",
[BTN_DEAD] = "BTN_DEAD",
[BTN_A] = "BTN_A",
[BTN_B] = "BTN_B",
[BTN_C] = "BTN_C",
[BTN_X] = "BTN_X",
[BTN_Y] = "BTN_Y",
[BTN_Z] = "BTN_Z",
[BTN_TL] = "BTN_TL",
[BTN_TR] = "BTN_TR",
[BTN_TL2] = "BTN_TL2",
[BTN_TR2] = "BTN_TR2",
[BTN_SELECT] = "BTN_SELECT",
[BTN_START] = "BTN_START",
[BTN_MODE] = "BTN_MODE",
[BTN_THUMBL] = "BTN_THUMBL",
[BTN_THUMBR] = "BTN_THUMBR",
[BTN_TOOL_PEN] = "BTN_TOOL_PEN",
[BTN_TOOL_RUBBER] = "BTN_TOOL_RUBBER",
[BTN_TOOL_BRUSH] = "BTN_TOOL_BRUSH",
[BTN_TOOL_PENCIL] = "BTN_TOOL_PENCIL",
[BTN_TOOL_AIRBRUSH] = "BTN_TOOL_AIRBRUSH",
[BTN_TOOL_FINGER] = "BTN_TOOL_FINGER",
[BTN_TOOL_MOUSE] = "BTN_TOOL_MOUSE",
[BTN_TOOL_LENS] = "BTN_TOOL_LENS",
[BTN_TOOL_QUINTTAP] = "BTN_TOOL_QUINTTAP",
[BTN_TOUCH] = "BTN_TOUCH",
[BTN_STYLUS] = "BTN_STYLUS",
[BTN_STYLUS2] = "BTN_STYLUS2",
[BTN_TOOL_DOUBLETAP] = "BTN_TOOL_DOUBLETAP",
[BTN_TOOL_TRIPLETAP] = "BTN_TOOL_TRIPLETAP",
[BTN_TOOL_QUADTAP] = "BTN_TOOL_QUADTAP",
[BTN_GEAR_DOWN] = "BTN_GEAR_DOWN",
[BTN_GEAR_UP] = "BTN_GEAR_UP",
[KEY_OK] = "KEY_OK",
[KEY_SELECT] = "KEY_SELECT",
[KEY_GOTO] = "KEY_GOTO",
[KEY_CLEAR] = "KEY_CLEAR",
[KEY_POWER2] = "KEY_POWER2",
[KEY_OPTION] = "KEY_OPTION",
[KEY_INFO] = "KEY_INFO",
[KEY_TIME] = "KEY_TIME",
[KEY_VENDOR] = "KEY_VENDOR",
[KEY_ARCHIVE] = "KEY_ARCHIVE",
[KEY_PROGRAM] = "KEY_PROGRAM",
[KEY_CHANNEL] = "KEY_CHANNEL",
[KEY_FAVORITES] = "KEY_FAVORITES",
[KEY_EPG] = "KEY_EPG",
[KEY_PVR] = "KEY_PVR",
[KEY_MHP] = "KEY_MHP",
[KEY_LANGUAGE] = "KEY_LANGUAGE",
[KEY_TITLE] = "KEY_TITLE",
[KEY_SUBTITLE] = "KEY_SUBTITLE",
[KEY_ANGLE] = "KEY_ANGLE",
[KEY_ZOOM] = "KEY_ZOOM",
[KEY_MODE] = "KEY_MODE",
[KEY_KEYBOARD] = "KEY_KEYBOARD",
[KEY_SCREEN] = "KEY_SCREEN",
[KEY_PC] = "KEY_PC",
[KEY_TV] = "KEY_TV",
[KEY_TV2] = "KEY_TV2",
[KEY_VCR] = "KEY_VCR",
[KEY_VCR2] = "KEY_VCR2",
[KEY_SAT] = "KEY_SAT",
[KEY_SAT2] = "KEY_SAT2",
[KEY_CD] = "KEY_CD",
[KEY_TAPE] = "KEY_TAPE",
[KEY_RADIO] = "KEY_RADIO",
[KEY_TUNER] = "KEY_TUNER",
[KEY_PLAYER] = "KEY_PLAYER",
[KEY_TEXT] = "KEY_TEXT",
[KEY_DVD] = "KEY_DVD",
[KEY_AUX] = "KEY_AUX",
[KEY_MP3] = "KEY_MP3",
[KEY_AUDIO] = "KEY_AUDIO",
[KEY_VIDEO] = "KEY_VIDEO",
[KEY_DIRECTORY] = "KEY_DIRECTORY",
[KEY_LIST] = "KEY_LIST",
[KEY_MEMO] = "KEY_MEMO",
[KEY_CALENDAR] = "KEY_CALENDAR",
[KEY_RED] = "KEY_RED",
[KEY_GREEN] = "KEY_GREEN",
[KEY_YELLOW] = "KEY_YELLOW",
[KEY_BLUE] = "KEY_BLUE",
[KEY_CHANNELUP] = "KEY_CHANNELUP",
[KEY_CHANNELDOWN] = "KEY_CHANNELDOWN",
[KEY_FIRST] = "KEY_FIRST",
[KEY_LAST] = "KEY_LAST",
[KEY_AB] = "KEY_AB",
[KEY_NEXT] = "KEY_NEXT",
[KEY_RESTART] = "KEY_RESTART",
[KEY_SLOW] = "KEY_SLOW",
[KEY_SHUFFLE] = "KEY_SHUFFLE",
[KEY_BREAK] = "KEY_BREAK",
[KEY_PREVIOUS] = "KEY_PREVIOUS",
[KEY_DIGITS] = "KEY_DIGITS",
[KEY_TEEN] = "KEY_TEEN",
[KEY_TWEN] = "KEY_TWEN",
[KEY_VIDEOPHONE] = "KEY_VIDEOPHONE",
[KEY_GAMES] = "KEY_GAMES",
[KEY_ZOOMIN] = "KEY_ZOOMIN",
[KEY_ZOOMOUT] = "KEY_ZOOMOUT",
[KEY_ZOOMRESET] = "KEY_ZOOMRESET",
[KEY_WORDPROCESSOR] = "KEY_WORDPROCESSOR",
[KEY_EDITOR] = "KEY_EDITOR",
[KEY_SPREADSHEET] = "KEY_SPREADSHEET",
[KEY_GRAPHICSEDITOR] = "KEY_GRAPHICSEDITOR",
[KEY_PRESENTATION] = "KEY_PRESENTATION",
[KEY_DATABASE] = "KEY_DATABASE",
[KEY_NEWS] = "KEY_NEWS",
[KEY_VOICEMAIL] = "KEY_VOICEMAIL",
[KEY_ADDRESSBOOK] = "KEY_ADDRESSBOOK",
[KEY_MESSENGER] = "KEY_MESSENGER",
[KEY_DISPLAYTOGGLE] = "KEY_DISPLAYTOGGLE",
[KEY_SPELLCHECK] = "KEY_SPELLCHECK",
[KEY_LOGOFF] = "KEY_LOGOFF",
[KEY_DOLLAR] = "KEY_DOLLAR",
[KEY_EURO] = "KEY_EURO",
[KEY_FRAMEBACK] = "KEY_FRAMEBACK",
[KEY_FRAMEFORWARD] = "KEY_FRAMEFORWARD",
[KEY_CONTEXT_MENU] = "KEY_CONTEXT_MENU",
[KEY_MEDIA_REPEAT] = "KEY_MEDIA_REPEAT",
[KEY_10CHANNELSUP] = "KEY_10CHANNELSUP",
[KEY_10CHANNELSDOWN] = "KEY_10CHANNELSDOWN",
[KEY_IMAGES] = "KEY_IMAGES",
[KEY_DEL_EOL] = "KEY_DEL_EOL",
[KEY_DEL_EOS] = "KEY_DEL_EOS",
[KEY_INS_LINE] = "KEY_INS_LINE",
[KEY_DEL_LINE] = "KEY_DEL_LINE",
[KEY_FN] = "KEY_FN",
[KEY_FN_ESC] = "KEY_FN_ESC",
[KEY_FN_F1] = "KEY_FN_F1",
[KEY_FN_F2] = "KEY_FN_F2",
[KEY_FN_F3] = "KEY_FN_F3",
[KEY_FN_F4] = "KEY_FN_F4",
[KEY_FN_F5] = "KEY_FN_F5",
[KEY_FN_F6] = "KEY_FN_F6",
[KEY_FN_F7] = "KEY_FN_F7",
[KEY_FN_F8] = "KEY_FN_F8",
[KEY_FN_F9] = "KEY_FN_F9",
[KEY_FN_F10] = "KEY_FN_F10",
[KEY_FN_F11] = "KEY_FN_F11",
[KEY_FN_F12] = "KEY_FN_F12",
[KEY_FN_1] = "KEY_FN_1",
[KEY_FN_2] = "KEY_FN_2",
[KEY_FN_D] = "KEY_FN_D",
[KEY_FN_E] = "KEY_FN_E",
[KEY_FN_F] = "KEY_FN_F",
[KEY_FN_S] = "KEY_FN_S",
[KEY_FN_B] = "KEY_FN_B",
[KEY_BRL_DOT1] = "KEY_BRL_DOT1",
[KEY_BRL_DOT2] = "KEY_BRL_DOT2",
[KEY_BRL_DOT3] = "KEY_BRL_DOT3",
[KEY_BRL_DOT4] = "KEY_BRL_DOT4",
[KEY_BRL_DOT5] = "KEY_BRL_DOT5",
[KEY_BRL_DOT6] = "KEY_BRL_DOT6",
[KEY_BRL_DOT7] = "KEY_BRL_DOT7",
[KEY_BRL_DOT8] = "KEY_BRL_DOT8",
[KEY_BRL_DOT9] = "KEY_BRL_DOT9",
[KEY_BRL_DOT10] = "KEY_BRL_DOT10",
[KEY_NUMERIC_0] = "KEY_NUMERIC_0",
[KEY_NUMERIC_1] = "KEY_NUMERIC_1",
[KEY_NUMERIC_2] = "KEY_NUMERIC_2",
[KEY_NUMERIC_3] = "KEY_NUMERIC_3",
[KEY_NUMERIC_4] = "KEY_NUMERIC_4",
[KEY_NUMERIC_5] = "KEY_NUMERIC_5",
[KEY_NUMERIC_6] = "KEY_NUMERIC_6",
[KEY_NUMERIC_7] = "KEY_NUMERIC_7",
[KEY_NUMERIC_8] = "KEY_NUMERIC_8",
[KEY_NUMERIC_9] = "KEY_NUMERIC_9",
[KEY_NUMERIC_STAR] = "KEY_NUMERIC_STAR",
[KEY_NUMERIC_POUND] = "KEY_NUMERIC_POUND",
[KEY_CAMERA_FOCUS] = "KEY_CAMERA_FOCUS",
[KEY_WPS_BUTTON] = "KEY_WPS_BUTTON",
[KEY_TOUCHPAD_TOGGLE] = "KEY_TOUCHPAD_TOGGLE",
[KEY_TOUCHPAD_ON] = "KEY_TOUCHPAD_ON",
[KEY_TOUCHPAD_OFF] = "KEY_TOUCHPAD_OFF",
[KEY_CAMERA_ZOOMIN] = "KEY_CAMERA_ZOOMIN",
[KEY_CAMERA_ZOOMOUT] = "KEY_CAMERA_ZOOMOUT",
[KEY_CAMERA_UP] = "KEY_CAMERA_UP",
[KEY_CAMERA_DOWN] = "KEY_CAMERA_DOWN",
[KEY_CAMERA_LEFT] = "KEY_CAMERA_LEFT",
[KEY_CAMERA_RIGHT] = "KEY_CAMERA_RIGHT",
[BTN_TRIGGER_HAPPY1] = "BTN_TRIGGER_HAPPY1",
[BTN_TRIGGER_HAPPY2] = "BTN_TRIGGER_HAPPY2",
[BTN_TRIGGER_HAPPY3] = "BTN_TRIGGER_HAPPY3",
[BTN_TRIGGER_HAPPY4] = "BTN_TRIGGER_HAPPY4",
[BTN_TRIGGER_HAPPY5] = "BTN_TRIGGER_HAPPY5",
[BTN_TRIGGER_HAPPY6] = "BTN_TRIGGER_HAPPY6",
[BTN_TRIGGER_HAPPY7] = "BTN_TRIGGER_HAPPY7",
[BTN_TRIGGER_HAPPY8] = "BTN_TRIGGER_HAPPY8",
[BTN_TRIGGER_HAPPY9] = "BTN_TRIGGER_HAPPY9",
[BTN_TRIGGER_HAPPY10] = "BTN_TRIGGER_HAPPY10",
[BTN_TRIGGER_HAPPY11] = "BTN_TRIGGER_HAPPY11",
[BTN_TRIGGER_HAPPY12] = "BTN_TRIGGER_HAPPY12",
[BTN_TRIGGER_HAPPY13] = "BTN_TRIGGER_HAPPY13",
[BTN_TRIGGER_HAPPY14] = "BTN_TRIGGER_HAPPY14",
[BTN_TRIGGER_HAPPY15] = "BTN_TRIGGER_HAPPY15",
[BTN_TRIGGER_HAPPY16] = "BTN_TRIGGER_HAPPY16",
[BTN_TRIGGER_HAPPY17] = "BTN_TRIGGER_HAPPY17",
[BTN_TRIGGER_HAPPY18] = "BTN_TRIGGER_HAPPY18",
[BTN_TRIGGER_HAPPY19] = "BTN_TRIGGER_HAPPY19",
[BTN_TRIGGER_HAPPY20] = "BTN_TRIGGER_HAPPY20",
[BTN_TRIGGER_HAPPY21] = "BTN_TRIGGER_HAPPY21",
[BTN_TRIGGER_HAPPY22] = "BTN_TRIGGER_HAPPY22",
[BTN_TRIGGER_HAPPY23] = "BTN_TRIGGER_HAPPY23",
[BTN_TRIGGER_HAPPY24] = "BTN_TRIGGER_HAPPY24",
[BTN_TRIGGER_HAPPY25] = "BTN_TRIGGER_HAPPY25",
[BTN_TRIGGER_HAPPY26] = "BTN_TRIGGER_HAPPY26",
[BTN_TRIGGER_HAPPY27] = "BTN_TRIGGER_HAPPY27",
[BTN_TRIGGER_HAPPY28] = "BTN_TRIGGER_HAPPY28",
[BTN_TRIGGER_HAPPY29] = "BTN_TRIGGER_HAPPY29",
[BTN_TRIGGER_HAPPY30] = "BTN_TRIGGER_HAPPY30",
[BTN_TRIGGER_HAPPY31] = "BTN_TRIGGER_HAPPY31",
[BTN_TRIGGER_HAPPY32] = "BTN_TRIGGER_HAPPY32",
[BTN_TRIGGER_HAPPY33] = "BTN_TRIGGER_HAPPY33",
[BTN_TRIGGER_HAPPY34] = "BTN_TRIGGER_HAPPY34",
[BTN_TRIGGER_HAPPY35] = "BTN_TRIGGER_HAPPY35",
[BTN_TRIGGER_HAPPY36] = "BTN_TRIGGER_HAPPY36",
[BTN_TRIGGER_HAPPY37] = "BTN_TRIGGER_HAPPY37",
[BTN_TRIGGER_HAPPY38] = "BTN_TRIGGER_HAPPY38",
[BTN_TRIGGER_HAPPY39] = "BTN_TRIGGER_HAPPY39",
[BTN_TRIGGER_HAPPY40] = "BTN_TRIGGER_HAPPY40",
[KEY_MAX] = "KEY_MAX",
};
static const char * const led_map[LED_MAX + 1] = {
[0 ... LED_MAX] = NULL,
[LED_NUML] = "LED_NUML",
[LED_CAPSL] = "LED_CAPSL",
[LED_SCROLLL] = "LED_SCROLLL",
[LED_COMPOSE] = "LED_COMPOSE",
[LED_KANA] = "LED_KANA",
[LED_SLEEP] = "LED_SLEEP",
[LED_SUSPEND] = "LED_SUSPEND",
[LED_MUTE] = "LED_MUTE",
[LED_MISC] = "LED_MISC",
[LED_MAIL] = "LED_MAIL",
[LED_CHARGING] = "LED_CHARGING",
[LED_MAX] = "LED_MAX",
};
static const char * const snd_map[SND_MAX + 1] = {
[0 ... SND_MAX] = NULL,
[SND_CLICK] = "SND_CLICK",
[SND_BELL] = "SND_BELL",
[SND_TONE] = "SND_TONE",
[SND_MAX] = "SND_MAX",
};
static const char * const msc_map[MSC_MAX + 1] = {
[0 ... MSC_MAX] = NULL,
[MSC_SERIAL] = "MSC_SERIAL",
[MSC_PULSELED] = "MSC_PULSELED",
[MSC_GESTURE] = "MSC_GESTURE",
[MSC_RAW] = "MSC_RAW",
[MSC_SCAN] = "MSC_SCAN",
[MSC_TIMESTAMP] = "MSC_TIMESTAMP",
[MSC_MAX] = "MSC_MAX",
};
static const char * const sw_map[SW_MAX + 1] = {
[0 ... SW_MAX] = NULL,
[SW_LID] = "SW_LID",
[SW_TABLET_MODE] = "SW_TABLET_MODE",
[SW_HEADPHONE_INSERT] = "SW_HEADPHONE_INSERT",
[SW_RFKILL_ALL] = "SW_RFKILL_ALL",
[SW_MICROPHONE_INSERT] = "SW_MICROPHONE_INSERT",
[SW_DOCK] = "SW_DOCK",
[SW_LINEOUT_INSERT] = "SW_LINEOUT_INSERT",
[SW_JACK_PHYSICAL_INSERT] = "SW_JACK_PHYSICAL_INSERT",
[SW_VIDEOOUT_INSERT] = "SW_VIDEOOUT_INSERT",
[SW_CAMERA_LENS_COVER] = "SW_CAMERA_LENS_COVER",
[SW_KEYPAD_SLIDE] = "SW_KEYPAD_SLIDE",
[SW_FRONT_PROXIMITY] = "SW_FRONT_PROXIMITY",
[SW_ROTATE_LOCK] = "SW_ROTATE_LOCK",
[SW_LINEIN_INSERT] = "SW_LINEIN_INSERT",
[SW_MAX] = "SW_MAX",
};
static const char * const ff_map[FF_MAX + 1] = {
[0 ... FF_MAX] = NULL,
[FF_STATUS_STOPPED] = "FF_STATUS_STOPPED",
[FF_STATUS_MAX] = "FF_STATUS_MAX",
[FF_AUTOCENTER] = "FF_AUTOCENTER",
[FF_GAIN] = "FF_GAIN",
[FF_RUMBLE] = "FF_RUMBLE",
[FF_PERIODIC] = "FF_PERIODIC",
[FF_CONSTANT] = "FF_CONSTANT",
[FF_SPRING] = "FF_SPRING",
[FF_FRICTION] = "FF_FRICTION",
[FF_DAMPER] = "FF_DAMPER",
[FF_INERTIA] = "FF_INERTIA",
[FF_RAMP] = "FF_RAMP",
[FF_SQUARE] = "FF_SQUARE",
[FF_TRIANGLE] = "FF_TRIANGLE",
[FF_SINE] = "FF_SINE",
[FF_SAW_UP] = "FF_SAW_UP",
[FF_SAW_DOWN] = "FF_SAW_DOWN",
[FF_CUSTOM] = "FF_CUSTOM",
[FF_MAX] = "FF_MAX",
};
static const char * const syn_map[SYN_MAX + 1] = {
[0 ... SYN_MAX] = NULL,
[SYN_REPORT] = "SYN_REPORT",
[SYN_CONFIG] = "SYN_CONFIG",
[SYN_MT_REPORT] = "SYN_MT_REPORT",
[SYN_DROPPED] = "SYN_DROPPED",
};
static const char * const input_prop_map[INPUT_PROP_MAX + 1] = {
[0 ... INPUT_PROP_MAX] = NULL,
[INPUT_PROP_POINTER] = "INPUT_PROP_POINTER",
[INPUT_PROP_DIRECT] = "INPUT_PROP_DIRECT",
[INPUT_PROP_BUTTONPAD] = "INPUT_PROP_BUTTONPAD",
[INPUT_PROP_SEMI_MT] = "INPUT_PROP_SEMI_MT",
[INPUT_PROP_MAX] = "INPUT_PROP_MAX",
};
static const char * const * const map[EV_MAX + 1] = {
[0 ... EV_MAX] = NULL,
[EV_REL] = rel_map,
[EV_ABS] = abs_map,
[EV_KEY] = key_map,
[EV_LED] = led_map,
[EV_SND] = snd_map,
[EV_MSC] = msc_map,
[EV_SW] = sw_map,
[EV_FF] = ff_map,
[EV_SYN] = syn_map,
};
static const char * event_get_type_name(int type) {
return ev_map[type];
}
static const char * event_get_code_name(int type, int code) {
return map[type] ? map[type][code] : NULL;
}
#endif /* EVENT_NAMES_H */

120
test/libevdev-events.c Normal file
View file

@ -0,0 +1,120 @@
/*
* 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.
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <linux/input.h>
#include "libevdev.h"
#include "event-names.h"
void
print_code_bits(struct libevdev *dev, unsigned int type, unsigned int max)
{
unsigned int i;
for (i = 0; i <= max; i++) {
if (libevdev_has_event_code(dev, type, i))
printf("%s: %s\n",
event_get_type_name(type),
event_get_code_name(type, i));
}
}
int callback(struct libevdev *dev, struct input_event *ev, void *userdata)
{
if (ev->type == EV_SYN)
printf("Event: time %ld.%06ld, ++++++++++++++++++++ %s +++++++++++++++\n",
ev->time.tv_sec,
ev->time.tv_usec,
event_get_type_name(ev->type));
else
printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n",
ev->time.tv_sec,
ev->time.tv_usec,
ev->type,
event_get_type_name(ev->type),
ev->code,
event_get_code_name(ev->type, ev->code),
ev->value);
return 0;
}
int sync_callback(struct libevdev *dev, struct input_event *ev, void *userdata)
{
printf("SYNC: ");
callback(dev, ev, userdata);
return 0;
}
int
main(int argc, char **argv)
{
struct libevdev *dev = NULL;
const char *file;
int fd;
int rc = 1;
if (argc < 2)
goto out;
file = argv[1];
fd = open(file, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror("Failed to open device");
goto out;
}
dev = libevdev_new(fd);
if (!dev) {
fprintf(stderr, "Failed to init libevdev\n");
goto out;
}
if (libevdev_set_callbacks(dev, &callback, &sync_callback, NULL) != 0) {
fprintf(stderr, "Failed to set callbacks");
goto out;
}
do {
rc = libevdev_read_events(dev, ER_ALL);
if (rc == 1) {
printf("::::::::::::::::::::: dropped ::::::::::::::::::::::\n");
rc = libevdev_read_events(dev, ER_ALL | ER_SYNC);
}
} while (rc == 1 || rc == 0 || rc == -EAGAIN);
if (rc != 0 && rc != -EAGAIN)
fprintf(stderr, "Failed to handle events: %s\n", strerror(rc));
rc = 0;
out:
libevdev_free(dev);
return rc;
}

143
test/libevdev-print.c Normal file
View file

@ -0,0 +1,143 @@
/*
* 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.
*/
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <linux/input.h>
#include "libevdev.h"
#include "event-names.h"
static void
print_abs_bits(struct libevdev *dev, int axis)
{
const struct input_absinfo *abs;
if (!libevdev_has_event_code(dev, EV_ABS, axis))
return;
abs = libevdev_get_abs_info(dev, axis);
printf(" Value %6d\n", abs->value);
printf(" Min %6d\n", abs->minimum);
printf(" Max %6d\n", abs->maximum);
if (abs->fuzz)
printf(" Fuzz %6d\n", abs->fuzz);
if (abs->flat)
printf(" Flat %6d\n", abs->flat);
if (abs->resolution)
printf(" Resolution %6d\n", abs->resolution);
}
static void
print_code_bits(struct libevdev *dev, unsigned int type, unsigned int max)
{
unsigned int i;
for (i = 0; i <= max; i++) {
if (!libevdev_has_event_code(dev, type, i))
continue;
printf(" Event code %i (%s)\n", i, event_get_code_name(type, i));
if (type == EV_ABS)
print_abs_bits(dev, i);
}
}
static void
print_bits(struct libevdev *dev)
{
unsigned int i;
printf("Supported events:\n");
for (i = 0; i <= EV_MAX; i++) {
if (libevdev_has_event_type(dev, i))
printf(" Event type %d (%s)\n", i, event_get_type_name(i));
switch(i) {
case EV_KEY:
print_code_bits(dev, EV_KEY, KEY_MAX);
break;
case EV_REL:
print_code_bits(dev, EV_REL, REL_MAX);
break;
case EV_ABS:
print_code_bits(dev, EV_ABS, ABS_MAX);
break;
case EV_LED:
print_code_bits(dev, EV_LED, LED_MAX);
break;
}
}
}
static void
print_props(struct libevdev *dev)
{
unsigned int i;
printf("Properties:\n");
for (i = 0; i <= INPUT_PROP_MAX; i++) {
if (libevdev_has_property(dev, i))
printf(" Property type %d (%s)\n", i, input_prop_map[i]);
}
}
int
main(int argc, char **argv)
{
struct libevdev *dev;
const char *file;
int fd;
if (argc < 2)
return 1;
file = argv[1];
fd = open(file, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror("Failed to open device");
return 1;
}
dev = libevdev_new(fd);
if (!dev) {
fprintf(stderr, "Failed to init libevdev\n");
return 1;
}
printf("Input device ID: bus %#x vendor %#x product %#x\n",
libevdev_get_bustype(dev),
libevdev_get_vid(dev),
libevdev_get_pid(dev));
printf("Input device name: \"%s\"\n", libevdev_get_name(dev));
print_bits(dev);
print_props(dev);
libevdev_free(dev);
return 0;
}