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