• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3# Parses linux/input.h scanning for #define KEY_FOO 134
4# Prints C header files or Python files that can be used as
5# mapping and lookup tables.
6#
7
8import re
9import sys
10
11
12class Bits(object):
13    def __init__(self):
14        self.max_codes = {}
15
16
17prefixes = [
18    "EV_",
19    "REL_",
20    "ABS_",
21    "KEY_",
22    "BTN_",
23    "LED_",
24    "SND_",
25    "MSC_",
26    "SW_",
27    "FF_",
28    "SYN_",
29    "REP_",
30    "INPUT_PROP_",
31    "MT_TOOL_",
32]
33
34duplicates = [
35    "EV_VERSION",
36    "BTN_MISC",
37    "BTN_MOUSE",
38    "BTN_JOYSTICK",
39    "BTN_GAMEPAD",
40    "BTN_DIGI",
41    "BTN_WHEEL",
42    "BTN_TRIGGER_HAPPY",
43    "SW_MAX",
44    "REP_MAX",
45]
46
47btn_additional = [
48    [0, "BTN_A"],
49    [0, "BTN_B"],
50    [0, "BTN_X"],
51    [0, "BTN_Y"],
52]
53
54code_prefixes = [
55    "REL_",
56    "ABS_",
57    "KEY_",
58    "BTN_",
59    "LED_",
60    "SND_",
61    "MSC_",
62    "SW_",
63    "FF_",
64    "SYN_",
65    "REP_",
66]
67
68
69def print_bits(bits, prefix):
70    if not hasattr(bits, prefix):
71        return
72    print("static const char * const %s_map[%s_MAX + 1] = {" % (prefix, prefix.upper()))
73    for val, name in sorted(list(getattr(bits, prefix).items())):
74        print("    [%s] = \"%s\"," % (name, name))
75    if prefix == "key":
76        for val, name in sorted(list(getattr(bits, "btn").items())):
77            print("    [%s] = \"%s\"," % (name, name))
78    print("};")
79    print("")
80
81
82def print_map(bits):
83    print("static const char * const * const event_type_map[EV_MAX + 1] = {")
84
85    for prefix in prefixes:
86        if prefix in ["BTN_", "EV_", "INPUT_PROP_", "MT_TOOL_"]:
87            continue
88        print("    [EV_%s] = %s_map," % (prefix[:-1], prefix[:-1].lower()))
89
90    print("};")
91    print("")
92
93    print("#if __clang__")
94    print("#pragma clang diagnostic push")
95    print("#pragma clang diagnostic ignored \"-Winitializer-overrides\"")
96    print("#elif __GNUC__")
97    print("#pragma GCC diagnostic push")
98    print("#pragma GCC diagnostic ignored \"-Woverride-init\"")
99    print("#endif")
100    print("static const int ev_max[EV_MAX + 1] = {")
101    for val in range(bits.max_codes["EV_MAX"] + 1):
102        if val in bits.ev:
103            prefix = bits.ev[val][3:]
104            if prefix + "_" in prefixes:
105                print("    %s_MAX," % prefix)
106                continue
107        print("    -1,")
108    print("};")
109    print("#if __clang__")
110    print("#pragma clang diagnostic pop /* \"-Winitializer-overrides\" */")
111    print("#elif __GNUC__")
112    print("#pragma GCC diagnostic pop /* \"-Woverride-init\" */")
113    print("#endif")
114    print("")
115
116
117def print_lookup(bits, prefix):
118    if not hasattr(bits, prefix):
119        return
120
121    names = sorted(list(getattr(bits, prefix).items()))
122    if prefix == "btn":
123        names = names + btn_additional
124
125    # We need to manually add the _MAX codes because some are
126    # duplicates
127    maxname = "%s_MAX" % (prefix.upper())
128    if maxname in duplicates:
129        names.append((bits.max_codes[maxname], maxname))
130
131    for val, name in sorted(names, key=lambda e: e[1]):
132        print("    { .name = \"%s\", .value = %s }," % (name, name))
133
134
135def print_lookup_table(bits):
136    print("struct name_entry {")
137    print("    const char *name;")
138    print("    unsigned int value;")
139    print("};")
140    print("")
141    print("static const struct name_entry tool_type_names[] = {")
142    print_lookup(bits, "mt_tool")
143    print("};")
144    print("")
145    print("static const struct name_entry ev_names[] = {")
146    print_lookup(bits, "ev")
147    print("};")
148    print("")
149
150    print("static const struct name_entry code_names[] = {")
151    for prefix in sorted(code_prefixes, key=lambda e: e):
152        print_lookup(bits, prefix[:-1].lower())
153    print("};")
154    print("")
155    print("static const struct name_entry prop_names[] = {")
156    print_lookup(bits, "input_prop")
157    print("};")
158    print("")
159
160
161def print_mapping_table(bits):
162    print("/* THIS FILE IS GENERATED, DO NOT EDIT */")
163    print("")
164    print("#ifndef EVENT_NAMES_H")
165    print("#define EVENT_NAMES_H")
166    print("")
167
168    for prefix in prefixes:
169        if prefix == "BTN_":
170            continue
171        print_bits(bits, prefix[:-1].lower())
172
173    print_map(bits)
174    print_lookup_table(bits)
175
176    print("#endif /* EVENT_NAMES_H */")
177
178
179def parse_define(bits, line):
180    m = re.match(r"^#define\s+(\w+)\s+(\w+)", line)
181    if m is None:
182        return
183
184    name = m.group(1)
185
186    try:
187        value = int(m.group(2), 0)
188    except ValueError:
189        return
190
191    for prefix in prefixes:
192        if not name.startswith(prefix):
193            continue
194
195        if name.endswith("_MAX"):
196            bits.max_codes[name] = value
197
198        if name in duplicates:
199            return
200
201        attrname = prefix[:-1].lower()
202
203        if not hasattr(bits, attrname):
204            setattr(bits, attrname, {})
205        b = getattr(bits, attrname)
206        b[value] = name
207
208
209def parse(lines):
210    bits = Bits()
211    for line in lines:
212        if not line.startswith("#define"):
213            continue
214        parse_define(bits, line)
215
216    return bits
217
218
219def usage(prog):
220    print("Usage: %s <files>".format(prog))
221
222
223if __name__ == "__main__":
224    if len(sys.argv) <= 1:
225        usage(sys.argv[0])
226        sys.exit(2)
227
228    from itertools import chain
229    lines = chain(*[open(f).readlines() for f in sys.argv[1:]])
230    bits = parse(lines)
231    print_mapping_table(bits)
232