2013-05-27 14:59:41 +10:00
|
|
|
/*
|
|
|
|
|
* 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>
|
2013-07-24 13:37:53 +10:00
|
|
|
#include <poll.h>
|
2013-05-27 14:59:41 +10:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
2013-05-30 09:00:13 +10:00
|
|
|
#include <stdarg.h>
|
2013-06-04 16:24:11 +10:00
|
|
|
#include <linux/uinput.h>
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
#include "libevdev.h"
|
|
|
|
|
#include "libevdev-int.h"
|
2013-06-04 15:46:03 +10:00
|
|
|
#include "libevdev-util.h"
|
2013-06-04 09:52:20 +10:00
|
|
|
#include "event-names.h"
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
#define MAXEVENTS 64
|
|
|
|
|
|
2013-07-03 14:58:22 +10:00
|
|
|
static int sync_mt_state(struct libevdev *dev, int create_events);
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
|
2013-05-30 11:05:24 +10:00
|
|
|
return queue_alloc(dev, QUEUE_SIZE);
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-05-30 09:00:13 +10:00
|
|
|
static void
|
|
|
|
|
_libevdev_log(struct libevdev *dev, const char *format, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
|
dev->log(format, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
libevdev_noop_log_func(const char *format, va_list args)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
struct libevdev*
|
2013-05-31 11:26:58 +10:00
|
|
|
libevdev_new(void)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
|
|
|
|
struct libevdev *dev;
|
|
|
|
|
|
|
|
|
|
dev = calloc(1, sizeof(*dev));
|
2013-05-31 11:26:01 +10:00
|
|
|
if (!dev)
|
|
|
|
|
return NULL;
|
2013-05-31 11:26:58 +10:00
|
|
|
dev->fd = -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
dev->num_slots = -1;
|
2013-05-30 13:58:45 +10:00
|
|
|
dev->current_slot = -1;
|
2013-05-30 09:00:13 +10:00
|
|
|
dev->log = libevdev_noop_log_func;
|
2013-06-27 10:21:44 +10:00
|
|
|
dev->grabbed = LIBEVDEV_UNGRAB;
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_NONE;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-31 11:26:58 +10:00
|
|
|
int
|
|
|
|
|
libevdev_new_from_fd(int fd, struct libevdev **dev)
|
|
|
|
|
{
|
|
|
|
|
struct libevdev *d;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
d = libevdev_new();
|
|
|
|
|
if (!d)
|
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
|
|
rc = libevdev_set_fd(d, fd);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
libevdev_free(d);
|
|
|
|
|
else
|
|
|
|
|
*dev = d;
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
void
|
|
|
|
|
libevdev_free(struct libevdev *dev)
|
|
|
|
|
{
|
2013-06-04 11:15:00 +10:00
|
|
|
if (!dev)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-06-03 14:20:34 +10:00
|
|
|
free(dev->name);
|
2013-06-03 13:59:06 +10:00
|
|
|
free(dev->phys);
|
|
|
|
|
free(dev->uniq);
|
2013-05-31 15:24:39 +10:00
|
|
|
queue_free(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
free(dev);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 09:00:13 +10:00
|
|
|
void
|
|
|
|
|
libevdev_set_log_handler(struct libevdev *dev, libevdev_log_func_t logfunc)
|
|
|
|
|
{
|
2013-06-04 14:53:30 +10:00
|
|
|
if (dev == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-05-30 09:00:13 +10:00
|
|
|
dev->log = logfunc ? logfunc : libevdev_noop_log_func;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
2013-06-03 13:59:06 +10:00
|
|
|
char buf[256];
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-05-31 14:53:42 +10:00
|
|
|
if (dev->fd != -1)
|
|
|
|
|
return -EBADF;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
rc = ioctl(fd, EVIOCGBIT(0, sizeof(dev->bits)), dev->bits);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-06-03 14:20:34 +10:00
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
rc = ioctl(fd, EVIOCGNAME(sizeof(buf) - 1), buf);
|
2013-05-27 14:59:41 +10:00
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-07-25 16:11:04 +10:00
|
|
|
free(dev->name);
|
2013-06-27 09:45:58 +10:00
|
|
|
dev->name = strdup(buf);
|
2013-06-03 14:20:34 +10:00
|
|
|
if (!dev->name) {
|
|
|
|
|
errno = ENOSPC;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 16:11:04 +10:00
|
|
|
free(dev->phys);
|
|
|
|
|
dev->phys = NULL;
|
2013-06-03 13:59:06 +10:00
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
rc = ioctl(fd, EVIOCGPHYS(sizeof(buf) - 1), buf);
|
|
|
|
|
if (rc < 0) {
|
|
|
|
|
/* uinput has no phys */
|
|
|
|
|
if (errno != ENOENT)
|
|
|
|
|
goto out;
|
|
|
|
|
} else {
|
2013-06-27 09:45:58 +10:00
|
|
|
dev->phys = strdup(buf);
|
2013-06-03 13:59:06 +10:00
|
|
|
if (!dev->phys) {
|
|
|
|
|
errno = ENOSPC;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 16:11:04 +10:00
|
|
|
free(dev->uniq);
|
|
|
|
|
dev->uniq = NULL;
|
2013-06-03 13:59:06 +10:00
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
rc = ioctl(fd, EVIOCGUNIQ(sizeof(buf) - 1), buf);
|
|
|
|
|
if (rc < 0) {
|
|
|
|
|
if (errno != ENOENT)
|
|
|
|
|
goto out;
|
|
|
|
|
} else {
|
2013-06-27 09:45:58 +10:00
|
|
|
dev->uniq = strdup(buf);
|
2013-06-03 13:59:06 +10:00
|
|
|
if (!dev->uniq) {
|
|
|
|
|
errno = ENOSPC;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
rc = ioctl(fd, EVIOCGID, &dev->ids);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-06-03 13:35:28 +10:00
|
|
|
rc = ioctl(fd, EVIOCGVERSION, &dev->driver_version);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
|
2013-06-05 16:30:00 +10:00
|
|
|
rc = ioctl(fd, EVIOCGBIT(EV_SW, sizeof(dev->sw_bits)), dev->sw_bits);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rc = ioctl(fd, EVIOCGBIT(EV_MSC, sizeof(dev->msc_bits)), dev->msc_bits);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rc = ioctl(fd, EVIOCGBIT(EV_FF, sizeof(dev->ff_bits)), dev->ff_bits);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
rc = ioctl(fd, EVIOCGBIT(EV_SND, sizeof(dev->snd_bits)), dev->snd_bits);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-08-14 09:44:21 +10:00
|
|
|
rc = ioctl(fd, EVIOCGKEY(sizeof(dev->key_values)), dev->key_values);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-08-14 09:29:41 +10:00
|
|
|
rc = ioctl(fd, EVIOCGLED(sizeof(dev->led_values)), dev->led_values);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-06-05 16:30:00 +10:00
|
|
|
/* rep is a special case, always set it to 1 for both values if EV_REP is set */
|
|
|
|
|
if (bit_is_set(dev->bits, EV_REP)) {
|
2013-07-29 12:04:58 +10:00
|
|
|
for (i = 0; i < REP_CNT; i++)
|
2013-06-05 16:30:00 +10:00
|
|
|
set_bit(dev->rep_bits, i);
|
|
|
|
|
rc = ioctl(fd, EVIOCGREP, dev->rep_values);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
for (i = ABS_X; i <= ABS_MAX; i++) {
|
|
|
|
|
if (bit_is_set(dev->abs_bits, i)) {
|
|
|
|
|
struct input_absinfo abs_info;
|
2013-06-03 16:36:10 +10:00
|
|
|
rc = ioctl(fd, EVIOCGABS(i), &abs_info);
|
2013-05-27 14:59:41 +10:00
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-06-03 16:36:10 +10:00
|
|
|
dev->abs_info[i] = abs_info;
|
2013-05-30 13:58:45 +10:00
|
|
|
if (i == ABS_MT_SLOT) {
|
2013-06-22 19:45:39 +10:00
|
|
|
dev->num_slots = abs_info.maximum + 1;
|
2013-05-30 13:58:45 +10:00
|
|
|
dev->current_slot = abs_info.value;
|
|
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-03 14:58:22 +10:00
|
|
|
dev->fd = fd;
|
|
|
|
|
sync_mt_state(dev, 0);
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
rc = init_event_queue(dev);
|
2013-07-03 14:58:22 +10:00
|
|
|
if (rc < 0) {
|
|
|
|
|
dev->fd = -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
return -rc;
|
2013-07-03 14:58:22 +10:00
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
libevdev_get_fd(const struct libevdev* dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
2013-06-03 16:20:35 +10:00
|
|
|
init_event(struct libevdev *dev, struct input_event *ev, int type, int code, int value)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
2013-06-03 16:20:35 +10:00
|
|
|
ev->time = dev->last_event_time;
|
2013-05-27 14:59:41 +10:00
|
|
|
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)];
|
|
|
|
|
|
|
|
|
|
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);
|
2013-05-30 11:05:24 +10:00
|
|
|
if (old ^ new) {
|
|
|
|
|
struct input_event *ev = queue_push(dev);
|
2013-06-03 16:20:35 +10:00
|
|
|
init_event(dev, ev, EV_KEY, i, new ? 1 : 0);
|
2013-05-30 11:05:24 +10:00
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
set_bit_state(dev->key_values, i, new);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
out:
|
|
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 09:29:41 +10:00
|
|
|
static int
|
|
|
|
|
sync_led_state(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
int i;
|
|
|
|
|
unsigned long ledstate[NLONGS(LED_MAX)];
|
|
|
|
|
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGLED(sizeof(ledstate)), ledstate);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < LED_MAX; i++) {
|
|
|
|
|
int old, new;
|
|
|
|
|
old = bit_is_set(dev->led_values, i);
|
|
|
|
|
new = bit_is_set(ledstate, i);
|
|
|
|
|
if (old ^ new) {
|
|
|
|
|
struct input_event *ev = queue_push(dev);
|
|
|
|
|
init_event(dev, ev, EV_LED, i, new ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
set_bit_state(dev->led_values, i, new);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
out:
|
|
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
static int
|
|
|
|
|
sync_abs_state(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = ABS_X; i <= ABS_MAX; i++) {
|
2013-05-30 10:42:24 +10:00
|
|
|
struct input_absinfo abs_info;
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
if (i >= ABS_MT_MIN && i <= ABS_MT_MAX)
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-05-30 10:42:24 +10:00
|
|
|
if (!bit_is_set(dev->abs_bits, i))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGABS(i), &abs_info);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
if (dev->abs_info[i].value != abs_info.value) {
|
2013-05-30 11:05:24 +10:00
|
|
|
struct input_event *ev = queue_push(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-06-03 16:20:35 +10:00
|
|
|
init_event(dev, ev, EV_ABS, i, abs_info.value);
|
2013-05-30 10:42:24 +10:00
|
|
|
dev->abs_info[i].value = abs_info.value;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
out:
|
|
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2013-07-03 14:58:22 +10:00
|
|
|
sync_mt_state(struct libevdev *dev, int create_events)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
int i;
|
|
|
|
|
struct mt_state {
|
|
|
|
|
int code;
|
|
|
|
|
int val[MAX_SLOTS];
|
|
|
|
|
} mt_state[ABS_MT_CNT];
|
|
|
|
|
|
|
|
|
|
for (i = ABS_MT_MIN; i < ABS_MT_MAX; i++) {
|
2013-05-30 12:18:39 +10:00
|
|
|
int idx;
|
2013-05-27 14:59:41 +10:00
|
|
|
if (i == ABS_MT_SLOT)
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-07-01 14:39:53 +10:00
|
|
|
if (!libevdev_has_event_code(dev, EV_ABS, i))
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-05-30 12:18:39 +10:00
|
|
|
idx = i - ABS_MT_MIN;
|
|
|
|
|
mt_state[idx].code = i;
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(struct mt_state)), &mt_state[idx]);
|
2013-05-27 14:59:41 +10:00
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < dev->num_slots; i++) {
|
|
|
|
|
int j;
|
2013-05-30 10:42:24 +10:00
|
|
|
struct input_event *ev;
|
|
|
|
|
|
2013-07-03 14:58:22 +10:00
|
|
|
if (create_events) {
|
|
|
|
|
ev = queue_push(dev);
|
|
|
|
|
init_event(dev, ev, EV_ABS, ABS_MT_SLOT, i);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
for (j = ABS_MT_MIN; j < ABS_MT_MAX; j++) {
|
2013-05-30 12:18:39 +10:00
|
|
|
int jdx = j - ABS_MT_MIN;
|
|
|
|
|
|
2013-06-03 16:36:34 +10:00
|
|
|
if (j == ABS_MT_SLOT)
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-07-01 14:39:53 +10:00
|
|
|
if (!libevdev_has_event_code(dev, EV_ABS, j))
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-05-30 10:42:24 +10:00
|
|
|
if (dev->mt_slot_vals[i][jdx] == mt_state[jdx].val[i])
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-07-03 14:58:22 +10:00
|
|
|
if (create_events) {
|
|
|
|
|
ev = queue_push(dev);
|
|
|
|
|
init_event(dev, ev, EV_ABS, j, mt_state[jdx].val[i]);
|
|
|
|
|
}
|
2013-05-30 10:42:24 +10:00
|
|
|
dev->mt_slot_vals[i][jdx] = mt_state[jdx].val[i];
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
out:
|
|
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2013-05-30 10:42:24 +10:00
|
|
|
sync_state(struct libevdev *dev)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
2013-05-30 12:20:21 +10:00
|
|
|
int i;
|
2013-05-27 14:59:41 +10:00
|
|
|
int rc = 0;
|
2013-05-30 10:42:24 +10:00
|
|
|
struct input_event *ev;
|
|
|
|
|
|
|
|
|
|
/* FIXME: if we have events in the queue after the SYN_DROPPED (which was
|
2013-05-30 12:20:21 +10:00
|
|
|
queue[0]) we need to shift this backwards. Except that chances are that the
|
|
|
|
|
queue may be either full or too full to prepend all the events needed for
|
2013-07-02 10:50:37 +10:00
|
|
|
SYNC_IN_PROGRESS.
|
2013-05-30 12:20:21 +10:00
|
|
|
|
|
|
|
|
so we search for the last sync event in the queue and drop everything before
|
|
|
|
|
including that event and rely on the kernel to tell us the right value for that
|
|
|
|
|
bitfield during the sync process.
|
2013-05-30 10:42:24 +10:00
|
|
|
*/
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-05-30 12:20:21 +10:00
|
|
|
for (i = queue_num_elements(dev) - 1; i >= 0; i--) {
|
|
|
|
|
struct input_event e;
|
|
|
|
|
queue_peek(dev, i, &e);
|
|
|
|
|
if (e.type == EV_SYN)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i > 0)
|
|
|
|
|
queue_shift_multiple(dev, i + 1, NULL);
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
if (libevdev_has_event_type(dev, EV_KEY))
|
2013-05-30 10:42:24 +10:00
|
|
|
rc = sync_key_state(dev);
|
2013-08-14 09:29:41 +10:00
|
|
|
if (libevdev_has_event_type(dev, EV_LED))
|
|
|
|
|
rc = sync_led_state(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
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))
|
2013-07-03 14:58:22 +10:00
|
|
|
rc = sync_mt_state(dev, 1);
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-05-30 11:05:24 +10:00
|
|
|
dev->queue_nsync = queue_num_elements(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-07-02 10:55:44 +10:00
|
|
|
if (dev->queue_nsync > 0) {
|
|
|
|
|
ev = queue_push(dev);
|
|
|
|
|
init_event(dev, ev, EV_SYN, SYN_REPORT, 0);
|
|
|
|
|
dev->queue_nsync++;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
|
2013-08-14 09:15:51 +10:00
|
|
|
set_bit_state(dev->key_values, e->code, e->value != 0);
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 13:58:45 +10:00
|
|
|
static int
|
|
|
|
|
update_mt_state(struct libevdev *dev, const struct input_event *e)
|
|
|
|
|
{
|
|
|
|
|
if (e->code == ABS_MT_SLOT) {
|
|
|
|
|
dev->current_slot = e->value;
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (dev->current_slot == -1)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
dev->mt_slot_vals[dev->current_slot][e->code - ABS_MT_MIN] = e->value;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
|
2013-05-30 13:58:45 +10:00
|
|
|
if (e->code >= ABS_MT_MIN && e->code <= ABS_MT_MAX)
|
|
|
|
|
return update_mt_state(dev, e);
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
dev->abs_info[e->code].value = e->value;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 09:29:41 +10:00
|
|
|
static int
|
|
|
|
|
update_led_state(struct libevdev *dev, const struct input_event *e)
|
|
|
|
|
{
|
|
|
|
|
if (!libevdev_has_event_type(dev, EV_LED))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (e->code > LED_MAX)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
set_bit_state(dev->led_values, e->code, e->value != 0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
2013-08-14 09:29:41 +10:00
|
|
|
case EV_LED:
|
|
|
|
|
rc = update_led_state(dev, e);
|
|
|
|
|
break;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-06-03 16:20:35 +10:00
|
|
|
dev->last_event_time = e->time;
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
read_more_events(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
int free_elem;
|
|
|
|
|
int len;
|
2013-05-30 11:05:24 +10:00
|
|
|
struct input_event *next;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-05-30 11:05:24 +10:00
|
|
|
free_elem = queue_num_free_elements(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
if (free_elem <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2013-05-30 11:05:24 +10:00
|
|
|
next = queue_next_element(dev);
|
|
|
|
|
len = read(dev->fd, next, free_elem * sizeof(struct input_event));
|
2013-05-27 14:59:41 +10:00
|
|
|
if (len < 0) {
|
2013-05-30 10:42:24 +10:00
|
|
|
return -errno;
|
2013-05-27 14:59:41 +10:00
|
|
|
} else if (len > 0 && len % sizeof(struct input_event) != 0)
|
|
|
|
|
return -EINVAL;
|
2013-05-30 11:05:24 +10:00
|
|
|
else if (len > 0) {
|
|
|
|
|
int nev = len/sizeof(struct input_event);
|
|
|
|
|
queue_set_num_elements(dev, queue_num_elements(dev) + nev);
|
|
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 10:42:24 +10:00
|
|
|
int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
2013-06-28 10:18:35 +10:00
|
|
|
if (!(flags & (LIBEVDEV_READ_NORMAL|LIBEVDEV_READ_SYNC|LIBEVDEV_FORCE_SYNC)))
|
2013-06-27 14:20:03 +10:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
2013-05-30 14:04:33 +10:00
|
|
|
if (flags & LIBEVDEV_READ_SYNC) {
|
2013-07-02 10:50:37 +10:00
|
|
|
if (dev->sync_state == SYNC_NEEDED) {
|
2013-05-30 10:42:24 +10:00
|
|
|
rc = sync_state(dev);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
return rc;
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_IN_PROGRESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dev->queue_nsync == 0) {
|
|
|
|
|
dev->sync_state = SYNC_NONE;
|
|
|
|
|
return -EAGAIN;
|
2013-05-30 10:42:24 +10:00
|
|
|
}
|
2013-07-02 10:50:37 +10:00
|
|
|
|
|
|
|
|
} else if (dev->sync_state != SYNC_NONE) {
|
2013-07-01 15:30:49 +10:00
|
|
|
struct input_event e;
|
|
|
|
|
|
|
|
|
|
/* call update_state for all events here, otherwise the library has the wrong view
|
|
|
|
|
of the device too */
|
2013-07-02 10:50:37 +10:00
|
|
|
while (queue_shift(dev, &e) == 0) {
|
|
|
|
|
dev->queue_nsync--;
|
2013-07-01 15:30:49 +10:00
|
|
|
update_state(dev, &e);
|
2013-07-02 10:50:37 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->sync_state = SYNC_NONE;
|
2013-05-31 15:01:32 +10:00
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-07-02 10:50:37 +10:00
|
|
|
/* FIXME: if the first event after SYNC_IN_PROGRESS is a SYN_DROPPED, log this */
|
2013-06-28 12:51:16 +10:00
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
/* Always read in some more events. Best case this smoothes over a potential SYN_DROPPED,
|
2013-07-01 15:46:23 +10:00
|
|
|
worst case we don't read fast enough and end up with SYN_DROPPED anyway.
|
|
|
|
|
|
|
|
|
|
Except if the fd is in blocking mode and we still have events from the last read, don't
|
|
|
|
|
read in any more.
|
|
|
|
|
*/
|
2013-07-01 10:06:55 +10:00
|
|
|
do {
|
2013-07-01 15:46:23 +10:00
|
|
|
if (!(flags & LIBEVDEV_READ_BLOCKING) ||
|
|
|
|
|
queue_num_elements(dev) == 0) {
|
|
|
|
|
rc = read_more_events(dev);
|
|
|
|
|
if (rc < 0 && rc != -EAGAIN)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-07-01 10:06:55 +10:00
|
|
|
if (flags & LIBEVDEV_FORCE_SYNC) {
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_NEEDED;
|
2013-07-01 10:06:55 +10:00
|
|
|
rc = 1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2013-06-28 10:18:35 +10:00
|
|
|
|
|
|
|
|
|
2013-07-01 10:06:55 +10:00
|
|
|
if (queue_shift(dev, ev) != 0)
|
|
|
|
|
return -EAGAIN;
|
|
|
|
|
|
|
|
|
|
update_state(dev, ev);
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-07-01 10:06:55 +10:00
|
|
|
/* if we disabled a code, get the next event instead */
|
|
|
|
|
} while(!libevdev_has_event_code(dev, ev->type, ev->code));
|
2013-05-30 10:42:24 +10:00
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
if (ev->type == EV_SYN && ev->code == SYN_DROPPED) {
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_NEEDED;
|
2013-05-30 10:42:24 +10:00
|
|
|
rc = 1;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-05-30 14:04:33 +10:00
|
|
|
if (flags & LIBEVDEV_READ_SYNC && dev->queue_nsync > 0) {
|
2013-05-30 10:42:24 +10:00
|
|
|
dev->queue_nsync--;
|
|
|
|
|
rc = 1;
|
2013-07-02 10:50:37 +10:00
|
|
|
if (dev->queue_nsync == 0)
|
|
|
|
|
dev->sync_state = SYNC_NONE;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-24 13:37:53 +10:00
|
|
|
int libevdev_has_event_pending(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
struct pollfd fds = { dev->fd, POLLIN, 0 };
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -EBADF;
|
|
|
|
|
|
|
|
|
|
if (queue_num_elements(dev) != 0)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
rc = poll(&fds, 1, 0);
|
|
|
|
|
return (rc >= 0) ? rc : -errno;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
const char *
|
|
|
|
|
libevdev_get_name(const struct libevdev *dev)
|
|
|
|
|
{
|
2013-06-26 18:13:24 +10:00
|
|
|
return dev->name ? dev->name : "";
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-06-03 13:59:06 +10:00
|
|
|
const char *
|
|
|
|
|
libevdev_get_phys(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->phys;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
libevdev_get_uniq(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->uniq;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 16:11:04 +10:00
|
|
|
#define STRING_SETTER(field) \
|
|
|
|
|
void libevdev_set_##field(struct libevdev *dev, const char *field) \
|
|
|
|
|
{ \
|
|
|
|
|
if (field == NULL) \
|
|
|
|
|
return; \
|
|
|
|
|
free(dev->field); \
|
|
|
|
|
dev->field = strdup(field); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STRING_SETTER(name);
|
|
|
|
|
STRING_SETTER(phys);
|
|
|
|
|
STRING_SETTER(uniq);
|
|
|
|
|
|
2013-07-25 16:21:32 +10:00
|
|
|
|
2013-07-30 13:48:55 +10:00
|
|
|
#define PRODUCT_GETTER(name, field) \
|
|
|
|
|
int libevdev_get_##name(const struct libevdev *dev) \
|
|
|
|
|
{ \
|
|
|
|
|
return dev->ids.field; \
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-01 13:22:07 +10:00
|
|
|
PRODUCT_GETTER(product_id, product); /* DEPRECATED */
|
|
|
|
|
PRODUCT_GETTER(vendor_id, vendor); /* DEPRECATED */
|
|
|
|
|
PRODUCT_GETTER(bustype, bustype); /* DEPRECATED */
|
|
|
|
|
PRODUCT_GETTER(version, version); /* DEPRECATED */
|
|
|
|
|
|
|
|
|
|
PRODUCT_GETTER(id_product, product);
|
|
|
|
|
PRODUCT_GETTER(id_vendor, vendor);
|
|
|
|
|
PRODUCT_GETTER(id_bustype, bustype);
|
|
|
|
|
PRODUCT_GETTER(id_version, version);
|
2013-06-03 13:35:28 +10:00
|
|
|
|
2013-07-25 16:21:32 +10:00
|
|
|
#define PRODUCT_SETTER(field) \
|
|
|
|
|
void libevdev_set_id_##field(struct libevdev *dev, int field) \
|
|
|
|
|
{ \
|
|
|
|
|
dev->ids.field = field;\
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PRODUCT_SETTER(product);
|
|
|
|
|
PRODUCT_SETTER(vendor);
|
|
|
|
|
PRODUCT_SETTER(bustype);
|
|
|
|
|
PRODUCT_SETTER(version);
|
|
|
|
|
|
2013-06-03 13:35:28 +10:00
|
|
|
int libevdev_get_driver_version(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->driver_version;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
int
|
|
|
|
|
libevdev_has_property(const struct libevdev *dev, unsigned int prop)
|
|
|
|
|
{
|
|
|
|
|
return (prop <= INPUT_PROP_MAX) && bit_is_set(dev->props, prop);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-29 15:34:37 +10:00
|
|
|
int
|
|
|
|
|
libevdev_enable_property(struct libevdev *dev, unsigned int prop)
|
|
|
|
|
{
|
|
|
|
|
if (prop > INPUT_PROP_MAX)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
set_bit(dev->props, prop);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
2013-06-05 11:22:35 +10:00
|
|
|
int max;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
if (!libevdev_has_event_type(dev, type))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (type == EV_SYN)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
max = type_to_mask_const(dev, type, &mask);
|
|
|
|
|
|
2013-06-05 11:22:35 +10:00
|
|
|
if (max == -1 || code > max)
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
2013-08-14 09:29:41 +10:00
|
|
|
case EV_LED: value = bit_is_set(dev->led_values, code); break;
|
2013-05-27 14:59:41 +10:00
|
|
|
default:
|
|
|
|
|
value = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 14:46:24 +10:00
|
|
|
int libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned int code, int value)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
struct input_event e;
|
|
|
|
|
|
|
|
|
|
if (!libevdev_has_event_type(dev, type) || !libevdev_has_event_code(dev, type, code))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
e.type = type;
|
|
|
|
|
e.code = code;
|
|
|
|
|
e.value = value;
|
|
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
|
case EV_ABS: rc = update_abs_state(dev, &e); break;
|
|
|
|
|
case EV_KEY: rc = update_key_state(dev, &e); break;
|
2013-08-14 09:29:41 +10:00
|
|
|
case EV_LED: rc = update_led_state(dev, &e); break;
|
2013-08-09 14:46:24 +10:00
|
|
|
default:
|
|
|
|
|
rc = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 14:46:24 +10:00
|
|
|
int
|
|
|
|
|
libevdev_set_slot_value(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))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (slot >= dev->num_slots || slot >= MAX_SLOTS)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (code > ABS_MT_MAX || code < ABS_MT_MIN)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (code == ABS_MT_SLOT) {
|
|
|
|
|
if (value < 0 || value >= libevdev_get_num_slots(dev))
|
|
|
|
|
return -1;
|
|
|
|
|
dev->current_slot = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->mt_slot_vals[slot][code - ABS_MT_MIN] = value;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 14:02:17 +10:00
|
|
|
int
|
|
|
|
|
libevdev_get_current_slot(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->current_slot;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 13:06:23 +10:00
|
|
|
#define ABS_GETTER(name, field) \
|
|
|
|
|
int libevdev_get_abs_##name(const struct libevdev *dev, unsigned int code) \
|
|
|
|
|
{ \
|
|
|
|
|
const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code); \
|
|
|
|
|
return absinfo ? absinfo->field : 0; \
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-07-30 11:25:00 +10:00
|
|
|
ABS_GETTER(max, maximum); /* DEPRECATED */
|
|
|
|
|
ABS_GETTER(min, minimum); /* DEPRECATED */
|
|
|
|
|
ABS_GETTER(maximum, maximum);
|
|
|
|
|
ABS_GETTER(minimum, minimum);
|
2013-07-25 13:06:23 +10:00
|
|
|
ABS_GETTER(fuzz, fuzz)
|
|
|
|
|
ABS_GETTER(flat, flat)
|
|
|
|
|
ABS_GETTER(resolution, resolution)
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-07-24 15:52:02 +10:00
|
|
|
#define ABS_SETTER(field) \
|
|
|
|
|
void libevdev_set_abs_##field(struct libevdev *dev, unsigned int code, int val) \
|
|
|
|
|
{ \
|
|
|
|
|
if (!libevdev_has_event_code(dev, EV_ABS, code)) \
|
|
|
|
|
return; \
|
|
|
|
|
dev->abs_info[code].field = val; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ABS_SETTER(maximum)
|
|
|
|
|
ABS_SETTER(minimum)
|
|
|
|
|
ABS_SETTER(fuzz)
|
|
|
|
|
ABS_SETTER(flat)
|
|
|
|
|
ABS_SETTER(resolution)
|
|
|
|
|
|
|
|
|
|
void libevdev_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
|
|
|
|
|
{
|
|
|
|
|
if (!libevdev_has_event_code(dev, EV_ABS, code))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
dev->abs_info[code] = *abs;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
int
|
|
|
|
|
libevdev_enable_event_type(struct libevdev *dev, unsigned int type)
|
|
|
|
|
{
|
|
|
|
|
if (type > EV_MAX)
|
2013-06-29 17:34:32 +10:00
|
|
|
return -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-07-29 11:46:01 +10:00
|
|
|
if (libevdev_has_event_type(dev, type))
|
|
|
|
|
return 0;
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
set_bit(dev->bits, type);
|
|
|
|
|
|
2013-07-29 11:46:01 +10:00
|
|
|
if (type == EV_REP) {
|
|
|
|
|
int delay = 0, period = 0;
|
|
|
|
|
libevdev_enable_event_code(dev, EV_REP, REP_DELAY, &delay);
|
|
|
|
|
libevdev_enable_event_code(dev, EV_REP, REP_PERIOD, &period);
|
|
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
libevdev_disable_event_type(struct libevdev *dev, unsigned int type)
|
|
|
|
|
{
|
2013-07-01 10:08:02 +10:00
|
|
|
if (type > EV_MAX || type == EV_SYN)
|
2013-06-29 17:34:32 +10:00
|
|
|
return -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
clear_bit(dev->bits, type);
|
|
|
|
|
|
|
|
|
|
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))
|
2013-06-29 17:34:32 +10:00
|
|
|
return -1;
|
2013-07-01 09:35:16 +10:00
|
|
|
|
2013-07-29 11:46:01 +10:00
|
|
|
switch(type) {
|
|
|
|
|
case EV_SYN:
|
|
|
|
|
return 0;
|
|
|
|
|
case EV_ABS:
|
|
|
|
|
case EV_REP:
|
|
|
|
|
if (data == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (data != NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-07-26 16:51:17 +10:00
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
max = type_to_mask(dev, type, &mask);
|
|
|
|
|
|
|
|
|
|
if (code > max)
|
2013-06-29 17:34:32 +10:00
|
|
|
return -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
set_bit(mask, code);
|
|
|
|
|
|
|
|
|
|
if (type == EV_ABS) {
|
|
|
|
|
const struct input_absinfo *abs = data;
|
|
|
|
|
dev->abs_info[code] = *abs;
|
2013-07-29 11:46:01 +10:00
|
|
|
} else if (type == EV_REP) {
|
|
|
|
|
const int *value = data;
|
|
|
|
|
dev->rep_values[code] = *value;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
2013-06-29 17:34:32 +10:00
|
|
|
return -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
max = type_to_mask(dev, type, &mask);
|
|
|
|
|
|
|
|
|
|
if (code > max)
|
2013-06-29 17:34:32 +10:00
|
|
|
return -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
clear_bit(mask, code);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 13:47:00 +10:00
|
|
|
/* DEPRECATED */
|
2013-05-27 14:59:41 +10:00
|
|
|
int
|
|
|
|
|
libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
|
2013-08-09 13:47:00 +10:00
|
|
|
{
|
|
|
|
|
return libevdev_kernel_set_abs_info(dev, code, abs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (code > ABS_MAX)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2013-06-30 15:27:24 +10:00
|
|
|
rc = ioctl(dev->fd, EVIOCSABS(code), abs);
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
|
2013-05-31 14:48:43 +10:00
|
|
|
if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (grab == dev->grabbed)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (grab == LIBEVDEV_GRAB)
|
2013-05-27 14:59:41 +10:00
|
|
|
rc = ioctl(dev->fd, EVIOCGRAB, (void *)1);
|
2013-05-31 14:48:43 +10:00
|
|
|
else if (grab == LIBEVDEV_UNGRAB)
|
2013-05-27 14:59:41 +10:00
|
|
|
rc = ioctl(dev->fd, EVIOCGRAB, (void *)0);
|
|
|
|
|
|
|
|
|
|
if (rc == 0)
|
|
|
|
|
dev->grabbed = grab;
|
|
|
|
|
|
|
|
|
|
return rc < 0 ? -errno : 0;
|
|
|
|
|
}
|
2013-06-04 09:52:20 +10:00
|
|
|
|
2013-07-04 10:07:44 +10:00
|
|
|
int
|
|
|
|
|
libevdev_is_event_type(const struct input_event *ev, unsigned int type)
|
|
|
|
|
{
|
|
|
|
|
return type < EV_MAX && ev->type == type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
libevdev_is_event_code(const struct input_event *ev, unsigned int type, unsigned int code)
|
|
|
|
|
{
|
|
|
|
|
return type < EV_MAX &&
|
|
|
|
|
ev->type == type &&
|
|
|
|
|
(type == EV_SYN || code <= libevdev_get_event_type_max(type)) &&
|
|
|
|
|
ev->code == code;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-04 09:52:20 +10:00
|
|
|
const char*
|
|
|
|
|
libevdev_get_event_type_name(unsigned int type)
|
|
|
|
|
{
|
|
|
|
|
if (type > EV_MAX)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return ev_map[type];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
libevdev_get_event_code_name(unsigned int type, unsigned int code)
|
|
|
|
|
{
|
|
|
|
|
if (type > EV_MAX)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (code > ev_max[type])
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return event_type_map[type][code];
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-30 11:25:00 +10:00
|
|
|
/* DEPRECATED */
|
2013-06-04 09:52:20 +10:00
|
|
|
const char*
|
|
|
|
|
libevdev_get_input_prop_name(unsigned int prop)
|
2013-07-30 11:25:00 +10:00
|
|
|
{
|
|
|
|
|
return libevdev_get_property_name(prop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char*
|
|
|
|
|
libevdev_get_property_name(unsigned int prop)
|
2013-06-04 09:52:20 +10:00
|
|
|
{
|
|
|
|
|
if (prop > INPUT_PROP_MAX)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return input_prop_map[prop];
|
|
|
|
|
}
|
2013-06-05 16:01:25 +10:00
|
|
|
|
|
|
|
|
int
|
|
|
|
|
libevdev_get_event_type_max(unsigned int type)
|
|
|
|
|
{
|
|
|
|
|
if (type > EV_MAX)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return ev_max[type];
|
|
|
|
|
}
|
2013-06-09 19:48:19 +10:00
|
|
|
|
|
|
|
|
int
|
|
|
|
|
libevdev_get_repeat(struct libevdev *dev, int *delay, int *period)
|
|
|
|
|
{
|
|
|
|
|
if (!libevdev_has_event_type(dev, EV_REP))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if (delay != NULL)
|
|
|
|
|
*delay = dev->rep_values[REP_DELAY];
|
|
|
|
|
if (period != NULL)
|
|
|
|
|
*period = dev->rep_values[REP_PERIOD];
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|