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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Generate C++ header files for DOM keyboard event values.
7
8 Run it like this:
9 gen_key_codes.py \
10 --input_dom=dom_values.txt \
11 --input_native=native_codes.txt \
12 --output_dom_code_declaration=domcode.h \
13 --output_dom_code_definition=domcode_definition.h \
14 --output_dom_code_string=domcode_string.h \
15 --output_dom_code_table=domcode_table.h \
16 --output_dom_key_declaration=domkey.h \
17 --output_dom_key_string=domkey_string.h \
18 --output_dom_key_table=domkey_table.h \
19 --output_dom_key_definition=domkey_definition.h \
20 --output_native=native_data.h
21
22 Inputs:
23
24 --input_dom
25 Table of DOM Level 3 .code and .key values.
26
27 --input_native
28 Table of platform-native scan codes and corresponding DOM .code values.
29
30 Output:
31
32 --output_dom_{code|key}_declaration
33 Header containing 'enum class' forward declaration.
34
35 --output_dom_{code|key}_definition
36 Header containing enumeration values.
37
38 --output_dom_{code|key}_string
39 Table of DOM string values indexed by enumeration value.
40
41 --output_dom_{code|key}_table
42 Table of DOM string values and corresponding enumerators.
43
44 --output_native
45 Table of platform-native scan codes and corresponding |DomKey|s.
46
47 """
48
49 import argparse
50 import csv
51 import sys
52
53 def CamelCaseToCMacro(s):
54 """Convert CamelCase as used by W3C to C_MACRO_STYLE as used by Chromium."""
55 r = ''
56 n = len(s)
57 for i in range(0, n):
58 if s[i].isupper() and i > 0 and i + 1 < n and not s[i + 1].isupper():
59 r += '_'
60 r += s[i].upper()
61 return r
62
63 def StringToCString(s):
64 """Converts to a C-style string (assuming no escapes required), or nullptr."""
65 if s is None:
66 return 'nullptr'
67 return '"' + s + '"'
68
69 class NameFields:
70 """Implements 'DomString[-EnumId[-Comment]]' syntax for DOM value columns."""
71 def __init__(self, name, delimiter='-'):
72 self.fields = name.split(delimiter)
73 def _field(self, index):
74 return self.fields[min(index, len(self.fields) - 1)]
75 def GetDomString(self):
76 s = self._field(0)
77 return s if (s or self._field(1)) else None
78 def GetEnumId(self, prefix=''):
79 s = self._field(1)
80 return (prefix + CamelCaseToCMacro(s)) if s else None
81
82 def IntOrNone(s):
83 if s == '-':
84 return None
85 return int(s, base=0)
86
87 def IsNotComment(line):
88 """Implements the input file comment line convention."""
89 return not line[0].isspace()
90
91 def SplitLine(line):
92 """Split the input line into a list of fields separated by white space."""
93 # Using csv.reader to split the line allows for escaping and quoting.
94 return csv.reader([line], delimiter=' ', skipinitialspace=True).next()
95
96 class Header:
97 """Wrap output in a C header file."""
98 def __init__(self, filename, comments, wrappers):
99 self.out = sys.stdout if filename == '-' else open(filename, 'wb')
100 for c in comments:
101 self.out.write('// ' + c + '\n')
102 guard = (''.join([c.upper() if c.isalpha() else '_' for c in filename]) +
103 '_').lstrip('_')
104 self.wrappers = [('#ifndef {0}\n#define {0}'.format(guard),
105 '#endif // {}'.format(guard))] + wrappers
106 def __enter__(self):
107 for begin, _ in self.wrappers:
108 self.out.write(begin + '\n')
109 return self.out
110 def __exit__(self, typ, value, traceback):
111 for _, end in reversed(self.wrappers):
112 self.out.write(end + '\n')
113 if self.out != sys.stdout:
114 self.out.close()
115
116 class CK:
117 """Things we do for both .code and .key."""
118 def __init__(self, name):
119 # Names of things.
120 self.name = name
121 self.enum = 'Dom' + name.capitalize()
122 self.macro = CamelCaseToCMacro(self.enum)
123 self.var = self.macro.lower()
124 self.basename = ''.join(filter(str.isalpha, list(self.var)))
125 # Accumulated data.
126 self.name_by_value = {}
127 self.id_by_value = {}
128 self.string_by_value = {}
129 self.id_by_string = {}
130 self.value_by_id = {}
131 # Generated files.
132 self.headers = {
133 'declaration': {
134 'argument': '--output_{}_declaration'.format(self.var),
135 'file': '{}.h'.format(self.basename),
136 'help': 'Enumeration type for DOM Level 3 .{}.'.format(name),
137 'wrap': [('namespace ui {', '} // namespace ui'),
138 ('enum {} {{'.format(self.enum), '};')],
139 'generator': self.GenerateEnumValues
140 # For C++11 enum class:
141 # 'wrap': [('namespace ui {', '} // namespace ui')],
142 # 'generator': self.GenerateEnumDeclaration
143 },
144 # For C++11 enum class:
145 # 'definition': {
146 # 'argument': '--output_{}_definition'.format(self.var),
147 # 'file': '{}_definition.h'.format(self.basename),
148 # 'help': 'Enumeration of DOM Level 3 .{} values.'.format(name),
149 # 'wrap': [('namespace ui {', '} // namespace ui'),
150 # ('enum class {} {{'.format(self.enum), '};')],
151 # 'generator': self.GenerateEnumValues
152 # },
153 'table': {
154 'argument': '--output_{}_table'.format(self.var),
155 'file': '{}_table.h'.format(self.basename),
156 'help':
157 'Table of DOM Level 3 .{} strings and enum values.'.format(name),
158 'wrap': [('const DomKeyCodeEntry<{}> {}_table[] = {{'
159 .format(self.enum, self.var),
160 '};')],
161 'generator': self.GenerateTable
162 },
163 'strings': {
164 'argument': '--output_{}_string'.format(self.var),
165 'file': '{}_string.h'.format(self.basename),
166 'help':
167 'DOM .{} strings indexed by {} integer value.'.format(name, self.enum),
168 'wrap': [('const char* const {}_string[] = {{'.format(self.var), '};')],
169 'generator': self.GenerateStrings
170 }
171 }
172
173 def AddArguments(self, parser):
174 for h in self.headers.values():
175 h['arg'] = parser.add_argument(h['argument'],
176 default=h['file'],
177 help=h['help'])
178
179 def GenerateFiles(self, args, danger):
180 for h in self.headers.values():
181 with Header(vars(args)[h['arg'].dest],
182 [danger, h['help']],
183 h['wrap']) as out:
184 h['generator'](out)
185
186 def GenerateEnumDeclaration(self, out):
187 out.write('enum class {};\n'.format(self.enum))
188
189 def GenerateEnumValues(self, out):
190 for v, i in sorted(self.id_by_value.iteritems()):
191 out.write(' {}_{} = 0x{:03X},'.format(self.macro, i, v))
192 # For C++11 enum class:
193 # out.write(' {} = 0x{:03X},'.format(i, v))
194 s = self.string_by_value.get(v)
195 if s:
196 out.write(' // ' + s)
197 out.write('\n')
198
199 def GenerateTable(self, out):
200 for s, i in sorted(self.id_by_string.iteritems()):
201 out.write(' {{{}, {}_{}}},\n'.format(StringToCString(s), self.macro, i))
202 # For C++11 enum class:
203 #out.write(' {{{}, {}::{}}},\n'.format(StringToCString(s), self.enum, i))
204
205 def GenerateStrings(self, out):
206 for v in range(0, 1 + max(self.string_by_value)):
207 out.write(' /* 0x{:03X} */ {},\n'
208 .format(v, StringToCString(self.string_by_value.get(v))))
209 # out.write('#define MAX_{}_STRING_FOR_TEST 0x{:03X}\n'
210 # .format(self.macro, max(self.string_by_value)))
211 # out.write('#define NUM_{}_STRINGS_FOR_TEST 0x{:03X}\n'
212 # .format(self.macro, len(self.string_by_value)))
213
214 def AddEntry(self, value, name):
215 value = int(value, base=0)
216 identifier = NameFields(name).GetEnumId()
217 if identifier:
218 self.value_by_id[identifier] = value
219 self.name_by_value[value] = name
220 self.id_by_value[value] = identifier
221 string = NameFields(name).GetDomString()
222 if string is not None:
223 self.string_by_value[value] = string
224 self.id_by_string[string] = identifier
225
226 def Some(a, b):
227 return a if a is not None else b
228
229 def main(argv):
230 fail = 0
231 codes = CK('code')
232 keys = CK('key')
233
234 parser = argparse.ArgumentParser()
235 parser.add_argument('--input_dom', default='dom_values.txt')
236 parser.add_argument('--input_native', default='native_codes.txt')
237 codes.AddArguments(parser)
238 keys.AddArguments(parser)
239 parser.add_argument('--output_native', default='native_data.h')
240 args = parser.parse_args(argv[1:])
241
242 # Read the --input_dom file.
243 with open(args.input_dom, 'rb') as input_dom:
244 for line in filter(IsNotComment, input_dom):
245 column = SplitLine(line)
246 codes.AddEntry(column[0], column[1])
247 keys.AddEntry(column[0], column[2])
248
249 # Read the --input_native file into various dictionaries,
250 # checking it against --input_dom.
251 xkb_by_usb = {}
252 win_by_usb = {}
253 mac_by_usb = {}
254 code_by_usb = {}
255 usb_name_by_usb = {}
256 with open(args.input_native, 'rb') as input_native:
257 for line in filter(IsNotComment, input_native):
258 column = SplitLine(line)
259 usb = int(column[0], base=0)
260 xkb_by_usb[usb] = IntOrNone(column[1])
261 win_by_usb[usb] = IntOrNone(column[2])
262 mac_by_usb[usb] = IntOrNone(column[3])
263 usb_name_by_usb[usb] = column[5]
264 code_id = NameFields(column[4]).GetEnumId()
265 if code_id is None:
266 code_value = None
267 else:
268 code_value = codes.value_by_id.get(code_id, None)
269 if code_value is None:
270 fail = 1
271 sys.stderr.write('error: code {} in {} but not in {}\n'
272 .format(column[4],
273 args.input_native,
274 args.input_dom))
275 code_by_usb[usb] = code_value
276
277 # Write output files.
278 danger = ('DO NOT MODIFY. GENERATED BY ' + sys.argv[0] +
279 ' FROM ' + args.input_dom + '.')
280
281 codes.GenerateFiles(args, danger)
282 keys.GenerateFiles(args, danger)
283
284 with Header(args.output_native,
285 [danger, 'Table of native key codes.'],
286 [('const KeycodeMapEntry usb_keycode_map[] = {', '};')]) as out:
287 for usb, code in code_by_usb.iteritems():
288 # For C++11 enum class:
289 #out.write(' USB_KEYMAP(0x{:06X}, 0x{:04X}, 0x{:04X}, 0x{:04X}, {}::{}),'
290 out.write(' USB_KEYMAP(0x{:06X}, 0x{:04X}, 0x{:04X}, 0x{:04X}, {}_{}),'
291 .format(usb,
292 Some(xkb_by_usb[usb], xkb_by_usb[0]),
293 Some(win_by_usb[usb], win_by_usb[0]),
294 Some(mac_by_usb[usb], mac_by_usb[0]),
295 codes.macro,
296 # For C++11 enum class:
297 # codes.enum,
298 codes.id_by_value.get(code, codes.id_by_value[0])))
299 if usb_name_by_usb[usb]:
300 out.write(' // {}'.format(usb_name_by_usb[usb]))
301 out.write('\n')
302
303
304 return fail
305
306 if __name__ == '__main__':
307 sys.exit(main(sys.argv))
308
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698