#include <string.h>
#include <unistd.h>
#include <stdarg.h>
-#include <linux/uinput.h>
+#include <stdbool.h>
#include "libevdev.h"
#include "libevdev-int.h"
}
static void
-_libevdev_log(struct libevdev *dev, const char *format, ...)
+libevdev_dflt_log_func(enum libevdev_log_priority priority,
+ void *data,
+ const char *file, int line, const char *func,
+ const char *format, va_list args)
+{
+ 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:
+ prefix = "libevdev INVALID LOG PRIORITY";
+ 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);
+}
+
+/*
+ * Global logging settings.
+ */
+struct logdata log_data = {
+ LIBEVDEV_LOG_INFO,
+ libevdev_dflt_log_func,
+ NULL,
+};
+
+void
+log_msg(enum libevdev_log_priority priority,
+ void *data,
+ const char *file, int line, const char *func,
+ const char *format, ...)
{
va_list args;
+ if (!log_data.handler)
+ return;
+
va_start(args, format);
- dev->log(format, args);
+ log_data.handler(priority, data, file, line, func, format, args);
va_end(args);
}
static void
-libevdev_noop_log_func(const char *format, va_list args)
+libevdev_reset(struct libevdev *dev)
{
+ memset(dev, 0, sizeof(*dev));
+ dev->fd = -1;
+ dev->initialized = false;
+ dev->num_slots = -1;
+ dev->current_slot = -1;
+ dev->grabbed = LIBEVDEV_UNGRAB;
+ dev->sync_state = SYNC_NONE;
+ libevdev_enable_event_type(dev, EV_SYN);
}
-struct libevdev*
+LIBEVDEV_EXPORT struct libevdev*
libevdev_new(void)
{
struct libevdev *dev;
- dev = calloc(1, sizeof(*dev));
+ dev = malloc(sizeof(*dev));
if (!dev)
return NULL;
- dev->fd = -1;
- dev->num_slots = -1;
- dev->current_slot = -1;
- dev->log = libevdev_noop_log_func;
- dev->grabbed = LIBEVDEV_UNGRAB;
- dev->sync_state = SYNC_NONE;
+
+ libevdev_reset(dev);
return dev;
}
-int
+LIBEVDEV_EXPORT int
libevdev_new_from_fd(int fd, struct libevdev **dev)
{
struct libevdev *d;
d = libevdev_new();
if (!d)
- return -ENOSPC;
+ return -ENOMEM;
rc = libevdev_set_fd(d, fd);
if (rc < 0)
return rc;
}
-void
+LIBEVDEV_EXPORT void
libevdev_free(struct libevdev *dev)
{
if (!dev)
free(dev);
}
-void
-libevdev_set_log_handler(struct libevdev *dev, libevdev_log_func_t logfunc)
+LIBEVDEV_EXPORT void
+libevdev_set_log_function(libevdev_log_func_t logfunc, void *data)
{
- if (dev == NULL)
- return;
+ log_data.handler = logfunc;
+ log_data.userdata = data;
+}
- dev->log = logfunc ? logfunc : libevdev_noop_log_func;
+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;
}
-int
+LIBEVDEV_EXPORT enum libevdev_log_priority
+libevdev_get_log_priority(void)
+{
+ return log_data.priority;
+}
+
+LIBEVDEV_EXPORT int
libevdev_change_fd(struct libevdev *dev, int fd)
{
- if (dev->fd == -1)
+ if (!dev->initialized) {
+ log_bug("device not initialized. call libevdev_set_fd() first\n");
return -1;
+ }
dev->fd = fd;
return 0;
}
-int
+LIBEVDEV_EXPORT int
libevdev_set_fd(struct libevdev* dev, int fd)
{
int rc;
int i;
char buf[256];
- if (dev->fd != -1)
+ if (dev->initialized) {
+ log_bug("device already initialized.\n");
+ return -EBADF;
+ } else if (fd < 0)
return -EBADF;
+ libevdev_reset(dev);
+
rc = ioctl(fd, EVIOCGBIT(0, sizeof(dev->bits)), dev->bits);
if (rc < 0)
goto out;
free(dev->name);
dev->name = strdup(buf);
if (!dev->name) {
- errno = ENOSPC;
+ errno = ENOMEM;
goto out;
}
} else {
dev->phys = strdup(buf);
if (!dev->phys) {
- errno = ENOSPC;
+ errno = ENOMEM;
goto out;
}
}
} else {
dev->uniq = strdup(buf);
if (!dev->uniq) {
- errno = ENOSPC;
+ errno = ENOMEM;
goto out;
}
}
if (rc < 0)
goto out;
+ /* 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.
+ */
rc = ioctl(fd, EVIOCGPROP(sizeof(dev->props)), dev->props);
- if (rc < 0)
+ if (rc < 0 && errno != EINVAL)
goto out;
rc = ioctl(fd, EVIOCGBIT(EV_REL, sizeof(dev->rel_bits)), dev->rel_bits);
if (rc < 0)
goto out;
+ rc = ioctl(fd, EVIOCGLED(sizeof(dev->led_values)), dev->led_values);
+ if (rc < 0)
+ goto out;
+
+ rc = ioctl(fd, EVIOCGSW(sizeof(dev->sw_values)), dev->sw_values);
+ if (rc < 0)
+ goto out;
+
/* 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)) {
for (i = 0; i < REP_CNT; i++)
* Same with the valuators, really, but they may not change.
*/
+ dev->initialized = true;
out:
+ if (rc)
+ libevdev_reset(dev);
return rc ? -errno : 0;
}
-int
+LIBEVDEV_EXPORT int
libevdev_get_fd(const struct libevdev* dev)
{
return dev->fd;
{
int rc;
int i;
- unsigned long keystate[NLONGS(KEY_MAX)];
+ unsigned long keystate[NLONGS(KEY_CNT)] = {0};
rc = ioctl(dev->fd, EVIOCGKEY(sizeof(keystate)), keystate);
if (rc < 0)
goto out;
- for (i = 0; i < KEY_MAX; i++) {
+ for (i = 0; i < KEY_CNT; i++) {
int old, new;
old = bit_is_set(dev->key_values, i);
new = bit_is_set(keystate, i);
struct input_event *ev = queue_push(dev);
init_event(dev, ev, EV_KEY, i, new ? 1 : 0);
}
- set_bit_state(dev->key_values, i, new);
}
+ memcpy(dev->key_values, keystate, rc);
+
rc = 0;
out:
return rc ? -errno : 0;
}
static int
+sync_sw_state(struct libevdev *dev)
+{
+ int rc;
+ int i;
+ unsigned long swstate[NLONGS(SW_CNT)] = {0};
+
+ 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);
+ if (old ^ new) {
+ struct input_event *ev = queue_push(dev);
+ init_event(dev, ev, EV_SW, i, new ? 1 : 0);
+ }
+ }
+
+ memcpy(dev->sw_values, swstate, rc);
+
+ rc = 0;
+out:
+ return rc ? -errno : 0;
+}
+
+static int
+sync_led_state(struct libevdev *dev)
+{
+ int rc;
+ int i;
+ unsigned long ledstate[NLONGS(LED_CNT)] = {0};
+
+ rc = ioctl(dev->fd, EVIOCGLED(sizeof(ledstate)), ledstate);
+ if (rc < 0)
+ goto out;
+
+ for (i = 0; i < LED_CNT; 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);
+ }
+ }
+
+ memcpy(dev->led_values, ledstate, rc);
+
+ rc = 0;
+out:
+ return rc ? -errno : 0;
+}
+static int
sync_abs_state(struct libevdev *dev)
{
int rc;
int i;
- for (i = ABS_X; i <= ABS_MAX; i++) {
+ for (i = ABS_X; i < ABS_CNT; i++) {
struct input_absinfo abs_info;
if (i >= ABS_MT_MIN && i <= ABS_MT_MAX)
{
int rc;
int i;
+ int ioctl_success = 0;
struct mt_state {
int code;
int val[MAX_SLOTS];
} mt_state[ABS_MT_CNT];
- for (i = ABS_MT_MIN; i < ABS_MT_MAX; i++) {
+ memset(&mt_state, 0, sizeof(mt_state));
+
+ for (i = ABS_MT_MIN; i <= ABS_MT_MAX; i++) {
int idx;
if (i == ABS_MT_SLOT)
continue;
idx = i - ABS_MT_MIN;
mt_state[idx].code = i;
rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(struct mt_state)), &mt_state[idx]);
- if (rc < 0)
- goto out;
+ if (rc < 0) {
+ /* if the first ioctl fails with -EINVAL, chances are the kernel
+ doesn't support the ioctl. Simply continue */
+ if (errno == -EINVAL && !ioctl_success) {
+ rc = 0;
+ } else /* if the second, ... ioctl fails, really fail */
+ goto out;
+ } else if (ioctl_success == 0)
+ ioctl_success = 1;
}
for (i = 0; i < dev->num_slots; i++) {
init_event(dev, ev, EV_ABS, ABS_MT_SLOT, i);
}
- for (j = ABS_MT_MIN; j < ABS_MT_MAX; j++) {
+ for (j = ABS_MT_MIN; j <= ABS_MT_MAX; j++) {
int jdx = j - ABS_MT_MIN;
if (j == ABS_MT_SLOT)
*/
for (i = queue_num_elements(dev) - 1; i >= 0; i--) {
- struct input_event e;
+ struct input_event e = {{0,0}, 0, 0, 0};
queue_peek(dev, i, &e);
if (e.type == EV_SYN)
break;
if (libevdev_has_event_type(dev, EV_KEY))
rc = sync_key_state(dev);
+ if (libevdev_has_event_type(dev, EV_LED))
+ rc = sync_led_state(dev);
+ if (libevdev_has_event_type(dev, EV_SW))
+ rc = sync_sw_state(dev);
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))
update_mt_state(struct libevdev *dev, const struct input_event *e)
{
if (e->code == ABS_MT_SLOT) {
+ int i;
dev->current_slot = e->value;
+ /* 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))
+ dev->abs_info[i].value = dev->mt_slot_vals[dev->current_slot][i - ABS_MT_MIN];
+ }
+
return 0;
} else if (dev->current_slot == -1)
return 1;
return 1;
if (e->code >= ABS_MT_MIN && e->code <= ABS_MT_MAX)
- return update_mt_state(dev, e);
+ update_mt_state(dev, e);
dev->abs_info[e->code].value = e->value;
}
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;
+}
+
+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;
+}
+
+static int
update_state(struct libevdev *dev, const struct input_event *e)
{
int rc = 0;
case EV_ABS:
rc = update_abs_state(dev, e);
break;
+ case EV_LED:
+ rc = update_led_state(dev, e);
+ break;
+ case EV_SW:
+ rc = update_sw_state(dev, e);
+ break;
}
dev->last_event_time = e->time;
return 0;
}
-int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev)
+LIBEVDEV_EXPORT int
+libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev)
{
- int rc = 0;
+ int rc = LIBEVDEV_READ_STATUS_SUCCESS;
- if (dev->fd < 0)
- return -ENODEV;
+ if (!dev->initialized) {
+ log_bug("device not initialized. call libevdev_set_fd() first\n");
+ return -EBADF;
+ } else if (dev->fd < 0)
+ return -EBADF;
- if (!(flags & (LIBEVDEV_READ_NORMAL|LIBEVDEV_READ_SYNC|LIBEVDEV_FORCE_SYNC)))
+ if (!(flags & (LIBEVDEV_READ_FLAG_NORMAL|LIBEVDEV_READ_FLAG_SYNC|LIBEVDEV_READ_FLAG_FORCE_SYNC))) {
+ log_bug("invalid flags %#x\n.\n", flags);
return -EINVAL;
+ }
- if (flags & LIBEVDEV_READ_SYNC) {
+ if (flags & LIBEVDEV_READ_FLAG_SYNC) {
if (dev->sync_state == SYNC_NEEDED) {
rc = sync_state(dev);
if (rc != 0)
read in any more.
*/
do {
- if (!(flags & LIBEVDEV_READ_BLOCKING) ||
+ if (!(flags & LIBEVDEV_READ_FLAG_BLOCKING) ||
queue_num_elements(dev) == 0) {
rc = read_more_events(dev);
if (rc < 0 && rc != -EAGAIN)
goto out;
}
- if (flags & LIBEVDEV_FORCE_SYNC) {
+ if (flags & LIBEVDEV_READ_FLAG_FORCE_SYNC) {
dev->sync_state = SYNC_NEEDED;
- rc = 1;
+ rc = LIBEVDEV_READ_STATUS_SYNC;
goto out;
}
rc = 0;
if (ev->type == EV_SYN && ev->code == SYN_DROPPED) {
dev->sync_state = SYNC_NEEDED;
- rc = 1;
+ rc = LIBEVDEV_READ_STATUS_SYNC;
}
- if (flags & LIBEVDEV_READ_SYNC && dev->queue_nsync > 0) {
+ if (flags & LIBEVDEV_READ_FLAG_SYNC && dev->queue_nsync > 0) {
dev->queue_nsync--;
- rc = 1;
+ rc = LIBEVDEV_READ_STATUS_SYNC;
if (dev->queue_nsync == 0)
dev->sync_state = SYNC_NONE;
}
return rc;
}
-int libevdev_has_event_pending(struct libevdev *dev)
+LIBEVDEV_EXPORT int
+libevdev_has_event_pending(struct libevdev *dev)
{
struct pollfd fds = { dev->fd, POLLIN, 0 };
int rc;
- if (dev->fd < 0)
+ if (!dev->initialized) {
+ log_bug("device not initialized. call libevdev_set_fd() first\n");
+ return -EBADF;
+ } else if (dev->fd < 0)
return -EBADF;
if (queue_num_elements(dev) != 0)
return (rc >= 0) ? rc : -errno;
}
-const char *
+LIBEVDEV_EXPORT const char *
libevdev_get_name(const struct libevdev *dev)
{
return dev->name ? dev->name : "";
}
-const char *
+LIBEVDEV_EXPORT const char *
libevdev_get_phys(const struct libevdev *dev)
{
return dev->phys;
}
-const char *
+LIBEVDEV_EXPORT const char *
libevdev_get_uniq(const struct libevdev *dev)
{
return dev->uniq;
}
#define STRING_SETTER(field) \
-void libevdev_set_##field(struct libevdev *dev, const char *field) \
+LIBEVDEV_EXPORT void libevdev_set_##field(struct libevdev *dev, const char *field) \
{ \
if (field == NULL) \
return; \
dev->field = strdup(field); \
}
-STRING_SETTER(name);
-STRING_SETTER(phys);
-STRING_SETTER(uniq);
+STRING_SETTER(name)
+STRING_SETTER(phys)
+STRING_SETTER(uniq)
-#define PRODUCT_GETTER(name, field) \
-int libevdev_get_##name(const struct libevdev *dev) \
+#define PRODUCT_GETTER(name) \
+LIBEVDEV_EXPORT int libevdev_get_id_##name(const struct libevdev *dev) \
{ \
- return dev->ids.field; \
+ return dev->ids.name; \
}
-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);
+PRODUCT_GETTER(product)
+PRODUCT_GETTER(vendor)
+PRODUCT_GETTER(bustype)
+PRODUCT_GETTER(version)
#define PRODUCT_SETTER(field) \
-void libevdev_set_id_##field(struct libevdev *dev, int field) \
+LIBEVDEV_EXPORT 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);
+PRODUCT_SETTER(product)
+PRODUCT_SETTER(vendor)
+PRODUCT_SETTER(bustype)
+PRODUCT_SETTER(version)
-int libevdev_get_driver_version(const struct libevdev *dev)
+LIBEVDEV_EXPORT int
+libevdev_get_driver_version(const struct libevdev *dev)
{
return dev->driver_version;
}
-int
+LIBEVDEV_EXPORT int
libevdev_has_property(const struct libevdev *dev, unsigned int prop)
{
return (prop <= INPUT_PROP_MAX) && bit_is_set(dev->props, prop);
}
-int
+LIBEVDEV_EXPORT int
libevdev_enable_property(struct libevdev *dev, unsigned int prop)
{
if (prop > INPUT_PROP_MAX)
return 0;
}
-int
+LIBEVDEV_EXPORT int
libevdev_has_event_type(const struct libevdev *dev, unsigned int type)
{
- return (type <= EV_MAX) && bit_is_set(dev->bits, type);
+ return type == EV_SYN ||(type <= EV_MAX && bit_is_set(dev->bits, type));
}
-int
+LIBEVDEV_EXPORT int
libevdev_has_event_code(const struct libevdev *dev, unsigned int type, unsigned int code)
{
const unsigned long *mask;
max = type_to_mask_const(dev, type, &mask);
- if (max == -1 || code > max)
+ if (max == -1 || code > (unsigned int)max)
return 0;
return bit_is_set(mask, code);
}
-int
+LIBEVDEV_EXPORT int
libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned int code)
{
int value;
switch (type) {
case EV_ABS: value = dev->abs_info[code].value; break;
case EV_KEY: value = bit_is_set(dev->key_values, code); break;
+ case EV_LED: value = bit_is_set(dev->led_values, code); break;
+ case EV_SW: value = bit_is_set(dev->sw_values, code); break;
+ 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;
default:
value = 0;
break;
return value;
}
-int
+LIBEVDEV_EXPORT 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;
+ case EV_LED: rc = update_led_state(dev, &e); break;
+ case EV_SW: rc = update_sw_state(dev, &e); break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+LIBEVDEV_EXPORT int
libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, unsigned int code, int *value)
{
if (libevdev_has_event_type(dev, type) &&
return 0;
}
-int
+LIBEVDEV_EXPORT 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)
+ if (dev->num_slots < 0 || slot >= (unsigned int)dev->num_slots || slot >= MAX_SLOTS)
return 0;
if (code > ABS_MT_MAX || code < ABS_MT_MIN)
return dev->mt_slot_vals[slot][code - ABS_MT_MIN];
}
-int
+LIBEVDEV_EXPORT 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 (dev->num_slots == -1 || slot >= (unsigned int)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;
+}
+
+LIBEVDEV_EXPORT 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) {
+ dev->num_slots >= 0 &&
+ slot < (unsigned int)dev->num_slots && slot < MAX_SLOTS) {
*value = libevdev_get_slot_value(dev, slot, code);
return 1;
} else
return 0;
}
-int
+LIBEVDEV_EXPORT int
libevdev_get_num_slots(const struct libevdev *dev)
{
return dev->num_slots;
}
-int
+LIBEVDEV_EXPORT int
libevdev_get_current_slot(const struct libevdev *dev)
{
return dev->current_slot;
}
-const struct input_absinfo*
+LIBEVDEV_EXPORT const struct input_absinfo*
libevdev_get_abs_info(const struct libevdev *dev, unsigned int code)
{
if (!libevdev_has_event_type(dev, EV_ABS) ||
return &dev->abs_info[code];
}
-#define ABS_GETTER(name, field) \
-int libevdev_get_abs_##name(const struct libevdev *dev, unsigned int code) \
+#define ABS_GETTER(name) \
+LIBEVDEV_EXPORT 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; \
+ return absinfo ? absinfo->name : 0; \
}
-ABS_GETTER(max, maximum); /* DEPRECATED */
-ABS_GETTER(min, minimum); /* DEPRECATED */
-ABS_GETTER(maximum, maximum);
-ABS_GETTER(minimum, minimum);
-ABS_GETTER(fuzz, fuzz)
-ABS_GETTER(flat, flat)
-ABS_GETTER(resolution, resolution)
+ABS_GETTER(maximum)
+ABS_GETTER(minimum)
+ABS_GETTER(fuzz)
+ABS_GETTER(flat)
+ABS_GETTER(resolution)
#define ABS_SETTER(field) \
-void libevdev_set_abs_##field(struct libevdev *dev, unsigned int code, int val) \
+LIBEVDEV_EXPORT void libevdev_set_abs_##field(struct libevdev *dev, unsigned int code, int val) \
{ \
if (!libevdev_has_event_code(dev, EV_ABS, code)) \
return; \
ABS_SETTER(flat)
ABS_SETTER(resolution)
-void libevdev_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
+LIBEVDEV_EXPORT 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;
}
-int
+LIBEVDEV_EXPORT int
libevdev_enable_event_type(struct libevdev *dev, unsigned int type)
{
+ int max;
+
if (type > EV_MAX)
return -1;
if (libevdev_has_event_type(dev, type))
return 0;
+ max = libevdev_event_type_get_max(type);
+ if (max == -1)
+ return -1;
+
set_bit(dev->bits, type);
if (type == EV_REP) {
return 0;
}
-int
+LIBEVDEV_EXPORT int
libevdev_disable_event_type(struct libevdev *dev, unsigned int type)
{
+ int max;
+
if (type > EV_MAX || type == EV_SYN)
return -1;
+ max = libevdev_event_type_get_max(type);
+ if (max == -1)
+ return -1;
+
clear_bit(dev->bits, type);
return 0;
}
-int
+LIBEVDEV_EXPORT int
libevdev_enable_event_code(struct libevdev *dev, unsigned int type,
unsigned int code, const void *data)
{
unsigned int max;
- unsigned long *mask;
+ unsigned long *mask = NULL;
if (libevdev_enable_event_type(dev, type))
return -1;
max = type_to_mask(dev, type, &mask);
- if (code > max)
+ if (code > max || (int)max == -1)
return -1;
set_bit(mask, code);
return 0;
}
-int
+LIBEVDEV_EXPORT int
libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned int code)
{
unsigned int max;
- unsigned long *mask;
+ unsigned long *mask = NULL;
- if (type > EV_MAX)
+ if (type > EV_MAX || type == EV_SYN)
return -1;
max = type_to_mask(dev, type, &mask);
- if (code > max)
+ if (code > max || (int)max == -1)
return -1;
clear_bit(mask, code);
return 0;
}
-/* DEPRECATED */
-int
-libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
-{
- return libevdev_kernel_set_abs_info(dev, code, abs);
-}
-
-int
+LIBEVDEV_EXPORT int
libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
{
int rc;
+ if (!dev->initialized) {
+ log_bug("device not initialized. call libevdev_set_fd() first\n");
+ return -EBADF;
+ } else if (dev->fd < 0)
+ return -EBADF;
+
if (code > ABS_MAX)
return -EINVAL;
return rc;
}
-int
-libevdev_grab(struct libevdev *dev, int grab)
+LIBEVDEV_EXPORT int
+libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab)
{
int rc = 0;
- if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB)
+ if (!dev->initialized) {
+ log_bug("device not initialized. call libevdev_set_fd() first\n");
+ return -EBADF;
+ } else if (dev->fd < 0)
+ return -EBADF;
+
+ if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB) {
+ log_bug("invalid grab parameter %#x\n", grab);
return -EINVAL;
+ }
if (grab == dev->grabbed)
return 0;
return rc < 0 ? -errno : 0;
}
-int
-libevdev_is_event_type(const struct input_event *ev, unsigned int type)
+LIBEVDEV_EXPORT int
+libevdev_event_is_type(const struct input_event *ev, unsigned int type)
{
- return type < EV_MAX && ev->type == type;
+ return type < EV_CNT && ev->type == type;
}
-int
-libevdev_is_event_code(const struct input_event *ev, unsigned int type, unsigned int code)
+LIBEVDEV_EXPORT int
+libevdev_event_is_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;
+ int max;
+
+ if (!libevdev_event_is_type(ev, type))
+ return 0;
+
+ max = libevdev_event_type_get_max(type);
+ return (max > -1 && code <= (unsigned int)max && ev->code == code);
}
-const char*
-libevdev_get_event_type_name(unsigned int type)
+LIBEVDEV_EXPORT const char*
+libevdev_event_type_get_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)
+LIBEVDEV_EXPORT const char*
+libevdev_event_code_get_name(unsigned int type, unsigned int code)
{
- if (type > EV_MAX)
- return NULL;
+ int max = libevdev_event_type_get_max(type);
- if (code > ev_max[type])
+ if (max == -1 || code > (unsigned int)max)
return NULL;
return event_type_map[type][code];
}
-/* DEPRECATED */
-const char*
-libevdev_get_input_prop_name(unsigned int prop)
-{
- return libevdev_get_property_name(prop);
-}
-
-const char*
-libevdev_get_property_name(unsigned int prop)
+LIBEVDEV_EXPORT const char*
+libevdev_property_get_name(unsigned int prop)
{
if (prop > INPUT_PROP_MAX)
return NULL;
return input_prop_map[prop];
}
-int
-libevdev_get_event_type_max(unsigned int type)
+LIBEVDEV_EXPORT int
+libevdev_event_type_get_max(unsigned int type)
{
if (type > EV_MAX)
return -1;
return ev_max[type];
}
-int
-libevdev_get_repeat(struct libevdev *dev, int *delay, int *period)
+LIBEVDEV_EXPORT int
+libevdev_get_repeat(const struct libevdev *dev, int *delay, int *period)
{
if (!libevdev_has_event_type(dev, EV_REP))
return -1;
return 0;
}
+
+LIBEVDEV_EXPORT int
+libevdev_kernel_set_led_value(struct libevdev *dev, unsigned int code, enum libevdev_led_value value)
+{
+ return libevdev_kernel_set_led_values(dev, code, value, -1);
+}
+
+LIBEVDEV_EXPORT int
+libevdev_kernel_set_led_values(struct libevdev *dev, ...)
+{
+ struct input_event ev[LED_MAX + 1];
+ enum libevdev_led_value val;
+ va_list args;
+ int code;
+ int rc = 0;
+ size_t nleds = 0;
+
+ if (!dev->initialized) {
+ log_bug("device not initialized. call libevdev_set_fd() first\n");
+ return -EBADF;
+ } else if (dev->fd < 0)
+ return -EBADF;
+
+ 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;
+ }
+ val = va_arg(args, enum libevdev_led_value);
+ 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) {
+ ev[nleds].type = EV_SYN;
+ ev[nleds++].code = SYN_REPORT;
+
+ rc = write(libevdev_get_fd(dev), ev, nleds * sizeof(ev[0]));
+ if (rc > 0) {
+ nleds--; /* last is EV_SYN */
+ while (nleds--)
+ update_led_state(dev, &ev[nleds]);
+ }
+ rc = (rc != -1) ? 0 : -errno;
+ }
+
+ return rc;
+}
+
+LIBEVDEV_EXPORT int
+libevdev_set_clock_id(struct libevdev *dev, int clockid)
+{
+ if (!dev->initialized) {
+ log_bug("device not initialized. call libevdev_set_fd() first\n");
+ return -EBADF;
+ } else if (dev->fd < 0)
+ return -EBADF;
+
+ return ioctl(dev->fd, EVIOCSCLOCKID, &clockid) ? -errno : 0;
+}