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.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-02-14 10:13:18 +10:00
|
|
|
#include "config.h"
|
2013-05-27 14:59:41 +10:00
|
|
|
#include <errno.h>
|
2020-04-27 18:01:12 -07:00
|
|
|
#include <limits.h>
|
2013-07-24 13:37:53 +10:00
|
|
|
#include <poll.h>
|
2020-04-27 18:01:12 -07:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdint.h>
|
2013-05-27 14:59:41 +10:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include "libevdev-int.h"
|
2013-06-04 15:46:03 +10:00
|
|
|
#include "libevdev-util.h"
|
2020-04-27 18:01:12 -07:00
|
|
|
#include "libevdev.h"
|
|
|
|
|
|
2013-06-04 09:52:20 +10:00
|
|
|
#include "event-names.h"
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
#define MAXEVENTS 64
|
|
|
|
|
|
2014-04-01 17:01:39 +10:00
|
|
|
enum event_filter_status {
|
|
|
|
|
EVENT_FILTER_NONE, /**< Event untouched by filters */
|
|
|
|
|
EVENT_FILTER_MODIFIED, /**< Event was modified */
|
|
|
|
|
EVENT_FILTER_DISCARD, /**< Discard current event */
|
|
|
|
|
};
|
|
|
|
|
|
2020-02-13 16:50:17 +10:00
|
|
|
/* Keeps a record of touches during SYN_DROPPED */
|
|
|
|
|
enum touch_state {
|
|
|
|
|
TOUCH_OFF,
|
|
|
|
|
TOUCH_STARTED, /* Started during SYN_DROPPED */
|
|
|
|
|
TOUCH_STOPPED, /* Stopped during SYN_DROPPED */
|
|
|
|
|
TOUCH_ONGOING, /* Existed before, still have same tracking ID */
|
|
|
|
|
TOUCH_CHANGED, /* Existed before but have new tracking ID now, so
|
|
|
|
|
stopped + started in that slot */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct slot_change_state {
|
|
|
|
|
enum touch_state state;
|
|
|
|
|
unsigned long axes[NLONGS(ABS_CNT)]; /* bitmask for updated axes */
|
|
|
|
|
};
|
|
|
|
|
|
2020-02-13 18:14:50 +10:00
|
|
|
static int sync_mt_state(struct libevdev *dev,
|
|
|
|
|
struct slot_change_state *changes_out);
|
2020-02-13 21:35:51 +10:00
|
|
|
static int
|
|
|
|
|
update_key_state(struct libevdev *dev, const struct input_event *e);
|
2013-07-03 14:58:22 +10:00
|
|
|
|
2014-02-27 11:34:47 +10:00
|
|
|
static inline int*
|
|
|
|
|
slot_value(const struct libevdev *dev, int slot, int axis)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(slot > dev->num_slots)) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "Slot %d exceeds number of slots (%d)\n", slot, dev->num_slots);
|
2014-02-27 11:34:47 +10:00
|
|
|
slot = 0;
|
|
|
|
|
}
|
|
|
|
|
if (unlikely(axis < ABS_MT_MIN || axis > ABS_MT_MAX)) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "MT axis %d is outside the valid range [%d,%d]\n",
|
2014-02-27 11:34:47 +10:00
|
|
|
axis, ABS_MT_MIN, ABS_MT_MAX);
|
|
|
|
|
axis = ABS_MT_MIN;
|
|
|
|
|
}
|
|
|
|
|
return &dev->mt_slot_vals[slot * ABS_MT_CNT + axis - ABS_MT_MIN];
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
static int
|
|
|
|
|
init_event_queue(struct libevdev *dev)
|
|
|
|
|
{
|
2014-01-17 09:24:20 +10:00
|
|
|
const int MIN_QUEUE_SIZE = 256;
|
|
|
|
|
int nevents = 1; /* terminating SYN_REPORT */
|
|
|
|
|
int nslots;
|
|
|
|
|
unsigned int type, code;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2014-01-17 09:24:20 +10:00
|
|
|
/* count the number of axes, keys, etc. to get a better idea at how
|
|
|
|
|
many events per EV_SYN we could possibly get. That's the max we
|
|
|
|
|
may get during SYN_DROPPED too. Use double that, just so we have
|
2015-03-23 14:01:58 +10:00
|
|
|
room for events while syncing a device.
|
2014-01-17 09:24:20 +10:00
|
|
|
*/
|
|
|
|
|
for (type = EV_KEY; type < EV_MAX; type++) {
|
|
|
|
|
int max = libevdev_event_type_get_max(type);
|
|
|
|
|
for (code = 0; max > 0 && code < (unsigned int) max; code++) {
|
|
|
|
|
if (libevdev_has_event_code(dev, type, code))
|
|
|
|
|
nevents++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2014-01-17 09:24:20 +10:00
|
|
|
nslots = libevdev_get_num_slots(dev);
|
|
|
|
|
if (nslots > 1) {
|
|
|
|
|
int num_mt_axes = 0;
|
|
|
|
|
|
2015-03-23 14:02:15 +10:00
|
|
|
for (code = ABS_MT_SLOT; code <= ABS_MAX; code++) {
|
2014-01-17 09:24:20 +10:00
|
|
|
if (libevdev_has_event_code(dev, EV_ABS, code))
|
|
|
|
|
num_mt_axes++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We already counted the first slot in the initial count */
|
|
|
|
|
nevents += num_mt_axes * (nslots - 1);
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-07 15:00:24 +10:00
|
|
|
return queue_alloc(dev, max(MIN_QUEUE_SIZE, nevents * 2));
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-05-30 09:00:13 +10:00
|
|
|
static void
|
2013-09-03 16:58:29 +10:00
|
|
|
libevdev_dflt_log_func(enum libevdev_log_priority priority,
|
2013-08-26 13:24:26 +10:00
|
|
|
void *data,
|
|
|
|
|
const char *file, int line, const char *func,
|
|
|
|
|
const char *format, va_list args)
|
|
|
|
|
{
|
2013-09-03 16:58:29 +10:00
|
|
|
const char *prefix;
|
|
|
|
|
switch(priority) {
|
|
|
|
|
case LIBEVDEV_LOG_ERROR: prefix = "libevdev error"; break;
|
|
|
|
|
case LIBEVDEV_LOG_INFO: prefix = "libevdev info"; break;
|
|
|
|
|
case LIBEVDEV_LOG_DEBUG:
|
|
|
|
|
prefix = "libevdev debug";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2013-09-18 14:37:35 +10:00
|
|
|
prefix = "libevdev INVALID LOG PRIORITY";
|
2013-09-03 16:58:29 +10:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* default logging format:
|
|
|
|
|
libevev error in libevdev_some_func: blah blah
|
|
|
|
|
libevev info in libevdev_some_func: blah blah
|
|
|
|
|
libevev debug in file.c:123:libevdev_some_func: blah blah
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "%s in ", prefix);
|
|
|
|
|
if (priority == LIBEVDEV_LOG_DEBUG)
|
|
|
|
|
fprintf(stderr, "%s:%d:", file, line);
|
|
|
|
|
fprintf(stderr, "%s: ", func);
|
|
|
|
|
vfprintf(stderr, format, args);
|
2013-08-26 13:24:26 +10:00
|
|
|
}
|
|
|
|
|
|
2015-08-23 18:27:28 +02:00
|
|
|
static void
|
|
|
|
|
fix_invalid_absinfo(const struct libevdev *dev,
|
|
|
|
|
int axis,
|
|
|
|
|
struct input_absinfo* abs_info)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* The reported absinfo for ABS_MT_TRACKING_ID is sometimes
|
|
|
|
|
* uninitialized for certain mtk-soc, due to init code mangling
|
|
|
|
|
* in the vendor kernel.
|
|
|
|
|
*/
|
|
|
|
|
if (axis == ABS_MT_TRACKING_ID &&
|
|
|
|
|
abs_info->maximum == abs_info->minimum) {
|
|
|
|
|
abs_info->minimum = -1;
|
|
|
|
|
abs_info->maximum = 0xFFFF;
|
|
|
|
|
log_bug(dev,
|
|
|
|
|
"Device \"%s\" has invalid ABS_MT_TRACKING_ID range",
|
|
|
|
|
dev->name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-26 13:24:26 +10:00
|
|
|
/*
|
|
|
|
|
* Global logging settings.
|
|
|
|
|
*/
|
2014-05-14 16:36:49 +10:00
|
|
|
static struct logdata log_data = {
|
|
|
|
|
.priority = LIBEVDEV_LOG_INFO,
|
|
|
|
|
.global_handler = libevdev_dflt_log_func,
|
|
|
|
|
.userdata = NULL,
|
2013-08-26 13:24:26 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void
|
2014-08-18 14:03:43 +10:00
|
|
|
_libevdev_log_msg(const struct libevdev *dev,
|
|
|
|
|
enum libevdev_log_priority priority,
|
|
|
|
|
const char *file, int line, const char *func,
|
|
|
|
|
const char *format, ...)
|
2013-05-30 09:00:13 +10:00
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
|
2014-05-14 16:36:49 +10:00
|
|
|
if (dev && dev->log.device_handler) {
|
|
|
|
|
/**
|
2014-11-17 11:26:29 +10:00
|
|
|
* if both global handler and device handler are set
|
2014-05-14 16:36:49 +10:00
|
|
|
* we've set up the handlers wrong. And that means we'll
|
|
|
|
|
* likely get the printf args wrong and cause all sorts of
|
|
|
|
|
* mayhem. Seppuku is called for.
|
|
|
|
|
*/
|
|
|
|
|
if (unlikely(dev->log.global_handler))
|
|
|
|
|
abort();
|
|
|
|
|
|
|
|
|
|
if (priority > dev->log.priority)
|
|
|
|
|
return;
|
2020-05-26 14:10:31 +10:00
|
|
|
} else if (!log_data.global_handler || priority > log_data.priority) {
|
2013-09-03 16:58:29 +10:00
|
|
|
return;
|
2020-05-26 14:10:31 +10:00
|
|
|
} else if (unlikely(log_data.device_handler)) {
|
2014-05-14 16:36:49 +10:00
|
|
|
abort(); /* Seppuku, see above */
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2014-05-14 16:36:49 +10:00
|
|
|
|
2013-05-30 09:00:13 +10:00
|
|
|
va_start(args, format);
|
2014-05-14 16:36:49 +10:00
|
|
|
if (dev && dev->log.device_handler)
|
|
|
|
|
dev->log.device_handler(dev, priority, dev->log.userdata, file, line, func, format, args);
|
|
|
|
|
else
|
|
|
|
|
log_data.global_handler(priority, log_data.userdata, file, line, func, format, args);
|
2013-05-30 09:00:13 +10:00
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-22 11:27:42 +10:00
|
|
|
static void
|
|
|
|
|
libevdev_reset(struct libevdev *dev)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
2014-05-14 16:36:49 +10:00
|
|
|
enum libevdev_log_priority pri = dev->log.priority;
|
|
|
|
|
libevdev_device_log_func_t handler = dev->log.device_handler;
|
|
|
|
|
|
2014-02-27 11:22:27 +10:00
|
|
|
free(dev->name);
|
|
|
|
|
free(dev->phys);
|
|
|
|
|
free(dev->uniq);
|
2014-02-27 11:34:47 +10:00
|
|
|
free(dev->mt_slot_vals);
|
2013-10-22 11:27:42 +10:00
|
|
|
memset(dev, 0, sizeof(*dev));
|
2013-05-31 11:26:58 +10:00
|
|
|
dev->fd = -1;
|
2013-10-08 15:16:32 +10:00
|
|
|
dev->initialized = false;
|
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-06-27 10:21:44 +10:00
|
|
|
dev->grabbed = LIBEVDEV_UNGRAB;
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_NONE;
|
2014-05-14 16:36:49 +10:00
|
|
|
dev->log.priority = pri;
|
|
|
|
|
dev->log.device_handler = handler;
|
2013-10-24 14:21:31 +10:00
|
|
|
libevdev_enable_event_type(dev, EV_SYN);
|
2013-10-22 11:27:42 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LIBEVDEV_EXPORT struct libevdev*
|
|
|
|
|
libevdev_new(void)
|
|
|
|
|
{
|
|
|
|
|
struct libevdev *dev;
|
|
|
|
|
|
2014-02-27 11:22:27 +10:00
|
|
|
dev = calloc(1, sizeof(*dev));
|
2013-10-22 11:27:42 +10:00
|
|
|
if (!dev)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
libevdev_reset(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-31 11:26:58 +10:00
|
|
|
libevdev_new_from_fd(int fd, struct libevdev **dev)
|
|
|
|
|
{
|
|
|
|
|
struct libevdev *d;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
d = libevdev_new();
|
|
|
|
|
if (!d)
|
2013-08-31 12:23:44 +10:00
|
|
|
return -ENOMEM;
|
2013-05-31 11:26:58 +10:00
|
|
|
|
|
|
|
|
rc = libevdev_set_fd(d, fd);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
libevdev_free(d);
|
|
|
|
|
else
|
|
|
|
|
*dev = d;
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT void
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_free(struct libevdev *dev)
|
|
|
|
|
{
|
2013-06-04 11:15:00 +10:00
|
|
|
if (!dev)
|
|
|
|
|
return;
|
|
|
|
|
|
2013-05-31 15:24:39 +10:00
|
|
|
queue_free(dev);
|
2014-04-02 11:48:14 +10:00
|
|
|
libevdev_reset(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
free(dev);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-26 13:24:26 +10:00
|
|
|
LIBEVDEV_EXPORT void
|
|
|
|
|
libevdev_set_log_function(libevdev_log_func_t logfunc, void *data)
|
|
|
|
|
{
|
2014-05-14 16:36:49 +10:00
|
|
|
log_data.global_handler = logfunc;
|
2013-08-26 13:24:26 +10:00
|
|
|
log_data.userdata = data;
|
|
|
|
|
}
|
2013-06-04 14:53:30 +10:00
|
|
|
|
2013-08-26 13:24:26 +10:00
|
|
|
LIBEVDEV_EXPORT void
|
|
|
|
|
libevdev_set_log_priority(enum libevdev_log_priority priority)
|
|
|
|
|
{
|
|
|
|
|
if (priority > LIBEVDEV_LOG_DEBUG)
|
|
|
|
|
priority = LIBEVDEV_LOG_DEBUG;
|
|
|
|
|
log_data.priority = priority;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LIBEVDEV_EXPORT enum libevdev_log_priority
|
|
|
|
|
libevdev_get_log_priority(void)
|
|
|
|
|
{
|
|
|
|
|
return log_data.priority;
|
2013-05-30 09:00:13 +10:00
|
|
|
}
|
|
|
|
|
|
2014-05-14 16:36:49 +10:00
|
|
|
LIBEVDEV_EXPORT void
|
|
|
|
|
libevdev_set_device_log_function(struct libevdev *dev,
|
|
|
|
|
libevdev_device_log_func_t logfunc,
|
|
|
|
|
enum libevdev_log_priority priority,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
if (!dev) {
|
|
|
|
|
log_bug(NULL, "device must not be NULL\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->log.priority = priority;
|
|
|
|
|
dev->log.device_handler = logfunc;
|
|
|
|
|
dev->log.userdata = data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum libevdev_log_priority
|
2014-08-18 14:03:43 +10:00
|
|
|
_libevdev_log_priority(const struct libevdev *dev)
|
2014-05-14 16:36:49 +10:00
|
|
|
{
|
|
|
|
|
if (dev && dev->log.device_handler)
|
|
|
|
|
return dev->log.priority;
|
2020-08-27 00:42:20 -07:00
|
|
|
return libevdev_get_log_priority();
|
2014-05-14 16:36:49 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_change_fd(struct libevdev *dev, int fd)
|
|
|
|
|
{
|
2013-10-08 15:16:32 +10:00
|
|
|
if (!dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
|
2013-05-27 14:59:41 +10:00
|
|
|
return -1;
|
2013-08-31 12:53:36 +10:00
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
dev->fd = fd;
|
2017-12-13 09:20:55 +10:00
|
|
|
dev->grabbed = LIBEVDEV_UNGRAB;
|
2013-05-27 14:59:41 +10:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 11:18:37 +10:00
|
|
|
static void
|
|
|
|
|
reset_tracking_ids(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
if (dev->num_slots == -1 ||
|
|
|
|
|
!libevdev_has_event_code(dev, EV_ABS, ABS_MT_TRACKING_ID))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (int slot = 0; slot < dev->num_slots; slot++)
|
|
|
|
|
libevdev_set_slot_value(dev, slot, ABS_MT_TRACKING_ID, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
free_slots(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
dev->num_slots = -1;
|
|
|
|
|
free(dev->mt_slot_vals);
|
|
|
|
|
dev->mt_slot_vals = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
init_slots(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
const struct input_absinfo *abs_info;
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
|
|
free(dev->mt_slot_vals);
|
|
|
|
|
dev->mt_slot_vals = NULL;
|
|
|
|
|
|
|
|
|
|
/* devices with ABS_RESERVED aren't MT devices,
|
|
|
|
|
see the documentation for multitouch-related
|
|
|
|
|
functions for more details */
|
|
|
|
|
if (libevdev_has_event_code(dev, EV_ABS, ABS_RESERVED) ||
|
|
|
|
|
!libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) {
|
|
|
|
|
if (dev->num_slots != -1) {
|
|
|
|
|
free_slots(dev);
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
abs_info = libevdev_get_abs_info(dev, ABS_MT_SLOT);
|
|
|
|
|
|
|
|
|
|
free_slots(dev);
|
|
|
|
|
dev->num_slots = abs_info->maximum + 1;
|
|
|
|
|
dev->mt_slot_vals = calloc(dev->num_slots * ABS_MT_CNT, sizeof(int));
|
|
|
|
|
if (!dev->mt_slot_vals) {
|
|
|
|
|
rc = -ENOMEM;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
dev->current_slot = abs_info->value;
|
|
|
|
|
|
|
|
|
|
reset_tracking_ids(dev);
|
|
|
|
|
out:
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
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-10-08 15:16:32 +10:00
|
|
|
if (dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device already initialized.\n");
|
2013-05-31 14:53:42 +10:00
|
|
|
return -EBADF;
|
2020-08-27 00:42:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fd < 0) {
|
2013-10-08 15:27:27 +10:00
|
|
|
return -EBADF;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-10-22 11:27:42 +10:00
|
|
|
libevdev_reset(dev);
|
|
|
|
|
|
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) {
|
2013-08-31 12:23:44 +10:00
|
|
|
errno = ENOMEM;
|
2013-06-03 14:20:34 +10:00
|
|
|
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) {
|
2013-08-31 12:23:44 +10:00
|
|
|
errno = ENOMEM;
|
2013-06-03 13:59:06 +10:00
|
|
|
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) {
|
2013-08-31 12:23:44 +10:00
|
|
|
errno = ENOMEM;
|
2013-06-03 13:59:06 +10:00
|
|
|
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-10-08 13:09:50 +10:00
|
|
|
/* Built on a kernel with props, running against a kernel without property
|
|
|
|
|
support. This should not be a fatal case, we'll be missing properties but other
|
|
|
|
|
than that everything is as expected.
|
|
|
|
|
*/
|
2013-05-27 14:59:41 +10:00
|
|
|
rc = ioctl(fd, EVIOCGPROP(sizeof(dev->props)), dev->props);
|
2013-10-08 13:09:50 +10:00
|
|
|
if (rc < 0 && errno != EINVAL)
|
2013-05-27 14:59:41 +10:00
|
|
|
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-08-14 19:52:25 +10:00
|
|
|
rc = ioctl(fd, EVIOCGSW(sizeof(dev->sw_values)), dev->sw_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;
|
|
|
|
|
|
2015-08-23 18:27:28 +02:00
|
|
|
fix_invalid_absinfo(dev, i, &abs_info);
|
|
|
|
|
|
2013-06-03 16:36:10 +10:00
|
|
|
dev->abs_info[i] = abs_info;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-03 14:58:22 +10:00
|
|
|
dev->fd = fd;
|
2014-04-01 15:40:09 +10:00
|
|
|
|
2019-06-14 11:18:37 +10:00
|
|
|
rc = init_slots(dev);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
goto out;
|
2014-04-01 15:40:09 +10:00
|
|
|
|
2020-02-13 18:14:50 +10:00
|
|
|
if (dev->num_slots != -1) {
|
|
|
|
|
struct slot_change_state unused[dev->num_slots];
|
|
|
|
|
sync_mt_state(dev, unused);
|
|
|
|
|
}
|
2013-07-03 14:58:22 +10:00
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-10-08 15:16:32 +10:00
|
|
|
dev->initialized = true;
|
2013-05-27 14:59:41 +10:00
|
|
|
out:
|
2013-10-22 11:27:42 +10:00
|
|
|
if (rc)
|
|
|
|
|
libevdev_reset(dev);
|
2013-05-27 14:59:41 +10:00
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_get_fd(const struct libevdev* dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
sync_key_state(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
int i;
|
2013-08-29 15:52:54 +10:00
|
|
|
unsigned long keystate[NLONGS(KEY_CNT)] = {0};
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGKEY(sizeof(keystate)), keystate);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-08-29 15:38:53 +10:00
|
|
|
for (i = 0; i < KEY_CNT; i++) {
|
2013-05-27 14:59:41 +10:00
|
|
|
int old, new;
|
|
|
|
|
old = bit_is_set(dev->key_values, i);
|
|
|
|
|
new = bit_is_set(keystate, i);
|
2020-02-11 13:51:17 +10:00
|
|
|
if (old ^ new)
|
|
|
|
|
queue_push_event(dev, EV_KEY, i, new ? 1 : 0);
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 15:52:54 +10:00
|
|
|
memcpy(dev->key_values, keystate, rc);
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
rc = 0;
|
|
|
|
|
out:
|
|
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 19:52:25 +10:00
|
|
|
static int
|
|
|
|
|
sync_sw_state(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
int i;
|
2013-08-29 15:52:54 +10:00
|
|
|
unsigned long swstate[NLONGS(SW_CNT)] = {0};
|
2013-08-14 19:52:25 +10:00
|
|
|
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGSW(sizeof(swstate)), swstate);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < SW_CNT; i++) {
|
|
|
|
|
int old, new;
|
|
|
|
|
old = bit_is_set(dev->sw_values, i);
|
|
|
|
|
new = bit_is_set(swstate, i);
|
2020-02-11 13:51:17 +10:00
|
|
|
if (old ^ new)
|
|
|
|
|
queue_push_event(dev, EV_SW, i, new ? 1 : 0);
|
2013-08-14 19:52:25 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 15:52:54 +10:00
|
|
|
memcpy(dev->sw_values, swstate, rc);
|
|
|
|
|
|
2013-08-14 19:52:25 +10:00
|
|
|
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;
|
2013-08-29 15:52:54 +10:00
|
|
|
unsigned long ledstate[NLONGS(LED_CNT)] = {0};
|
2013-08-14 09:29:41 +10:00
|
|
|
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGLED(sizeof(ledstate)), ledstate);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
2013-08-29 15:38:53 +10:00
|
|
|
for (i = 0; i < LED_CNT; i++) {
|
2013-08-14 09:29:41 +10:00
|
|
|
int old, new;
|
|
|
|
|
old = bit_is_set(dev->led_values, i);
|
|
|
|
|
new = bit_is_set(ledstate, i);
|
|
|
|
|
if (old ^ new) {
|
2020-02-11 13:51:17 +10:00
|
|
|
queue_push_event(dev, EV_LED, i, new ? 1 : 0);
|
2013-08-14 09:29:41 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 15:52:54 +10:00
|
|
|
memcpy(dev->led_values, ledstate, rc);
|
|
|
|
|
|
2013-08-14 09:29:41 +10:00
|
|
|
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;
|
|
|
|
|
|
2013-08-29 15:38:53 +10:00
|
|
|
for (i = ABS_X; i < ABS_CNT; 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) {
|
2020-02-11 13:51:17 +10:00
|
|
|
queue_push_event(dev, 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
|
2020-02-13 18:14:50 +10:00
|
|
|
sync_mt_state(struct libevdev *dev,
|
|
|
|
|
struct slot_change_state changes_out[dev->num_slots])
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
2020-02-19 13:18:48 +10:00
|
|
|
#define MAX_SLOTS 256
|
2020-02-19 13:31:48 +10:00
|
|
|
int rc = 0;
|
2020-02-19 13:18:48 +10:00
|
|
|
struct slot_change_state changes[MAX_SLOTS] = {0};
|
2020-03-05 13:37:46 +10:00
|
|
|
unsigned int nslots = min(MAX_SLOTS, dev->num_slots);
|
2014-04-01 15:32:46 +10:00
|
|
|
|
2020-02-13 08:28:32 +10:00
|
|
|
for (int axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
|
2020-02-12 22:05:33 +10:00
|
|
|
/* EVIOCGMTSLOTS required format */
|
|
|
|
|
struct mt_sync_state {
|
|
|
|
|
uint32_t code;
|
2020-02-19 13:18:48 +10:00
|
|
|
int32_t val[MAX_SLOTS];
|
2020-02-12 22:05:33 +10:00
|
|
|
} mt_state;
|
|
|
|
|
|
2020-02-13 08:28:59 +10:00
|
|
|
if (axis == ABS_MT_SLOT ||
|
|
|
|
|
!libevdev_has_event_code(dev, EV_ABS, axis))
|
2013-07-01 14:39:53 +10:00
|
|
|
continue;
|
|
|
|
|
|
2020-02-12 22:05:33 +10:00
|
|
|
mt_state.code = axis;
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(mt_state)), &mt_state);
|
2020-02-11 13:23:44 +10:00
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
2014-02-27 13:10:35 +10:00
|
|
|
|
2020-03-05 13:37:46 +10:00
|
|
|
for (unsigned int slot = 0; slot < nslots; slot++) {
|
2020-02-13 16:39:20 +10:00
|
|
|
int val_before = *slot_value(dev, slot, axis),
|
|
|
|
|
val_after = mt_state.val[slot];
|
|
|
|
|
|
2020-02-13 16:50:17 +10:00
|
|
|
if (axis == ABS_MT_TRACKING_ID) {
|
|
|
|
|
if (val_before == -1 && val_after != -1) {
|
|
|
|
|
changes[slot].state = TOUCH_STARTED;
|
|
|
|
|
} else if (val_before != -1 && val_after == -1) {
|
|
|
|
|
changes[slot].state = TOUCH_STOPPED;
|
|
|
|
|
} else if (val_before != -1 && val_after != -1 &&
|
|
|
|
|
val_before == val_after) {
|
|
|
|
|
changes[slot].state = TOUCH_ONGOING;
|
|
|
|
|
} else if (val_before != -1 && val_after != -1 &&
|
|
|
|
|
val_before != val_after) {
|
|
|
|
|
changes[slot].state = TOUCH_CHANGED;
|
|
|
|
|
} else {
|
|
|
|
|
changes[slot].state = TOUCH_OFF;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 16:39:20 +10:00
|
|
|
if (val_before == val_after)
|
2020-02-11 13:23:44 +10:00
|
|
|
continue;
|
2014-02-27 13:10:35 +10:00
|
|
|
|
2020-02-13 16:39:20 +10:00
|
|
|
*slot_value(dev, slot, axis) = val_after;
|
2020-02-11 13:23:44 +10:00
|
|
|
|
2020-02-13 16:50:17 +10:00
|
|
|
set_bit(changes[slot].axes, axis);
|
2020-02-11 13:23:44 +10:00
|
|
|
/* note that this slot has updates */
|
2020-02-13 16:50:17 +10:00
|
|
|
set_bit(changes[slot].axes, ABS_MT_SLOT);
|
2013-07-03 14:58:22 +10:00
|
|
|
}
|
2014-02-27 13:10:35 +10:00
|
|
|
}
|
2013-07-03 14:58:22 +10:00
|
|
|
|
2020-03-05 13:37:46 +10:00
|
|
|
if (dev->num_slots > MAX_SLOTS)
|
|
|
|
|
memset(changes_out, 0, sizeof(*changes) * dev->num_slots);
|
|
|
|
|
|
|
|
|
|
memcpy(changes_out, changes, sizeof(*changes) * nslots);
|
2020-02-13 18:14:50 +10:00
|
|
|
out:
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2013-05-30 12:18:39 +10:00
|
|
|
|
2020-02-13 20:39:41 +10:00
|
|
|
static void
|
|
|
|
|
terminate_slots(struct libevdev *dev,
|
|
|
|
|
const struct slot_change_state changes[dev->num_slots],
|
|
|
|
|
int *last_reported_slot)
|
2020-02-13 18:14:50 +10:00
|
|
|
{
|
2020-02-13 21:35:51 +10:00
|
|
|
const unsigned int map[] = {BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
|
|
|
|
|
BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP,
|
|
|
|
|
BTN_TOOL_QUINTTAP};
|
2020-02-13 18:14:50 +10:00
|
|
|
bool touches_stopped = false;
|
2020-02-13 21:35:51 +10:00
|
|
|
int ntouches_before = 0, ntouches_after = 0;
|
2014-03-06 11:54:00 +10:00
|
|
|
|
2020-02-13 21:35:51 +10:00
|
|
|
/* For BTN_TOOL_* emulation, we need to know how many touches we had
|
|
|
|
|
* before and how many we have left once we terminate all the ones
|
|
|
|
|
* that changed and all the ones that stopped.
|
|
|
|
|
*/
|
2020-02-13 18:14:50 +10:00
|
|
|
for (int slot = 0; slot < dev->num_slots; slot++) {
|
2020-02-13 21:35:51 +10:00
|
|
|
switch(changes[slot].state) {
|
|
|
|
|
case TOUCH_OFF:
|
|
|
|
|
break;
|
|
|
|
|
case TOUCH_CHANGED:
|
|
|
|
|
case TOUCH_STOPPED:
|
2020-02-13 21:09:24 +10:00
|
|
|
queue_push_event(dev, EV_ABS, ABS_MT_SLOT, slot);
|
|
|
|
|
queue_push_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
|
2014-03-06 11:54:00 +10:00
|
|
|
|
2020-02-13 21:09:24 +10:00
|
|
|
*last_reported_slot = slot;
|
|
|
|
|
touches_stopped = true;
|
2020-02-13 21:35:51 +10:00
|
|
|
ntouches_before++;
|
|
|
|
|
break;
|
|
|
|
|
case TOUCH_ONGOING:
|
|
|
|
|
ntouches_before++;
|
|
|
|
|
ntouches_after++;
|
|
|
|
|
break;
|
|
|
|
|
case TOUCH_STARTED:
|
|
|
|
|
break;
|
2020-02-13 21:09:24 +10:00
|
|
|
}
|
2014-03-06 11:54:00 +10:00
|
|
|
}
|
|
|
|
|
|
2020-02-13 18:14:50 +10:00
|
|
|
/* If any of the touches stopped, we need to split the sync state
|
|
|
|
|
into two frames - one with all the stopped touches, one with the
|
|
|
|
|
new touches starting (if any) */
|
2020-02-13 21:35:51 +10:00
|
|
|
if (touches_stopped) {
|
|
|
|
|
/* Send through the required BTN_TOOL_ 0 and 1 events for
|
|
|
|
|
* the previous and current number of fingers. And update
|
|
|
|
|
* our own key state accordingly, so that during the second
|
|
|
|
|
* sync event frame sync_key_state() sets everything correctly
|
|
|
|
|
* for the *real* number of touches.
|
|
|
|
|
*/
|
2020-02-19 13:28:38 +10:00
|
|
|
if (ntouches_before > 0 && ntouches_before <= 5) {
|
2020-02-13 21:35:51 +10:00
|
|
|
struct input_event ev = {
|
|
|
|
|
.type = EV_KEY,
|
|
|
|
|
.code = map[ntouches_before - 1],
|
|
|
|
|
.value = 0,
|
|
|
|
|
};
|
|
|
|
|
queue_push_event(dev, ev.type, ev.code, ev.value);
|
|
|
|
|
update_key_state(dev, &ev);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 13:28:38 +10:00
|
|
|
if (ntouches_after > 0 && ntouches_after <= 5) {
|
2020-02-13 21:35:51 +10:00
|
|
|
struct input_event ev = {
|
|
|
|
|
.type = EV_KEY,
|
|
|
|
|
.code = map[ntouches_after - 1],
|
|
|
|
|
.value = 1,
|
|
|
|
|
};
|
|
|
|
|
queue_push_event(dev, ev.type, ev.code, ev.value);
|
|
|
|
|
update_key_state(dev, &ev);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-13 18:14:50 +10:00
|
|
|
queue_push_event(dev, EV_SYN, SYN_REPORT, 0);
|
2020-02-13 21:35:51 +10:00
|
|
|
}
|
2020-02-13 20:39:41 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
push_mt_sync_events(struct libevdev *dev,
|
|
|
|
|
const struct slot_change_state changes[dev->num_slots],
|
|
|
|
|
int last_reported_slot)
|
|
|
|
|
{
|
|
|
|
|
struct input_absinfo abs_info;
|
|
|
|
|
int rc;
|
2020-02-13 18:14:50 +10:00
|
|
|
|
2020-02-13 08:28:32 +10:00
|
|
|
for (int slot = 0; slot < dev->num_slots; slot++) {
|
Terminate all stopped/changed touches during SYN_DROPPED in the first frame
The previous event processing had subtle issues with touches stopping during
SYN_DROPPED. All of the device state was processed in the same frame, but if
any touch changed tracking ID during SYN_DROPPED, an inserted SYN_REPORT
resulted in a weird split of events:
- the first frame had all key/sw/abs updates including those slots that
changed tracking ID, but not the ones that were fully terminated.
- the second frame had only the slots states for newly started touches **and**
the slot state for touches terminated during SYN_DROPPED but not restarted.
In other words, where three fingers were on the touchpad and slot 0 was lifted
and put down again and slot 1 was lifted but *not* put down again, our frames
contained:
- frame 1: terminate slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
- frame 2: start slot 0, terminate slot 1
Where there was no touch changing tracking ID, only one frame was generated.
The BTN_TOOL updates were buggy, they may not match the number of fingers down
as seen on a frame-by-frame basis. This triggered libinput bug
https://gitlab.freedesktop.org/libinput/libinput/issues/422
This patch changes the above example to
- frame 1: terminate slot 0, terminate slot 1
- frame 2: start slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
Notably, the first frame no longer contains the BTN_TOOL bits. This patch is
one of two, the BTN_TOOL sync bits are part of a follow-up patch.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-13 21:11:14 +10:00
|
|
|
/* stopped touches were already terminated in
|
|
|
|
|
* terminate_slots */
|
|
|
|
|
if (changes[slot].state == TOUCH_STOPPED ||
|
|
|
|
|
!bit_is_set(changes[slot].axes, ABS_MT_SLOT))
|
2014-02-27 13:10:35 +10:00
|
|
|
continue;
|
2013-06-03 16:36:34 +10:00
|
|
|
|
2020-02-11 13:51:17 +10:00
|
|
|
queue_push_event(dev, EV_ABS, ABS_MT_SLOT, slot);
|
2014-03-05 12:03:57 +10:00
|
|
|
last_reported_slot = slot;
|
2013-07-01 14:39:53 +10:00
|
|
|
|
2020-02-13 08:28:32 +10:00
|
|
|
for (int axis = ABS_MT_MIN; axis <= ABS_MT_MAX; axis++) {
|
2014-02-27 13:10:35 +10:00
|
|
|
if (axis == ABS_MT_SLOT ||
|
|
|
|
|
!libevdev_has_event_code(dev, EV_ABS, axis))
|
2013-05-30 10:42:24 +10:00
|
|
|
continue;
|
|
|
|
|
|
2020-02-13 16:50:17 +10:00
|
|
|
if (bit_is_set(changes[slot].axes, axis))
|
2020-02-11 13:51:17 +10:00
|
|
|
queue_push_event(dev, EV_ABS, axis,
|
|
|
|
|
*slot_value(dev, slot, axis));
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-05 12:03:57 +10:00
|
|
|
/* add one last slot event to make sure the client is on the same
|
|
|
|
|
slot as the kernel */
|
|
|
|
|
|
|
|
|
|
rc = ioctl(dev->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
dev->current_slot = abs_info.value;
|
|
|
|
|
|
2020-02-11 13:51:17 +10:00
|
|
|
if (dev->current_slot != last_reported_slot)
|
|
|
|
|
queue_push_event(dev, EV_ABS, ABS_MT_SLOT, dev->current_slot);
|
2014-03-05 12:03:57 +10:00
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
rc = 0;
|
|
|
|
|
out:
|
|
|
|
|
return rc ? -errno : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-07 15:01:44 +10:00
|
|
|
static int
|
|
|
|
|
read_more_events(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
int free_elem;
|
|
|
|
|
int len;
|
|
|
|
|
struct input_event *next;
|
|
|
|
|
|
|
|
|
|
free_elem = queue_num_free_elements(dev);
|
|
|
|
|
if (free_elem <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
next = queue_next_element(dev);
|
|
|
|
|
len = read(dev->fd, next, free_elem * sizeof(struct input_event));
|
2020-08-27 00:42:20 -07:00
|
|
|
if (len < 0)
|
2014-04-07 15:01:44 +10:00
|
|
|
return -errno;
|
2020-08-27 00:42:20 -07:00
|
|
|
|
|
|
|
|
if (len > 0 && len % sizeof(struct input_event) != 0)
|
2014-04-07 15:01:44 +10:00
|
|
|
return -EINVAL;
|
2020-08-27 00:42:20 -07:00
|
|
|
|
|
|
|
|
if (len > 0) {
|
2014-04-07 15:01:44 +10:00
|
|
|
int nev = len/sizeof(struct input_event);
|
|
|
|
|
queue_set_num_elements(dev, queue_num_elements(dev) + nev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
static inline void
|
|
|
|
|
drain_events(struct libevdev *dev)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
int rc;
|
|
|
|
|
size_t nelem;
|
|
|
|
|
int iterations = 0;
|
|
|
|
|
const int max_iterations = 8; /* EVDEV_BUF_PACKETS in
|
|
|
|
|
kernel/drivers/input/evedev.c */
|
|
|
|
|
|
|
|
|
|
queue_shift_multiple(dev, queue_num_elements(dev), NULL);
|
2013-05-30 10:42:24 +10:00
|
|
|
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
do {
|
|
|
|
|
rc = read_more_events(dev);
|
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
|
return;
|
2013-05-30 12:20:21 +10:00
|
|
|
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
if (rc < 0) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_error(dev, "Failed to drain events before sync.\n");
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nelem = queue_num_elements(dev);
|
|
|
|
|
queue_shift_multiple(dev, nelem, NULL);
|
|
|
|
|
} while (iterations++ < max_iterations && nelem >= queue_size(dev));
|
|
|
|
|
|
|
|
|
|
/* Our buffer should be roughly the same or bigger than the kernel
|
|
|
|
|
buffer in most cases, so we usually don't expect to recurse. If
|
|
|
|
|
we do, make sure we stop after max_iterations and proceed with
|
|
|
|
|
what we have. This could happen if events queue up faster than
|
|
|
|
|
we can drain them.
|
2013-05-30 10:42:24 +10:00
|
|
|
*/
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
if (iterations >= max_iterations)
|
2014-05-14 16:36:49 +10:00
|
|
|
log_info(dev, "Unable to drain events, buffer size mismatch.\n");
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
static int
|
|
|
|
|
sync_state(struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
Terminate all stopped/changed touches during SYN_DROPPED in the first frame
The previous event processing had subtle issues with touches stopping during
SYN_DROPPED. All of the device state was processed in the same frame, but if
any touch changed tracking ID during SYN_DROPPED, an inserted SYN_REPORT
resulted in a weird split of events:
- the first frame had all key/sw/abs updates including those slots that
changed tracking ID, but not the ones that were fully terminated.
- the second frame had only the slots states for newly started touches **and**
the slot state for touches terminated during SYN_DROPPED but not restarted.
In other words, where three fingers were on the touchpad and slot 0 was lifted
and put down again and slot 1 was lifted but *not* put down again, our frames
contained:
- frame 1: terminate slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
- frame 2: start slot 0, terminate slot 1
Where there was no touch changing tracking ID, only one frame was generated.
The BTN_TOOL updates were buggy, they may not match the number of fingers down
as seen on a frame-by-frame basis. This triggered libinput bug
https://gitlab.freedesktop.org/libinput/libinput/issues/422
This patch changes the above example to
- frame 1: terminate slot 0, terminate slot 1
- frame 2: start slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
Notably, the first frame no longer contains the BTN_TOOL bits. This patch is
one of two, the BTN_TOOL sync bits are part of a follow-up patch.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-13 21:11:14 +10:00
|
|
|
bool want_mt_sync = false;
|
|
|
|
|
int last_reported_slot = 0;
|
|
|
|
|
struct slot_change_state changes[dev->num_slots > 0 ? dev->num_slots : 1];
|
|
|
|
|
memset(changes, 0, sizeof(changes));
|
2013-05-30 12:20:21 +10:00
|
|
|
|
Drain all events before synchronizing after SYN_DROPPED
The kernel ring buffer drops all events on SYN_DROPPED, but then continues to
fill up again. So by the time we read the events, the kernel's client buffer is
essentially like this:
SYN_DROPPED, ev1, ev2, ev3, ...., evN
The kernel's device state represents the device after evN, and that is what
the ioctls return. For EV_KEY, EV_SND, EV_LED and EV_SW the kernel removes
potential duplicates from the client buffer [1], it doesn't do so for EV_ABS.
So we can't actually sync while there are events on the wire because the
events represent an earlier state. So simply discard all events in the kernel
buffer, synchronize, and then start processing again. We lose some granularity
but at least the events are correct.
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/evdev.c?id=483180281f0ac60d1138710eb21f4b9961901294
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-07 15:16:28 +10:00
|
|
|
/* see section "Discarding events before synchronizing" in
|
|
|
|
|
* libevdev/libevdev.h */
|
|
|
|
|
drain_events(dev);
|
2013-05-30 12:20:21 +10:00
|
|
|
|
Terminate all stopped/changed touches during SYN_DROPPED in the first frame
The previous event processing had subtle issues with touches stopping during
SYN_DROPPED. All of the device state was processed in the same frame, but if
any touch changed tracking ID during SYN_DROPPED, an inserted SYN_REPORT
resulted in a weird split of events:
- the first frame had all key/sw/abs updates including those slots that
changed tracking ID, but not the ones that were fully terminated.
- the second frame had only the slots states for newly started touches **and**
the slot state for touches terminated during SYN_DROPPED but not restarted.
In other words, where three fingers were on the touchpad and slot 0 was lifted
and put down again and slot 1 was lifted but *not* put down again, our frames
contained:
- frame 1: terminate slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
- frame 2: start slot 0, terminate slot 1
Where there was no touch changing tracking ID, only one frame was generated.
The BTN_TOOL updates were buggy, they may not match the number of fingers down
as seen on a frame-by-frame basis. This triggered libinput bug
https://gitlab.freedesktop.org/libinput/libinput/issues/422
This patch changes the above example to
- frame 1: terminate slot 0, terminate slot 1
- frame 2: start slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
Notably, the first frame no longer contains the BTN_TOOL bits. This patch is
one of two, the BTN_TOOL sync bits are part of a follow-up patch.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-13 21:11:14 +10:00
|
|
|
/* We generate one or two event frames during sync.
|
|
|
|
|
* The first one (if it exists) terminates all slots that have
|
|
|
|
|
* either terminated during SYN_DROPPED or changed their tracking
|
|
|
|
|
* ID.
|
|
|
|
|
*
|
|
|
|
|
* The second frame syncs everything up to the current state of the
|
|
|
|
|
* device - including re-starting those slots that have a changed
|
|
|
|
|
* tracking id.
|
|
|
|
|
*/
|
|
|
|
|
if (dev->num_slots > -1 &&
|
|
|
|
|
libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) {
|
|
|
|
|
want_mt_sync = true;
|
|
|
|
|
rc = sync_mt_state(dev, changes);
|
|
|
|
|
if (rc == 0)
|
|
|
|
|
terminate_slots(dev, changes, &last_reported_slot);
|
|
|
|
|
else
|
|
|
|
|
want_mt_sync = false;
|
|
|
|
|
}
|
|
|
|
|
|
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-08-14 19:52:25 +10:00
|
|
|
if (libevdev_has_event_type(dev, EV_SW))
|
|
|
|
|
rc = sync_sw_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);
|
Terminate all stopped/changed touches during SYN_DROPPED in the first frame
The previous event processing had subtle issues with touches stopping during
SYN_DROPPED. All of the device state was processed in the same frame, but if
any touch changed tracking ID during SYN_DROPPED, an inserted SYN_REPORT
resulted in a weird split of events:
- the first frame had all key/sw/abs updates including those slots that
changed tracking ID, but not the ones that were fully terminated.
- the second frame had only the slots states for newly started touches **and**
the slot state for touches terminated during SYN_DROPPED but not restarted.
In other words, where three fingers were on the touchpad and slot 0 was lifted
and put down again and slot 1 was lifted but *not* put down again, our frames
contained:
- frame 1: terminate slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
- frame 2: start slot 0, terminate slot 1
Where there was no touch changing tracking ID, only one frame was generated.
The BTN_TOOL updates were buggy, they may not match the number of fingers down
as seen on a frame-by-frame basis. This triggered libinput bug
https://gitlab.freedesktop.org/libinput/libinput/issues/422
This patch changes the above example to
- frame 1: terminate slot 0, terminate slot 1
- frame 2: start slot 0, BTN_TOOL_TRIPLETAP 0, BTN_TOOL_DOUBLETAP 1
Notably, the first frame no longer contains the BTN_TOOL bits. This patch is
one of two, the BTN_TOOL sync bits are part of a follow-up patch.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-02-13 21:11:14 +10:00
|
|
|
if (rc == 0 && want_mt_sync)
|
|
|
|
|
push_mt_sync_events(dev, changes, last_reported_slot);
|
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) {
|
2020-02-11 13:51:17 +10:00
|
|
|
queue_push_event(dev, EV_SYN, SYN_REPORT, 0);
|
2013-07-02 10:55:44 +10:00
|
|
|
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)
|
|
|
|
|
{
|
2013-11-20 11:58:08 +10:00
|
|
|
if (e->code == ABS_MT_SLOT && dev->num_slots > -1) {
|
2013-08-15 11:10:17 +10:00
|
|
|
int i;
|
2013-05-30 13:58:45 +10:00
|
|
|
dev->current_slot = e->value;
|
2013-08-15 11:10:17 +10:00
|
|
|
/* sync abs_info with the current slot values */
|
|
|
|
|
for (i = ABS_MT_SLOT + 1; i <= ABS_MT_MAX; i++) {
|
|
|
|
|
if (libevdev_has_event_code(dev, EV_ABS, i))
|
2014-02-27 11:34:47 +10:00
|
|
|
dev->abs_info[i].value = *slot_value(dev, dev->current_slot, i);
|
2013-08-15 11:10:17 +10:00
|
|
|
}
|
|
|
|
|
|
2013-05-30 13:58:45 +10:00
|
|
|
return 0;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-05-30 13:58:45 +10:00
|
|
|
|
2020-08-27 00:42:20 -07:00
|
|
|
if (dev->current_slot == -1)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2014-02-27 11:34:47 +10:00
|
|
|
*slot_value(dev, dev->current_slot, e->code) = e->value;
|
2013-05-30 13:58:45 +10:00
|
|
|
|
|
|
|
|
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)
|
2013-08-15 11:10:17 +10:00
|
|
|
update_mt_state(dev, e);
|
2013-05-30 13:58:45 +10:00
|
|
|
|
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-08-14 19:52:25 +10:00
|
|
|
static int
|
|
|
|
|
update_sw_state(struct libevdev *dev, const struct input_event *e)
|
|
|
|
|
{
|
|
|
|
|
if (!libevdev_has_event_type(dev, EV_SW))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (e->code > SW_MAX)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
set_bit_state(dev->sw_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-08-14 19:52:25 +10:00
|
|
|
case EV_SW:
|
|
|
|
|
rc = update_sw_state(dev, e);
|
|
|
|
|
break;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2018-01-15 16:21:08 -08:00
|
|
|
dev->last_event_time.tv_sec = e->input_event_sec;
|
|
|
|
|
dev->last_event_time.tv_usec = e->input_event_usec;
|
2013-06-03 16:20:35 +10:00
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-05 10:57:01 +10:00
|
|
|
/**
|
|
|
|
|
* Sanitize/modify events where needed.
|
|
|
|
|
*/
|
2014-04-01 17:01:39 +10:00
|
|
|
static inline enum event_filter_status
|
|
|
|
|
sanitize_event(const struct libevdev *dev,
|
|
|
|
|
struct input_event *ev,
|
|
|
|
|
enum SyncState sync_state)
|
2014-03-05 10:57:01 +10:00
|
|
|
{
|
2016-08-17 10:48:43 +10:00
|
|
|
if (!libevdev_has_event_code(dev, ev->type, ev->code))
|
|
|
|
|
return EVENT_FILTER_DISCARD;
|
|
|
|
|
|
2014-03-05 10:57:01 +10:00
|
|
|
if (unlikely(dev->num_slots > -1 &&
|
|
|
|
|
libevdev_event_is_code(ev, EV_ABS, ABS_MT_SLOT) &&
|
|
|
|
|
(ev->value < 0 || ev->value >= dev->num_slots))) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "Device \"%s\" received an invalid slot index %d."
|
2014-03-05 10:57:01 +10:00
|
|
|
"Capping to announced max slot number %d.\n",
|
|
|
|
|
dev->name, ev->value, dev->num_slots - 1);
|
|
|
|
|
ev->value = dev->num_slots - 1;
|
2014-04-01 17:01:39 +10:00
|
|
|
return EVENT_FILTER_MODIFIED;
|
|
|
|
|
|
|
|
|
|
/* Drop any invalid tracking IDs, they are only supposed to go from
|
|
|
|
|
N to -1 or from -1 to N. Never from -1 to -1, or N to M. Very
|
|
|
|
|
unlikely to ever happen from a real device.
|
|
|
|
|
*/
|
2020-08-27 00:42:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unlikely(sync_state == SYNC_NONE &&
|
2014-04-01 17:01:39 +10:00
|
|
|
dev->num_slots > -1 &&
|
|
|
|
|
libevdev_event_is_code(ev, EV_ABS, ABS_MT_TRACKING_ID) &&
|
|
|
|
|
((ev->value == -1 &&
|
|
|
|
|
*slot_value(dev, dev->current_slot, ABS_MT_TRACKING_ID) == -1) ||
|
|
|
|
|
(ev->value != -1 &&
|
|
|
|
|
*slot_value(dev, dev->current_slot, ABS_MT_TRACKING_ID) != -1)))) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "Device \"%s\" received a double tracking ID %d in slot %d.\n",
|
2014-04-01 17:01:39 +10:00
|
|
|
dev->name, ev->value, dev->current_slot);
|
|
|
|
|
return EVENT_FILTER_DISCARD;
|
2014-03-05 10:57:01 +10:00
|
|
|
}
|
|
|
|
|
|
2014-04-01 17:01:39 +10:00
|
|
|
return EVENT_FILTER_NONE;
|
2014-03-05 10:57:01 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
2013-09-11 10:32:36 +10:00
|
|
|
int rc = LIBEVDEV_READ_STATUS_SUCCESS;
|
2014-04-01 17:01:39 +10:00
|
|
|
enum event_filter_status filter_status;
|
2015-04-07 07:12:01 +10:00
|
|
|
const unsigned int valid_flags = LIBEVDEV_READ_FLAG_NORMAL |
|
|
|
|
|
LIBEVDEV_READ_FLAG_SYNC |
|
|
|
|
|
LIBEVDEV_READ_FLAG_FORCE_SYNC |
|
|
|
|
|
LIBEVDEV_READ_FLAG_BLOCKING;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-10-08 15:16:32 +10:00
|
|
|
if (!dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
|
2013-08-31 12:33:33 +10:00
|
|
|
return -EBADF;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2020-08-27 00:42:20 -07:00
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -EBADF;
|
|
|
|
|
|
2015-04-07 07:12:01 +10:00
|
|
|
if ((flags & valid_flags) == 0) {
|
2014-11-17 11:51:04 +10:00
|
|
|
log_bug(dev, "invalid flags %#x.\n", flags);
|
2013-06-27 14:20:03 +10:00
|
|
|
return -EINVAL;
|
2013-08-31 12:53:36 +10:00
|
|
|
}
|
2013-06-27 14:20:03 +10:00
|
|
|
|
2013-09-11 11:04:54 +10:00
|
|
|
if (flags & LIBEVDEV_READ_FLAG_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--;
|
2014-04-01 17:01:39 +10:00
|
|
|
if (sanitize_event(dev, &e, dev->sync_state) != EVENT_FILTER_DISCARD)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
/* 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 {
|
2019-01-16 13:55:25 +10:00
|
|
|
if (queue_num_elements(dev) == 0) {
|
2013-07-01 15:46:23 +10:00
|
|
|
rc = read_more_events(dev);
|
|
|
|
|
if (rc < 0 && rc != -EAGAIN)
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-09-11 11:04:54 +10:00
|
|
|
if (flags & LIBEVDEV_READ_FLAG_FORCE_SYNC) {
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_NEEDED;
|
2013-09-11 10:32:36 +10:00
|
|
|
rc = LIBEVDEV_READ_STATUS_SYNC;
|
2013-07-01 10:06:55 +10:00
|
|
|
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;
|
|
|
|
|
|
2014-04-01 17:01:39 +10:00
|
|
|
filter_status = sanitize_event(dev, ev, dev->sync_state);
|
|
|
|
|
if (filter_status != EVENT_FILTER_DISCARD)
|
|
|
|
|
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 */
|
2014-04-01 17:01:39 +10:00
|
|
|
} while(filter_status == EVENT_FILTER_DISCARD ||
|
|
|
|
|
!libevdev_has_event_code(dev, ev->type, ev->code));
|
2013-05-30 10:42:24 +10:00
|
|
|
|
2014-02-25 09:44:35 +10:00
|
|
|
rc = LIBEVDEV_READ_STATUS_SUCCESS;
|
2013-05-30 10:42:24 +10:00
|
|
|
if (ev->type == EV_SYN && ev->code == SYN_DROPPED) {
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_NEEDED;
|
2013-09-11 10:32:36 +10:00
|
|
|
rc = LIBEVDEV_READ_STATUS_SYNC;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-09-11 11:04:54 +10:00
|
|
|
if (flags & LIBEVDEV_READ_FLAG_SYNC && dev->queue_nsync > 0) {
|
2013-05-30 10:42:24 +10:00
|
|
|
dev->queue_nsync--;
|
2013-09-11 10:32:36 +10:00
|
|
|
rc = LIBEVDEV_READ_STATUS_SYNC;
|
2019-01-16 13:55:25 +10:00
|
|
|
if (dev->queue_nsync == 0)
|
2013-07-02 10:50:37 +10:00
|
|
|
dev->sync_state = SYNC_NONE;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_has_event_pending(struct libevdev *dev)
|
2013-07-24 13:37:53 +10:00
|
|
|
{
|
|
|
|
|
struct pollfd fds = { dev->fd, POLLIN, 0 };
|
|
|
|
|
int rc;
|
|
|
|
|
|
2013-10-08 15:16:32 +10:00
|
|
|
if (!dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
|
2013-07-24 13:37:53 +10:00
|
|
|
return -EBADF;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-07-24 13:37:53 +10:00
|
|
|
|
2020-08-27 00:42:20 -07:00
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -EBADF;
|
|
|
|
|
|
2013-07-24 13:37:53 +10:00
|
|
|
if (queue_num_elements(dev) != 0)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
rc = poll(&fds, 1, 0);
|
|
|
|
|
return (rc >= 0) ? rc : -errno;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT const char *
|
2013-05-27 14:59:41 +10:00
|
|
|
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-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT const char *
|
2013-06-03 13:59:06 +10:00
|
|
|
libevdev_get_phys(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->phys;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT const char *
|
2013-06-03 13:59:06 +10:00
|
|
|
libevdev_get_uniq(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->uniq;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-25 16:11:04 +10:00
|
|
|
#define STRING_SETTER(field) \
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT void libevdev_set_##field(struct libevdev *dev, const char *field) \
|
2013-07-25 16:11:04 +10:00
|
|
|
{ \
|
|
|
|
|
if (field == NULL) \
|
|
|
|
|
return; \
|
|
|
|
|
free(dev->field); \
|
|
|
|
|
dev->field = strdup(field); \
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-22 10:30:14 +10:00
|
|
|
STRING_SETTER(name)
|
|
|
|
|
STRING_SETTER(phys)
|
|
|
|
|
STRING_SETTER(uniq)
|
2013-07-25 16:11:04 +10:00
|
|
|
|
2013-08-23 10:49:56 +10:00
|
|
|
#define PRODUCT_GETTER(name) \
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int libevdev_get_id_##name(const struct libevdev *dev) \
|
2013-07-30 13:48:55 +10:00
|
|
|
{ \
|
2013-08-23 10:49:56 +10:00
|
|
|
return dev->ids.name; \
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-11-22 10:30:14 +10:00
|
|
|
PRODUCT_GETTER(product)
|
|
|
|
|
PRODUCT_GETTER(vendor)
|
|
|
|
|
PRODUCT_GETTER(bustype)
|
|
|
|
|
PRODUCT_GETTER(version)
|
2013-06-03 13:35:28 +10:00
|
|
|
|
2013-07-25 16:21:32 +10:00
|
|
|
#define PRODUCT_SETTER(field) \
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT void libevdev_set_id_##field(struct libevdev *dev, int field) \
|
2013-07-25 16:21:32 +10:00
|
|
|
{ \
|
|
|
|
|
dev->ids.field = field;\
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-22 10:30:14 +10:00
|
|
|
PRODUCT_SETTER(product)
|
|
|
|
|
PRODUCT_SETTER(vendor)
|
|
|
|
|
PRODUCT_SETTER(bustype)
|
|
|
|
|
PRODUCT_SETTER(version)
|
2013-07-25 16:21:32 +10:00
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_get_driver_version(const struct libevdev *dev)
|
2013-06-03 13:35:28 +10:00
|
|
|
{
|
|
|
|
|
return dev->driver_version;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_has_property(const struct libevdev *dev, unsigned int prop)
|
|
|
|
|
{
|
|
|
|
|
return (prop <= INPUT_PROP_MAX) && bit_is_set(dev->props, prop);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-07-29 15:34:37 +10:00
|
|
|
libevdev_enable_property(struct libevdev *dev, unsigned int prop)
|
|
|
|
|
{
|
|
|
|
|
if (prop > INPUT_PROP_MAX)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
set_bit(dev->props, prop);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-17 03:03:17 -05:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_disable_property(struct libevdev *dev, unsigned int prop)
|
|
|
|
|
{
|
|
|
|
|
if (prop > INPUT_PROP_MAX)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
clear_bit(dev->props, prop);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_has_event_type(const struct libevdev *dev, unsigned int type)
|
|
|
|
|
{
|
2013-10-24 14:21:31 +10:00
|
|
|
return type == EV_SYN ||(type <= EV_MAX && bit_is_set(dev->bits, type));
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_has_event_code(const struct libevdev *dev, unsigned int type, unsigned int code)
|
|
|
|
|
{
|
2014-03-18 13:44:39 +10:00
|
|
|
const unsigned long *mask = NULL;
|
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-08-23 10:28:57 +10:00
|
|
|
if (max == -1 || code > (unsigned int)max)
|
2013-05-27 14:59:41 +10:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return bit_is_set(mask, code);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned int code)
|
|
|
|
|
{
|
2014-03-18 14:00:07 +10:00
|
|
|
int value = 0;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
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-08-14 19:52:25 +10:00
|
|
|
case EV_SW: value = bit_is_set(dev->sw_values, code); break;
|
2013-12-04 20:21:09 +10:00
|
|
|
case EV_REP:
|
|
|
|
|
switch(code) {
|
|
|
|
|
case REP_DELAY:
|
|
|
|
|
libevdev_get_repeat(dev, &value, NULL);
|
|
|
|
|
break;
|
|
|
|
|
case REP_PERIOD:
|
|
|
|
|
libevdev_get_repeat(dev, NULL, &value);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
value = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2013-05-27 14:59:41 +10:00
|
|
|
default:
|
|
|
|
|
value = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned int code, int value)
|
2013-08-09 14:46:24 +10:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2014-04-01 17:01:39 +10:00
|
|
|
if (sanitize_event(dev, &e, SYNC_NONE) != EVENT_FILTER_NONE)
|
2014-03-05 10:57:01 +10:00
|
|
|
return -1;
|
|
|
|
|
|
2013-08-09 14:46:24 +10:00
|
|
|
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-14 19:52:25 +10:00
|
|
|
case EV_SW: rc = update_sw_state(dev, &e); break;
|
2013-08-09 14:46:24 +10:00
|
|
|
default:
|
|
|
|
|
rc = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2020-08-27 00:42:20 -07:00
|
|
|
|
|
|
|
|
return 0;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
|
2014-02-27 11:34:47 +10:00
|
|
|
if (dev->num_slots < 0 || slot >= (unsigned int)dev->num_slots)
|
2013-05-27 14:59:41 +10:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (code > ABS_MT_MAX || code < ABS_MT_MIN)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2014-02-27 11:34:47 +10:00
|
|
|
return *slot_value(dev, slot, code);
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-08-09 14:46:24 +10:00
|
|
|
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;
|
|
|
|
|
|
2014-02-27 11:34:47 +10:00
|
|
|
if (dev->num_slots == -1 || slot >= (unsigned int)dev->num_slots)
|
2013-08-09 14:46:24 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 11:34:47 +10:00
|
|
|
*slot_value(dev, slot, code) = value;
|
2013-08-09 14:46:24 +10:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
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) &&
|
2013-08-23 10:28:57 +10:00
|
|
|
dev->num_slots >= 0 &&
|
2014-02-27 11:34:47 +10:00
|
|
|
slot < (unsigned int)dev->num_slots) {
|
2013-05-27 14:59:41 +10:00
|
|
|
*value = libevdev_get_slot_value(dev, slot, code);
|
|
|
|
|
return 1;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2020-08-27 00:42:20 -07:00
|
|
|
|
|
|
|
|
return 0;
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_get_num_slots(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->num_slots;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-30 14:02:17 +10:00
|
|
|
libevdev_get_current_slot(const struct libevdev *dev)
|
|
|
|
|
{
|
|
|
|
|
return dev->current_slot;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT const struct input_absinfo*
|
2013-05-27 14:59:41 +10:00
|
|
|
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-08-23 10:49:56 +10:00
|
|
|
#define ABS_GETTER(name) \
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int libevdev_get_abs_##name(const struct libevdev *dev, unsigned int code) \
|
2013-07-25 13:06:23 +10:00
|
|
|
{ \
|
|
|
|
|
const struct input_absinfo *absinfo = libevdev_get_abs_info(dev, code); \
|
2013-08-23 10:49:56 +10:00
|
|
|
return absinfo ? absinfo->name : 0; \
|
2013-05-27 14:59:41 +10:00
|
|
|
}
|
|
|
|
|
|
2013-11-22 10:30:14 +10:00
|
|
|
ABS_GETTER(maximum)
|
|
|
|
|
ABS_GETTER(minimum)
|
|
|
|
|
ABS_GETTER(fuzz)
|
|
|
|
|
ABS_GETTER(flat)
|
|
|
|
|
ABS_GETTER(resolution)
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-07-24 15:52:02 +10:00
|
|
|
#define ABS_SETTER(field) \
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT void libevdev_set_abs_##field(struct libevdev *dev, unsigned int code, int val) \
|
2013-07-24 15:52:02 +10:00
|
|
|
{ \
|
|
|
|
|
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)
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT void
|
|
|
|
|
libevdev_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
|
2013-07-24 15:52:02 +10:00
|
|
|
{
|
|
|
|
|
if (!libevdev_has_event_code(dev, EV_ABS, code))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
dev->abs_info[code] = *abs;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_enable_event_type(struct libevdev *dev, unsigned int type)
|
|
|
|
|
{
|
2013-10-24 14:30:40 +10:00
|
|
|
int max;
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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-10-24 14:30:40 +10:00
|
|
|
max = libevdev_event_type_get_max(type);
|
|
|
|
|
if (max == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_disable_event_type(struct libevdev *dev, unsigned int type)
|
|
|
|
|
{
|
2013-10-24 14:30:40 +10:00
|
|
|
int max;
|
|
|
|
|
|
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
|
|
|
|
2013-10-24 14:30:40 +10:00
|
|
|
max = libevdev_event_type_get_max(type);
|
|
|
|
|
if (max == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
clear_bit(dev->bits, type);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_enable_event_code(struct libevdev *dev, unsigned int type,
|
|
|
|
|
unsigned int code, const void *data)
|
|
|
|
|
{
|
|
|
|
|
unsigned int max;
|
2013-08-26 08:39:55 +10:00
|
|
|
unsigned long *mask = NULL;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2013-10-24 14:30:40 +10:00
|
|
|
if (code > max || (int)max == -1)
|
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;
|
2019-06-14 11:18:37 +10:00
|
|
|
if (code == ABS_MT_SLOT) {
|
|
|
|
|
if (init_slots(dev) != 0)
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (code == ABS_MT_TRACKING_ID) {
|
|
|
|
|
reset_tracking_ids(dev);
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-05-27 14:59:41 +10:00
|
|
|
libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned int code)
|
|
|
|
|
{
|
|
|
|
|
unsigned int max;
|
2013-08-26 08:39:55 +10:00
|
|
|
unsigned long *mask = NULL;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
2013-10-24 14:18:30 +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
|
|
|
|
|
|
|
|
max = type_to_mask(dev, type, &mask);
|
|
|
|
|
|
2013-10-24 14:30:40 +10:00
|
|
|
if (code > max || (int)max == -1)
|
2013-06-29 17:34:32 +10:00
|
|
|
return -1;
|
2013-05-27 14:59:41 +10:00
|
|
|
|
|
|
|
|
clear_bit(mask, code);
|
|
|
|
|
|
2019-06-14 11:18:37 +10:00
|
|
|
if (type == EV_ABS) {
|
|
|
|
|
if (code == ABS_MT_SLOT) {
|
|
|
|
|
if (init_slots(dev) != 0)
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (code == ABS_MT_TRACKING_ID) {
|
|
|
|
|
reset_tracking_ids(dev);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-08-09 13:47:00 +10:00
|
|
|
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;
|
|
|
|
|
|
2013-10-08 15:16:32 +10:00
|
|
|
if (!dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
|
2013-08-31 12:37:14 +10:00
|
|
|
return -EBADF;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-08-31 12:37:14 +10:00
|
|
|
|
2020-08-27 00:42:20 -07:00
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -EBADF;
|
|
|
|
|
|
2013-05-27 14:59:41 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-08-14 10:17:59 +10:00
|
|
|
libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab)
|
2013-05-27 14:59:41 +10:00
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
|
2013-10-08 15:16:32 +10:00
|
|
|
if (!dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
|
2013-08-31 12:37:14 +10:00
|
|
|
return -EBADF;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-08-31 12:37:14 +10:00
|
|
|
|
2020-08-27 00:42:20 -07:00
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -EBADF;
|
|
|
|
|
|
2013-08-31 12:53:36 +10:00
|
|
|
if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "invalid grab parameter %#x\n", grab);
|
2013-05-31 14:48:43 +10:00
|
|
|
return -EINVAL;
|
2013-08-31 12:53:36 +10:00
|
|
|
}
|
2013-05-31 14:48:43 +10:00
|
|
|
|
|
|
|
|
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-08-27 13:33:37 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_event_is_type(const struct input_event *ev, unsigned int type)
|
2013-07-04 10:07:44 +10:00
|
|
|
{
|
2013-08-29 11:17:08 +10:00
|
|
|
return type < EV_CNT && ev->type == type;
|
2013-07-04 10:07:44 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-27 13:33:37 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_event_is_code(const struct input_event *ev, unsigned int type, unsigned int code)
|
2013-07-04 10:07:44 +10:00
|
|
|
{
|
2013-08-23 10:25:08 +10:00
|
|
|
int max;
|
|
|
|
|
|
2013-08-27 13:33:37 +10:00
|
|
|
if (!libevdev_event_is_type(ev, type))
|
2013-08-23 10:25:08 +10:00
|
|
|
return 0;
|
|
|
|
|
|
2013-08-27 13:33:37 +10:00
|
|
|
max = libevdev_event_type_get_max(type);
|
2013-08-23 10:25:08 +10:00
|
|
|
return (max > -1 && code <= (unsigned int)max && ev->code == code);
|
2013-07-04 10:07:44 +10:00
|
|
|
}
|
|
|
|
|
|
2013-08-27 13:33:37 +10:00
|
|
|
LIBEVDEV_EXPORT const char*
|
|
|
|
|
libevdev_event_type_get_name(unsigned int type)
|
2013-06-04 09:52:20 +10:00
|
|
|
{
|
|
|
|
|
if (type > EV_MAX)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return ev_map[type];
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-27 13:33:37 +10:00
|
|
|
LIBEVDEV_EXPORT const char*
|
|
|
|
|
libevdev_event_code_get_name(unsigned int type, unsigned int code)
|
2013-06-04 09:52:20 +10:00
|
|
|
{
|
2013-08-27 13:33:37 +10:00
|
|
|
int max = libevdev_event_type_get_max(type);
|
2013-06-04 09:52:20 +10:00
|
|
|
|
2013-08-23 10:20:50 +10:00
|
|
|
if (max == -1 || code > (unsigned int)max)
|
2013-06-04 09:52:20 +10:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return event_type_map[type][code];
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-15 13:51:43 +10:00
|
|
|
LIBEVDEV_EXPORT const char *
|
|
|
|
|
libevdev_event_value_get_name(unsigned int type,
|
|
|
|
|
unsigned int code,
|
|
|
|
|
int value)
|
|
|
|
|
{
|
|
|
|
|
/* This is a simplified version because nothing else
|
|
|
|
|
is an enum like ABS_MT_TOOL_TYPE so we don't need
|
|
|
|
|
a generic lookup */
|
|
|
|
|
if (type != EV_ABS || code != ABS_MT_TOOL_TYPE)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2020-07-15 13:32:40 +10:00
|
|
|
if (value < 0 || value > MT_TOOL_MAX)
|
2018-06-15 13:51:43 +10:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return mt_tool_map[value];
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-27 13:33:37 +10:00
|
|
|
LIBEVDEV_EXPORT const char*
|
|
|
|
|
libevdev_property_get_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
|
|
|
|
2013-08-27 13:33:37 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_event_type_get_max(unsigned int type)
|
2013-06-05 16:01:25 +10:00
|
|
|
{
|
|
|
|
|
if (type > EV_MAX)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return ev_max[type];
|
|
|
|
|
}
|
2013-06-09 19:48:19 +10:00
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-12-04 20:15:28 +10:00
|
|
|
libevdev_get_repeat(const struct libevdev *dev, int *delay, int *period)
|
2013-06-09 19:48:19 +10:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
2013-08-09 13:21:28 +10:00
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-08-14 10:17:59 +10:00
|
|
|
libevdev_kernel_set_led_value(struct libevdev *dev, unsigned int code, enum libevdev_led_value value)
|
2013-08-09 13:21:28 +10:00
|
|
|
{
|
|
|
|
|
return libevdev_kernel_set_led_values(dev, code, value, -1);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-29 11:50:09 +10:00
|
|
|
LIBEVDEV_EXPORT int
|
2013-08-09 13:21:28 +10:00
|
|
|
libevdev_kernel_set_led_values(struct libevdev *dev, ...)
|
|
|
|
|
{
|
2013-08-09 17:38:51 +02:00
|
|
|
struct input_event ev[LED_MAX + 1];
|
2013-08-14 10:17:59 +10:00
|
|
|
enum libevdev_led_value val;
|
2013-08-09 13:21:28 +10:00
|
|
|
va_list args;
|
|
|
|
|
int code;
|
|
|
|
|
int rc = 0;
|
|
|
|
|
size_t nleds = 0;
|
|
|
|
|
|
2013-10-08 15:16:32 +10:00
|
|
|
if (!dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
|
2013-08-31 12:37:14 +10:00
|
|
|
return -EBADF;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-08-31 12:37:14 +10:00
|
|
|
|
2020-08-27 00:42:20 -07:00
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -EBADF;
|
|
|
|
|
|
2013-08-09 13:21:28 +10:00
|
|
|
memset(ev, 0, sizeof(ev));
|
|
|
|
|
|
|
|
|
|
va_start(args, dev);
|
|
|
|
|
code = va_arg(args, unsigned int);
|
|
|
|
|
while (code != -1) {
|
|
|
|
|
if (code > LED_MAX) {
|
|
|
|
|
rc = -EINVAL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-08-14 10:17:59 +10:00
|
|
|
val = va_arg(args, enum libevdev_led_value);
|
2013-08-09 13:21:28 +10:00
|
|
|
if (val != LIBEVDEV_LED_ON && val != LIBEVDEV_LED_OFF) {
|
|
|
|
|
rc = -EINVAL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libevdev_has_event_code(dev, EV_LED, code)) {
|
|
|
|
|
struct input_event *e = ev;
|
|
|
|
|
|
|
|
|
|
while (e->type > 0 && e->code != code)
|
|
|
|
|
e++;
|
|
|
|
|
|
|
|
|
|
if (e->type == 0)
|
|
|
|
|
nleds++;
|
|
|
|
|
e->type = EV_LED;
|
|
|
|
|
e->code = code;
|
|
|
|
|
e->value = (val == LIBEVDEV_LED_ON);
|
|
|
|
|
}
|
|
|
|
|
code = va_arg(args, unsigned int);
|
|
|
|
|
}
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
|
|
if (rc == 0 && nleds > 0) {
|
2013-08-09 17:38:51 +02:00
|
|
|
ev[nleds].type = EV_SYN;
|
|
|
|
|
ev[nleds++].code = SYN_REPORT;
|
|
|
|
|
|
2013-08-09 13:21:28 +10:00
|
|
|
rc = write(libevdev_get_fd(dev), ev, nleds * sizeof(ev[0]));
|
|
|
|
|
if (rc > 0) {
|
2013-08-09 17:38:51 +02:00
|
|
|
nleds--; /* last is EV_SYN */
|
2013-08-09 13:21:28 +10:00
|
|
|
while (nleds--)
|
|
|
|
|
update_led_state(dev, &ev[nleds]);
|
|
|
|
|
}
|
|
|
|
|
rc = (rc != -1) ? 0 : -errno;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
2013-09-12 13:42:24 +10:00
|
|
|
|
|
|
|
|
LIBEVDEV_EXPORT int
|
|
|
|
|
libevdev_set_clock_id(struct libevdev *dev, int clockid)
|
|
|
|
|
{
|
2013-10-08 15:16:32 +10:00
|
|
|
if (!dev->initialized) {
|
2014-05-14 16:36:49 +10:00
|
|
|
log_bug(dev, "device not initialized. call libevdev_set_fd() first\n");
|
2013-09-12 13:42:24 +10:00
|
|
|
return -EBADF;
|
2020-05-26 14:10:31 +10:00
|
|
|
}
|
2013-09-12 13:42:24 +10:00
|
|
|
|
2020-08-27 00:42:20 -07:00
|
|
|
if (dev->fd < 0)
|
|
|
|
|
return -EBADF;
|
|
|
|
|
|
2013-09-12 13:42:24 +10:00
|
|
|
return ioctl(dev->fd, EVIOCSCLOCKID, &clockid) ? -errno : 0;
|
|
|
|
|
}
|