[PATCH v2 evemu] Record the state of SW/LED in the evemu file

Peter Hutterer peter.hutterer at who-t.net
Wed Jul 22 00:05:05 PDT 2015


There is no evdev ioctl to set the state of a device without sending an event
through the device, so we can't replicate the state without altering the
recorded event sequence. For this reason, we use the libevdev shortcut to
query the state rather than adding an evemu-specific API to get the state.

The state is printed to the comments, and optionally printed to the recording
(0 is assumed when missing).

EV_KEY can give us the state but we don't print it, unlike the others a key
state is too transient.
EV_SND could be added, if we ever see demand for it.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v1:
- dropped EV_SND, who cares...
- update file format to record LED/SW state

 README.md   | 11 ++++++--
 src/evemu.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 98 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 4b4b812..78c4bf6 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ Device Description Format
 evemu produces two different data formats, one for the device description
 and one for the device event data. hex data is without a 0x prefix.
 
-    # EVEMU 1.2
+    # EVEMU 1.3
     # comments start with a # character and go to the end of the line
     N: <device name>
     I: <bustype (hex)> <vendor (hex)> <product (hex)> <version (hex)>
@@ -49,12 +49,18 @@ and one for the device event data. hex data is without a 0x prefix.
     B: <index (hex)> <byte 8 (hex)> ...
      --- for each absolute axis ---
     A: <index (hex)> <min> <max> <fuzz> <flat> <resolution>
+     --- for each LED ---
+    L: <index (hex)> <state>
+     --- for each switch ---
+    S: <index (hex)> <state>
 
 The first line is a special comment and taken to describe the file format
 version. It is always comment character (#), space, "EVEMU", space, followed
 by a numeric version number in the format major.minor.
 If the line is missing, file format 1.0 is assumed.
 
+If L and S are missing, the state of each LED/switch is 0
+
 minor version numbers are additions of new fields, or alterations of a
 field.
 major version numbers are large redesigns of the format
@@ -65,6 +71,7 @@ Current file format versions supported:
  * 1.1 - comments may be present at any line of the file, including at the
 	 end of a line
  * 1.2 - abs axis information has the resolution appended
+ * 1.3 - LED/switch state added
 
 Event Data Format
 -----------------
@@ -97,4 +104,4 @@ Copyright
 
  * Copyright (C) 2010 Henrik Rydberg <rydberg at euromail.se>
  * Copyright (C) 2010 Canonical Ltd.
- * Copyright (C) 2013 Red Hat, Inc.
+ * Copyright (C) 2013-2015 Red Hat, Inc.
diff --git a/src/evemu.c b/src/evemu.c
index 642597b..12a0038 100644
--- a/src/evemu.c
+++ b/src/evemu.c
@@ -3,7 +3,7 @@
  * evemu - Kernel device emulation
  *
  * Copyright (C) 2010-2012 Canonical Ltd.
- * Copyright (C) 2013 Red Hat, Inc.
+ * Copyright (C) 2013-2015 Red Hat, Inc.
  *
  * This library is free software: you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License version 3
@@ -59,7 +59,7 @@
 /* File format version we write out
    NOTE: if you bump the version number, make sure you update README */
 #define EVEMU_FILE_MAJOR 1
-#define EVEMU_FILE_MINOR 2
+#define EVEMU_FILE_MINOR 3
 
 #define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
 
@@ -296,10 +296,21 @@ static void write_abs(FILE *fp, int index, const struct input_absinfo *abs)
 		abs->minimum, abs->maximum, abs->fuzz, abs->flat, abs->resolution);
 }
 
