summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2011-07-20 18:25:03 +0100
committerPeter Hutterer <peter.hutterer@who-t.net>2011-07-22 09:55:37 +1000
commit8a10dfe3b7bc53b319107de89434922a2c79ef94 (patch)
tree4bc3f50a848f0b4161a38c1775e38cfb84d08701
parent6015b4c4cf0efeb845673c37d80f3049e86c04a1 (diff)
Add one-shot query functionality
Add functionality to query 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. Original capture-mode functionality is left unchanged and is still activated by default. New usage modes are explained in the man page. Signed-off-by: Daniel Drake <dsd@laptop.org> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--evtest.c248
-rw-r--r--evtest.txt33
2 files changed, 266 insertions, 15 deletions
diff --git a/evtest.c b/evtest.c
index eb04a51..022229e 100644
--- a/evtest.c
+++ b/evtest.c
@@ -49,6 +49,8 @@
49#include <stdlib.h> 49#include <stdlib.h>
50#include <dirent.h> 50#include <dirent.h>
51#include <errno.h> 51#include <errno.h>
52#include <getopt.h>
53#include <ctype.h>
52 54
53#define BITS_PER_LONG (sizeof(long) * 8) 55#define BITS_PER_LONG (sizeof(long) * 8)
54#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) 56#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
@@ -69,6 +71,83 @@
69 71
70#define NAME_ELEMENT(element) [element] = #element 72#define NAME_ELEMENT(element) [element] = #element
71 73
74enum evtest_mode {
75 MODE_CAPTURE,
76 MODE_QUERY,
77};
78
79static const struct query_mode {
80 const char *name;
81 int event_type;
82 int max;
83 int rq;
84} query_modes[] = {
85 { "EV_KEY", EV_KEY, KEY_MAX, EVIOCGKEY(KEY_MAX) },
86 { "EV_LED", EV_LED, LED_MAX, EVIOCGLED(LED_MAX) },
87 { "EV_SND", EV_SND, SND_MAX, EVIOCGSND(SND_MAX) },
88 { "EV_SW", EV_SW, SW_MAX, EVIOCGSW(SW_MAX) },
89};
90
91/**
92 * Look up an entry in the query_modes table by its textual name. The search
93 * is case-insensitive.
94 *
95 * @param mode The name of the entry to be found.
96 *
97 * @return The requested query_mode, or NULL if it could not be found.
98 */
99static const struct query_mode *find_query_mode_by_name(const char *name)
100{
101 int i;
102 for (i = 0; i < sizeof(query_modes) / sizeof(*query_modes); i++) {
103 const struct query_mode *mode = &query_modes[i];
104 if (strcmp(mode->name, name) == 0)
105 return mode;
106 }
107 return NULL;
108}
109
110/**
111 * Look up an entry in the query_modes table by value.
112 *
113 * @param event_type The value of the entry to be found.
114 *
115 * @return The requested query_mode, or NULL if it could not be found.
116 */
117static const struct query_mode *find_query_mode_by_value(int event_type)
118{
119 int i;
120 for (i = 0; i < sizeof(query_modes) / sizeof(*query_modes); i++) {
121 const struct query_mode *mode = &query_modes[i];
122 if (mode->event_type == event_type)
123 return mode;
124 }
125 return NULL;
126}
127
128/**
129 * Find a query_mode based on a string identifier. The string can either
130 * be a numerical value (e.g. "5") or the name of the event type in question
131 * (e.g. "EV_SW").
132 *
133 * @param query_mode The mode to search for
134 *
135 * @return The requested code's numerical value, or negative on error.
136 */
137static const struct query_mode *find_query_mode(const char *query_mode)
138{
139 if (isdigit(query_mode[0])) {
140 unsigned long val;
141 errno = 0;
142 val = strtoul(query_mode, NULL, 0);
143 if (errno)
144 return NULL;
145 return find_query_mode_by_value(val);
146 } else {
147 return find_query_mode_by_name(query_mode);
148 }
149}
150
72static const char * const events[EV_MAX + 1] = { 151static const char * const events[EV_MAX + 1] = {
73 [0 ... EV_MAX] = NULL, 152 [0 ... EV_MAX] = NULL,
74 NAME_ELEMENT(EV_SYN), NAME_ELEMENT(EV_KEY), 153 NAME_ELEMENT(EV_SYN), NAME_ELEMENT(EV_KEY),
@@ -480,6 +559,41 @@ static const char * const * const names[EV_MAX + 1] = {
480}; 559};
481 560
482/** 561/**
562 * Convert a string to a specific key/snd/led/sw code. The string can either
563 * be the name of the key in question (e.g. "SW_DOCK") or the numerical
564 * value, either as decimal (e.g. "5") or as hex (e.g. "0x5").
565 *
566 * @param mode The mode being queried (key, snd, led, sw)
567 * @param kstr The string to parse and convert
568 *
569 * @return The requested code's numerical value, or negative on error.
570 */
571static int get_keycode(const struct query_mode *query_mode, const char *kstr)
572{
573 if (isdigit(kstr[0])) {
574 unsigned long val;
575 errno = 0;
576 val = strtoul(kstr, NULL, 0);
577 if (errno) {
578 fprintf(stderr, "Could not interpret value %s\n", kstr);
579 return -1;
580 }
581 return (int) val;
582 } else {
583 const char * const *keynames = names[query_mode->event_type];
584 int i;
585
586 for (i = 0; i < query_mode->max; i++) {
587 const char *name = keynames[i];
588 if (name && strcmp(name, kstr) == 0)
589 return i;
590 }
591
592 return -1;
593 }
594}
595
596/**
483 * Filter for the AutoDevProbe scandir on /dev/input. 597 * Filter for the AutoDevProbe scandir on /dev/input.
484 * 598 *
485 * @param dir The current directory entry provided by scandir. 599 * @param dir The current directory entry provided by scandir.
@@ -544,10 +658,22 @@ static char* scan_devices(void)
544/** 658/**
545 * Print usage information. 659 * Print usage information.
546 */ 660 */
547static void usage(void) 661static int usage(void)
548{ 662{
549 printf("Usage: evtest /dev/input/eventX\n"); 663 printf("USAGE:\n");
550 printf("Where X = input device number\n"); 664 printf(" Grab mode:\n");
665 printf(" %s /dev/input/eventX\n", program_invocation_short_name);
666 printf("\n");
667 printf(" Query mode: (check exit code)\n");
668 printf(" %s --query /dev/input/eventX <type> <value>\n",
669 program_invocation_short_name);
670
671 printf("\n");
672 printf("<type> is one of: EV_KEY, EV_SW, EV_LED, EV_SND\n");
673 printf("<value> can either be a numerical value, or the textual name of the\n");
674 printf("key/switch/LED/sound being queried (e.g. SW_DOCK).\n");
675
676 return EXIT_FAILURE;
551} 677}
552 678
553/** 679/**
@@ -700,10 +826,8 @@ static int do_capture(const char *device)
700 fprintf(stderr, "Not running as root, no devices may be available.\n"); 826 fprintf(stderr, "Not running as root, no devices may be available.\n");
701 827
702 filename = scan_devices(); 828 filename = scan_devices();
703 if (!filename) { 829 if (!filename)
704 usage(); 830 return usage();
705 return EXIT_FAILURE;
706 }
707 } else 831 } else
708 filename = strdup(device); 832 filename = strdup(device);
709 833
@@ -743,14 +867,118 @@ static int do_capture(const char *device)
743 return print_events(fd); 867 return print_events(fd);
744} 868}
745 869
870/**
871 * Perform a one-shot state query on a specific device. The query can be of
872 * any known mode, on any valid keycode.
873 *
874 * @param device Path to the evdev device node that should be queried.
875 * @param query_mode The event type that is being queried (e.g. key, switch)
876 * @param keycode The code of the key/switch/sound/LED to be queried
877 * @return 0 if the state bit is unset, 10 if the state bit is set, 1 on error.
878 */
879static int query_device(const char *device, const struct query_mode *query_mode, int keycode)
880{
881 int fd;
882 int r;
883 unsigned long state[NBITS(query_mode->max)];
884
885 fd = open(device, O_RDONLY);
886 if (fd < 0) {
887 perror("open");
888 return EXIT_FAILURE;
889 }
890 memset(state, 0, sizeof(state));
891 r = ioctl(fd, query_mode->rq, state);
892 close(fd);
893
894 if (r == -1) {
895 perror("ioctl");
896 return EXIT_FAILURE;
897 }
898
899 if (test_bit(keycode, state))
900 return 10; /* different from EXIT_FAILURE */
901 else
902 return 0;
903}
904
905/**
906 * Enter query mode. The requested event device will be queried for the state
907 * of a particular switch/key/sound/LED.
908 *
909 * @param device The device to query.
910 * @param mode The mode (event type) that is to be queried (snd, sw, key, led)
911 * @param keycode The key code to query the state of.
912 * @return 0 if the state bit is unset, 10 if the state bit is set.
913 */
914static int do_query(const char *device, const char *event_type, const char *keyname)
915{
916 const struct query_mode *query_mode;
917 int keycode;
918
919 if (!device) {
920 fprintf(stderr, "Device argument is required for query.\n");
921 return usage();
922 }
923
924 query_mode = find_query_mode(event_type);
925 if (!query_mode) {
926 fprintf(stderr, "Unrecognised event type: %s\n", event_type);
927 return usage();
928 }
929
930 keycode = get_keycode(query_mode, keyname);
931 if (keycode < 0) {
932 fprintf(stderr, "Unrecognised key name: %s\n", keyname);
933 return usage();
934 } else if (keycode > query_mode->max) {
935 fprintf(stderr, "Key %d is out of bounds.\n", keycode);
936 return EXIT_FAILURE;
937 }
938
939 return query_device(device, query_mode, keycode);
940}
941
942static const struct option long_options[] = {
943 { "query", no_argument, NULL, MODE_QUERY },
944 { 0, },
945};
946
746int main (int argc, char **argv) 947int main (int argc, char **argv)
747{ 948{
748 const char *device = NULL; 949 const char *device = NULL;
950 const char *keyname;
951 const char *event_type;
952 enum evtest_mode mode = MODE_CAPTURE;
749 953
750 if (argc >= 2) 954 while (1) {
751 device = argv[1]; 955 int option_index = 0;
956 int c = getopt_long(argc, argv, "", long_options, &option_index);
957 if (c == -1)
958 break;
959 switch (c) {
960 case MODE_QUERY:
961 mode = c;
962 break;
963 default:
964 return usage();
965 }
966 }
967
968 if (optind < argc)
969 device = argv[optind++];
970
971 if (mode == MODE_CAPTURE)
972 return do_capture(device);
973
974 if ((argc - optind) < 2) {
975 fprintf(stderr, "Query mode requires device, type and key parameters\n");
976 return usage();
977 }
752 978
753 return do_capture(device); 979 event_type = argv[optind++];
980 keyname = argv[optind++];
981 return do_query(device, event_type, keyname);
754} 982}
755 983
756/* vim: set noexpandtab tabstop=8 shiftwidth=8: */ 984/* vim: set noexpandtab tabstop=8 shiftwidth=8: */
diff --git a/evtest.txt b/evtest.txt
index 685a4de..5ae7092 100644
--- a/evtest.txt
+++ b/evtest.txt
@@ -4,17 +4,33 @@ EVTEST(1)
4NAME 4NAME
5---- 5----
6 6
7 evtest - Input device event monitor 7 evtest - Input device event monitor and query tool
8 8
9SYNOPSIS 9SYNOPSIS
10-------- 10--------
11 evtest "/dev/input/eventX" 11 evtest /dev/input/eventX
12
13 evtest --query /dev/input/eventX <type> <value>
12 14
13DESCRIPTION 15DESCRIPTION
14----------- 16-----------
15evtest displays information on the input device specified on the command 17The first invocation type displayed above ("capture mode") causes evtest to
16line, including all the events supported by the device. It then monitors the 18display information about the specified input device, including all the events
17device and displays all the events layer events generated. 19supported by the device. It then monitors the device and displays all the
20events layer events generated.
21
22In the second invocation type ("query mode"), evtest performs a one-shot query
23of the state of a specific key *value* of an event *type*.
24
25*type* is one of: *EV_KEY*, *EV_SW*, *EV_SND*, *EV_LED* (or the numerical value)
26
27*value* can be either a decimal representation (e.g. 44), hex
28(e.g. 0x2c), or the constant name (e.g. KEY_Z) of the key/switch/sound/LED
29being queried.
30
31If the state bit is set (key pressed, switch on, ...), evtest exits with
32code 0. If the state bit is unset (key depressed, switch off, ...), evtest
33exits with code 10. No other output is generated.
18 34
19evtest needs to be able to read from the device; in most cases this means it 35evtest needs to be able to read from the device; in most cases this means it
20must be run as root. 36must be run as root.
@@ -32,6 +48,13 @@ when debugging a synaptics device from within X. VT switching to a TTY or
32shutting down the X server terminates this grab and synaptics devices can be 48shutting down the X server terminates this grab and synaptics devices can be
33debugged. 49debugged.
34 50
51EXIT CODE
52---------
53evtest returns 1 on error.
54
55When used to query state, evtest returns 0 if the state bit is unset and
5610 if the state bit is set.
57
35SEE ALSO 58SEE ALSO
36-------- 59--------
37inputattach(1) 60inputattach(1)