Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(910)

Unified Diff: ui/events/keycodes/dom4/generate_dom_values.py

Issue 641753003: DOM Level 3 .code and .key value enumerations. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/events/keycodes/dom4/generate_dom_values.py
diff --git a/ui/events/keycodes/dom4/generate_dom_values.py b/ui/events/keycodes/dom4/generate_dom_values.py
new file mode 100755
index 0000000000000000000000000000000000000000..2c7dd64079c639947d0219e9245d26cb8d237595
--- /dev/null
+++ b/ui/events/keycodes/dom4/generate_dom_values.py
@@ -0,0 +1,308 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generate C++ header files for DOM keyboard event values.
+
+Run it like this:
+ gen_key_codes.py \
+ --input_dom=dom_values.txt \
+ --input_native=native_codes.txt \
+ --output_dom_code_declaration=domcode.h \
+ --output_dom_code_definition=domcode_definition.h \
+ --output_dom_code_string=domcode_string.h \
+ --output_dom_code_table=domcode_table.h \
+ --output_dom_key_declaration=domkey.h \
+ --output_dom_key_string=domkey_string.h \
+ --output_dom_key_table=domkey_table.h \
+ --output_dom_key_definition=domkey_definition.h \
+ --output_native=native_data.h
+
+Inputs:
+
+ --input_dom
+ Table of DOM Level 3 .code and .key values.
+
+ --input_native
+ Table of platform-native scan codes and corresponding DOM .code values.
+
+Output:
+
+ --output_dom_{code|key}_declaration
+ Header containing 'enum class' forward declaration.
+
+ --output_dom_{code|key}_definition
+ Header containing enumeration values.
+
+ --output_dom_{code|key}_string
+ Table of DOM string values indexed by enumeration value.
+
+ --output_dom_{code|key}_table
+ Table of DOM string values and corresponding enumerators.
+
+ --output_native
+ Table of platform-native scan codes and corresponding |DomKey|s.
+
+"""
+
+import argparse
+import csv
+import sys
+
+def CamelCaseToCMacro(s):
+ """Convert CamelCase as used by W3C to C_MACRO_STYLE as used by Chromium."""
+ r = ''
+ n = len(s)
+ for i in range(0, n):
+ if s[i].isupper() and i > 0 and i + 1 < n and not s[i + 1].isupper():
+ r += '_'
+ r += s[i].upper()
+ return r
+
+def StringToCString(s):
+ """Converts to a C-style string (assuming no escapes required), or nullptr."""
+ if s is None:
+ return 'nullptr'
+ return '"' + s + '"'
+
+class NameFields:
+ """Implements 'DomString[-EnumId[-Comment]]' syntax for DOM value columns."""
+ def __init__(self, name, delimiter='-'):
+ self.fields = name.split(delimiter)
+ def _field(self, index):
+ return self.fields[min(index, len(self.fields) - 1)]
+ def GetDomString(self):
+ s = self._field(0)
+ return s if (s or self._field(1)) else None
+ def GetEnumId(self, prefix=''):
+ s = self._field(1)
+ return (prefix + CamelCaseToCMacro(s)) if s else None
+
+def IntOrNone(s):
+ if s == '-':
+ return None
+ return int(s, base=0)
+
+def IsNotComment(line):
+ """Implements the input file comment line convention."""
+ return not line[0].isspace()
+
+def SplitLine(line):
+ """Split the input line into a list of fields separated by white space."""
+ # Using csv.reader to split the line allows for escaping and quoting.
+ return csv.reader([line], delimiter=' ', skipinitialspace=True).next()
+
+class Header:
+ """Wrap output in a C header file."""
+ def __init__(self, filename, comments, wrappers):
+ self.out = sys.stdout if filename == '-' else open(filename, 'wb')
+ for c in comments:
+ self.out.write('// ' + c + '\n')
+ guard = (''.join([c.upper() if c.isalpha() else '_' for c in filename]) +
+ '_').lstrip('_')
+ self.wrappers = [('#ifndef {0}\n#define {0}'.format(guard),
+ '#endif // {}'.format(guard))] + wrappers
+ def __enter__(self):
+ for begin, _ in self.wrappers:
+ self.out.write(begin + '\n')
+ return self.out
+ def __exit__(self, typ, value, traceback):
+ for _, end in reversed(self.wrappers):
+ self.out.write(end + '\n')
+ if self.out != sys.stdout:
+ self.out.close()
+
+class CK:
+ """Things we do for both .code and .key."""
+ def __init__(self, name):
+ # Names of things.
+ self.name = name
+ self.enum = 'Dom' + name.capitalize()
+ self.macro = CamelCaseToCMacro(self.enum)
+ self.var = self.macro.lower()
+ self.basename = ''.join(filter(str.isalpha, list(self.var)))
+ # Accumulated data.
+ self.name_by_value = {}
+ self.id_by_value = {}
+ self.string_by_value = {}
+ self.id_by_string = {}
+ self.value_by_id = {}
+ # Generated files.
+ self.headers = {
+ 'declaration': {
+ 'argument': '--output_{}_declaration'.format(self.var),
+ 'file': '{}.h'.format(self.basename),
+ 'help': 'Enumeration type for DOM Level 3 .{}.'.format(name),
+ 'wrap': [('namespace ui {', '} // namespace ui'),
+ ('enum {} {{'.format(self.enum), '};')],
+ 'generator': self.GenerateEnumValues
+# For C++11 enum class:
+# 'wrap': [('namespace ui {', '} // namespace ui')],
+# 'generator': self.GenerateEnumDeclaration
+ },
+# For C++11 enum class:
+# 'definition': {
+# 'argument': '--output_{}_definition'.format(self.var),
+# 'file': '{}_definition.h'.format(self.basename),
+# 'help': 'Enumeration of DOM Level 3 .{} values.'.format(name),
+# 'wrap': [('namespace ui {', '} // namespace ui'),
+# ('enum class {} {{'.format(self.enum), '};')],
+# 'generator': self.GenerateEnumValues
+# },
+ 'table': {
+ 'argument': '--output_{}_table'.format(self.var),
+ 'file': '{}_table.h'.format(self.basename),
+ 'help':
+ 'Table of DOM Level 3 .{} strings and enum values.'.format(name),
+ 'wrap': [('const DomKeyCodeEntry<{}> {}_table[] = {{'
+ .format(self.enum, self.var),
+ '};')],
+ 'generator': self.GenerateTable
+ },
+ 'strings': {
+ 'argument': '--output_{}_string'.format(self.var),
+ 'file': '{}_string.h'.format(self.basename),
+ 'help':
+ 'DOM .{} strings indexed by {} integer value.'.format(name, self.enum),
+ 'wrap': [('const char* const {}_string[] = {{'.format(self.var), '};')],
+ 'generator': self.GenerateStrings
+ }
+ }
+
+ def AddArguments(self, parser):
+ for h in self.headers.values():
+ h['arg'] = parser.add_argument(h['argument'],
+ default=h['file'],
+ help=h['help'])
+
+ def GenerateFiles(self, args, danger):
+ for h in self.headers.values():
+ with Header(vars(args)[h['arg'].dest],
+ [danger, h['help']],
+ h['wrap']) as out:
+ h['generator'](out)
+
+ def GenerateEnumDeclaration(self, out):
+ out.write('enum class {};\n'.format(self.enum))
+
+ def GenerateEnumValues(self, out):
+ for v, i in sorted(self.id_by_value.iteritems()):
+ out.write(' {}_{} = 0x{:03X},'.format(self.macro, i, v))
+ # For C++11 enum class:
+ # out.write(' {} = 0x{:03X},'.format(i, v))
+ s = self.string_by_value.get(v)
+ if s:
+ out.write(' // ' + s)
+ out.write('\n')
+
+ def GenerateTable(self, out):
+ for s, i in sorted(self.id_by_string.iteritems()):
+ out.write(' {{{}, {}_{}}},\n'.format(StringToCString(s), self.macro, i))
+ # For C++11 enum class:
+ #out.write(' {{{}, {}::{}}},\n'.format(StringToCString(s), self.enum, i))
+
+ def GenerateStrings(self, out):
+ for v in range(0, 1 + max(self.string_by_value)):
+ out.write(' /* 0x{:03X} */ {},\n'
+ .format(v, StringToCString(self.string_by_value.get(v))))
+# out.write('#define MAX_{}_STRING_FOR_TEST 0x{:03X}\n'
+# .format(self.macro, max(self.string_by_value)))
+# out.write('#define NUM_{}_STRINGS_FOR_TEST 0x{:03X}\n'
+# .format(self.macro, len(self.string_by_value)))
+
+ def AddEntry(self, value, name):
+ value = int(value, base=0)
+ identifier = NameFields(name).GetEnumId()
+ if identifier:
+ self.value_by_id[identifier] = value
+ self.name_by_value[value] = name
+ self.id_by_value[value] = identifier
+ string = NameFields(name).GetDomString()
+ if string is not None:
+ self.string_by_value[value] = string
+ self.id_by_string[string] = identifier
+
+def Some(a, b):
+ return a if a is not None else b
+
+def main(argv):
+ fail = 0
+ codes = CK('code')
+ keys = CK('key')
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--input_dom', default='dom_values.txt')
+ parser.add_argument('--input_native', default='native_codes.txt')
+ codes.AddArguments(parser)
+ keys.AddArguments(parser)
+ parser.add_argument('--output_native', default='native_data.h')
+ args = parser.parse_args(argv[1:])
+
+ # Read the --input_dom file.
+ with open(args.input_dom, 'rb') as input_dom:
+ for line in filter(IsNotComment, input_dom):
+ column = SplitLine(line)
+ codes.AddEntry(column[0], column[1])
+ keys.AddEntry(column[0], column[2])
+
+ # Read the --input_native file into various dictionaries,
+ # checking it against --input_dom.
+ xkb_by_usb = {}
+ win_by_usb = {}
+ mac_by_usb = {}
+ code_by_usb = {}
+ usb_name_by_usb = {}
+ with open(args.input_native, 'rb') as input_native:
+ for line in filter(IsNotComment, input_native):
+ column = SplitLine(line)
+ usb = int(column[0], base=0)
+ xkb_by_usb[usb] = IntOrNone(column[1])
+ win_by_usb[usb] = IntOrNone(column[2])
+ mac_by_usb[usb] = IntOrNone(column[3])
+ usb_name_by_usb[usb] = column[5]
+ code_id = NameFields(column[4]).GetEnumId()
+ if code_id is None:
+ code_value = None
+ else:
+ code_value = codes.value_by_id.get(code_id, None)
+ if code_value is None:
+ fail = 1
+ sys.stderr.write('error: code {} in {} but not in {}\n'
+ .format(column[4],
+ args.input_native,
+ args.input_dom))
+ code_by_usb[usb] = code_value
+
+ # Write output files.
+ danger = ('DO NOT MODIFY. GENERATED BY ' + sys.argv[0] +
+ ' FROM ' + args.input_dom + '.')
+
+ codes.GenerateFiles(args, danger)
+ keys.GenerateFiles(args, danger)
+
+ with Header(args.output_native,
+ [danger, 'Table of native key codes.'],
+ [('const KeycodeMapEntry usb_keycode_map[] = {', '};')]) as out:
+ for usb, code in code_by_usb.iteritems():
+ # For C++11 enum class:
+ #out.write(' USB_KEYMAP(0x{:06X}, 0x{:04X}, 0x{:04X}, 0x{:04X}, {}::{}),'
+ out.write(' USB_KEYMAP(0x{:06X}, 0x{:04X}, 0x{:04X}, 0x{:04X}, {}_{}),'
+ .format(usb,
+ Some(xkb_by_usb[usb], xkb_by_usb[0]),
+ Some(win_by_usb[usb], win_by_usb[0]),
+ Some(mac_by_usb[usb], mac_by_usb[0]),
+ codes.macro,
+ # For C++11 enum class:
+ # codes.enum,
+ codes.id_by_value.get(code, codes.id_by_value[0])))
+ if usb_name_by_usb[usb]:
+ out.write(' // {}'.format(usb_name_by_usb[usb]))
+ out.write('\n')
+
+
+ return fail
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
+

Powered by Google App Engine
This is Rietveld 408576698