]> git.proxmox.com Git - pve-qemu.git/blob - keycodemapdb/tools/keymap-gen
bump version to 2.11.1-1
[pve-qemu.git] / keycodemapdb / tools / keymap-gen
1 #!/usr/bin/python
2 # -*- python -*-
3 #
4 # Keycode Map Generator
5 #
6 # Copyright (C) 2009-2017 Red Hat, Inc.
7 #
8 # This file is dual license under the terms of the GPLv2 or later
9 # and 3-clause BSD licenses.
10 #
11
12 # Requires >= 2.6
13 from __future__ import print_function
14
15 import csv
16 try:
17 import argparse
18 except:
19 import os, sys
20 sys.path.append(os.path.join(os.path.dirname(__file__), "../thirdparty"))
21 import argparse
22 import hashlib
23 import time
24 import sys
25
26 class Database:
27
28 # Linux: linux/input.h
29 MAP_LINUX = "linux"
30
31 # OS-X: Carbon/HIToolbox/Events.h
32 MAP_OSX = "osx"
33
34 # AT Set 1: linux/drivers/input/keyboard/atkbd.c
35 # (atkbd_set2_keycode + atkbd_unxlate_table)
36 MAP_ATSET1 = "atset1"
37
38 # AT Set 2: linux/drivers/input/keyboard/atkbd.c
39 # (atkbd_set2_keycode)
40 MAP_ATSET2 = "atset2"
41
42 # AT Set 3: linux/drivers/input/keyboard/atkbd.c
43 # (atkbd_set3_keycode)
44 MAP_ATSET3 = "atset3"
45
46 # Linux RAW: linux/drivers/char/keyboard.c (x86_keycodes)
47 MAP_XTKBD = "xtkbd"
48
49 # USB HID: linux/drivers/hid/usbhid/usbkbd.c (usb_kbd_keycode)
50 MAP_USB = "usb"
51
52 # Win32: mingw32/winuser.h
53 MAP_WIN32 = "win32"
54
55 # XWin XT: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h}
56 # (xt + manually transcribed)
57 MAP_XWINXT = "xwinxt"
58
59 # X11: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
60 MAP_X11 = "x11"
61
62 # XKBD XT: xf86-input-keyboard/src/at_scancode.c
63 # (xt + manually transcribed)
64 MAP_XKBDXT = "xkbdxt"
65
66 # Xorg with evdev: linux + an offset
67 MAP_XORGEVDEV = "xorgevdev"
68
69 # Xorg with kbd: xkbdxt + an offset
70 MAP_XORGKBD = "xorgkbd"
71
72 # Xorg with OS-X: osx + an offset
73 MAP_XORGXQUARTZ = "xorgxquartz"
74
75 # Xorg + Cygwin: xwinxt + an offset
76 MAP_XORGXWIN = "xorgxwin"
77
78 # QEMU key numbers: xtkbd + special re-encoding of high bit
79 MAP_QNUM = "qnum"
80
81 # HTML codes
82 MAP_HTML = "html"
83
84 # XKB key names
85 MAP_XKB = "xkb"
86
87 # QEMU keycodes
88 MAP_QCODE = "qcode"
89
90 # Sun / Sparc scan codes
91 # Reference: "SPARC International Keyboard Spec 1", page 7 "US scan set"
92 MAP_SUN = "sun"
93
94 # Apple Desktop Bus
95 # Reference: http://www.archive.org/stream/apple-guide-macintosh-family-hardware/Apple_Guide_to_the_Macintosh_Family_Hardware_2e#page/n345/mode/2up
96 MAP_ADB = "adb"
97
98 MAP_LIST = (
99 MAP_LINUX,
100 MAP_OSX,
101 MAP_ATSET1,
102 MAP_ATSET2,
103 MAP_ATSET3,
104 MAP_USB,
105 MAP_WIN32,
106 MAP_XWINXT,
107 MAP_XKBDXT,
108 MAP_X11,
109 MAP_HTML,
110 MAP_XKB,
111 MAP_QCODE,
112 MAP_SUN,
113 MAP_ADB,
114
115 # These are derived from maps above
116 MAP_XTKBD,
117 MAP_XORGEVDEV,
118 MAP_XORGKBD,
119 MAP_XORGXQUARTZ,
120 MAP_XORGXWIN,
121 MAP_QNUM,
122 )
123
124 CODE_COLUMNS = {
125 MAP_LINUX: 1,
126 MAP_OSX: 3,
127 MAP_ATSET1: 4,
128 MAP_ATSET2: 5,
129 MAP_ATSET3: 6,
130 MAP_USB: 7,
131 MAP_WIN32: 9,
132 MAP_XWINXT: 10,
133 MAP_XKBDXT: 11,
134 MAP_X11: 13,
135 MAP_HTML: 14,
136 MAP_XKB: 15,
137 MAP_SUN: 17,
138 MAP_ADB: 18,
139 }
140
141 ENUM_COLUMNS = {
142 MAP_QCODE: 14,
143 }
144
145 NAME_COLUMNS = {
146 MAP_LINUX: 0,
147 MAP_OSX: 2,
148 MAP_WIN32: 8,
149 MAP_X11: 12,
150 MAP_HTML: 14,
151 MAP_XKB: 15,
152 MAP_QCODE: 16,
153 }
154
155 ENUM_BOUND = {
156 MAP_QCODE: "Q_KEY_CODE__MAX",
157 }
158
159 def __init__(self):
160
161 self.mapto = {}
162 self.mapfrom = {}
163 self.mapname = {}
164 self.mapchecksum = None
165
166 for name in self.MAP_LIST:
167 # Key is a MAP_LINUX, value is a MAP_XXX
168 self.mapto[name] = {}
169 # key is a MAP_XXX, value is a MAP_LINUX
170 self.mapfrom[name] = {}
171
172 for name in self.NAME_COLUMNS.keys():
173 # key is a MAP_LINUX, value is a string
174 self.mapname[name] = {}
175
176 def _generate_checksum(self, filename):
177 hash = hashlib.sha256()
178 with open(filename, "rb") as f:
179 for chunk in iter(lambda: f.read(4096), b""):
180 hash.update(chunk)
181 self.mapchecksum = hash.hexdigest()
182
183 def load(self, filename):
184 self._generate_checksum(filename)
185
186 with open(filename, 'r') as f:
187 reader = csv.reader(f)
188
189 first = True
190
191 for row in reader:
192 # Discard column headings
193 if first:
194 first = False
195 continue
196
197 # We special case MAP_LINUX since that is out
198 # master via which all other mappings are done
199 linux = self.load_linux(row)
200
201 # Now load all the remaining master data values
202 self.load_data(row, linux)
203
204 # Then load all the keycode names
205 self.load_names(row, linux)
206
207 # Finally calculate derived key maps
208 self.derive_data(row, linux)
209
210 def load_linux(self, row):
211 col = self.CODE_COLUMNS[self.MAP_LINUX]
212 linux = row[col]
213
214 if linux.startswith("0x"):
215 linux = int(linux, 16)
216 else:
217 linux = int(linux, 10)
218
219 self.mapto[self.MAP_LINUX][linux] = linux
220 self.mapfrom[self.MAP_LINUX][linux] = linux
221
222 return linux
223
224
225 def load_data(self, row, linux):
226 for mapname in self.CODE_COLUMNS:
227 if mapname == self.MAP_LINUX:
228 continue
229
230 col = self.CODE_COLUMNS[mapname]
231 val = row[col]
232
233 if val == "":
234 continue
235
236 if val.startswith("0x"):
237 val = int(val, 16)
238 elif val.isdigit():
239 val = int(val, 10)
240
241 self.mapto[mapname][linux] = val
242 self.mapfrom[mapname][val] = linux
243
244 def load_names(self, row, linux):
245 for mapname in self.NAME_COLUMNS:
246 col = self.NAME_COLUMNS[mapname]
247 val = row[col]
248
249 if val == "":
250 continue
251
252 self.mapname[mapname][linux] = val
253
254
255 def derive_data(self, row, linux):
256 # Linux RAW is XT scan codes with special encoding of the
257 # 0xe0 scan codes
258 if linux in self.mapto[self.MAP_ATSET1]:
259 at1 = self.mapto[self.MAP_ATSET1][linux]
260 if at1 > 0x7f:
261 assert((at1 & ~0x7f) == 0xe000)
262 xtkbd = 0x100 | (at1 & 0x7f)
263 else:
264 xtkbd = at1
265 self.mapto[self.MAP_XTKBD][linux] = xtkbd
266 self.mapfrom[self.MAP_XTKBD][xtkbd] = linux
267
268 # Xorg KBD is XKBD XT offset by 8
269 if linux in self.mapto[self.MAP_XKBDXT]:
270 xorgkbd = self.mapto[self.MAP_XKBDXT][linux] + 8
271 self.mapto[self.MAP_XORGKBD][linux] = xorgkbd
272 self.mapfrom[self.MAP_XORGKBD][xorgkbd] = linux
273
274 # Xorg evdev is Linux offset by 8
275 self.mapto[self.MAP_XORGEVDEV][linux] = linux + 8
276 self.mapfrom[self.MAP_XORGEVDEV][linux + 8] = linux
277
278 # Xorg XQuartx is OS-X offset by 8
279 if linux in self.mapto[self.MAP_OSX]:
280 xorgxquartz = self.mapto[self.MAP_OSX][linux] + 8
281 self.mapto[self.MAP_XORGXQUARTZ][linux] = xorgxquartz
282 self.mapfrom[self.MAP_XORGXQUARTZ][xorgxquartz] = linux
283
284 # Xorg Xwin (aka Cygwin) is XWin XT offset by 8
285 if linux in self.mapto[self.MAP_XWINXT]:
286 xorgxwin = self.mapto[self.MAP_XWINXT][linux] + 8
287 self.mapto[self.MAP_XORGXWIN][linux] = xorgxwin
288 self.mapfrom[self.MAP_XORGXWIN][xorgxwin] = linux
289
290 # QNUM keycodes are XT scan codes with a slightly
291 # different encoding of 0xe0 scan codes
292 if linux in self.mapto[self.MAP_ATSET1]:
293 at1 = self.mapto[self.MAP_ATSET1][linux]
294 if at1 > 0x7f:
295 assert((at1 & ~0x7f) == 0xe000)
296 qnum = 0x80 | (at1 & 0x7f)
297 else:
298 qnum = at1
299 self.mapto[self.MAP_QNUM][linux] = qnum
300 self.mapfrom[self.MAP_QNUM][qnum] = linux
301
302 # Hack for compatibility with previous mistakes in handling
303 # Print/SysRq. The preferred qnum for Print/SysRq is 0x54,
304 # but QEMU previously allowed 0xb7 too
305 if qnum == 0x54:
306 self.mapfrom[self.MAP_QNUM][0xb7] = self.mapfrom[self.MAP_QNUM][0x54]
307
308 if linux in self.mapname[self.MAP_QCODE]:
309 qcodeenum = self.mapname[self.MAP_QCODE][linux]
310 qcodeenum = "Q_KEY_CODE_" + qcodeenum.upper()
311 self.mapto[self.MAP_QCODE][linux] = qcodeenum
312 self.mapfrom[self.MAP_QCODE][qcodeenum] = linux
313
314 class LanguageGenerator(object):
315
316 def _boilerplate(self, lines):
317 raise NotImplementedError()
318
319 def generate_header(self, database, args):
320 today = time.strftime("%Y-%m-%d %H:%M")
321 self._boilerplate([
322 "This file is auto-generated from keymaps.csv on %s" % today,
323 "Database checksum sha256(%s)" % database.mapchecksum,
324 "To re-generate, run:",
325 " %s" % args,
326 ])
327
328 class LanguageSrcGenerator(LanguageGenerator):
329
330 TYPE_INT = "integer"
331 TYPE_STRING = "string"
332 TYPE_ENUM = "enum"
333
334 def _array_start(self, varname, length, defvalue, fromtype, totype):
335 raise NotImplementedError()
336
337 def _array_end(self, fromtype, totype):
338 raise NotImplementedError()
339
340 def _array_entry(self, index, value, comment, fromtype, totype):
341 raise NotImplementedError()
342
343 def generate_code_map(self, varname, database, frommapname, tomapname):
344 if frommapname not in database.mapfrom:
345 raise Exception("Unknown map %s, expected one of %s" % (
346 frommapname, ", ".join(database.mapfrom.keys())))
347 if tomapname not in database.mapto:
348 raise Exception("Unknown map %s, expected one of %s" % (
349 tomapname, ", ".join(database.mapto.keys())))
350
351 tolinux = database.mapfrom[frommapname]
352 fromlinux = database.mapto[tomapname]
353
354 if varname is None:
355 varname = "code_map_%s_to_%s" % (frommapname, tomapname)
356
357 if frommapname in database.ENUM_COLUMNS:
358 fromtype = self.TYPE_ENUM
359 elif type(tolinux.keys()[0]) == str:
360 fromtype = self.TYPE_STRING
361 else:
362 fromtype = self.TYPE_INT
363
364 if tomapname in database.ENUM_COLUMNS:
365 totype = self.TYPE_ENUM
366 elif type(fromlinux.values()[0]) == str:
367 totype = self.TYPE_STRING
368 else:
369 totype = self.TYPE_INT
370
371 keys = tolinux.keys()
372 keys.sort()
373 if fromtype == self.TYPE_INT:
374 keys = range(keys[-1] + 1)
375
376 if fromtype == self.TYPE_ENUM:
377 keymax = database.ENUM_BOUND[frommapname]
378 else:
379 keymax = len(keys)
380
381 defvalue = fromlinux.get(0, None)
382 if fromtype == self.TYPE_ENUM:
383 self._array_start(varname, keymax, defvalue, fromtype, totype)
384 else:
385 self._array_start(varname, keymax, None, fromtype, totype)
386
387 for src in keys:
388 linux = tolinux.get(src, None)
389 if linux is None:
390 dst = None
391 else:
392 dst = fromlinux.get(linux, defvalue)
393
394 comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
395 self._label(database, Database.MAP_LINUX, linux, linux),
396 self._label(database, tomapname, dst, linux))
397 self._array_entry(src, dst, comment, fromtype, totype)
398 self._array_end(fromtype, totype)
399
400 def generate_code_table(self, varname, database, mapname):
401 if mapname not in database.mapto:
402 raise Exception("Unknown map %s, expected one of %s" % (
403 mapname, ", ".join(database.mapto.keys())))
404
405 keys = database.mapto[Database.MAP_LINUX].keys()
406 keys.sort()
407 names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
408
409 if varname is None:
410 varname = "code_table_%s" % mapname
411
412 if mapname in database.ENUM_COLUMNS:
413 totype = self.TYPE_ENUM
414 elif type(database.mapto[mapname].values()[0]) == str:
415 totype = self.TYPE_STRING
416 else:
417 totype = self.TYPE_INT
418
419 self._array_start(varname, len(keys), None, self.TYPE_INT, totype)
420
421 defvalue = database.mapto[mapname].get(0, None)
422 for i in range(len(keys)):
423 key = keys[i]
424 dst = database.mapto[mapname].get(key, defvalue)
425 self._array_entry(i, dst, names[i], self.TYPE_INT, totype)
426
427 self._array_end(self.TYPE_INT, totype)
428
429 def generate_name_map(self, varname, database, frommapname, tomapname):
430 if frommapname not in database.mapfrom:
431 raise Exception("Unknown map %s, expected one of %s" % (
432 frommapname, ", ".join(database.mapfrom.keys())))
433 if tomapname not in database.mapname:
434 raise Exception("Unknown map %s, expected one of %s" % (
435 tomapname, ", ".join(database.mapname.keys())))
436
437 tolinux = database.mapfrom[frommapname]
438 fromlinux = database.mapname[tomapname]
439
440 if varname is None:
441 varname = "name_map_%s_to_%s" % (frommapname, tomapname)
442
443 keys = tolinux.keys()
444 keys.sort()
445 if type(keys[0]) == int:
446 keys = range(keys[-1] + 1)
447
448 if type(keys[0]) == int:
449 fromtype = self.TYPE_INT
450 else:
451 fromtype = self.TYPE_STRING
452
453 self._array_start(varname, len(keys), None, fromtype, self.TYPE_STRING)
454
455 for src in keys:
456 linux = tolinux.get(src, None)
457 if linux is None:
458 dst = None
459 else:
460 dst = fromlinux.get(linux, None)
461
462 comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
463 self._label(database, Database.MAP_LINUX, linux, linux),
464 self._label(database, tomapname, dst, linux))
465 self._array_entry(src, dst, comment, fromtype, self.TYPE_STRING)
466 self._array_end(fromtype, self.TYPE_STRING)
467
468 def generate_name_table(self, varname, database, mapname):
469 if mapname not in database.mapname:
470 raise Exception("Unknown map %s, expected one of %s" % (
471 mapname, ", ".join(database.mapname.keys())))
472
473 keys = database.mapto[Database.MAP_LINUX].keys()
474 keys.sort()
475 names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
476
477 if varname is None:
478 varname = "name_table_%s" % mapname
479
480 self._array_start(varname, len(keys), None, self.TYPE_INT, self.TYPE_STRING)
481
482 for i in range(len(keys)):
483 key = keys[i]
484 dst = database.mapname[mapname].get(key, None)
485 self._array_entry(i, dst, names[i], self.TYPE_INT, self.TYPE_STRING)
486
487 self._array_end(self.TYPE_INT, self.TYPE_STRING)
488
489 def _label(self, database, mapname, val, linux):
490 if mapname in database.mapname:
491 return "%s:%s (%s)" % (mapname, val, database.mapname[mapname].get(linux, "unnamed"))
492 else:
493 return "%s:%s" % (mapname, val)
494
495 class LanguageDocGenerator(LanguageGenerator):
496
497 def _array_start_name_doc(self, varname, namemap):
498 raise NotImplementedError()
499
500 def _array_start_code_doc(self, varname, namemap, codemap):
501 raise NotImplementedError()
502
503 def _array_end(self):
504 raise NotImplementedError()
505
506 def _array_name_entry(self, value, name):
507 raise NotImplementedError()
508
509 def _array_code_entry(self, value, name):
510 raise NotImplementedError()
511
512 def generate_name_docs(self, varname, database, mapname):
513 if mapname not in database.mapname:
514 raise Exception("Unknown map %s, expected one of %s" % (
515 mapname, ", ".join(database.mapname.keys())))
516
517 keys = database.mapto[Database.MAP_LINUX].keys()
518 keys.sort()
519 names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
520
521 if varname is None:
522 varname = mapname
523
524 self._array_start_name_doc(varname, mapname)
525
526 for i in range(len(keys)):
527 key = keys[i]
528 dst = database.mapname[mapname].get(key, None)
529 self._array_name_entry(key, dst)
530
531 self._array_end()
532
533
534 def generate_code_docs(self, varname, database, mapname):
535 if mapname not in database.mapfrom:
536 raise Exception("Unknown map %s, expected one of %s" % (
537 mapname, ", ".join(database.mapfrom.keys())))
538
539 tolinux = database.mapfrom[mapname]
540 keys = tolinux.keys()
541 keys.sort()
542 if mapname in database.mapname:
543 names = database.mapname[mapname]
544 namemap = mapname
545 else:
546 names = database.mapname[Database.MAP_LINUX]
547 namemap = Database.MAP_LINUX
548
549 if varname is None:
550 varname = mapname
551
552 self._array_start_code_doc(varname, mapname, namemap)
553
554 for i in range(len(keys)):
555 key = keys[i]
556 self._array_code_entry(key, names.get(tolinux[key], "unnamed"))
557
558 self._array_end()
559
560 class CLanguageGenerator(LanguageSrcGenerator):
561
562 def __init__(self, inttypename, strtypename, lentypename):
563 self.inttypename = inttypename
564 self.strtypename = strtypename
565 self.lentypename = lentypename
566
567 def _boilerplate(self, lines):
568 print("/*")
569 for line in lines:
570 print(" * %s" % line)
571 print("*/")
572
573 def _array_start(self, varname, length, defvalue, fromtype, totype):
574 self._varname = varname;
575 totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
576 if fromtype in (self.TYPE_INT, self.TYPE_ENUM):
577 if type(length) == str:
578 print("const %s %s[%s] = {" % (totypename, varname, length))
579 else:
580 print("const %s %s[%d] = {" % (totypename, varname, length))
581 else:
582 print("const struct _%s {" % varname)
583 print(" const %s from;" % self.strtypename)
584 print(" const %s to;" % totypename)
585 print("} %s[] = {" % varname)
586
587 if defvalue != None:
588 if totype == self.TYPE_ENUM:
589 if type(length) == str:
590 print(" [0 ... %s-1] = %s," % (length, defvalue))
591 else:
592 print(" [0 ... 0x%x-1] = %s," % (length, defvalue))
593 else:
594 if type(length) == str:
595 print(" [0 ... %s-1] = 0x%x," % (length, defvalue))
596 else:
597 print(" [0 ... 0x%x-1] = 0x%x," % (length, defvalue))
598
599 def _array_end(self, fromtype, totype):
600 print("};")
601 print("const %s %s_len = sizeof(%s)/sizeof(%s[0]);" %
602 (self.lentypename, self._varname, self._varname, self._varname))
603
604 def _array_entry(self, index, value, comment, fromtype, totype):
605 if value is None:
606 return
607 if fromtype == self.TYPE_INT:
608 indexfmt = "0x%x"
609 elif fromtype == self.TYPE_ENUM:
610 indexfmt = "%s"
611 else:
612 indexfmt = "\"%s\""
613
614 if totype == self.TYPE_INT:
615 valuefmt = "0x%x"
616 elif totype == self.TYPE_ENUM:
617 valuefmt = "%s"
618 else:
619 valuefmt = "\"%s\""
620
621 if fromtype != self.TYPE_STRING:
622 print((" [" + indexfmt + "] = " + valuefmt + ", /* %s */") % (index, value, comment))
623 else:
624 print((" {" + indexfmt + ", " + valuefmt + "}, /* %s */") % (index, value, comment))
625
626 class CppLanguageGenerator(CLanguageGenerator):
627
628 def _array_start(self, varname, length, defvalue, fromtype, totype):
629 if fromtype == self.TYPE_ENUM:
630 raise NotImplementedError("Enums not supported as source in C++ generator")
631 totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
632 if fromtype == self.TYPE_INT:
633 print("#include <vector>")
634 print("const std::vector<%s> %s = {" % (totypename, varname))
635 else:
636 print("#include <map>")
637 print("#include <string>")
638 print("const std::map<const std::string, %s> %s = {" % (totypename, varname))
639
640 def _array_end(self, fromtype, totype):
641 print("};")
642
643 # designated initializers not available in C++
644 def _array_entry(self, index, value, comment, fromtype, totype):
645 if fromtype == self.TYPE_STRING:
646 return super(CppLanguageGenerator, self)._array_entry(index, value, comment, fromtype, totype)
647
648 if value is None:
649 print(" 0, /* %s */" % comment)
650 elif totype == self.TYPE_INT:
651 print(" 0x%x, /* %s */" % (value, comment))
652 elif totype == self.TYPE_ENUM:
653 print(" %s, /* %s */" % (value, comment))
654 else:
655 print(" \"%s\", /* %s */" % (value, comment))
656
657 class StdCLanguageGenerator(CLanguageGenerator):
658
659 def __init__(self):
660 super(StdCLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
661
662 class StdCppLanguageGenerator(CppLanguageGenerator):
663
664 def __init__(self):
665 super(StdCppLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
666
667 class GLib2LanguageGenerator(CLanguageGenerator):
668
669 def __init__(self):
670 super(GLib2LanguageGenerator, self).__init__("guint16", "gchar *", "guint")
671
672 class PythonLanguageGenerator(LanguageSrcGenerator):
673
674 def _boilerplate(self, lines):
675 print("#")
676 for line in lines:
677 print("# %s" % line)
678 print("#")
679
680 def _array_start(self, varname, length, defvalue, fromtype, totype):
681 if fromtype == self.TYPE_ENUM:
682 raise NotImplementedError("Enums not supported as source in Python generator")
683
684 if fromtype != self.TYPE_STRING:
685 print("%s = [" % varname)
686 else:
687 print("%s = {" % varname)
688
689 def _array_end(self, fromtype, totype):
690 if fromtype != self.TYPE_STRING:
691 print("]")
692 else:
693 print("}")
694
695 def _array_entry(self, index, value, comment, fromtype, totype):
696 if fromtype == self.TYPE_INT:
697 if value is None:
698 print(" None, # %s" % (comment))
699 elif totype == self.TYPE_INT:
700 print(" 0x%x, # %s" % (value, comment))
701 elif totype == self.TYPE_ENUM:
702 print(" %s, # %s" % (value, comment))
703 else:
704 print(" \"%s\", # %s" % (value, comment))
705 else:
706 if value is None:
707 print(" \"%s\": None, # %s" % (index, comment))
708 elif totype == self.TYPE_INT:
709 print(" \"%s\": 0x%x, # %s" % (index, value, comment))
710 elif totype == self.TYPE_ENUM:
711 print(" \"%s\": %s, # %s" % (index, value, comment))
712 else:
713 print(" \"%s\": \"%s\", # %s" % (index, value, comment))
714
715 class PerlLanguageGenerator(LanguageSrcGenerator):
716
717 def _boilerplate(self, lines):
718 print("#")
719 for line in lines:
720 print("# %s" % line)
721 print("#")
722
723 def _array_start(self, varname, length, defvalue, fromtype, totype):
724 if fromtype == self.TYPE_ENUN:
725 raise NotImplementedError("Enums not supported as source in Python generator")
726 if fromtype == self.TYPE_INT:
727 print("my @%s = (" % varname)
728 else:
729 print("my %%%s = (" % varname)
730
731 def _array_end(self, fromtype, totype):
732 print(");")
733
734 def _array_entry(self, index, value, comment, fromtype, totype):
735 if fromtype == self.TYPE_INT:
736 if value is None:
737 print(" undef, # %s" % (comment))
738 elif totype == self.TYPE_INT:
739 print(" 0x%x, # %s" % (value, comment))
740 elif totype == self.TYPE_ENUM:
741 print(" %s, # %s" % (value, comment))
742 else:
743 print(" \"%s\", # %s" % (value, comment))
744 else:
745 if value is None:
746 print(" \"%s\", undef, # %s" % (index, comment))
747 elif totype == self.TYPE_INT:
748 print(" \"%s\", 0x%x, # %s" % (index, value, comment))
749 elif totype == self.TYPE_ENUM:
750 print(" \"%s\", 0x%x, # %s" % (index, value, comment))
751 else:
752 print(" \"%s\", \"%s\", # %s" % (index, value, comment))
753
754 class JavaScriptLanguageGenerator(LanguageSrcGenerator):
755
756 def _boilerplate(self, lines):
757 print("/*")
758 for line in lines:
759 print(" * %s" % line)
760 print("*/")
761
762 def _array_start(self, varname, length, defvalue, fromtype, totype):
763 print("export default {")
764
765 def _array_end(self, fromtype, totype):
766 print("};")
767
768 def _array_entry(self, index, value, comment, fromtype, totype):
769 if value is None:
770 return
771
772 if fromtype == self.TYPE_INT:
773 fromfmt = "0x%x"
774 elif fromtype == self.TYPE_ENUM:
775 fromfmt = "%s"
776 else:
777 fromfmt = "\"%s\""
778
779 if totype == self.TYPE_INT:
780 tofmt = "0x%x"
781 elif totype == self.TYPE_ENUM:
782 tofmt = "%s"
783 else:
784 tofmt = "\"%s\""
785
786 print((" " + fromfmt + ": " + tofmt + ", /* %s */") % (index, value, comment))
787
788 class PodLanguageGenerator(LanguageDocGenerator):
789
790 def _boilerplate(self, lines):
791 print("#")
792 for line in lines:
793 print("# %s" % line)
794 print("#")
795
796 def _array_start_name_doc(self, varname, namemap):
797 print("=head1 %s" % varname)
798 print("")
799 print("List of %s key code names, with corresponding key code values" % namemap)
800 print("")
801 print("=over 4")
802 print("")
803
804 def _array_start_code_doc(self, varname, codemap, namemap):
805 print("=head1 %s" % varname)
806 print("")
807 print("List of %s key code values, with corresponding %s key code names" % (codemap, namemap))
808 print("")
809 print("=over 4")
810 print("")
811
812 def _array_end(self):
813 print("=back")
814 print("")
815
816 def _array_name_entry(self, value, name):
817 print("=item %s" % name)
818 print("")
819 print("Key value %d (0x%x)" % (value, value))
820 print("")
821
822 def _array_code_entry(self, value, name):
823 print("=item %d (0x%x)" % (value, value))
824 print("")
825 print("Key name %s" % name)
826 print("")
827
828 SRC_GENERATORS = {
829 "stdc": StdCLanguageGenerator(),
830 "stdc++": StdCppLanguageGenerator(),
831 "glib2": GLib2LanguageGenerator(),
832 "python2": PythonLanguageGenerator(),
833 "python3": PythonLanguageGenerator(),
834 "perl": PerlLanguageGenerator(),
835 "js": JavaScriptLanguageGenerator(),
836 }
837 DOC_GENERATORS = {
838 "pod": PodLanguageGenerator(),
839 }
840
841 def code_map(args):
842 database = Database()
843 database.load(args.keymaps)
844
845 cliargs = ["keymap-gen", "--lang=%s" % args.lang]
846 if args.varname is not None:
847 cliargs.append("--varname=%s" % args.varname)
848 cliargs.extend(["code-map", "keymaps.csv", args.frommapname, args.tomapname])
849 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
850
851 SRC_GENERATORS[args.lang].generate_code_map(args.varname, database, args.frommapname, args.tomapname)
852
853 def code_table(args):
854 database = Database()
855 database.load(args.keymaps)
856
857 cliargs = ["keymap-gen", "--lang=%s" % args.lang]
858 if args.varname is not None:
859 cliargs.append("--varname=%s" % args.varname)
860 cliargs.extend(["code-table", "keymaps.csv", args.mapname])
861 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
862
863 SRC_GENERATORS[args.lang].generate_code_table(args.varname, database, args.mapname)
864
865 def name_map(args):
866 database = Database()
867 database.load(args.keymaps)
868
869 cliargs = ["keymap-gen", "--lang=%s" % args.lang]
870 if args.varname is not None:
871 cliargs.append("--varname=%s" % args.varname)
872 cliargs.extend(["name-map", "keymaps.csv", args.frommapname, args.tomapname])
873 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
874
875 SRC_GENERATORS[args.lang].generate_name_map(args.varname, database, args.frommapname, args.tomapname)
876
877 def name_table(args):
878 database = Database()
879 database.load(args.keymaps)
880
881
882 cliargs = ["keymap-gen", "--lang=%s" % args.lang]
883 if args.varname is not None:
884 cliargs.append("--varname=%s" % args.varname)
885 cliargs.extend(["name-table", "keymaps.csv", args.mapname])
886 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
887
888 SRC_GENERATORS[args.lang].generate_name_table(args.varname, database, args.mapname)
889
890 def code_docs(args):
891 database = Database()
892 database.load(args.keymaps)
893
894
895 cliargs = ["keymap-gen", "--lang=%s" % args.lang]
896 if args.varname is not None:
897 cliargs.append("--varname=%s" % args.varname)
898 cliargs.extend(["code-docs", "keymaps.csv", args.mapname])
899 DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
900
901 DOC_GENERATORS[args.lang].generate_code_docs(args.varname, database, args.mapname)
902
903 def name_docs(args):
904 database = Database()
905 database.load(args.keymaps)
906
907
908 cliargs = ["keymap-gen", "--lang=%s" % args.lang]
909 if args.varname is not None:
910 cliargs.append("--varname=%s" % args.varname)
911 cliargs.extend(["name-docs", "keymaps.csv", args.mapname])
912 DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
913
914 DOC_GENERATORS[args.lang].generate_name_docs(args.varname, database, args.mapname)
915
916 def usage():
917 print ("Please select a command:")
918 print (" 'code-map', 'code-table', 'name-map', 'name-table', 'docs'")
919 sys.exit(1)
920
921 def main():
922 parser = argparse.ArgumentParser()
923
924 parser.add_argument("--lang", default="stdc",
925 help="Output language, (src=%s, doc=%s)" % (
926 ",".join(SRC_GENERATORS.keys()),
927 ",".join(DOC_GENERATORS.keys())))
928 parser.add_argument("--varname", default=None,
929 help="Data variable name")
930
931 subparsers = parser.add_subparsers(help="sub-command help")
932
933 codemapparser = subparsers.add_parser("code-map", help="Generate a mapping between code tables")
934 codemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
935 codemapparser.add_argument("frommapname", help="Source code table name")
936 codemapparser.add_argument("tomapname", help="Target code table name")
937 codemapparser.set_defaults(func=code_map)
938
939 codetableparser = subparsers.add_parser("code-table", help="Generate a flat code table")
940 codetableparser.add_argument("keymaps", help="Path to keymap CSV data file")
941 codetableparser.add_argument("mapname", help="Code table name")
942 codetableparser.set_defaults(func=code_table)
943
944 namemapparser = subparsers.add_parser("name-map", help="Generate a mapping to names")
945 namemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
946 namemapparser.add_argument("frommapname", help="Source code table name")
947 namemapparser.add_argument("tomapname", help="Target name table name")
948 namemapparser.set_defaults(func=name_map)
949
950 nametableparser = subparsers.add_parser("name-table", help="Generate a flat name table")
951 nametableparser.add_argument("keymaps", help="Path to keymap CSV data file")
952 nametableparser.add_argument("mapname", help="Name table name")
953 nametableparser.set_defaults(func=name_table)
954
955 codedocsparser = subparsers.add_parser("code-docs", help="Generate code documentation")
956 codedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
957 codedocsparser.add_argument("mapname", help="Code table name")
958 codedocsparser.set_defaults(func=code_docs)
959
960 namedocsparser = subparsers.add_parser("name-docs", help="Generate name documentation")
961 namedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
962 namedocsparser.add_argument("mapname", help="Name table name")
963 namedocsparser.set_defaults(func=name_docs)
964
965 args = parser.parse_args()
966 if hasattr(args, "func"):
967 args.func(args)
968 else:
969 usage()
970
971
972 main()