mirror of
https://gitlab.freedesktop.org/libevdev/libevdev.git
synced 2026-05-05 19:18:02 +02:00
Keep the LED state and sync it after SYN_DROPPED
This enables libevdev_get_event_value(dev, EV_LED, LED_NUML); to check if a LED is on or off. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
parent
74d9b4c72d
commit
bfb6c1c6c5
3 changed files with 107 additions and 0 deletions
|
|
@ -89,6 +89,7 @@ struct libevdev {
|
||||||
unsigned long ff_bits[NLONGS(FF_CNT)];
|
unsigned long ff_bits[NLONGS(FF_CNT)];
|
||||||
unsigned long snd_bits[NLONGS(SND_CNT)];
|
unsigned long snd_bits[NLONGS(SND_CNT)];
|
||||||
unsigned long key_values[NLONGS(KEY_CNT)];
|
unsigned long key_values[NLONGS(KEY_CNT)];
|
||||||
|
unsigned long led_values[NLONGS(LED_CNT)];
|
||||||
struct input_absinfo abs_info[ABS_CNT];
|
struct input_absinfo abs_info[ABS_CNT];
|
||||||
unsigned int mt_slot_vals[MAX_SLOTS][ABS_MT_CNT];
|
unsigned int mt_slot_vals[MAX_SLOTS][ABS_MT_CNT];
|
||||||
int num_slots; /**< valid slots in mt_slot_vals */
|
int num_slots; /**< valid slots in mt_slot_vals */
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,10 @@ libevdev_set_fd(struct libevdev* dev, int fd)
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto out;
|
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 */
|
/* 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)) {
|
if (bit_is_set(dev->bits, EV_REP)) {
|
||||||
for (i = 0; i < REP_CNT; i++)
|
for (i = 0; i < REP_CNT; i++)
|
||||||
|
|
@ -321,6 +325,32 @@ out:
|
||||||
return rc ? -errno : 0;
|
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
|
static int
|
||||||
sync_abs_state(struct libevdev *dev)
|
sync_abs_state(struct libevdev *dev)
|
||||||
{
|
{
|
||||||
|
|
@ -441,6 +471,8 @@ sync_state(struct libevdev *dev)
|
||||||
|
|
||||||
if (libevdev_has_event_type(dev, EV_KEY))
|
if (libevdev_has_event_type(dev, EV_KEY))
|
||||||
rc = sync_key_state(dev);
|
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))
|
if (rc == 0 && libevdev_has_event_type(dev, EV_ABS))
|
||||||
rc = sync_abs_state(dev);
|
rc = sync_abs_state(dev);
|
||||||
if (rc == 0 && libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT))
|
if (rc == 0 && libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT))
|
||||||
|
|
@ -502,6 +534,20 @@ update_abs_state(struct libevdev *dev, const struct input_event *e)
|
||||||
return 0;
|
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
|
static int
|
||||||
update_state(struct libevdev *dev, const struct input_event *e)
|
update_state(struct libevdev *dev, const struct input_event *e)
|
||||||
{
|
{
|
||||||
|
|
@ -517,6 +563,9 @@ update_state(struct libevdev *dev, const struct input_event *e)
|
||||||
case EV_ABS:
|
case EV_ABS:
|
||||||
rc = update_abs_state(dev, e);
|
rc = update_abs_state(dev, e);
|
||||||
break;
|
break;
|
||||||
|
case EV_LED:
|
||||||
|
rc = update_led_state(dev, e);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->last_event_time = e->time;
|
dev->last_event_time = e->time;
|
||||||
|
|
@ -765,6 +814,7 @@ libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EV_ABS: value = dev->abs_info[code].value; break;
|
case EV_ABS: value = dev->abs_info[code].value; break;
|
||||||
case EV_KEY: value = bit_is_set(dev->key_values, code); 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:
|
default:
|
||||||
value = 0;
|
value = 0;
|
||||||
break;
|
break;
|
||||||
|
|
@ -788,6 +838,7 @@ int libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned i
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case EV_ABS: rc = update_abs_state(dev, &e); break;
|
case EV_ABS: rc = update_abs_state(dev, &e); break;
|
||||||
case EV_KEY: rc = update_key_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:
|
default:
|
||||||
rc = -1;
|
rc = -1;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -453,6 +453,52 @@ START_TEST(test_syn_delta_mt)
|
||||||
}
|
}
|
||||||
END_TEST
|
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)
|
START_TEST(test_skipped_sync)
|
||||||
{
|
{
|
||||||
struct uinput_device* uidev;
|
struct uinput_device* uidev;
|
||||||
|
|
@ -828,6 +874,8 @@ START_TEST(test_event_value_setters)
|
||||||
EV_KEY, BTN_LEFT,
|
EV_KEY, BTN_LEFT,
|
||||||
EV_KEY, BTN_MIDDLE,
|
EV_KEY, BTN_MIDDLE,
|
||||||
EV_KEY, BTN_RIGHT,
|
EV_KEY, BTN_RIGHT,
|
||||||
|
EV_LED, LED_NUML,
|
||||||
|
EV_LED, LED_CAPSL,
|
||||||
-1);
|
-1);
|
||||||
ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
|
ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc));
|
||||||
|
|
||||||
|
|
@ -849,6 +897,12 @@ START_TEST(test_event_value_setters)
|
||||||
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_X), 10);
|
||||||
ck_assert_int_eq(libevdev_get_event_value(dev, EV_ABS, ABS_Y), 20);
|
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);
|
uinput_device_free(uidev);
|
||||||
libevdev_free(dev);
|
libevdev_free(dev);
|
||||||
|
|
||||||
|
|
@ -996,6 +1050,7 @@ libevdev_events(void)
|
||||||
tcase_add_test(tc, test_syn_delta_button);
|
tcase_add_test(tc, test_syn_delta_button);
|
||||||
tcase_add_test(tc, test_syn_delta_abs);
|
tcase_add_test(tc, test_syn_delta_abs);
|
||||||
tcase_add_test(tc, test_syn_delta_mt);
|
tcase_add_test(tc, test_syn_delta_mt);
|
||||||
|
tcase_add_test(tc, test_syn_delta_led);
|
||||||
suite_add_tcase(s, tc);
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
tc = tcase_create("skipped syncs");
|
tc = tcase_create("skipped syncs");
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue