]> git.proxmox.com Git - pve-qemu.git/blame - keycodemapdb/tools/keymap-gen
buildsys: fixup submodule target
[pve-qemu.git] / keycodemapdb / tools / keymap-gen
CommitLineData
6838f038
WB
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
13from __future__ import print_function
14
15import csv
16try:
17 import argparse
18except:
19 import os, sys
20 sys.path.append(os.path.join(os.path.dirname(__file__), "../thirdparty"))
21 import argparse
22import hashlib
23import time
24import sys
25
26class 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
314class LanguageGenerator(object):
315
316 def _boilerplate(self, lines):
317 raise NotImplementedError()
318
319 def generate_header(self, database, args):
6838f038 320 self._boilerplate([
263fef5b 321 "This file is auto-generated from keymaps.csv",
6838f038
WB
322 "Database checksum sha256(%s)" % database.mapchecksum,
323 "To re-generate, run:",
324 " %s" % args,
325 ])
326
327class LanguageSrcGenerator(LanguageGenerator):
328
329 TYPE_INT = "integer"
330 TYPE_STRING = "string"
331 TYPE_ENUM = "enum"
332
333 def _array_start(self, varname, length, defvalue, fromtype, totype):
334 raise NotImplementedError()
335
336 def _array_end(self, fromtype, totype):
337 raise NotImplementedError()
338
339 def _array_entry(self, index, value, comment, fromtype, totype):
340 raise NotImplementedError()
341
342 def generate_code_map(self, varname, database, frommapname, tomapname):
343 if frommapname not in database.mapfrom:
344 raise Exception("Unknown map %s, expected one of %s" % (
345 frommapname, ", ".join(database.mapfrom.keys())))
346 if tomapname not in database.mapto:
347 raise Exception("Unknown map %s, expected one of %s" % (
348 tomapname, ", ".join(database.mapto.keys())))
349
350 tolinux = database.mapfrom[frommapname]
351 fromlinux = database.mapto[tomapname]
352
353 if varname is None:
354 varname = "code_map_%s_to_%s" % (frommapname, tomapname)
355
356 if frommapname in database.ENUM_COLUMNS:
357 fromtype = self.TYPE_ENUM
53e83913 358 elif type(list(tolinux.keys())[0]) == str:
6838f038
WB
359 fromtype = self.TYPE_STRING
360 else:
361 fromtype = self.TYPE_INT
362
363 if tomapname in database.ENUM_COLUMNS:
364 totype = self.TYPE_ENUM
53e83913 365 elif type(list(fromlinux.values())[0]) == str:
6838f038
WB
366 totype = self.TYPE_STRING
367 else:
368 totype = self.TYPE_INT
369
53e83913 370 keys = list(tolinux.keys())
6838f038
WB
371 keys.sort()
372 if fromtype == self.TYPE_INT:
373 keys = range(keys[-1] + 1)
374
375 if fromtype == self.TYPE_ENUM:
376 keymax = database.ENUM_BOUND[frommapname]
377 else:
378 keymax = len(keys)
379
380 defvalue = fromlinux.get(0, None)
381 if fromtype == self.TYPE_ENUM:
382 self._array_start(varname, keymax, defvalue, fromtype, totype)
383 else:
384 self._array_start(varname, keymax, None, fromtype, totype)
385
386 for src in keys:
387 linux = tolinux.get(src, None)
388 if linux is None:
389 dst = None
390 else:
391 dst = fromlinux.get(linux, defvalue)
392
393 comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
394 self._label(database, Database.MAP_LINUX, linux, linux),
395 self._label(database, tomapname, dst, linux))
396 self._array_entry(src, dst, comment, fromtype, totype)
397 self._array_end(fromtype, totype)
398
399 def generate_code_table(self, varname, database, mapname):
400 if mapname not in database.mapto:
401 raise Exception("Unknown map %s, expected one of %s" % (
402 mapname, ", ".join(database.mapto.keys())))
403
53e83913 404 keys = list(database.mapto[Database.MAP_LINUX].keys())
6838f038
WB
405 keys.sort()
406 names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
407
408 if varname is None:
409 varname = "code_table_%s" % mapname
410
411 if mapname in database.ENUM_COLUMNS:
412 totype = self.TYPE_ENUM
53e83913 413 elif type(list(database.mapto[mapname].values())[0]) == str:
6838f038
WB
414 totype = self.TYPE_STRING
415 else:
416 totype = self.TYPE_INT
417
418 self._array_start(varname, len(keys), None, self.TYPE_INT, totype)
419
420 defvalue = database.mapto[mapname].get(0, None)
421 for i in range(len(keys)):
422 key = keys[i]
423 dst = database.mapto[mapname].get(key, defvalue)
424 self._array_entry(i, dst, names[i], self.TYPE_INT, totype)
425
426 self._array_end(self.TYPE_INT, totype)
427
428 def generate_name_map(self, varname, database, frommapname, tomapname):
429 if frommapname not in database.mapfrom:
430 raise Exception("Unknown map %s, expected one of %s" % (
431 frommapname, ", ".join(database.mapfrom.keys())))
432 if tomapname not in database.mapname:
433 raise Exception("Unknown map %s, expected one of %s" % (
434 tomapname, ", ".join(database.mapname.keys())))
435
436 tolinux = database.mapfrom[frommapname]
437 fromlinux = database.mapname[tomapname]
438
439 if varname is None:
440 varname = "name_map_%s_to_%s" % (frommapname, tomapname)
441
53e83913 442 keys = list(tolinux.keys())
6838f038
WB
443 keys.sort()
444 if type(keys[0]) == int:
445 keys = range(keys[-1] + 1)
446
447 if type(keys[0]) == int:
448 fromtype = self.TYPE_INT
449 else:
450 fromtype = self.TYPE_STRING
451
452 self._array_start(varname, len(keys), None, fromtype, self.TYPE_STRING)
453
454 for src in keys:
455 linux = tolinux.get(src, None)
456 if linux is None:
457 dst = None
458 else:
459 dst = fromlinux.get(linux, None)
460
461 comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
462 self._label(database, Database.MAP_LINUX, linux, linux),
463 self._label(database, tomapname, dst, linux))
464 self._array_entry(src, dst, comment, fromtype, self.TYPE_STRING)
465 self._array_end(fromtype, self.TYPE_STRING)
466
467 def generate_name_table(self, varname, database, mapname):
468 if mapname not in database.mapname:
469 raise Exception("Unknown map %s, expected one of %s" % (
470 mapname, ", ".join(database.mapname.keys())))
471
53e83913 472 keys = list(database.mapto[Database.MAP_LINUX].keys())
6838f038
WB
473 keys.sort()
474 names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
475
476 if varname is None:
477 varname = "name_table_%s" % mapname
478
479 self._array_start(varname, len(keys), None, self.TYPE_INT, self.TYPE_STRING)
480
481 for i in range(len(keys)):
482 key = keys[i]
483 dst = database.mapname[mapname].get(key, None)
484 self._array_entry(i, dst, names[i], self.TYPE_INT, self.TYPE_STRING)
485
486 self._array_end(self.TYPE_INT, self.TYPE_STRING)
487
488 def _label(self, database, mapname, val, linux):
489 if mapname in database.mapname:
490 return "%s:%s (%s)" % (mapname, val, database.mapname[mapname].get(linux, "unnamed"))
491 else:
492 return "%s:%s" % (mapname, val)
493
494class LanguageDocGenerator(LanguageGenerator):
495
496 def _array_start_name_doc(self, varname, namemap):
497 raise NotImplementedError()
498
499 def _array_start_code_doc(self, varname, namemap, codemap):
500 raise NotImplementedError()
501
502 def _array_end(self):
503 raise NotImplementedError()
504
505 def _array_name_entry(self, value, name):
506 raise NotImplementedError()
507
508 def _array_code_entry(self, value, name):
509 raise NotImplementedError()
510
263fef5b 511 def generate_name_docs(self, title, subtitle, database, mapname):
6838f038
WB
512 if mapname not in database.mapname:
513 raise Exception("Unknown map %s, expected one of %s" % (
514 mapname, ", ".join(database.mapname.keys())))
515
53e83913 516 keys = list(database.mapto[Database.MAP_LINUX].keys())
6838f038
WB
517 keys.sort()
518 names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
519
263fef5b
SR
520 if title is None:
521 title = mapname
522 if subtitle is None:
523 subtitle = "Docs for %s" % mapname
6838f038 524
263fef5b 525 self._array_start_name_doc(title, subtitle, mapname)
6838f038
WB
526
527 for i in range(len(keys)):
528 key = keys[i]
529 dst = database.mapname[mapname].get(key, None)
530 self._array_name_entry(key, dst)
531
532 self._array_end()
533
534
263fef5b 535 def generate_code_docs(self, title, subtitle, database, mapname):
6838f038
WB
536 if mapname not in database.mapfrom:
537 raise Exception("Unknown map %s, expected one of %s" % (
538 mapname, ", ".join(database.mapfrom.keys())))
539
540 tolinux = database.mapfrom[mapname]
53e83913 541 keys = list(tolinux.keys())
6838f038
WB
542 keys.sort()
543 if mapname in database.mapname:
544 names = database.mapname[mapname]
545 namemap = mapname
546 else:
547 names = database.mapname[Database.MAP_LINUX]
548 namemap = Database.MAP_LINUX
549
263fef5b
SR
550 if title is None:
551 title = mapname
552 if subtitle is None:
553 subtitle = "Docs for %s" % mapname
6838f038 554
263fef5b 555 self._array_start_code_doc(title, subtitle, mapname, namemap)
6838f038
WB
556
557 for i in range(len(keys)):
558 key = keys[i]
559 self._array_code_entry(key, names.get(tolinux[key], "unnamed"))
560
561 self._array_end()
562
563class CLanguageGenerator(LanguageSrcGenerator):
564
565 def __init__(self, inttypename, strtypename, lentypename):
566 self.inttypename = inttypename
567 self.strtypename = strtypename
568 self.lentypename = lentypename
569
570 def _boilerplate(self, lines):
571 print("/*")
572 for line in lines:
573 print(" * %s" % line)
574 print("*/")
575
576 def _array_start(self, varname, length, defvalue, fromtype, totype):
577 self._varname = varname;
578 totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
579 if fromtype in (self.TYPE_INT, self.TYPE_ENUM):
580 if type(length) == str:
581 print("const %s %s[%s] = {" % (totypename, varname, length))
582 else:
583 print("const %s %s[%d] = {" % (totypename, varname, length))
584 else:
585 print("const struct _%s {" % varname)
586 print(" const %s from;" % self.strtypename)
587 print(" const %s to;" % totypename)
588 print("} %s[] = {" % varname)
589
590 if defvalue != None:
591 if totype == self.TYPE_ENUM:
592 if type(length) == str:
593 print(" [0 ... %s-1] = %s," % (length, defvalue))
594 else:
595 print(" [0 ... 0x%x-1] = %s," % (length, defvalue))
596 else:
597 if type(length) == str:
598 print(" [0 ... %s-1] = 0x%x," % (length, defvalue))
599 else:
600 print(" [0 ... 0x%x-1] = 0x%x," % (length, defvalue))
601
602 def _array_end(self, fromtype, totype):
603 print("};")
604 print("const %s %s_len = sizeof(%s)/sizeof(%s[0]);" %
605 (self.lentypename, self._varname, self._varname, self._varname))
606
607 def _array_entry(self, index, value, comment, fromtype, totype):
608 if value is None:
609 return
610 if fromtype == self.TYPE_INT:
611 indexfmt = "0x%x"
612 elif fromtype == self.TYPE_ENUM:
613 indexfmt = "%s"
614 else:
615 indexfmt = "\"%s\""
616
617 if totype == self.TYPE_INT:
618 valuefmt = "0x%x"
619 elif totype == self.TYPE_ENUM:
620 valuefmt = "%s"
621 else:
622 valuefmt = "\"%s\""
623
624 if fromtype != self.TYPE_STRING:
625 print((" [" + indexfmt + "] = " + valuefmt + ", /* %s */") % (index, value, comment))
626 else:
627 print((" {" + indexfmt + ", " + valuefmt + "}, /* %s */") % (index, value, comment))
628
263fef5b
SR
629class StdCLanguageGenerator(CLanguageGenerator):
630
631 def __init__(self):
632 super(StdCLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
633
634class GLib2LanguageGenerator(CLanguageGenerator):
635
636 def __init__(self):
637 super(GLib2LanguageGenerator, self).__init__("guint16", "gchar *", "guint")
638
639class CHeaderLanguageGenerator(LanguageSrcGenerator):
640
641 def __init__(self, inttypename, strtypename, lentypename):
642 self.inttypename = inttypename
643 self.strtypename = strtypename
644 self.lentypename = lentypename
645
646 def _boilerplate(self, lines):
647 print("/*")
648 for line in lines:
649 print(" * %s" % line)
650 print("*/")
651
652 def _array_start(self, varname, length, defvalue, fromtype, totype):
653 self._varname = varname
654 if fromtype == self.TYPE_STRING:
655 self._length = 0
656 else:
657 self._length = length
658
659 def _array_end(self, fromtype, totype):
660 totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
661 if fromtype == self.TYPE_STRING:
662 vartypename = "struct _%s" % self._varname
663 print("%s {" % vartypename)
664 print(" const %s from;" % self.strtypename)
665 print(" const %s to;" % totypename)
666 print("};")
667 else:
668 vartypename = totypename
669 if type(self._length) == str:
670 print("extern const %s %s[%s];" % (vartypename, self._varname, self._length))
671 else:
672 print("extern const %s %s[%d];" % (vartypename, self._varname, self._length))
673 print("extern const %s %s_len;" % (self.lentypename, self._varname))
674
675 def _array_entry(self, index, value, comment, fromtype, totype):
676 if value is None:
677 return
678 if fromtype == self.TYPE_STRING:
679 self._length += 1
680
681class StdCHeaderLanguageGenerator(CHeaderLanguageGenerator):
682
683 def __init__(self):
684 super(StdCHeaderLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
685
686class GLib2HeaderLanguageGenerator(CHeaderLanguageGenerator):
687
688 def __init__(self):
689 super(GLib2HeaderLanguageGenerator, self).__init__("guint16", "gchar *", "guint")
690
6838f038
WB
691class CppLanguageGenerator(CLanguageGenerator):
692
693 def _array_start(self, varname, length, defvalue, fromtype, totype):
694 if fromtype == self.TYPE_ENUM:
695 raise NotImplementedError("Enums not supported as source in C++ generator")
696 totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
697 if fromtype == self.TYPE_INT:
698 print("#include <vector>")
263fef5b 699 print("extern const std::vector<%s> %s;" % (totypename, varname));
6838f038
WB
700 print("const std::vector<%s> %s = {" % (totypename, varname))
701 else:
702 print("#include <map>")
703 print("#include <string>")
263fef5b 704 print("extern const std::map<const std::string, %s> %s;" % (totypename, varname))
6838f038
WB
705 print("const std::map<const std::string, %s> %s = {" % (totypename, varname))
706
707 def _array_end(self, fromtype, totype):
708 print("};")
709
710 # designated initializers not available in C++
711 def _array_entry(self, index, value, comment, fromtype, totype):
712 if fromtype == self.TYPE_STRING:
713 return super(CppLanguageGenerator, self)._array_entry(index, value, comment, fromtype, totype)
714
715 if value is None:
716 print(" 0, /* %s */" % comment)
717 elif totype == self.TYPE_INT:
718 print(" 0x%x, /* %s */" % (value, comment))
719 elif totype == self.TYPE_ENUM:
720 print(" %s, /* %s */" % (value, comment))
721 else:
722 print(" \"%s\", /* %s */" % (value, comment))
723
6838f038
WB
724class StdCppLanguageGenerator(CppLanguageGenerator):
725
726 def __init__(self):
727 super(StdCppLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
728
263fef5b
SR
729class CppHeaderLanguageGenerator(CHeaderLanguageGenerator):
730
731 def _array_start(self, varname, length, defvalue, fromtype, totype):
732 if fromtype == self.TYPE_ENUM:
733 raise NotImplementedError("Enums not supported as source in C++ generator")
734 totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
735 if fromtype == self.TYPE_INT:
736 print("#include <vector>")
737 print("extern const std::vector<%s> %s;" % (totypename, varname));
738 else:
739 print("#include <map>")
740 print("#include <string>")
741 print("extern const std::map<const std::string, %s> %s;" % (totypename, varname))
742
743 def _array_end(self, fromtype, totype):
744 pass
745
746 # designated initializers not available in C++
747 def _array_entry(self, index, value, comment, fromtype, totype):
748 pass
749
750class StdCppHeaderLanguageGenerator(CppHeaderLanguageGenerator):
6838f038
WB
751
752 def __init__(self):
263fef5b 753 super(StdCppHeaderLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
6838f038
WB
754
755class PythonLanguageGenerator(LanguageSrcGenerator):
756
757 def _boilerplate(self, lines):
758 print("#")
759 for line in lines:
760 print("# %s" % line)
761 print("#")
762
763 def _array_start(self, varname, length, defvalue, fromtype, totype):
764 if fromtype == self.TYPE_ENUM:
765 raise NotImplementedError("Enums not supported as source in Python generator")
766
767 if fromtype != self.TYPE_STRING:
768 print("%s = [" % varname)
769 else:
770 print("%s = {" % varname)
771
772 def _array_end(self, fromtype, totype):
773 if fromtype != self.TYPE_STRING:
774 print("]")
775 else:
776 print("}")
777
778 def _array_entry(self, index, value, comment, fromtype, totype):
779 if fromtype == self.TYPE_INT:
780 if value is None:
781 print(" None, # %s" % (comment))
782 elif totype == self.TYPE_INT:
783 print(" 0x%x, # %s" % (value, comment))
784 elif totype == self.TYPE_ENUM:
785 print(" %s, # %s" % (value, comment))
786 else:
787 print(" \"%s\", # %s" % (value, comment))
788 else:
789 if value is None:
790 print(" \"%s\": None, # %s" % (index, comment))
791 elif totype == self.TYPE_INT:
792 print(" \"%s\": 0x%x, # %s" % (index, value, comment))
793 elif totype == self.TYPE_ENUM:
794 print(" \"%s\": %s, # %s" % (index, value, comment))
795 else:
796 print(" \"%s\": \"%s\", # %s" % (index, value, comment))
797
798class PerlLanguageGenerator(LanguageSrcGenerator):
799
800 def _boilerplate(self, lines):
801 print("#")
802 for line in lines:
803 print("# %s" % line)
804 print("#")
805
806 def _array_start(self, varname, length, defvalue, fromtype, totype):
807 if fromtype == self.TYPE_ENUN:
808 raise NotImplementedError("Enums not supported as source in Python generator")
809 if fromtype == self.TYPE_INT:
810 print("my @%s = (" % varname)
811 else:
812 print("my %%%s = (" % varname)
813
814 def _array_end(self, fromtype, totype):
815 print(");")
816
817 def _array_entry(self, index, value, comment, fromtype, totype):
818 if fromtype == self.TYPE_INT:
819 if value is None:
820 print(" undef, # %s" % (comment))
821 elif totype == self.TYPE_INT:
822 print(" 0x%x, # %s" % (value, comment))
823 elif totype == self.TYPE_ENUM:
824 print(" %s, # %s" % (value, comment))
825 else:
826 print(" \"%s\", # %s" % (value, comment))
827 else:
828 if value is None:
829 print(" \"%s\", undef, # %s" % (index, comment))
830 elif totype == self.TYPE_INT:
831 print(" \"%s\", 0x%x, # %s" % (index, value, comment))
832 elif totype == self.TYPE_ENUM:
833 print(" \"%s\", 0x%x, # %s" % (index, value, comment))
834 else:
835 print(" \"%s\", \"%s\", # %s" % (index, value, comment))
836
837class JavaScriptLanguageGenerator(LanguageSrcGenerator):
838
839 def _boilerplate(self, lines):
840 print("/*")
841 for line in lines:
842 print(" * %s" % line)
843 print("*/")
844
845 def _array_start(self, varname, length, defvalue, fromtype, totype):
846 print("export default {")
847
848 def _array_end(self, fromtype, totype):
849 print("};")
850
851 def _array_entry(self, index, value, comment, fromtype, totype):
852 if value is None:
853 return
854
855 if fromtype == self.TYPE_INT:
856 fromfmt = "0x%x"
857 elif fromtype == self.TYPE_ENUM:
858 fromfmt = "%s"
859 else:
860 fromfmt = "\"%s\""
861
862 if totype == self.TYPE_INT:
863 tofmt = "0x%x"
864 elif totype == self.TYPE_ENUM:
865 tofmt = "%s"
866 else:
867 tofmt = "\"%s\""
868
869 print((" " + fromfmt + ": " + tofmt + ", /* %s */") % (index, value, comment))
870
871class PodLanguageGenerator(LanguageDocGenerator):
872
873 def _boilerplate(self, lines):
874 print("#")
875 for line in lines:
876 print("# %s" % line)
877 print("#")
878
263fef5b
SR
879 def _array_start_name_doc(self, title, subtitle, namemap):
880 print("=head1 NAME")
881 print("")
882 print("%s - %s" % (title, subtitle))
883 print("")
884 print("=head1 DESCRIPTION")
6838f038
WB
885 print("")
886 print("List of %s key code names, with corresponding key code values" % namemap)
887 print("")
888 print("=over 4")
889 print("")
890
263fef5b
SR
891 def _array_start_code_doc(self, title, subtitle, codemap, namemap):
892 print("=head1 NAME")
893 print("")
894 print("%s - %s" % (title, subtitle))
895 print("")
896 print("=head1 DESCRIPTION")
6838f038
WB
897 print("")
898 print("List of %s key code values, with corresponding %s key code names" % (codemap, namemap))
899 print("")
900 print("=over 4")
901 print("")
902
903 def _array_end(self):
904 print("=back")
905 print("")
906
907 def _array_name_entry(self, value, name):
908 print("=item %s" % name)
909 print("")
910 print("Key value %d (0x%x)" % (value, value))
911 print("")
912
913 def _array_code_entry(self, value, name):
914 print("=item %d (0x%x)" % (value, value))
915 print("")
916 print("Key name %s" % name)
917 print("")
918
263fef5b
SR
919class RSTLanguageGenerator(LanguageDocGenerator):
920
921 def _boilerplate(self, lines):
922 print("..")
923 for line in lines:
924 print(" %s" % line)
925 print("")
926
927 def _array_start_name_doc(self, title, subtitle, namemap):
928 print("=" * len(title))
929 print(title)
930 print("=" * len(title))
931 print("")
932 print("-" * len(subtitle))
933 print(subtitle)
934 print("-" * len(subtitle))
935 print("")
936 print(":Manual section: 7")
937 print(":Manual group: Virtualization Support")
938 print("")
939 print("DESCRIPTION")
940 print("===========")
941 print("List of %s key code names, with corresponding key code values" % namemap)
942 print("")
943
944 def _array_start_code_doc(self, title, subtitle, codemap, namemap):
945 print("=" * len(title))
946 print(title)
947 print("=" * len(title))
948 print("")
949 print("-" * len(subtitle))
950 print(subtitle)
951 print("-" * len(subtitle))
952 print("")
953 print(":Manual section: 7")
954 print(":Manual group: Virtualization Support")
955 print("")
956 print("DESCRIPTION")
957 print("===========")
958 print("List of %s key code values, with corresponding %s key code names" % (codemap, namemap))
959 print("")
960
961 def _array_end(self):
962 print("")
963
964 def _array_name_entry(self, value, name):
965 print("* %s" % name)
966 print("")
967 print(" Key value %d (0x%x)" % (value, value))
968 print("")
969
970 def _array_code_entry(self, value, name):
971 print("* %d (0x%x)" % (value, value))
972 print("")
973 print(" Key name %s" % name)
974 print("")
975
6838f038
WB
976SRC_GENERATORS = {
977 "stdc": StdCLanguageGenerator(),
263fef5b 978 "stdc-header": StdCHeaderLanguageGenerator(),
6838f038 979 "stdc++": StdCppLanguageGenerator(),
263fef5b 980 "stdc++-header": StdCppHeaderLanguageGenerator(),
6838f038 981 "glib2": GLib2LanguageGenerator(),
263fef5b 982 "glib2-header": GLib2HeaderLanguageGenerator(),
6838f038
WB
983 "python2": PythonLanguageGenerator(),
984 "python3": PythonLanguageGenerator(),
985 "perl": PerlLanguageGenerator(),
986 "js": JavaScriptLanguageGenerator(),
987}
988DOC_GENERATORS = {
989 "pod": PodLanguageGenerator(),
263fef5b 990 "rst": RSTLanguageGenerator(),
6838f038
WB
991}
992
993def code_map(args):
994 database = Database()
995 database.load(args.keymaps)
996
263fef5b 997 cliargs = ["keymap-gen", "code-map", "--lang=%s" % args.lang]
6838f038
WB
998 if args.varname is not None:
999 cliargs.append("--varname=%s" % args.varname)
263fef5b 1000 cliargs.extend(["keymaps.csv", args.frommapname, args.tomapname])
6838f038
WB
1001 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
1002
1003 SRC_GENERATORS[args.lang].generate_code_map(args.varname, database, args.frommapname, args.tomapname)
1004
1005def code_table(args):
1006 database = Database()
1007 database.load(args.keymaps)
1008
263fef5b 1009 cliargs = ["keymap-gen", "code-table", "--lang=%s" % args.lang]
6838f038
WB
1010 if args.varname is not None:
1011 cliargs.append("--varname=%s" % args.varname)
263fef5b 1012 cliargs.extend(["keymaps.csv", args.mapname])
6838f038
WB
1013 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
1014
1015 SRC_GENERATORS[args.lang].generate_code_table(args.varname, database, args.mapname)
1016
1017def name_map(args):
1018 database = Database()
1019 database.load(args.keymaps)
1020
263fef5b 1021 cliargs = ["keymap-gen", "name-map", "--lang=%s" % args.lang]
6838f038
WB
1022 if args.varname is not None:
1023 cliargs.append("--varname=%s" % args.varname)
263fef5b 1024 cliargs.extend(["keymaps.csv", args.frommapname, args.tomapname])
6838f038
WB
1025 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
1026
1027 SRC_GENERATORS[args.lang].generate_name_map(args.varname, database, args.frommapname, args.tomapname)
1028
1029def name_table(args):
1030 database = Database()
1031 database.load(args.keymaps)
1032
1033
263fef5b 1034 cliargs = ["keymap-gen", "name-table", "--lang=%s" % args.lang]
6838f038
WB
1035 if args.varname is not None:
1036 cliargs.append("--varname=%s" % args.varname)
263fef5b 1037 cliargs.extend(["keymaps.csv", args.mapname])
6838f038
WB
1038 SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
1039
1040 SRC_GENERATORS[args.lang].generate_name_table(args.varname, database, args.mapname)
1041
1042def code_docs(args):
1043 database = Database()
1044 database.load(args.keymaps)
1045
1046
263fef5b
SR
1047 cliargs = ["keymap-gen", "code-docs", "--lang=%s" % args.lang]
1048 if args.title is not None:
1049 cliargs.append("--title=%s" % args.title)
1050 if args.subtitle is not None:
1051 cliargs.append("--subtitle=%s" % args.subtitle)
1052 cliargs.extend(["keymaps.csv", args.mapname])
6838f038
WB
1053 DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
1054
263fef5b 1055 DOC_GENERATORS[args.lang].generate_code_docs(args.title, args.subtitle, database, args.mapname)
6838f038
WB
1056
1057def name_docs(args):
1058 database = Database()
1059 database.load(args.keymaps)
1060
1061
263fef5b
SR
1062 cliargs = ["keymap-gen", "name-docs", "--lang=%s" % args.lang]
1063 if args.title is not None:
1064 cliargs.append("--title=%s" % args.title)
1065 if args.subtitle is not None:
1066 cliargs.append("--subtitle=%s" % args.subtitle)
1067 cliargs.extend(["keymaps.csv", args.mapname])
6838f038
WB
1068 DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
1069
263fef5b 1070 DOC_GENERATORS[args.lang].generate_name_docs(args.title, args.subtitle, database, args.mapname)
6838f038
WB
1071
1072def usage():
1073 print ("Please select a command:")
1074 print (" 'code-map', 'code-table', 'name-map', 'name-table', 'docs'")
1075 sys.exit(1)
1076
1077def main():
1078 parser = argparse.ArgumentParser()
1079
6838f038
WB
1080 subparsers = parser.add_subparsers(help="sub-command help")
1081
1082 codemapparser = subparsers.add_parser("code-map", help="Generate a mapping between code tables")
263fef5b
SR
1083 codemapparser.add_argument("--varname", default=None, help="Data variable name")
1084 codemapparser.add_argument("--lang", default="stdc",
1085 help="Output language (%s)" % (
1086 ",".join(SRC_GENERATORS.keys())))
6838f038
WB
1087 codemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
1088 codemapparser.add_argument("frommapname", help="Source code table name")
1089 codemapparser.add_argument("tomapname", help="Target code table name")
1090 codemapparser.set_defaults(func=code_map)
1091
1092 codetableparser = subparsers.add_parser("code-table", help="Generate a flat code table")
263fef5b
SR
1093 codetableparser.add_argument("--lang", default="stdc",
1094 help="Output language (%s)" % (
1095 ",".join(SRC_GENERATORS.keys())))
1096 codetableparser.add_argument("--varname", default=None, help="Data variable name")
6838f038
WB
1097 codetableparser.add_argument("keymaps", help="Path to keymap CSV data file")
1098 codetableparser.add_argument("mapname", help="Code table name")
1099 codetableparser.set_defaults(func=code_table)
1100
1101 namemapparser = subparsers.add_parser("name-map", help="Generate a mapping to names")
263fef5b
SR
1102 namemapparser.add_argument("--lang", default="stdc",
1103 help="Output language (%s)" % (
1104 ",".join(SRC_GENERATORS.keys())))
1105 namemapparser.add_argument("--varname", default=None, help="Data variable name")
6838f038
WB
1106 namemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
1107 namemapparser.add_argument("frommapname", help="Source code table name")
1108 namemapparser.add_argument("tomapname", help="Target name table name")
1109 namemapparser.set_defaults(func=name_map)
1110
1111 nametableparser = subparsers.add_parser("name-table", help="Generate a flat name table")
263fef5b
SR
1112 nametableparser.add_argument("--lang", default="stdc",
1113 help="Output language, (%s)" % (
1114 ",".join(SRC_GENERATORS.keys())))
1115 nametableparser.add_argument("--varname", default=None, help="Data variable name")
6838f038
WB
1116 nametableparser.add_argument("keymaps", help="Path to keymap CSV data file")
1117 nametableparser.add_argument("mapname", help="Name table name")
1118 nametableparser.set_defaults(func=name_table)
1119
1120 codedocsparser = subparsers.add_parser("code-docs", help="Generate code documentation")
263fef5b
SR
1121 codedocsparser.add_argument("--lang", default="pod",
1122 help="Output language (%s)" % (
1123 ",".join(DOC_GENERATORS.keys())))
1124 codedocsparser.add_argument("--title", default=None, help="Document title")
1125 codedocsparser.add_argument("--subtitle", default=None, help="Document subtitle")
6838f038
WB
1126 codedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
1127 codedocsparser.add_argument("mapname", help="Code table name")
1128 codedocsparser.set_defaults(func=code_docs)
1129
1130 namedocsparser = subparsers.add_parser("name-docs", help="Generate name documentation")
263fef5b
SR
1131 namedocsparser.add_argument("--lang", default="pod",
1132 help="Output language (%s)" % (
1133 ",".join(DOC_GENERATORS.keys())))
1134 namedocsparser.add_argument("--title", default=None, help="Document title")
1135 namedocsparser.add_argument("--subtitle", default=None, help="Document subtitle")
6838f038
WB
1136 namedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
1137 namedocsparser.add_argument("mapname", help="Name table name")
1138 namedocsparser.set_defaults(func=name_docs)
1139
1140 args = parser.parse_args()
1141 if hasattr(args, "func"):
1142 args.func(args)
1143 else:
1144 usage()
1145
1146
1147main()