+static void write_led(FILE *fp, int index, int state)
+{
+	fprintf(fp, "L: %02x %d\n", index, state);
+}
+
+static void write_sw(FILE *fp, int index, int state)
+{
+	fprintf(fp, "S: %02x %d\n", index, state);
+}
+
 /* Print an evtest-like description */
 static void write_desc(const struct evemu_device *dev, FILE *fp)
 {
 	int i, j;
+	int state;
 	fprintf(fp, "# Input device name: \"%s\"\n", evemu_get_name(dev));
 	fprintf(fp, "# Input device ID: bus %#04x vendor %#04x product %#04x version %#04x\n",
 		evemu_get_id_bustype(dev), evemu_get_id_vendor(dev),
@@ -316,7 +327,8 @@ static void write_desc(const struct evemu_device *dev, FILE *fp)
 
 			fprintf(fp, "#     Event code %d (%s)\n",
 				    j, libevdev_event_code_get_name(i, j));
-			if (i == EV_ABS) {
+			switch(i) {
+				case EV_ABS:
 				fprintf(fp, "#       Value %6d\n"
 					    "#       Min   %6d\n"
 					    "#       Max   %6d\n"
@@ -329,6 +341,13 @@ static void write_desc(const struct evemu_device *dev, FILE *fp)
 					    evemu_get_abs_fuzz(dev, j),
 					    evemu_get_abs_flat(dev, j),
 					    evemu_get_abs_resolution(dev, j));
+				case EV_LED:
+				case EV_SW:
+					state = libevdev_get_event_value(dev->evdev, i, j);
+					fprintf(fp, "#        State %d\n", state);
+					break;
+				default:
+					break;
 			}
 		}
 	}
@@ -370,6 +389,7 @@ write_header(FILE *fp)
 int evemu_write(const struct evemu_device *dev, FILE *fp)
 {
 	int i;
+	int state;
 
 	write_header(fp);
 
@@ -390,6 +410,16 @@ int evemu_write(const struct evemu_device *dev, FILE *fp)
 		if (evemu_has_event(dev, EV_ABS, i))
 			write_abs(fp, i, libevdev_get_abs_info(dev->evdev, i));
 
+	for (i = 0; i < LED_CNT; i++)
+		if (evemu_has_event(dev, EV_LED, i) &&
+		    (state = libevdev_get_event_value(dev->evdev, EV_LED, i)) != 0)
+			write_led(fp, i, state);
+
+	for (i = 0; i < SW_CNT; i++)
+		if (evemu_has_event(dev, EV_SW, i) &&
+		    (state = libevdev_get_event_value(dev->evdev, EV_SW, i)) != 0)
+			write_sw(fp, i, state);
+
 	return 0;
 }
 
@@ -525,6 +555,50 @@ static int parse_abs(struct evemu_device *dev, const char *line, struct version
 	return 1;
 }
 
+static int parse_led(const char *line)
+{
+	int matched;
+	unsigned int index;
+	int state;
+
+	if (strlen(line) <= 2 || strncmp(line, "L:", 2) != 0)
+		return 0;
+
+	matched = sscanf(line, "L: %02x %d\n", &index, &state);
+
+	if (matched != 2) {
+		error(FATAL, "Invalid EV_LED line. Parsed %d numbers, expected 2: %s", matched, line);
+		return -1;
+	}
+
+	/* We can't set the LEDs directly, we'd have to send an event
+	 * through the device but that's potentially racy */
+
+	return 1;
+}
+
+static int parse_sw(const char *line)
+{
+	int matched;
+	unsigned int index;
+	int state;
+
+	if (strlen(line) <= 2 || strncmp(line, "S:", 2) != 0)
+		return 0;
+
+	matched = sscanf(line, "S: %02x %d\n", &index, &state);
+
+	if (matched != 2) {
+		error(FATAL, "Invalid EV_SW line. Parsed %d numbers, expected 2: %s", matched, line);
+		return -1;
+	}
+
+	/* We can't set the switches directly, we'd have to send an event
+	 * through the device but that's potentially racy */
+
+	return 1;
+}
+
 static struct version parse_file_format_version(const char *line)
 {
 	struct version v;
@@ -603,6 +677,18 @@ int evemu_read(struct evemu_device *dev, FILE *fp)
 	if (rc == -1)
 		goto out;
 
+	while((rc = parse_led(line)) > 0)
+		if (!next_line(fp, &line, &size))
+			break;
+	if (rc == -1)
+		goto out;
+
+	while((rc = parse_sw(line)) > 0)
+		if (!next_line(fp, &line, &size))
+			break;
+	if (rc == -1)
+		goto out;
+
 	rc = 1;
 
 out:
-- 
2.4.3



More information about the Input-tools mailing list