[PATCH evtest] Add evstate tool for evdev state querying

Daniel Drake dsd at laptop.org
Tue Jul 12 13:04:34 PDT 2011


evstate is a small utility that queries evdev state of a specific
key, switch, button, LED or sound event. This is useful in programs
such as powerd (http://wiki.laptop.org/go/Powerd) which need to query
things like the state of the laptop lid switch from shell code.

Signed-off-by: Daniel Drake <dsd at laptop.org>
---
 Makefile.am |    4 +-
 evstate.c   |  122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 evstate.txt |   43 +++++++++++++++++++++
 3 files changed, 167 insertions(+), 2 deletions(-)
 create mode 100644 evstate.c
 create mode 100644 evstate.txt

I wrote this tool without realising that evtest exists. Now that I have
found evtest, I see that it is similar (but doesn't quite fulfill the same
role).

Is this acceptable as-is, or would you prefer it merged into evtest as
another mode of functionality? I could see either way: evstate as a
trivial, small, standalone app is desirable as it will be called often by
powerd and other shell scripts, but in the interest of consolidation perhaps
it would instead make sense to make evtest offer this instant-query
functionality. What do you think?

diff --git a/Makefile.am b/Makefile.am
index c78d17d..51dd7ae 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 
-bin_PROGRAMS = evtest
-man_pages_src = evtest.txt
+bin_PROGRAMS = evtest evstate
+man_pages_src = evtest.txt evstate.txt
 
 if HAVE_LIBXML
 bin_PROGRAMS += evtest-capture
diff --git a/evstate.c b/evstate.c
new file mode 100644
index 0000000..f797403
--- /dev/null
+++ b/evstate.c
@@ -0,0 +1,122 @@
+/*
+ * evstate: query evdev key/led/sw/snd state
+ * Returns exit code 1 if the state bit is set (key pressed, LED on, etc.),
+ * and 0 if the state bit is unset.
+ *
+ * Copyright (C) 2011 One Laptop per Child
+ * Written by Daniel Drake <dsd at laptop.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/input.h>
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+
+static int test_bit(unsigned int nr, void *addr)
+{
+	return ((1UL << (nr % BITS_PER_LONG)) &
+		(((unsigned long *) addr)[nr / BITS_PER_LONG])) != 0;
+}
+
+static void __attribute__((noreturn)) usage(void)
+{
+	fprintf(stderr, "Usage: %s <device> <mode> <key>\n",
+			program_invocation_short_name);
+	fprintf(stderr, "Valid modes: key, led, snd, sw\n");
+	exit(2);
+}
+
+static const struct mode {
+	const char *name;
+	int max;
+	int rq;
+} requests[] = {
+	{ "key", KEY_MAX, EVIOCGKEY(KEY_MAX) },
+	{ "led", LED_MAX, EVIOCGLED(LED_MAX) },
+	{ "snd", SND_MAX, EVIOCGSND(SND_MAX) },
+	{ "sw",  SW_MAX, EVIOCGSW(SW_MAX) },
+};
+
+static const struct mode *find_mode(const char *name)
+{
+	int i;
+	for (i = 0; i < sizeof(requests) / sizeof(*requests); i++) {
+		const struct mode *mode = &requests[i];
+		if (strcmp(mode->name, name) == 0)
+			return mode;
+	}
+	return NULL;
+}
+
+static int query_state(const char *device, long int keyno,
+		       const struct mode *mode)
+{
+	uint8_t state[(mode->max / 8) + 1];
+	int fd;
+	int r;
+
+	if (keyno < 0 || keyno > mode->max) {
+		fprintf(stderr, "Unrecognised key %d\n", keyno);
+		exit(3);
+	}
+
+	fd = open(device, O_RDONLY);
+	if (fd == -1) {
+		perror("open");
+		exit(3);
+	}
+
+	memset(state, 0, sizeof(state));
+	r = ioctl(fd, mode->rq, state);
+	close(fd);
+
+	if (r == -1) {
+		perror("ioctl");
+		exit(3);
+	}
+
+	return test_bit(keyno, state);
+}
+
+int main(int argc, char **argv)
+{
+	const struct mode *mode;
+	long int keyno;
+
+	if (argc != 4)
+		usage();
+
+	mode = find_mode(argv[2]);
+	if (!mode) {
+		fprintf(stderr, "Unrecognised mode.\n");
+		usage();
+	}
+
+	keyno = strtol(argv[3], NULL, 10);
+	return query_state(argv[1], keyno, mode);
+}
+
diff --git a/evstate.txt b/evstate.txt
new file mode 100644
index 0000000..29b2156
--- /dev/null
+++ b/evstate.txt
@@ -0,0 +1,43 @@
+EVSTATE(1)
+==========
+
+NAME
+----
+
+       evstate - query evdev key/LED/switch/sound state
+
+SYNOPSIS
+--------
+       evstate device mode key
+
+DESCRIPTION
+-----------
+evstate  queries  the state of a Linux evdev key/button, LED, switch or sound
+status.
+
+Ordinarily, no textual output is produced.  evstate returns exit code 1 if
+the state bit is set (key pressed, LED on, etc.), or exit code 0 if the state
+bit is unset.
+
+*device* is the evdev device node of the input device you wish to query, such
+as /dev/input/event0.
+
+*mode* is one of key, led, snd, or sw.
+
+*key* is the index of the key/switch/event you wish to query in integer form
+(see <linux/input.h> for values).
+
+EXAMPLE
+-------
+Given /dev/input/event0 as the input device of my laptop dock switch, the
+following command will determine if the laptop is plugged into dock (SW_DOCK).
+
+       evstate /dev/input/event0 sw 5
+
+SEE ALSO
+--------
+evtest(1)
+
+AUTHOR
+------
+evstate was written by Daniel Drake <dsd at laptop.org>
-- 
1.7.5.4



More information about the xorg-devel mailing list