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