[PATCH libevdev 4/7] Keep the LED state and sync it after SYN_DROPPED

Peter Hutterer peter.hutterer at who-t.net
Tue Aug 13 17:50:51 PDT 2013


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 at who-t.net>
---
 libevdev/libevdev-int.h     |  1 +
 libevdev/libevdev.c         | 51 +++++++++++++++++++++++++++++++++++++++++
 test/test-libevdev-events.c | 55 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+)

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 cade991..bd0c58c 100644
--- a/libevdev/libevdev.c
+++ b/libevdev/libevdev.c
@@ -236,6 +236,10 @@ libevdev_set_fd(struct libevdev* dev, int fd)
 	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++)
@@ -322,6 +326,32 @@ out:
 }
 
 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)
 {
 	int rc;
@@ -441,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))
@@ -503,6 +535,20 @@ update_abs_state(struct libevdev *dev, const struct input_event *e)
 }
 
 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)
 {
 	int rc = 0;
@@ -517,6 +563,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;
@@ -765,6 +814,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;
@@ -788,6 +838,7 @@ int libevdev_set_event_value(struct libevdev *dev, unsigned int type, unsigned i
 	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;
diff --git a/test/test-libevdev-events.c b/test/test-libevdev-events.c
index 95105d1..afa426d 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;
@@ -828,6 +874,8 @@ START_TEST(test_event_value_setters)
 				    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));
 
@@ -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_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);
 
@@ -996,6 +1050,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");
-- 
1.8.2.1



More information about the Input-tools mailing list