aboutsummaryrefslogtreecommitdiffstats
path: root/ui/keycodemapdb/tools
diff options
context:
space:
mode:
Diffstat (limited to 'ui/keycodemapdb/tools')
-rwxr-xr-xui/keycodemapdb/tools/keymap-gen1196
1 files changed, 1196 insertions, 0 deletions
diff --git a/ui/keycodemapdb/tools/keymap-gen b/ui/keycodemapdb/tools/keymap-gen
new file mode 100755
index 000000000..ac4b05740
--- /dev/null
+++ b/ui/keycodemapdb/tools/keymap-gen
@@ -0,0 +1,1196 @@
+#!/usr/bin/python
+# -*- python -*-
+#
+# Keycode Map Generator
+#
+# Copyright (C) 2009-2017 Red Hat, Inc.
+#
+# This file is dual license under the terms of the GPLv2 or later
+# and 3-clause BSD licenses.
+#
+
+# Requires >= 2.6
+from __future__ import print_function
+
+import csv
+try:
+ import argparse
+except:
+ import os, sys
+ sys.path.append(os.path.join(os.path.dirname(__file__), "../thirdparty"))
+ import argparse
+import hashlib
+import time
+import sys
+
+class Database:
+
+ # Linux: linux/input.h
+ MAP_LINUX = "linux"
+
+ # OS-X: Carbon/HIToolbox/Events.h
+ MAP_OSX = "osx"
+
+ # AT Set 1: linux/drivers/input/keyboard/atkbd.c
+ # (atkbd_set2_keycode + atkbd_unxlate_table)
+ MAP_ATSET1 = "atset1"
+
+ # AT Set 2: linux/drivers/input/keyboard/atkbd.c
+ # (atkbd_set2_keycode)
+ MAP_ATSET2 = "atset2"
+
+ # AT Set 3: linux/drivers/input/keyboard/atkbd.c
+ # (atkbd_set3_keycode)
+ MAP_ATSET3 = "atset3"
+
+ # Linux RAW: linux/drivers/char/keyboard.c (x86_keycodes)
+ MAP_XTKBD = "xtkbd"
+
+ # USB HID: linux/drivers/hid/usbhid/usbkbd.c (usb_kbd_keycode)
+ MAP_USB = "usb"
+
+ # Win32: mingw32/winuser.h
+ MAP_WIN32 = "win32"
+
+ # XWin XT: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h}
+ # (xt + manually transcribed)
+ MAP_XWINXT = "xwinxt"
+
+ # X11: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
+ MAP_X11 = "x11"
+
+ # XKBD XT: xf86-input-keyboard/src/at_scancode.c
+ # (xt + manually transcribed)
+ MAP_XKBDXT = "xkbdxt"
+
+ # Xorg with evdev: linux + an offset
+ MAP_XORGEVDEV = "xorgevdev"
+
+ # Xorg with kbd: xkbdxt + an offset
+ MAP_XORGKBD = "xorgkbd"
+
+ # Xorg with OS-X: osx + an offset
+ MAP_XORGXQUARTZ = "xorgxquartz"
+
+ # Xorg + Cygwin: xwinxt + an offset
+ MAP_XORGXWIN = "xorgxwin"
+
+ # QEMU key numbers: xtkbd + special re-encoding of high bit
+ MAP_QNUM = "qnum"
+
+ # HTML codes
+ MAP_HTML = "html"
+
+ # XKB key names
+ MAP_XKB = "xkb"
+
+ # QEMU keycodes
+ MAP_QCODE = "qcode"
+
+ # Sun / Sparc scan codes
+ # Reference: "SPARC International Keyboard Spec 1", page 7 "US scan set"
+ MAP_SUN = "sun"
+
+ # Apple Desktop Bus
+ # Reference: http://www.archive.org/stream/apple-guide-macintosh-family-hardware/Apple_Guide_to_the_Macintosh_Family_Hardware_2e#page/n345/mode/2up
+ MAP_ADB = "adb"
+
+ MAP_LIST = (
+ MAP_LINUX,
+ MAP_OSX,
+ MAP_ATSET1,
+ MAP_ATSET2,
+ MAP_ATSET3,
+ MAP_USB,
+ MAP_WIN32,
+ MAP_XWINXT,
+ MAP_XKBDXT,
+ MAP_X11,
+ MAP_HTML,
+ MAP_XKB,
+ MAP_QCODE,
+ MAP_SUN,
+ MAP_ADB,
+
+ # These are derived from maps above
+ MAP_XTKBD,
+ MAP_XORGEVDEV,
+ MAP_XORGKBD,
+ MAP_XORGXQUARTZ,
+ MAP_XORGXWIN,
+ MAP_QNUM,
+ )
+
+ CODE_COLUMNS = {
+ MAP_LINUX: 1,
+ MAP_OSX: 3,
+ MAP_ATSET1: 4,
+ MAP_ATSET2: 5,
+ MAP_ATSET3: 6,
+ MAP_USB: 7,
+ MAP_WIN32: 9,
+ MAP_XWINXT: 10,
+ MAP_XKBDXT: 11,
+ MAP_X11: 13,
+ MAP_HTML: 14,
+ MAP_XKB: 15,
+ MAP_SUN: 17,
+ MAP_ADB: 18,
+ }
+
+ ENUM_COLUMNS = {
+ MAP_QCODE: 14,
+ }
+
+ NAME_COLUMNS = {
+ MAP_LINUX: 0,
+ MAP_OSX: 2,
+ MAP_WIN32: 8,
+ MAP_X11: 12,
+ MAP_HTML: 14,
+ MAP_XKB: 15,
+ MAP_QCODE: 16,
+ }
+
+ ENUM_BOUND = {
+ MAP_QCODE: "Q_KEY_CODE__MAX",
+ }
+
+ def __init__(self):
+
+ self.mapto = {}
+ self.mapfrom = {}
+ self.mapname = {}
+ self.mapchecksum = None
+
+ for name in self.MAP_LIST:
+ # Key is a MAP_LINUX, value is a MAP_XXX
+ self.mapto[name] = {}
+ # key is a MAP_XXX, value is a MAP_LINUX
+ self.mapfrom[name] = {}
+
+ for name in self.NAME_COLUMNS.keys():
+ # key is a MAP_LINUX, value is a string
+ self.mapname[name] = {}
+
+ def _generate_checksum(self, filename):
+ hash = hashlib.sha256()
+ with open(filename, "rb") as f:
+ for chunk in iter(lambda: f.read(4096), b""):
+ hash.update(chunk)
+ self.mapchecksum = hash.hexdigest()
+
+ def load(self, filename):
+ self._generate_checksum(filename)
+
+ with open(filename, 'r') as f:
+ reader = csv.reader(f)
+
+ first = True
+
+ for row in reader:
+ # Discard column headings
+ if first:
+ first = False
+ continue
+
+ # We special case MAP_LINUX since that is out
+ # master via which all other mappings are done
+ linux = self.load_linux(row)
+
+ # Now load all the remaining master data values
+ self.load_data(row, linux)
+
+ # Then load all the keycode names
+ self.load_names(row, linux)
+
+ # Finally calculate derived key maps
+ self.derive_data(row, linux)
+
+ def load_linux(self, row):
+ col = self.CODE_COLUMNS[self.MAP_LINUX]
+ linux = row[col]
+
+ if linux.startswith("0x"):
+ linux = int(linux, 16)
+ else:
+ linux = int(linux, 10)
+
+ self.mapto[self.MAP_LINUX][linux] = linux
+ self.mapfrom[self.MAP_LINUX][linux] = linux
+
+ return linux
+
+
+ def load_data(self, row, linux):
+ for mapname in self.CODE_COLUMNS:
+ if mapname == self.MAP_LINUX:
+ continue
+
+ col = self.CODE_COLUMNS[mapname]
+ val = row[col]
+
+ if val == "":
+ continue
+
+ if val.startswith("0x"):
+ val = int(val, 16)
+ elif val.isdigit():
+ val = int(val, 10)
+
+ self.mapto[mapname][linux] = val
+ self.mapfrom[mapname][val] = linux
+
+ def load_names(self, row, linux):
+ for mapname in self.NAME_COLUMNS:
+ col = self.NAME_COLUMNS[mapname]
+ val = row[col]
+
+ if val == "":
+ continue
+
+ self.mapname[mapname][linux] = val
+
+
+ def derive_data(self, row, linux):
+ # Linux RAW is XT scan codes with special encoding of the
+ # 0xe0 scan codes
+ if linux in self.mapto[self.MAP_ATSET1]:
+ at1 = self.mapto[self.MAP_ATSET1][linux]
+ if at1 > 0x7f:
+ assert((at1 & ~0x7f) == 0xe000)
+ xtkbd = 0x100 | (at1 & 0x7f)
+ else:
+ xtkbd = at1
+ self.mapto[self.MAP_XTKBD][linux] = xtkbd
+ self.mapfrom[self.MAP_XTKBD][xtkbd] = linux
+
+ # Xorg KBD is XKBD XT offset by 8
+ if linux in self.mapto[self.MAP_XKBDXT]:
+ xorgkbd = self.mapto[self.MAP_XKBDXT][linux] + 8
+ self.mapto[self.MAP_XORGKBD][linux] = xorgkbd
+ self.mapfrom[self.MAP_XORGKBD][xorgkbd] = linux
+
+ # Xorg evdev is Linux offset by 8
+ self.mapto[self.MAP_XORGEVDEV][linux] = linux + 8
+ self.mapfrom[self.MAP_XORGEVDEV][linux + 8] = linux
+
+ # Xorg XQuartx is OS-X offset by 8
+ if linux in self.mapto[self.MAP_OSX]:
+ xorgxquartz = self.mapto[self.MAP_OSX][linux] + 8
+ self.mapto[self.MAP_XORGXQUARTZ][linux] = xorgxquartz
+ self.mapfrom[self.MAP_XORGXQUARTZ][xorgxquartz] = linux
+
+ # Xorg Xwin (aka Cygwin) is XWin XT offset by 8
+ if linux in self.mapto[self.MAP_XWINXT]:
+ xorgxwin = self.mapto[self.MAP_XWINXT][linux] + 8
+ self.mapto[self.MAP_XORGXWIN][linux] = xorgxwin
+ self.mapfrom[self.MAP_XORGXWIN][xorgxwin] = linux
+
+ # QNUM keycodes are XT scan codes with a slightly
+ # different encoding of 0xe0 scan codes
+ if linux in self.mapto[self.MAP_ATSET1]:
+ at1 = self.mapto[self.MAP_ATSET1][linux]
+ if at1 > 0x7f:
+ assert((at1 & ~0x7f) == 0xe000)
+ qnum = 0x80 | (at1 & 0x7f)
+ else:
+ qnum = at1
+ self.mapto[self.MAP_QNUM][linux] = qnum
+ self.mapfrom[self.MAP_QNUM][qnum] = linux
+
+ # Hack for compatibility with previous mistakes in handling
+ # Print/SysRq. The preferred qnum for Print/SysRq is 0x54,
+ # but QEMU previously allowed 0xb7 too
+ if qnum == 0x54:
+ self.mapfrom[self.MAP_QNUM][0xb7] = self.mapfrom[self.MAP_QNUM][0x54]
+
+ if linux in self.mapname[self.MAP_QCODE]:
+ qcodeenum = self.mapname[self.MAP_QCODE][linux]
+ qcodeenum = "Q_KEY_CODE_" + qcodeenum.upper()
+ self.mapto[self.MAP_QCODE][linux] = qcodeenum
+ self.mapfrom[self.MAP_QCODE][qcodeenum] = linux
+
+class LanguageGenerator(object):
+
+ def _boilerplate(self, lines):
+ raise NotImplementedError()
+
+ def generate_header(self, database, args):
+ self._boilerplate([
+ "This file is auto-generated from keymaps.csv",
+ "Database checksum sha256(%s)" % database.mapchecksum,
+ "To re-generate, run:",
+ " %s" % args,
+ ])
+
+class LanguageSrcGenerator(LanguageGenerator):
+
+ TYPE_INT = "integer"
+ TYPE_STRING = "string"
+ TYPE_ENUM = "enum"
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ raise NotImplementedError()
+
+ def _array_end(self, fromtype, totype):
+ raise NotImplementedError()
+
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ raise NotImplementedError()
+
+ def generate_code_map(self, varname, database, frommapname, tomapname):
+ if frommapname not in database.mapfrom:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ frommapname, ", ".join(database.mapfrom.keys())))
+ if tomapname not in database.mapto:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ tomapname, ", ".join(database.mapto.keys())))
+
+ tolinux = database.mapfrom[frommapname]
+ fromlinux = database.mapto[tomapname]
+
+ if varname is None:
+ varname = "code_map_%s_to_%s" % (frommapname, tomapname)
+
+ if frommapname in database.ENUM_COLUMNS:
+ fromtype = self.TYPE_ENUM
+ elif type(list(tolinux.keys())[0]) == str:
+ fromtype = self.TYPE_STRING
+ else:
+ fromtype = self.TYPE_INT
+
+ if tomapname in database.ENUM_COLUMNS:
+ totype = self.TYPE_ENUM
+ elif type(list(fromlinux.values())[0]) == str:
+ totype = self.TYPE_STRING
+ else:
+ totype = self.TYPE_INT
+
+ keys = list(tolinux.keys())
+ keys.sort()
+ if fromtype == self.TYPE_INT:
+ keys = range(keys[-1] + 1)
+
+ if fromtype == self.TYPE_ENUM:
+ keymax = database.ENUM_BOUND[frommapname]
+ else:
+ keymax = len(keys)
+
+ defvalue = fromlinux.get(0, None)
+ if fromtype == self.TYPE_ENUM:
+ self._array_start(varname, keymax, defvalue, fromtype, totype)
+ else:
+ self._array_start(varname, keymax, None, fromtype, totype)
+
+ for src in keys:
+ linux = tolinux.get(src, None)
+ if linux is None:
+ dst = None
+ else:
+ dst = fromlinux.get(linux, defvalue)
+
+ comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
+ self._label(database, Database.MAP_LINUX, linux, linux),
+ self._label(database, tomapname, dst, linux))
+ self._array_entry(src, dst, comment, fromtype, totype)
+ self._array_end(fromtype, totype)
+
+ def generate_code_table(self, varname, database, mapname):
+ if mapname not in database.mapto:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ mapname, ", ".join(database.mapto.keys())))
+
+ keys = list(database.mapto[Database.MAP_LINUX].keys())
+ keys.sort()
+ names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
+
+ if varname is None:
+ varname = "code_table_%s" % mapname
+
+ if mapname in database.ENUM_COLUMNS:
+ totype = self.TYPE_ENUM
+ elif type(list(database.mapto[mapname].values())[0]) == str:
+ totype = self.TYPE_STRING
+ else:
+ totype = self.TYPE_INT
+
+ self._array_start(varname, len(keys), None, self.TYPE_INT, totype)
+
+ defvalue = database.mapto[mapname].get(0, None)
+ for i in range(len(keys)):
+ key = keys[i]
+ dst = database.mapto[mapname].get(key, defvalue)
+ self._array_entry(i, dst, names[i], self.TYPE_INT, totype)
+
+ self._array_end(self.TYPE_INT, totype)
+
+ def generate_name_map(self, varname, database, frommapname, tomapname):
+ if frommapname not in database.mapfrom:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ frommapname, ", ".join(database.mapfrom.keys())))
+ if tomapname not in database.mapname:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ tomapname, ", ".join(database.mapname.keys())))
+
+ tolinux = database.mapfrom[frommapname]
+ fromlinux = database.mapname[tomapname]
+
+ if varname is None:
+ varname = "name_map_%s_to_%s" % (frommapname, tomapname)
+
+ keys = list(tolinux.keys())
+ keys.sort()
+ if type(keys[0]) == int:
+ keys = range(keys[-1] + 1)
+
+ if type(keys[0]) == int:
+ fromtype = self.TYPE_INT
+ else:
+ fromtype = self.TYPE_STRING
+
+ self._array_start(varname, len(keys), None, fromtype, self.TYPE_STRING)
+
+ for src in keys:
+ linux = tolinux.get(src, None)
+ if linux is None:
+ dst = None
+ else:
+ dst = fromlinux.get(linux, None)
+
+ comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
+ self._label(database, Database.MAP_LINUX, linux, linux),
+ self._label(database, tomapname, dst, linux))
+ self._array_entry(src, dst, comment, fromtype, self.TYPE_STRING)
+ self._array_end(fromtype, self.TYPE_STRING)
+
+ def generate_name_table(self, varname, database, mapname):
+ if mapname not in database.mapname:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ mapname, ", ".join(database.mapname.keys())))
+
+ keys = list(database.mapto[Database.MAP_LINUX].keys())
+ keys.sort()
+ names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
+
+ if varname is None:
+ varname = "name_table_%s" % mapname
+
+ self._array_start(varname, len(keys), None, self.TYPE_INT, self.TYPE_STRING)
+
+ for i in range(len(keys)):
+ key = keys[i]
+ dst = database.mapname[mapname].get(key, None)
+ self._array_entry(i, dst, names[i], self.TYPE_INT, self.TYPE_STRING)
+
+ self._array_end(self.TYPE_INT, self.TYPE_STRING)
+
+ def _label(self, database, mapname, val, linux):
+ if mapname in database.mapname:
+ return "%s:%s (%s)" % (mapname, val, database.mapname[mapname].get(linux, "unnamed"))
+ else:
+ return "%s:%s" % (mapname, val)
+
+class LanguageDocGenerator(LanguageGenerator):
+
+ def _array_start_name_doc(self, varname, namemap):
+ raise NotImplementedError()
+
+ def _array_start_code_doc(self, varname, namemap, codemap):
+ raise NotImplementedError()
+
+ def _array_end(self):
+ raise NotImplementedError()
+
+ def _array_name_entry(self, value, name):
+ raise NotImplementedError()
+
+ def _array_code_entry(self, value, name):
+ raise NotImplementedError()
+
+ def generate_name_docs(self, title, subtitle, database, mapname):
+ if mapname not in database.mapname:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ mapname, ", ".join(database.mapname.keys())))
+
+ keys = list(database.mapto[Database.MAP_LINUX].keys())
+ keys.sort()
+ names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
+
+ if title is None:
+ title = mapname
+ if subtitle is None:
+ subtitle = "Docs for %s" % mapname
+
+ self._array_start_name_doc(title, subtitle, mapname)
+
+ for i in range(len(keys)):
+ key = keys[i]
+ dst = database.mapname[mapname].get(key, None)
+ self._array_name_entry(key, dst)
+
+ self._array_end()
+
+
+ def generate_code_docs(self, title, subtitle, database, mapname):
+ if mapname not in database.mapfrom:
+ raise Exception("Unknown map %s, expected one of %s" % (
+ mapname, ", ".join(database.mapfrom.keys())))
+
+ tolinux = database.mapfrom[mapname]
+ keys = list(tolinux.keys())
+ keys.sort()
+ if mapname in database.mapname:
+ names = database.mapname[mapname]
+ namemap = mapname
+ else:
+ names = database.mapname[Database.MAP_LINUX]
+ namemap = Database.MAP_LINUX
+
+ if title is None:
+ title = mapname
+ if subtitle is None:
+ subtitle = "Docs for %s" % mapname
+
+ self._array_start_code_doc(title, subtitle, mapname, namemap)
+
+ for i in range(len(keys)):
+ key = keys[i]
+ self._array_code_entry(key, names.get(tolinux[key], "unnamed"))
+
+ self._array_end()
+
+class CLanguageGenerator(LanguageSrcGenerator):
+
+ def __init__(self, inttypename, strtypename, lentypename):
+ self.inttypename = inttypename
+ self.strtypename = strtypename
+ self.lentypename = lentypename
+
+ def _boilerplate(self, lines):
+ print("/*")
+ for line in lines:
+ print(" * %s" % line)
+ print("*/")
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ self._varname = varname;
+ totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
+ if fromtype in (self.TYPE_INT, self.TYPE_ENUM):
+ if type(length) == str:
+ print("const %s %s[%s] = {" % (totypename, varname, length))
+ else:
+ print("const %s %s[%d] = {" % (totypename, varname, length))
+ else:
+ print("const struct _%s {" % varname)
+ print(" const %s from;" % self.strtypename)
+ print(" const %s to;" % totypename)
+ print("} %s[] = {" % varname)
+
+ if defvalue != None:
+ if totype == self.TYPE_ENUM:
+ if type(length) == str:
+ print(" [0 ... %s-1] = %s," % (length, defvalue))
+ else:
+ print(" [0 ... 0x%x-1] = %s," % (length, defvalue))
+ else:
+ if type(length) == str:
+ print(" [0 ... %s-1] = 0x%x," % (length, defvalue))
+ else:
+ print(" [0 ... 0x%x-1] = 0x%x," % (length, defvalue))
+
+ def _array_end(self, fromtype, totype):
+ print("};")
+ print("const %s %s_len = sizeof(%s)/sizeof(%s[0]);" %
+ (self.lentypename, self._varname, self._varname, self._varname))
+
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ if value is None:
+ return
+ if fromtype == self.TYPE_INT:
+ indexfmt = "0x%x"
+ elif fromtype == self.TYPE_ENUM:
+ indexfmt = "%s"
+ else:
+ indexfmt = "\"%s\""
+
+ if totype == self.TYPE_INT:
+ valuefmt = "0x%x"
+ elif totype == self.TYPE_ENUM:
+ valuefmt = "%s"
+ else:
+ valuefmt = "\"%s\""
+
+ if fromtype != self.TYPE_STRING:
+ print((" [" + indexfmt + "] = " + valuefmt + ", /* %s */") % (index, value, comment))
+ else:
+ print((" {" + indexfmt + ", " + valuefmt + "}, /* %s */") % (index, value, comment))
+
+class StdCLanguageGenerator(CLanguageGenerator):
+
+ def __init__(self):
+ super(StdCLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
+
+class GLib2LanguageGenerator(CLanguageGenerator):
+
+ def __init__(self):
+ super(GLib2LanguageGenerator, self).__init__("guint16", "gchar *", "guint")
+
+class CHeaderLanguageGenerator(LanguageSrcGenerator):
+
+ def __init__(self, inttypename, strtypename, lentypename):
+ self.inttypename = inttypename
+ self.strtypename = strtypename
+ self.lentypename = lentypename
+
+ def _boilerplate(self, lines):
+ print("/*")
+ for line in lines:
+ print(" * %s" % line)
+ print("*/")
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ self._varname = varname
+ if fromtype == self.TYPE_STRING:
+ self._length = 0
+ else:
+ self._length = length
+
+ def _array_end(self, fromtype, totype):
+ totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
+ if fromtype == self.TYPE_STRING:
+ vartypename = "struct _%s" % self._varname
+ print("%s {" % vartypename)
+ print(" const %s from;" % self.strtypename)
+ print(" const %s to;" % totypename)
+ print("};")
+ else:
+ vartypename = totypename
+ if type(self._length) == str:
+ print("extern const %s %s[%s];" % (vartypename, self._varname, self._length))
+ else:
+ print("extern const %s %s[%d];" % (vartypename, self._varname, self._length))
+ print("extern const %s %s_len;" % (self.lentypename, self._varname))
+
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ if value is None:
+ return
+ if fromtype == self.TYPE_STRING:
+ self._length += 1
+
+class StdCHeaderLanguageGenerator(CHeaderLanguageGenerator):
+
+ def __init__(self):
+ super(StdCHeaderLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
+
+class GLib2HeaderLanguageGenerator(CHeaderLanguageGenerator):
+
+ def __init__(self):
+ super(GLib2HeaderLanguageGenerator, self).__init__("guint16", "gchar *", "guint")
+
+class CppLanguageGenerator(CLanguageGenerator):
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ if fromtype == self.TYPE_ENUM:
+ raise NotImplementedError("Enums not supported as source in C++ generator")
+ totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
+ if fromtype == self.TYPE_INT:
+ print("#include <vector>")
+ print("extern const std::vector<%s> %s;" % (totypename, varname));
+ print("const std::vector<%s> %s = {" % (totypename, varname))
+ else:
+ print("#include <map>")
+ print("#include <string>")
+ print("extern const std::map<const std::string, %s> %s;" % (totypename, varname))
+ print("const std::map<const std::string, %s> %s = {" % (totypename, varname))
+
+ def _array_end(self, fromtype, totype):
+ print("};")
+
+ # designated initializers not available in C++
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ if fromtype == self.TYPE_STRING:
+ return super(CppLanguageGenerator, self)._array_entry(index, value, comment, fromtype, totype)
+
+ if value is None:
+ print(" 0, /* %s */" % comment)
+ elif totype == self.TYPE_INT:
+ print(" 0x%x, /* %s */" % (value, comment))
+ elif totype == self.TYPE_ENUM:
+ print(" %s, /* %s */" % (value, comment))
+ else:
+ print(" \"%s\", /* %s */" % (value, comment))
+
+class StdCppLanguageGenerator(CppLanguageGenerator):
+
+ def __init__(self):
+ super(StdCppLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
+
+class CppHeaderLanguageGenerator(CHeaderLanguageGenerator):
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ if fromtype == self.TYPE_ENUM:
+ raise NotImplementedError("Enums not supported as source in C++ generator")
+ totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
+ if fromtype == self.TYPE_INT:
+ print("#include <vector>")
+ print("extern const std::vector<%s> %s;" % (totypename, varname));
+ else:
+ print("#include <map>")
+ print("#include <string>")
+ print("extern const std::map<const std::string, %s> %s;" % (totypename, varname))
+
+ def _array_end(self, fromtype, totype):
+ pass
+
+ # designated initializers not available in C++
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ pass
+
+class StdCppHeaderLanguageGenerator(CppHeaderLanguageGenerator):
+
+ def __init__(self):
+ super(StdCppHeaderLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
+
+
+class RustLanguageGenerator(LanguageSrcGenerator):
+
+ def _boilerplate(self, lines):
+ print("//")
+ for line in lines:
+ print("// %s" % line)
+ print("//")
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ if fromtype == self.TYPE_ENUM:
+ raise NotImplementedError("Enums not supported as source in Rust generator")
+
+ totypename = "&str" if totype == self.TYPE_STRING else "u16"
+ if fromtype != self.TYPE_STRING:
+ print("pub static %s: &[%s] = &[" % (varname.upper(), totypename))
+ else:
+ print("pub static %s: phf::Map<&str, %s> = phf::phf_map! {" %
+ (varname.upper(), totypename))
+
+ def _array_end(self, fromtype, totype):
+ if fromtype != self.TYPE_STRING:
+ print("];")
+ else:
+ print("};")
+
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ none = "\"\"" if totype == self.TYPE_STRING else "0"
+ if fromtype == self.TYPE_INT:
+ if value is None:
+ print(" %s, // %s" % (none, comment))
+ elif totype == self.TYPE_INT:
+ print(" 0x%x, // %s" % (value, comment))
+ elif totype == self.TYPE_ENUM:
+ print(" %s, // %s" % (value, comment))
+ else:
+ print(" \"%s\", // %s" % (value, comment))
+ else:
+ if value is None:
+ print(" \"%s\" => %s, // %s" % (index, none, comment))
+ elif totype == self.TYPE_INT:
+ print(" \"%s\" => 0x%x, // %s" % (index, value, comment))
+ elif totype == self.TYPE_ENUM:
+ print(" \"%s\" => %s, // %s" % (index, value, comment))
+ else:
+ print(" \"%s\" => \"%s\", // %s" % (index, value, comment))
+
+
+class PythonLanguageGenerator(LanguageSrcGenerator):
+
+ def _boilerplate(self, lines):
+ print("#")
+ for line in lines:
+ print("# %s" % line)
+ print("#")
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ if fromtype == self.TYPE_ENUM:
+ raise NotImplementedError("Enums not supported as source in Python generator")
+
+ if fromtype != self.TYPE_STRING:
+ print("%s = [" % varname)
+ else:
+ print("%s = {" % varname)
+
+ def _array_end(self, fromtype, totype):
+ if fromtype != self.TYPE_STRING:
+ print("]")
+ else:
+ print("}")
+
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ if fromtype == self.TYPE_INT:
+ if value is None:
+ print(" None, # %s" % (comment))
+ elif totype == self.TYPE_INT:
+ print(" 0x%x, # %s" % (value, comment))
+ elif totype == self.TYPE_ENUM:
+ print(" %s, # %s" % (value, comment))
+ else:
+ print(" \"%s\", # %s" % (value, comment))
+ else:
+ if value is None:
+ print(" \"%s\": None, # %s" % (index, comment))
+ elif totype == self.TYPE_INT:
+ print(" \"%s\": 0x%x, # %s" % (index, value, comment))
+ elif totype == self.TYPE_ENUM:
+ print(" \"%s\": %s, # %s" % (index, value, comment))
+ else:
+ print(" \"%s\": \"%s\", # %s" % (index, value, comment))
+
+class PerlLanguageGenerator(LanguageSrcGenerator):
+
+ def _boilerplate(self, lines):
+ print("#")
+ for line in lines:
+ print("# %s" % line)
+ print("#")
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ if fromtype == self.TYPE_ENUN:
+ raise NotImplementedError("Enums not supported as source in Python generator")
+ if fromtype == self.TYPE_INT:
+ print("my @%s = (" % varname)
+ else:
+ print("my %%%s = (" % varname)
+
+ def _array_end(self, fromtype, totype):
+ print(");")
+
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ if fromtype == self.TYPE_INT:
+ if value is None:
+ print(" undef, # %s" % (comment))
+ elif totype == self.TYPE_INT:
+ print(" 0x%x, # %s" % (value, comment))
+ elif totype == self.TYPE_ENUM:
+ print(" %s, # %s" % (value, comment))
+ else:
+ print(" \"%s\", # %s" % (value, comment))
+ else:
+ if value is None:
+ print(" \"%s\", undef, # %s" % (index, comment))
+ elif totype == self.TYPE_INT:
+ print(" \"%s\", 0x%x, # %s" % (index, value, comment))
+ elif totype == self.TYPE_ENUM:
+ print(" \"%s\", 0x%x, # %s" % (index, value, comment))
+ else:
+ print(" \"%s\", \"%s\", # %s" % (index, value, comment))
+
+class JavaScriptLanguageGenerator(LanguageSrcGenerator):
+
+ def _boilerplate(self, lines):
+ print("/*")
+ for line in lines:
+ print(" * %s" % line)
+ print("*/")
+
+ def _array_start(self, varname, length, defvalue, fromtype, totype):
+ print("export default {")
+
+ def _array_end(self, fromtype, totype):
+ print("};")
+
+ def _array_entry(self, index, value, comment, fromtype, totype):
+ if value is None:
+ return
+
+ if fromtype == self.TYPE_INT:
+ fromfmt = "0x%x"
+ elif fromtype == self.TYPE_ENUM:
+ fromfmt = "%s"
+ else:
+ fromfmt = "\"%s\""
+
+ if totype == self.TYPE_INT:
+ tofmt = "0x%x"
+ elif totype == self.TYPE_ENUM:
+ tofmt = "%s"
+ else:
+ tofmt = "\"%s\""
+
+ print((" " + fromfmt + ": " + tofmt + ", /* %s */") % (index, value, comment))
+
+class PodLanguageGenerator(LanguageDocGenerator):
+
+ def _boilerplate(self, lines):
+ print("#")
+ for line in lines:
+ print("# %s" % line)
+ print("#")
+
+ def _array_start_name_doc(self, title, subtitle, namemap):
+ print("=head1 NAME")
+ print("")
+ print("%s - %s" % (title, subtitle))
+ print("")
+ print("=head1 DESCRIPTION")
+ print("")
+ print("List of %s key code names, with corresponding key code values" % namemap)
+ print("")
+ print("=over 4")
+ print("")
+
+ def _array_start_code_doc(self, title, subtitle, codemap, namemap):
+ print("=head1 NAME")
+ print("")
+ print("%s - %s" % (title, subtitle))
+ print("")
+ print("=head1 DESCRIPTION")
+ print("")
+ print("List of %s key code values, with corresponding %s key code names" % (codemap, namemap))
+ print("")
+ print("=over 4")
+ print("")
+
+ def _array_end(self):
+ print("=back")
+ print("")
+
+ def _array_name_entry(self, value, name):
+ print("=item %s" % name)
+ print("")
+ print("Key value %d (0x%x)" % (value, value))
+ print("")
+
+ def _array_code_entry(self, value, name):
+ print("=item %d (0x%x)" % (value, value))
+ print("")
+ print("Key name %s" % name)
+ print("")
+
+class RSTLanguageGenerator(LanguageDocGenerator):
+
+ def _boilerplate(self, lines):
+ print("..")
+ for line in lines:
+ print(" %s" % line)
+ print("")
+
+ def _array_start_name_doc(self, title, subtitle, namemap):
+ print("=" * len(title))
+ print(title)
+ print("=" * len(title))
+ print("")
+ print("-" * len(subtitle))
+ print(subtitle)
+ print("-" * len(subtitle))
+ print("")
+ print(":Manual section: 7")
+ print(":Manual group: Virtualization Support")
+ print("")
+ print("DESCRIPTION")
+ print("===========")
+ print("List of %s key code names, with corresponding key code values" % namemap)
+ print("")
+
+ def _array_start_code_doc(self, title, subtitle, codemap, namemap):
+ print("=" * len(title))
+ print(title)
+ print("=" * len(title))
+ print("")
+ print("-" * len(subtitle))
+ print(subtitle)
+ print("-" * len(subtitle))
+ print("")
+ print(":Manual section: 7")
+ print(":Manual group: Virtualization Support")
+ print("")
+ print("DESCRIPTION")
+ print("===========")
+ print("List of %s key code values, with corresponding %s key code names" % (codemap, namemap))
+ print("")
+
+ def _array_end(self):
+ print("")
+
+ def _array_name_entry(self, value, name):
+ print("* %s" % name)
+ print("")
+ print(" Key value %d (0x%x)" % (value, value))
+ print("")
+
+ def _array_code_entry(self, value, name):
+ print("* %d (0x%x)" % (value, value))
+ print("")
+ print(" Key name %s" % name)
+ print("")
+
+SRC_GENERATORS = {
+ "stdc": StdCLanguageGenerator(),
+ "stdc-header": StdCHeaderLanguageGenerator(),
+ "stdc++": StdCppLanguageGenerator(),
+ "stdc++-header": StdCppHeaderLanguageGenerator(),
+ "glib2": GLib2LanguageGenerator(),
+ "glib2-header": GLib2HeaderLanguageGenerator(),
+ "python2": PythonLanguageGenerator(),
+ "python3": PythonLanguageGenerator(),
+ "perl": PerlLanguageGenerator(),
+ "js": JavaScriptLanguageGenerator(),
+ "rust": RustLanguageGenerator(),
+}
+DOC_GENERATORS = {
+ "pod": PodLanguageGenerator(),
+ "rst": RSTLanguageGenerator(),
+}
+
+def code_map(args):
+ database = Database()
+ database.load(args.keymaps)
+
+ cliargs = ["keymap-gen", "code-map", "--lang=%s" % args.lang]
+ if args.varname is not None:
+ cliargs.append("--varname=%s" % args.varname)
+ cliargs.extend(["keymaps.csv", args.frommapname, args.tomapname])
+ SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+ SRC_GENERATORS[args.lang].generate_code_map(args.varname, database, args.frommapname, args.tomapname)
+
+def code_table(args):
+ database = Database()
+ database.load(args.keymaps)
+
+ cliargs = ["keymap-gen", "code-table", "--lang=%s" % args.lang]
+ if args.varname is not None:
+ cliargs.append("--varname=%s" % args.varname)
+ cliargs.extend(["keymaps.csv", args.mapname])
+ SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+ SRC_GENERATORS[args.lang].generate_code_table(args.varname, database, args.mapname)
+
+def name_map(args):
+ database = Database()
+ database.load(args.keymaps)
+
+ cliargs = ["keymap-gen", "name-map", "--lang=%s" % args.lang]
+ if args.varname is not None:
+ cliargs.append("--varname=%s" % args.varname)
+ cliargs.extend(["keymaps.csv", args.frommapname, args.tomapname])
+ SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+ SRC_GENERATORS[args.lang].generate_name_map(args.varname, database, args.frommapname, args.tomapname)
+
+def name_table(args):
+ database = Database()
+ database.load(args.keymaps)
+
+
+ cliargs = ["keymap-gen", "name-table", "--lang=%s" % args.lang]
+ if args.varname is not None:
+ cliargs.append("--varname=%s" % args.varname)
+ cliargs.extend(["keymaps.csv", args.mapname])
+ SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+ SRC_GENERATORS[args.lang].generate_name_table(args.varname, database, args.mapname)
+
+def code_docs(args):
+ database = Database()
+ database.load(args.keymaps)
+
+
+ cliargs = ["keymap-gen", "code-docs", "--lang=%s" % args.lang]
+ if args.title is not None:
+ cliargs.append("--title=%s" % args.title)
+ if args.subtitle is not None:
+ cliargs.append("--subtitle=%s" % args.subtitle)
+ cliargs.extend(["keymaps.csv", args.mapname])
+ DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+ DOC_GENERATORS[args.lang].generate_code_docs(args.title, args.subtitle, database, args.mapname)
+
+def name_docs(args):
+ database = Database()
+ database.load(args.keymaps)
+
+
+ cliargs = ["keymap-gen", "name-docs", "--lang=%s" % args.lang]
+ if args.title is not None:
+ cliargs.append("--title=%s" % args.title)
+ if args.subtitle is not None:
+ cliargs.append("--subtitle=%s" % args.subtitle)
+ cliargs.extend(["keymaps.csv", args.mapname])
+ DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
+
+ DOC_GENERATORS[args.lang].generate_name_docs(args.title, args.subtitle, database, args.mapname)
+
+def usage():
+ print ("Please select a command:")
+ print (" 'code-map', 'code-table', 'name-map', 'name-table', 'docs'")
+ sys.exit(1)
+
+def main():
+ parser = argparse.ArgumentParser()
+
+ subparsers = parser.add_subparsers(help="sub-command help")
+
+ codemapparser = subparsers.add_parser("code-map", help="Generate a mapping between code tables")
+ codemapparser.add_argument("--varname", default=None, help="Data variable name")
+ codemapparser.add_argument("--lang", default="stdc",
+ help="Output language (%s)" % (
+ ",".join(SRC_GENERATORS.keys())))
+ codemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
+ codemapparser.add_argument("frommapname", help="Source code table name")
+ codemapparser.add_argument("tomapname", help="Target code table name")
+ codemapparser.set_defaults(func=code_map)
+
+ codetableparser = subparsers.add_parser("code-table", help="Generate a flat code table")
+ codetableparser.add_argument("--lang", default="stdc",
+ help="Output language (%s)" % (
+ ",".join(SRC_GENERATORS.keys())))
+ codetableparser.add_argument("--varname", default=None, help="Data variable name")
+ codetableparser.add_argument("keymaps", help="Path to keymap CSV data file")
+ codetableparser.add_argument("mapname", help="Code table name")
+ codetableparser.set_defaults(func=code_table)
+
+ namemapparser = subparsers.add_parser("name-map", help="Generate a mapping to names")
+ namemapparser.add_argument("--lang", default="stdc",
+ help="Output language (%s)" % (
+ ",".join(SRC_GENERATORS.keys())))
+ namemapparser.add_argument("--varname", default=None, help="Data variable name")
+ namemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
+ namemapparser.add_argument("frommapname", help="Source code table name")
+ namemapparser.add_argument("tomapname", help="Target name table name")
+ namemapparser.set_defaults(func=name_map)
+
+ nametableparser = subparsers.add_parser("name-table", help="Generate a flat name table")
+ nametableparser.add_argument("--lang", default="stdc",
+ help="Output language, (%s)" % (
+ ",".join(SRC_GENERATORS.keys())))
+ nametableparser.add_argument("--varname", default=None, help="Data variable name")
+ nametableparser.add_argument("keymaps", help="Path to keymap CSV data file")
+ nametableparser.add_argument("mapname", help="Name table name")
+ nametableparser.set_defaults(func=name_table)
+
+ codedocsparser = subparsers.add_parser("code-docs", help="Generate code documentation")
+ codedocsparser.add_argument("--lang", default="pod",
+ help="Output language (%s)" % (
+ ",".join(DOC_GENERATORS.keys())))
+ codedocsparser.add_argument("--title", default=None, help="Document title")
+ codedocsparser.add_argument("--subtitle", default=None, help="Document subtitle")
+ codedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
+ codedocsparser.add_argument("mapname", help="Code table name")
+ codedocsparser.set_defaults(func=code_docs)
+
+ namedocsparser = subparsers.add_parser("name-docs", help="Generate name documentation")
+ namedocsparser.add_argument("--lang", default="pod",
+ help="Output language (%s)" % (
+ ",".join(DOC_GENERATORS.keys())))
+ namedocsparser.add_argument("--title", default=None, help="Document title")
+ namedocsparser.add_argument("--subtitle", default=None, help="Document subtitle")
+ namedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
+ namedocsparser.add_argument("mapname", help="Name table name")
+ namedocsparser.set_defaults(func=name_docs)
+
+ args = parser.parse_args()
+ if hasattr(args, "func"):
+ args.func(args)
+ else:
+ usage()
+
+
+main()