diff --git a/libevdev/libevdev-int.h b/libevdev/libevdev-int.h index a36be62..28933ef 100644 --- a/libevdev/libevdev-int.h +++ b/libevdev/libevdev-int.h @@ -89,6 +89,7 @@ struct libevdev { unsigned long ff_bits[NLONGS(FF_CNT)]; unsigned long snd_bits[NLONGS(SND_CNT)]; unsigned long key_values[NLONGS(KEY_CNT)]; + unsigned long led_values[NLONGS(LED_CNT)]; struct input_absinfo abs_info[ABS_CNT]; unsigned int mt_slot_vals[MAX_SLOTS][ABS_MT_CNT]; int num_slots; /**< valid slots in mt_slot_vals */ diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c index 0d315ec..8151026 100644 --- a/libevdev/libevdev.c +++ b/libevdev/libevdev.c @@ -232,6 +232,14 @@ libevdev_set_fd(struct libevdev* dev, int fd) if (rc < 0) goto out; + rc = ioctl(fd, EVIOCGKEY(sizeof(dev->key_values)), dev->key_values); + if (rc < 0) + goto out; + + rc = ioctl(fd, EVIOCGLED(sizeof(dev->led_values)), dev->led_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++) @@ -317,6 +325,32 @@ out: return rc ? -errno : 0; } +static int +sync_led_state(struct libevdev *dev) +{ + int rc; + int i; + unsigned long ledstate[NLONGS(LED_MAX)]; + + rc = ioctl(dev->fd, EVIOCGLED(sizeof(ledstate)), ledstate); + if (rc < 0) + goto out; + + for (i = 0; i < LED_MAX; i++) { + int old, new; + old = bit_is_set(dev->led_values, i); + new = bit_is_set(ledstate, i); + if (old ^ new) { + struct input_event *ev = queue_push(dev); + init_event(dev, ev, EV_LED, i, new ? 1 : 0); + } + set_bit_state(dev->led_values, i, new); + } + + rc = 0; +out: + return rc ? -errno : 0; +} static int sync_abs_state(struct libevdev *dev) { @@ -437,6 +471,8 @@ sync_state(struct libevdev *dev) 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 (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)) @@ -471,7 +507,14 @@ static int 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; @@ -491,13 +534,27 @@ update_abs_state(struct libevdev *dev, const struct input_event *e) 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; return 0; } +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_state(struct libevdev *dev, const struct input_event *e) { @@ -513,6 +570,9 @@ update_state(struct libevdev *dev, const struct input_event *e) case EV_ABS: rc = update_abs_state(dev, e); break; + case EV_LED: + rc = update_led_state(dev, e); + break; } dev->last_event_time = e->time; @@ -761,6 +821,7 @@ libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned 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; default: value = 0; break; @@ -769,6 +830,30 @@ libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned return value; } +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; + default: + rc = -1; + break; + } + + return rc; +} + int libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, unsigned int code, int *value) { @@ -795,6 +880,30 @@ libevdev_get_slot_value(const struct libevdev *dev, unsigned int slot, unsigned return dev->mt_slot_vals[slot][code - ABS_MT_MIN]; } +int +libevdev_set_slot_value(struct libevdev *dev, unsigned int slot, unsigned int code, int value) +{ + if (!libevdev_has_event_type(dev, EV_ABS) || !libevdev_has_event_code(dev, EV_ABS, code)) + return -1; + + if (slot >= dev->num_slots || slot >= MAX_SLOTS) + return -1; + + if (code > ABS_MT_MAX || code < ABS_MT_MIN) + return -1; + + if (code == ABS_MT_SLOT) { + if (value < 0 || value >= libevdev_get_num_slots(dev)) + return -1; + dev->current_slot = value; + } + + dev->mt_slot_vals[slot][code - ABS_MT_MIN] = value; + + + return 0; +} + int libevdev_fetch_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code, int *value) { @@ -957,8 +1066,15 @@ libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned in 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_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs) { int rc; @@ -975,7 +1091,7 @@ libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const str } int -libevdev_grab(struct libevdev *dev, int grab) +libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab) { int rc = 0; @@ -1070,3 +1186,66 @@ libevdev_get_repeat(struct libevdev *dev, int *delay, int *period) return 0; } + +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); +} + +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; + + 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; +} diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h index bd65175..6113f41 100644 --- a/libevdev/libevdev.h +++ b/libevdev/libevdev.h @@ -284,7 +284,7 @@ */ struct libevdev; -enum EvdevReadFlags { +enum libevdev_read_flag { LIBEVDEV_READ_SYNC = 1, /**< Process data in sync mode */ LIBEVDEV_READ_NORMAL = 2, /**< Process data in normal mode */ LIBEVDEV_FORCE_SYNC = 4, /**< Pretend the next event is a SYN_DROPPED. There is @@ -369,7 +369,7 @@ typedef void (*libevdev_log_func_t)(const char *format, va_list args); void libevdev_set_log_handler(struct libevdev *dev, libevdev_log_func_t logfunc); -enum EvdevGrabModes { +enum libevdev_grab_mode { LIBEVDEV_GRAB = 3, LIBEVDEV_UNGRAB = 4, }; @@ -390,7 +390,7 @@ enum EvdevGrabModes { * @return 0 if the device was successfull grabbed or ungrabbed, or a * negative errno in case of failure. */ -int libevdev_grab(struct libevdev *dev, int grab); +int libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab); /** * @ingroup init @@ -799,6 +799,10 @@ const struct input_absinfo* libevdev_get_abs_info(const struct libevdev *dev, un * Behaviour of this function is undefined if the device does not provide * the event. * + * If the device supports ABS_MT_SLOT, the value returned for any ABS_MT_* + * event code is the value of the currently active slot. You should use + * libevdev_get_slot_value() instead. + * * @param dev The evdev device, already initialized with libevdev_set_fd() * @param type The event type for the code to query (EV_SYN, EV_REL, etc.) * @param code The event code to query for, one of ABS_X, REL_X, etc. @@ -813,6 +817,34 @@ const struct input_absinfo* libevdev_get_abs_info(const struct libevdev *dev, un */ int libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned int code); +/** + * @ingroup kernel + * + * Set the value for a given event type and code. This only makes sense for + * some event types, e.g. setting the value for EV_REL is pointless. + * + * This is a local modification only affecting only this representation of + * this device. A future call to libevdev_get_event_value() will return this + * value, unless the value was overwritten by an event. + * + * If the device supports ABS_MT_SLOT, the value set for any ABS_MT_* + * event code is the value of the currently active slot. You should use + * libevdev_set_slot_value() instead. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param type The event type for the code to query (EV_SYN, EV_REL, etc.) + * @param code The event code to set the value for, one of ABS_X, LED_NUML, etc. + * @param value The new value to set + * + * @return 0 on success, or -1 on failure. + * @retval -1 the device does not have the event type or code enabled, or the code is outside the + * allowed limits for the given type, or the type cannot be set. + * + * @see libevdev_set_slot_value + * @see libevdev_get_event_value + */ +int libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned int code, int value); + /** * @ingroup bits * @@ -862,6 +894,34 @@ int libevdev_fetch_event_value(const struct libevdev *dev, unsigned int type, un */ int libevdev_get_slot_value(const struct libevdev *dev, unsigned int slot, unsigned int code); +/** + * @ingroup kernel + * + * Set the value for a given code for the given slot. + * + * This is a local modification only affecting only this representation of + * this device. A future call to libevdev_get_slot_value() will return this + * value, unless the value was overwritten by an event. + * + * This function does not set event values for axes outside the ABS_MT range, + * use libevdev_set_event_value() instead. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param slot The numerical slot number, must be smaller than the total number + * of slots on this device + * @param code The event code to set the value for, one of ABS_MT_POSITION_X, etc. + * @param value The new value to set + * + * @return 0 on success, or -1 on failure. + * @retval -1 the device does not have the event code enabled, or the code is + * outside the allowed limits for multitouch events, or the slot number is outside + * the limits for this device, or the device does not support multitouch events. + * + * @see libevdev_set_event_value + * @see libevdev_get_slot_value + */ +int libevdev_set_slot_value(struct libevdev *dev, unsigned int slot, unsigned int code, int value); + /** * @ingroup mt * @@ -1092,7 +1152,53 @@ int libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigne * * @see libevdev_enable_event_code */ -int libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs); +int libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs); + + +enum libevdev_led_value { + LIBEVDEV_LED_ON = 3, + LIBEVDEV_LED_OFF = 4, +}; + +/** + * @ingroup kernel + * + * Turn an LED on or off. Convenience function, if you need to modify multiple + * LEDs simultaneously, use libevdev_kernel_set_led_values() instead. + * + * @note enabling an LED requires write permissions on the device's file descriptor. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param code The EV_LED event code to modify, one of LED_NUML, LED_CAPSL, ... + * @param value Specifies whether to turn the LED on or off + * @return zero on success, or a negative errno on failure + */ +int libevdev_kernel_set_led_value(struct libevdev *dev, unsigned int code, enum libevdev_led_value value); + +/** + * @ingroup kernel + * + * Turn multiple LEDs on or off simultaneously. This function expects a pair + * of LED codes and values to set them to, terminated by a -1. For example, to + * switch the NumLock LED on but the CapsLock LED off, use: + * + * @code + * libevdev_kernel_set_led_values(dev, LED_NUML, LIBEVDEV_LED_ON, + * LED_CAPSL, LIBEVDEV_LED_OFF, + * -1); + * @endcode + * + * If any LED code or value is invalid, this function returns -EINVAL and no + * LEDs are modified. + * + * @note enabling an LED requires write permissions on the device's file descriptor. + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @param ... A pair of LED_* event codes and libevdev_led_value_t, followed by + * -1 to terminate the list. + * @return zero on success, or a negative errno on failure + */ +int libevdev_kernel_set_led_values(struct libevdev *dev, ...); /** * @ingroup misc @@ -1227,5 +1333,9 @@ int libevdev_get_vendor_id(const struct libevdev *dev) LIBEVDEV_DEPRECATED; int libevdev_get_bustype(const struct libevdev *dev) LIBEVDEV_DEPRECATED; int libevdev_get_version(const struct libevdev *dev) LIBEVDEV_DEPRECATED; +/* replacement: libevdev_kernel_set_abs_info */ +int libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs) LIBEVDEV_DEPRECATED; + + /**************************************/ #endif /* LIBEVDEV_H */ diff --git a/test/test-libevdev-events.c b/test/test-libevdev-events.c index 40f94dd..669de12 100644 --- a/test/test-libevdev-events.c +++ b/test/test-libevdev-events.c @@ -453,6 +453,52 @@ START_TEST(test_syn_delta_mt) } END_TEST +START_TEST(test_syn_delta_led) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_event ev; + + rc = test_create_device(&uidev, &dev, + EV_SYN, SYN_REPORT, + EV_SYN, SYN_DROPPED, + EV_LED, LED_NUML, + EV_LED, LED_CAPSL, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + uinput_device_event(uidev, EV_LED, LED_NUML, 1); + uinput_device_event(uidev, EV_LED, LED_CAPSL, 1); + uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0); + rc = libevdev_next_event(dev, LIBEVDEV_FORCE_SYNC, &ev); + ck_assert_int_eq(rc, 1); + + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, 1); + ck_assert_int_eq(ev.type, EV_LED); + ck_assert_int_eq(ev.code, LED_NUML); + ck_assert_int_eq(ev.value, 1); + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, 1); + ck_assert_int_eq(ev.type, EV_LED); + ck_assert_int_eq(ev.code, LED_CAPSL); + ck_assert_int_eq(ev.value, 1); + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, 1); + ck_assert_int_eq(ev.type, EV_SYN); + ck_assert_int_eq(ev.code, SYN_REPORT); + rc = libevdev_next_event(dev, LIBEVDEV_READ_SYNC, &ev); + ck_assert_int_eq(rc, -EAGAIN); + + ck_assert_int_eq(libevdev_get_event_value(dev, EV_LED, LED_NUML), 1); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_LED, LED_CAPSL), 1); + + uinput_device_free(uidev); + libevdev_free(dev); +} +END_TEST + START_TEST(test_skipped_sync) { struct uinput_device* uidev; @@ -806,6 +852,240 @@ START_TEST(test_mt_event_values_invalid) } END_TEST +START_TEST(test_event_value_setters) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_absinfo abs[2]; + + memset(abs, 0, sizeof(abs)); + abs[0].value = ABS_X; + abs[0].maximum = 1000; + + abs[1].value = ABS_Y; + abs[1].maximum = 1000; + + rc = test_create_abs_device(&uidev, &dev, + 2, abs, + EV_SYN, SYN_REPORT, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_MIDDLE, + EV_KEY, BTN_RIGHT, + EV_LED, LED_NUML, + EV_LED, LED_CAPSL, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + ck_assert_int_eq(libevdev_get_event_value(dev, EV_KEY, BTN_LEFT), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_X), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_Y), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_REL, REL_X), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_REL, REL_Y), 0); + + ck_assert_int_eq(libevdev_set_event_value(dev, EV_KEY, BTN_LEFT, 1), 0); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_KEY, BTN_RIGHT, 1), 0); + + ck_assert_int_eq(libevdev_get_event_value(dev, EV_KEY, BTN_LEFT), 1); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_KEY, BTN_RIGHT), 1); + + ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_X, 10), 0); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_Y, 20), 0); + + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_X), 10); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_Y), 20); + + ck_assert_int_eq(libevdev_set_event_value(dev, EV_LED, LED_NUML, 1), 0); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_LED, LED_CAPSL, 1), 0); + + ck_assert_int_eq(libevdev_get_event_value(dev, EV_LED, LED_NUML), 1); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_LED, LED_CAPSL), 1); + + uinput_device_free(uidev); + libevdev_free(dev); + +} +END_TEST + +START_TEST(test_event_value_setters_invalid) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_absinfo abs[2]; + + memset(abs, 0, sizeof(abs)); + abs[0].value = ABS_X; + abs[0].maximum = 1000; + + abs[1].value = ABS_Y; + abs[1].maximum = 1000; + + rc = test_create_abs_device(&uidev, &dev, + 2, abs, + EV_SYN, SYN_REPORT, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_MIDDLE, + EV_KEY, BTN_RIGHT, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + ck_assert_int_eq(libevdev_set_event_value(dev, EV_REL, REL_X, 1), -1); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_SW, SW_DOCK, 1), -1); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_Z, 1), -1); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_MAX + 1, 0, 1), -1); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_SYN, SYN_REPORT, 0), -1); + + uinput_device_free(uidev); + libevdev_free(dev); + +} +END_TEST + +START_TEST(test_event_mt_value_setters) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_absinfo abs[5]; + + memset(abs, 0, sizeof(abs)); + abs[0].value = ABS_X; + abs[0].maximum = 1000; + abs[1].value = ABS_MT_POSITION_X; + abs[1].maximum = 1000; + + abs[2].value = ABS_Y; + abs[2].maximum = 1000; + abs[3].value = ABS_MT_POSITION_Y; + abs[3].maximum = 1000; + + abs[4].value = ABS_MT_SLOT; + abs[4].maximum = 2; + + rc = test_create_abs_device(&uidev, &dev, + 5, abs, + EV_SYN, SYN_REPORT, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + ck_assert_int_eq(libevdev_set_slot_value(dev, 1, ABS_MT_POSITION_X, 1), 0); + ck_assert_int_eq(libevdev_set_slot_value(dev, 1, ABS_MT_POSITION_Y, 2), 0); + ck_assert_int_eq(libevdev_set_slot_value(dev, 0, ABS_MT_POSITION_X, 3), 0); + ck_assert_int_eq(libevdev_set_slot_value(dev, 0, ABS_MT_POSITION_Y, 4), 0); + + ck_assert_int_eq(libevdev_get_slot_value(dev, 1, ABS_MT_POSITION_X), 1); + ck_assert_int_eq(libevdev_get_slot_value(dev, 1, ABS_MT_POSITION_Y), 2); + ck_assert_int_eq(libevdev_get_slot_value(dev, 0, ABS_MT_POSITION_X), 3); + ck_assert_int_eq(libevdev_get_slot_value(dev, 0, ABS_MT_POSITION_Y), 4); + + ck_assert_int_eq(libevdev_set_slot_value(dev, 1, ABS_MT_SLOT, 1), 0); + ck_assert_int_eq(libevdev_get_slot_value(dev, 1, ABS_MT_SLOT), 1); + ck_assert_int_eq(libevdev_get_current_slot(dev), 1); + + uinput_device_free(uidev); + libevdev_free(dev); +} +END_TEST + +START_TEST(test_event_mt_value_setters_invalid) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_absinfo abs[5]; + + memset(abs, 0, sizeof(abs)); + abs[0].value = ABS_X; + abs[0].maximum = 1000; + abs[1].value = ABS_MT_POSITION_X; + abs[1].maximum = 1000; + + abs[2].value = ABS_Y; + abs[2].maximum = 1000; + abs[3].value = ABS_MT_POSITION_Y; + abs[3].maximum = 1000; + + abs[4].value = ABS_MT_SLOT; + abs[4].maximum = 2; + + rc = test_create_abs_device(&uidev, &dev, + 5, abs, + EV_SYN, SYN_REPORT, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + /* invalid axis */ + ck_assert_int_eq(libevdev_set_slot_value(dev, 1, ABS_Z, 1), -1); + /* valid, but non-mt axis */ + ck_assert_int_eq(libevdev_set_slot_value(dev, 1, ABS_X, 1), -1); + /* invalid mt axis */ + ck_assert_int_eq(libevdev_set_slot_value(dev, 1, ABS_MT_PRESSURE, 1), -1); + /* invalid slot no */ + ck_assert_int_eq(libevdev_set_slot_value(dev, 4, ABS_X, 1), -1); + + uinput_device_free(uidev); + libevdev_free(dev); +} +END_TEST + +START_TEST(test_event_mt_value_setters_current_slot) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_absinfo abs[5]; + + memset(abs, 0, sizeof(abs)); + abs[0].value = ABS_X; + abs[0].maximum = 1000; + abs[1].value = ABS_MT_POSITION_X; + abs[1].maximum = 1000; + + abs[2].value = ABS_Y; + abs[2].maximum = 1000; + abs[3].value = ABS_MT_POSITION_Y; + abs[3].maximum = 1000; + + abs[4].value = ABS_MT_SLOT; + abs[4].maximum = 2; + + rc = test_create_abs_device(&uidev, &dev, + 5, abs, + EV_SYN, SYN_REPORT, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + /* set_event_value/get_event_value works on the current slot */ + + ck_assert_int_eq(libevdev_get_current_slot(dev), 0); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_MT_POSITION_X, 1), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_MT_POSITION_X), 1); + ck_assert_int_eq(libevdev_get_slot_value(dev, 0, ABS_MT_POSITION_X), 1); + + ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_MT_SLOT, 1), 0); + ck_assert_int_eq(libevdev_get_current_slot(dev), 1); + ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_MT_POSITION_X, 2), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_MT_POSITION_X), 2); + ck_assert_int_eq(libevdev_get_slot_value(dev, 1, ABS_MT_POSITION_X), 2); + + /* set slot 0, but current is still slot 1 */ + ck_assert_int_eq(libevdev_set_slot_value(dev, 0, ABS_MT_POSITION_X, 3), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_MT_POSITION_X), 2); + + ck_assert_int_eq(libevdev_set_event_value(dev, EV_ABS, ABS_MT_SLOT, 0), 0); + ck_assert_int_eq(libevdev_get_current_slot(dev), 0); + ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_MT_POSITION_X), 3); + + uinput_device_free(uidev); + libevdev_free(dev); +} +END_TEST + Suite * libevdev_events(void) { @@ -823,6 +1103,7 @@ libevdev_events(void) tcase_add_test(tc, test_syn_delta_button); tcase_add_test(tc, test_syn_delta_abs); tcase_add_test(tc, test_syn_delta_mt); + tcase_add_test(tc, test_syn_delta_led); suite_add_tcase(s, tc); tc = tcase_create("skipped syncs"); @@ -838,6 +1119,14 @@ libevdev_events(void) tcase_add_test(tc, test_mt_event_values_invalid); suite_add_tcase(s, tc); + tc = tcase_create("event value setters"); + tcase_add_test(tc, test_event_value_setters); + tcase_add_test(tc, test_event_value_setters_invalid); + tcase_add_test(tc, test_event_mt_value_setters); + tcase_add_test(tc, test_event_mt_value_setters_invalid); + tcase_add_test(tc, test_event_mt_value_setters_current_slot); + suite_add_tcase(s, tc); + return s; } diff --git a/test/test-libevdev-has-event.c b/test/test-libevdev-has-event.c index 7ce616f..31a46ab 100644 --- a/test/test-libevdev-has-event.c +++ b/test/test-libevdev-has-event.c @@ -866,7 +866,7 @@ START_TEST(test_device_kernel_change_axis) abs.fuzz = 10; abs.flat = 20; abs.resolution = 30; - rc = libevdev_kernel_set_abs_value(dev, ABS_X, &abs); + rc = libevdev_kernel_set_abs_info(dev, ABS_X, &abs); ck_assert_int_eq(rc, 0); ck_assert_int_eq(libevdev_get_abs_minimum(dev, ABS_X), 500); @@ -915,7 +915,7 @@ START_TEST(test_device_kernel_change_axis_invalid) rc = libevdev_new_from_fd(uinput_device_get_fd(uidev), &dev); ck_assert_msg(rc == 0, "Failed to init device: %s", strerror(-rc));; - rc = libevdev_kernel_set_abs_value(dev, ABS_MAX + 1, &abs); + rc = libevdev_kernel_set_abs_info(dev, ABS_MAX + 1, &abs); ck_assert_int_eq(rc, -EINVAL); libevdev_free(dev); @@ -923,6 +923,153 @@ START_TEST(test_device_kernel_change_axis_invalid) } END_TEST +START_TEST(test_led_valid) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + + rc = test_create_device(&uidev, &dev, + EV_LED, LED_NUML, + EV_LED, LED_CAPSL, + EV_LED, LED_COMPOSE, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + rc = libevdev_kernel_set_led_value(dev, LED_NUML, LIBEVDEV_LED_ON); + ck_assert_int_eq(rc, 0); + rc = libevdev_kernel_set_led_value(dev, LED_NUML, LIBEVDEV_LED_OFF); + ck_assert_int_eq(rc, 0); + + rc = libevdev_kernel_set_led_values(dev, + LED_NUML, LIBEVDEV_LED_OFF, + LED_CAPSL, LIBEVDEV_LED_ON, + LED_COMPOSE, LIBEVDEV_LED_OFF, + -1); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_NUML)); + ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_CAPSL)); + ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE)); + + rc = libevdev_kernel_set_led_values(dev, + LED_NUML, LIBEVDEV_LED_ON, + LED_CAPSL, LIBEVDEV_LED_OFF, + LED_COMPOSE, LIBEVDEV_LED_ON, + -1); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_NUML)); + ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_CAPSL)); + ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE)); + + /* make sure we ignore unset leds */ + rc = libevdev_kernel_set_led_values(dev, + LED_NUML, LIBEVDEV_LED_ON, + LED_CAPSL, LIBEVDEV_LED_OFF, + LED_SCROLLL, LIBEVDEV_LED_OFF, + LED_COMPOSE, LIBEVDEV_LED_ON, + -1); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_NUML)); + ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_CAPSL)); + ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE)); + + libevdev_free(dev); + uinput_device_free(uidev); +} +END_TEST + +START_TEST(test_led_invalid) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + + rc = test_create_device(&uidev, &dev, + EV_LED, LED_NUML, + EV_LED, LED_CAPSL, + EV_LED, LED_COMPOSE, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + rc = libevdev_kernel_set_led_value(dev, LED_MAX + 1, LIBEVDEV_LED_ON); + ck_assert_int_eq(rc, -EINVAL); + + rc = libevdev_kernel_set_led_value(dev, LED_NUML, LIBEVDEV_LED_OFF + 1); + ck_assert_int_eq(rc, -EINVAL); + + rc = libevdev_kernel_set_led_value(dev, LED_SCROLLL, LIBEVDEV_LED_ON); + ck_assert_int_eq(rc, 0); + + rc = libevdev_kernel_set_led_values(dev, + LED_NUML, LIBEVDEV_LED_OFF + 1, + -1); + ck_assert_int_eq(rc, -EINVAL); + + rc = libevdev_kernel_set_led_values(dev, + LED_MAX + 1, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF + 1, + -1); + ck_assert_int_eq(rc, -EINVAL); + + rc = libevdev_kernel_set_led_values(dev, + LED_SCROLLL, LIBEVDEV_LED_OFF, + -1); + ck_assert_int_eq(rc, 0); + + libevdev_free(dev); + uinput_device_free(uidev); +} +END_TEST + +START_TEST(test_led_same) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + + rc = test_create_device(&uidev, &dev, + EV_LED, LED_NUML, + EV_LED, LED_CAPSL, + EV_LED, LED_COMPOSE, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + rc = libevdev_kernel_set_led_values(dev, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + LED_NUML, LIBEVDEV_LED_OFF, + LED_NUML, LIBEVDEV_LED_ON, + /* more than LED_CNT */ + -1); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(1, libevdev_get_event_value(dev, EV_LED, LED_NUML)); + ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_CAPSL)); + ck_assert_int_eq(0, libevdev_get_event_value(dev, EV_LED, LED_COMPOSE)); + + libevdev_free(dev); + uinput_device_free(uidev); +} +END_TEST Suite * libevdev_has_event_test(void) { @@ -971,6 +1118,12 @@ libevdev_has_event_test(void) tcase_add_test(tc, test_device_kernel_change_axis_invalid); suite_add_tcase(s, tc); + tc = tcase_create("led manipulation"); + tcase_add_test(tc, test_led_valid); + tcase_add_test(tc, test_led_invalid); + tcase_add_test(tc, test_led_same); + suite_add_tcase(s, tc); + return s; }