xref: /freebsd/usr.sbin/moused/moused/util-evdev.c (revision aef807876c305587c60f73e2cd914115d22a53fd)
1 /*
2  * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
3  * Copyright © 2013 Red Hat, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include <dev/evdev/input.h>
30 
31 #include "event-names.h"
32 #include "util-evdev.h"
33 
34 #define ARRAY_LENGTH(a) (sizeof(a) / (sizeof((a)[0])))
35 
36 struct name_lookup {
37 	const char *name;
38 	size_t len;
39 };
40 
41 static inline bool
startswith(const char * str,size_t len,const char * prefix,size_t plen)42 startswith(const char *str, size_t len, const char *prefix, size_t plen)
43 {
44 	return len >= plen && !strncmp(str, prefix, plen);
45 }
46 
type_from_prefix(const char * name,ssize_t len)47 static int type_from_prefix(const char *name, ssize_t len)
48 {
49 	const char *e;
50 	size_t i;
51 	ssize_t l;
52 
53 	/* MAX_ is not allowed, even though EV_MAX exists */
54 	if (startswith(name, len, "MAX_", 4))
55 		return -1;
56 	/* BTN_ is special as there is no EV_BTN type */
57 	if (startswith(name, len, "BTN_", 4))
58 		return EV_KEY;
59 	/* FF_STATUS_ is special as FF_ is a prefix of it, so test it first */
60 	if (startswith(name, len, "FF_STATUS_", 10))
61 		return EV_FF_STATUS;
62 
63 	for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) {
64 		/* skip EV_ prefix so @e is suffix of [EV_]XYZ */
65 		e = &ev_names[i].name[3];
66 		l = strlen(e);
67 
68 		/* compare prefix and test for trailing _ */
69 		if (len > l && startswith(name, len, e, l) && name[l] == '_')
70 			return ev_names[i].value;
71 	}
72 
73 	return -1;
74 }
75 
cmp_entry(const void * vlookup,const void * ventry)76 static int cmp_entry(const void *vlookup, const void *ventry)
77 {
78 	const struct name_lookup *lookup = vlookup;
79 	const struct name_entry *entry = ventry;
80 	int r;
81 
82 	r = strncmp(lookup->name, entry->name, lookup->len);
83 	if (!r) {
84 		if (entry->name[lookup->len])
85 			r = -1;
86 		else
87 			r = 0;
88 	}
89 
90 	return r;
91 }
92 
93 static const struct name_entry*
lookup_name(const struct name_entry * array,size_t asize,struct name_lookup * lookup)94 lookup_name(const struct name_entry *array, size_t asize,
95 	    struct name_lookup *lookup)
96 {
97 	const struct name_entry *entry;
98 
99 	entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry);
100 	if (!entry)
101 		return NULL;
102 
103 	return entry;
104 }
105 
106 int
libevdev_event_type_get_max(unsigned int type)107 libevdev_event_type_get_max(unsigned int type)
108 {
109 	if (type > EV_MAX)
110 		return -1;
111 
112 	return ev_max[type];
113 }
114 
115 int
libevdev_event_code_from_name(unsigned int type,const char * name)116 libevdev_event_code_from_name(unsigned int type, const char *name)
117 {
118 	struct name_lookup lookup;
119 	const struct name_entry *entry;
120 	int real_type;
121 	size_t len = strlen(name);
122 
123 	real_type = type_from_prefix(name, len);
124 	if (real_type < 0 || (unsigned int)real_type != type)
125 		return -1;
126 
127 	lookup.name = name;
128 	lookup.len = len;
129 
130 	entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
131 
132 	return entry ? (int)entry->value : -1;
133 }
134 
135 static int
libevdev_event_type_from_name_n(const char * name,size_t len)136 libevdev_event_type_from_name_n(const char *name, size_t len)
137 {
138 	struct name_lookup lookup;
139 	const struct name_entry *entry;
140 
141 	lookup.name = name;
142 	lookup.len = len;
143 
144 	entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup);
145 
146 	return entry ? (int)entry->value : -1;
147 }
148 
149 int
libevdev_event_type_from_name(const char * name)150 libevdev_event_type_from_name(const char *name)
151 {
152 	return libevdev_event_type_from_name_n(name, strlen(name));
153 }
154 
155 static int
libevdev_property_from_name_n(const char * name,size_t len)156 libevdev_property_from_name_n(const char *name, size_t len)
157 {
158 	struct name_lookup lookup;
159 	const struct name_entry *entry;
160 
161 	lookup.name = name;
162 	lookup.len = len;
163 
164 	entry = lookup_name(prop_names, ARRAY_LENGTH(prop_names), &lookup);
165 
166 	return entry ? (int)entry->value : -1;
167 }
168 
169 int
libevdev_property_from_name(const char * name)170 libevdev_property_from_name(const char *name)
171 {
172 	return libevdev_property_from_name_n(name, strlen(name));
173 }
174