Drive: Add BatchableRequest subclass.
[chromium-blink-merge.git] / ui / events / ozone / layout / xkb / xkb_keyboard_layout_engine.cc
blob63b89fe67c6db5ea99326cf44591bc54e6a86211
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.h"
7 #include <xkbcommon/xkbcommon-names.h>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/task_runner.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/threading/worker_pool.h"
16 #include "ui/events/event_constants.h"
17 #include "ui/events/keycodes/dom3/dom_code.h"
18 #include "ui/events/keycodes/dom3/dom_key.h"
19 #include "ui/events/keycodes/dom4/keycode_converter.h"
20 #include "ui/events/keycodes/keyboard_code_conversion.h"
21 #include "ui/events/ozone/layout/layout_util.h"
22 #include "ui/events/ozone/layout/xkb/xkb_keyboard_code_conversion.h"
24 namespace ui {
26 namespace {
28 typedef base::Callback<void(const std::string&,
29 scoped_ptr<char, base::FreeDeleter>)>
30 LoadKeymapCallback;
32 DomKey CharacterToDomKey(base::char16 character) {
33 switch (character) {
34 case 0x08:
35 return DomKey::BACKSPACE;
36 case 0x09:
37 return DomKey::TAB;
38 case 0x0A:
39 case 0x0D:
40 return DomKey::ENTER;
41 case 0x1B:
42 return DomKey::ESCAPE;
43 default:
44 return DomKey::CHARACTER;
48 KeyboardCode AlphanumericKeyboardCode(base::char16 character) {
49 // Plain ASCII letters and digits map directly to VKEY values.
50 if ((character >= '0') && (character <= '9'))
51 return static_cast<KeyboardCode>(VKEY_0 + character - '0');
52 if ((character >= 'a') && (character <= 'z'))
53 return static_cast<KeyboardCode>(VKEY_A + character - 'a');
54 if ((character >= 'A') && (character <= 'Z'))
55 return static_cast<KeyboardCode>(VKEY_A + character - 'A');
56 return VKEY_UNKNOWN;
59 // These tables map layout-dependent printable characters/codes
60 // to legacy Windows-based VKEY values.
62 // VKEYs are determined by the character produced from a DomCode without
63 // any modifiers, plus zero or more of the DomCode itself, the character
64 // produced with the Shift modifier, and the character produced with the
65 // AltGr modifier.
67 // A table of one or more PrintableSubEntry cases applies when the VKEY is
68 // not determined by the unmodified character value alone. Each such table
69 // corresponds to one unmodified character value. For an entry to match,
70 // the dom_code must match, and, if test_X is set, then the character for
71 // the key plus modifier X must also match.
72 struct PrintableSubEntry {
73 DomCode dom_code;
74 bool test_shift : 1;
75 bool test_altgr : 1;
76 base::char16 shift_character;
77 base::char16 altgr_character;
78 KeyboardCode key_code;
81 const base::char16 kNone = 0xFFFE;
82 const base::char16 kAny = 0xFFFF;
84 // U+0021 exclamation mark
85 const PrintableSubEntry kU0021[] = {
86 {DomCode::DIGIT1, 0, 0, kAny, kAny, VKEY_1},
87 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
88 {DomCode::SLASH, 0, 0, kAny, kAny, VKEY_OEM_8}};
90 // U+0022 quote
91 const PrintableSubEntry kU0022[] = {
92 {DomCode::DIGIT2, 0, 0, kAny, kAny, VKEY_2},
93 {DomCode::DIGIT3, 0, 0, kAny, kAny, VKEY_3}};
95 // U+0023 number sign
96 const PrintableSubEntry kU0023[] = {
97 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_OEM_7},
98 {DomCode::BACKSLASH, 1, 0, 0x0027, kAny, VKEY_OEM_2}, // apostrophe
99 {DomCode::BACKSLASH, 1, 1, 0x007E, kNone, VKEY_OEM_7}}; // ~, NoSymbol
101 // U+0024 dollar sign
102 const PrintableSubEntry kU0024[] = {
103 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_1},
104 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_8}};
106 // U+0027 apostrophe
107 const PrintableSubEntry kU0027[] = {
108 {DomCode::DIGIT4, 0, 0, kAny, kAny, VKEY_4},
109 {DomCode::KEY_Q, 0, 0, kAny, kAny, VKEY_OEM_7},
110 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_1},
111 {DomCode::SLASH, 0, 0, kAny, kAny, VKEY_OEM_7},
112 {DomCode::QUOTE, 1, 0, 0x0022, kAny, VKEY_OEM_7}, // quote
113 {DomCode::BACKQUOTE, 1, 0, 0x0022, kAny, VKEY_OEM_3}, // quote
114 {DomCode::BACKQUOTE, 1, 0, 0x00B7, kAny, VKEY_OEM_5}, // middle dot
115 {DomCode::BACKSLASH, 1, 0, kNone, kAny, VKEY_OEM_5}, // NoSymbol
116 {DomCode::MINUS, 1, 1, 0x003F, kNone, VKEY_OEM_4}, // ?, NoSymbol
117 {DomCode::MINUS, 1, 1, 0x003F, 0x00DD, VKEY_OEM_4}, // ?, Y acute
118 {DomCode::EQUAL, 1, 1, 0x002A, kNone, VKEY_OEM_PLUS}, // *, NoSymbol
119 {DomCode::QUOTE, 1, 1, 0x0040, kNone, VKEY_OEM_3}, // @, NoSymbol
120 {DomCode::BACKSLASH, 1, 1, 0x002A, kNone, VKEY_OEM_2}, // *, NoSymbol
121 {DomCode::BACKSLASH, 1, 1, 0x002A, 0x00BD, VKEY_OEM_5}, // *, one half
122 {DomCode::BACKSLASH, 1, 1, 0x002A, 0x0141, VKEY_OEM_2}, // *, L stroke
123 {DomCode::KEY_Z, 1, 1, 0x0022, kNone, VKEY_Z}, // quote, NoSymbol
124 {DomCode::KEY_Z, 1, 1, 0x0022, 0x0158, VKEY_OEM_7}}; // quote, R caron
126 // U+0028 left parenthesis
127 const PrintableSubEntry kU0028[] = {
128 {DomCode::DIGIT5, 0, 0, kAny, kAny, VKEY_5},
129 {DomCode::DIGIT9, 0, 0, kAny, kAny, VKEY_9},
130 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5}};
132 // U+0029 right parenthesis
133 const PrintableSubEntry kU0029[] = {
134 {DomCode::DIGIT0, 0, 0, kAny, kAny, VKEY_0},
135 {DomCode::MINUS, 0, 0, kAny, kAny, VKEY_OEM_4},
136 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6}};
138 // U+002A *
139 const PrintableSubEntry kU002A[] = {
140 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_1},
141 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5}};
143 // U+002B plus sign
144 const PrintableSubEntry kU002B[] = {
145 {DomCode::DIGIT1, 0, 0, kAny, kAny, VKEY_1},
146 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
147 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
148 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
149 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
150 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_2},
151 {DomCode::MINUS, 1, 1, 0x003F, kNone, VKEY_OEM_PLUS}, // ?, NoSymbol
152 {DomCode::MINUS, 1, 1, 0x003F, 0x005C, VKEY_OEM_MINUS}, // ?, backslash
153 {DomCode::MINUS, 1, 1, 0x003F, 0x0151, VKEY_OEM_PLUS}}; // ?, o''
155 // U+002C comma
156 const PrintableSubEntry kU002C[] = {
157 {DomCode::DIGIT3, 0, 0, kAny, kAny, VKEY_3},
158 {DomCode::DIGIT5, 0, 0, kAny, kAny, VKEY_5},
159 {DomCode::DIGIT6, 0, 0, kAny, kAny, VKEY_6},
160 {DomCode::DIGIT9, 0, 0, kAny, kAny, VKEY_9},
161 {DomCode::KEY_W, 0, 0, kAny, kAny, VKEY_OEM_COMMA},
162 {DomCode::KEY_V, 0, 0, kAny, kAny, VKEY_OEM_COMMA},
163 {DomCode::KEY_M, 0, 0, kAny, kAny, VKEY_OEM_COMMA},
164 {DomCode::COMMA, 0, 0, kAny, kAny, VKEY_OEM_COMMA}};
166 // U+002D hyphen-minus
167 const PrintableSubEntry kU002D[] = {
168 {DomCode::DIGIT2, 0, 0, kAny, kAny, VKEY_2},
169 {DomCode::DIGIT6, 0, 0, kAny, kAny, VKEY_6},
170 {DomCode::MINUS, 0, 0, kAny, kAny, VKEY_OEM_MINUS},
171 {DomCode::KEY_A, 0, 0, kAny, kAny, VKEY_OEM_MINUS},
172 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_MINUS},
173 {DomCode::SLASH, 1, 0, 0x003D, kAny, VKEY_OEM_MINUS}, // =
174 {DomCode::EQUAL, 1, 1, 0x005F, kNone, VKEY_OEM_MINUS}, // _, NoSymbol
175 {DomCode::EQUAL, 1, 1, 0x005F, 0x0157, VKEY_OEM_4}, // _, r cedilla
176 {DomCode::SLASH, 1, 1, 0x005F, kNone, VKEY_OEM_MINUS}, // _, NoSymbol
177 {DomCode::SLASH, 1, 1, 0x005F, 0x002A, VKEY_OEM_MINUS}, // _, *
178 {DomCode::SLASH, 1, 1, 0x005F, 0x002F, VKEY_OEM_2}, // _, /
179 {DomCode::SLASH, 1, 1, 0x005F, 0x006E, VKEY_OEM_MINUS}}; // _, n
181 // U+002E full stop
182 const PrintableSubEntry kU002E[] = {
183 {DomCode::DIGIT7, 0, 0, kAny, kAny, VKEY_7},
184 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
185 {DomCode::KEY_E, 0, 0, kAny, kAny, VKEY_OEM_PERIOD},
186 {DomCode::KEY_R, 0, 0, kAny, kAny, VKEY_OEM_PERIOD},
187 {DomCode::KEY_O, 0, 0, kAny, kAny, VKEY_OEM_PERIOD},
188 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7},
189 {DomCode::PERIOD, 0, 0, kAny, kAny, VKEY_OEM_PERIOD},
190 {DomCode::SLASH, 0, 0, kAny, kAny, VKEY_OEM_2}};
192 // U+002F /
193 const PrintableSubEntry kU002F[] = {
194 {DomCode::MINUS, 0, 0, kAny, kAny, VKEY_OEM_4},
195 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_2},
196 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_OEM_7},
197 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5},
198 {DomCode::SLASH, 0, 0, kAny, kAny, VKEY_OEM_2},
199 {DomCode::DIGIT3, 1, 0, 0x0033, kAny, VKEY_3}, // 3
200 {DomCode::DIGIT3, 1, 0, 0x003F, kAny, VKEY_OEM_2}, // ?
201 {DomCode::DIGIT0, 1, 0, 0x0030, kAny, VKEY_0}, // 0
202 {DomCode::DIGIT0, 1, 0, 0x003F, kAny, VKEY_OEM_2}}; // ?
204 // U+003A colon
205 const PrintableSubEntry kU003A[] = {
206 {DomCode::DIGIT1, 0, 0, kAny, kAny, VKEY_1},
207 {DomCode::DIGIT5, 0, 0, kAny, kAny, VKEY_5},
208 {DomCode::DIGIT6, 0, 0, kAny, kAny, VKEY_6},
209 {DomCode::PERIOD, 0, 0, kAny, kAny, VKEY_OEM_2}};
211 // U+003B semicolon
212 const PrintableSubEntry kU003B[] = {
213 {DomCode::DIGIT4, 0, 0, kAny, kAny, VKEY_4},
214 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
215 {DomCode::KEY_Q, 0, 0, kAny, kAny, VKEY_OEM_1},
216 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_1},
217 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6},
218 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_1},
219 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_OEM_3},
220 {DomCode::KEY_Z, 0, 0, kAny, kAny, VKEY_OEM_1},
221 {DomCode::COMMA, 0, 0, kAny, kAny, VKEY_OEM_PERIOD},
222 {DomCode::SLASH, 0, 0, kAny, kAny, VKEY_OEM_2}};
224 // U+003D =
225 const PrintableSubEntry kU003D[] = {
226 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
227 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
228 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
229 {DomCode::SLASH, 1, 0, 0x0025, kAny, VKEY_OEM_8}, // %
230 {DomCode::SLASH, 1, 0, 0x002B, kAny, VKEY_OEM_PLUS}, // +
231 {DomCode::MINUS, 1, 1, 0x0025, kNone, VKEY_OEM_PLUS}, // %, NoSymbol
232 {DomCode::MINUS, 1, 1, 0x0025, 0x002D, VKEY_OEM_MINUS}}; // %, -
234 // U+003F ?
235 const PrintableSubEntry kU003F[] = {
236 {DomCode::DIGIT2, 0, 0, kAny, kAny, VKEY_2},
237 {DomCode::DIGIT7, 0, 0, kAny, kAny, VKEY_7},
238 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
239 {DomCode::MINUS, 0, 0, kAny, kAny, VKEY_OEM_PLUS}};
241 // U+0040 @
242 const PrintableSubEntry kU0040[] = {
243 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6},
244 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
246 // U+005B left square bracket
247 const PrintableSubEntry kU005B[] = {
248 {DomCode::DIGIT1, 0, 0, kAny, kAny, VKEY_OEM_4},
249 {DomCode::MINUS, 0, 0, kAny, kAny, VKEY_OEM_4},
250 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_4},
251 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6},
252 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
254 // U+005C backslash
255 const PrintableSubEntry kU005C[] = {
256 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_4},
257 {DomCode::BACKSLASH, 1, 0, 0x002F, kAny, VKEY_OEM_7}, // /
258 {DomCode::BACKSLASH, 1, 0, 0x007C, kAny, VKEY_OEM_5}, // |
259 {DomCode::BACKQUOTE, 1, 1, 0x007C, 0x0031, VKEY_OEM_5}, // |, 1
260 {DomCode::BACKQUOTE, 1, 1, 0x007C, 0x0145, VKEY_OEM_3}}; // |, N cedilla
262 // U+005D right square bracket
263 const PrintableSubEntry kU005D[] = {
264 {DomCode::DIGIT2, 0, 0, kAny, kAny, VKEY_OEM_6},
265 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_6},
266 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6},
267 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_OEM_3},
268 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5}};
270 // U+005F _
271 const PrintableSubEntry kU005F[] = {
272 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
273 {DomCode::MINUS, 0, 0, kAny, kAny, VKEY_OEM_MINUS}};
275 // U+0060 grave accent
276 const PrintableSubEntry kU0060[] = {
277 {DomCode::BACKQUOTE, 1, 0, kNone, kAny, VKEY_OEM_3}, // NoSymbol
278 {DomCode::BACKQUOTE, 1, 0, 0x00AC, kAny, VKEY_OEM_8}, // not
279 {DomCode::BACKQUOTE, 1, 1, 0x007E, kNone, VKEY_OEM_3}, // ~, NoSymbol
280 {DomCode::BACKQUOTE, 1, 1, 0x007E, 0x0031, VKEY_OEM_3}, // ~, 1
281 {DomCode::BACKQUOTE, 1, 1, 0x007E, 0x003B, VKEY_OEM_3}, // ~, ;
282 {DomCode::BACKQUOTE, 1, 1, 0x007E, 0x0060, VKEY_OEM_3}, // ~, `
283 {DomCode::BACKQUOTE, 1, 1, 0x007E, 0x00BF, VKEY_OEM_3}, // ~, inverted ?
284 {DomCode::BACKQUOTE, 1, 1, 0x007E, 0x0151, VKEY_OEM_3}}; // ~, o''
286 // U+00A7 section
287 const PrintableSubEntry kU00A7[] = {
288 {DomCode::DIGIT4, 0, 0, kAny, kAny, VKEY_4},
289 {DomCode::DIGIT6, 0, 0, kAny, kAny, VKEY_6},
290 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7},
291 {DomCode::BACKQUOTE, 1, 0, 0x00B0, kAny, VKEY_OEM_2}, // degree
292 {DomCode::BACKQUOTE, 1, 0, 0x00BD, kAny, VKEY_OEM_5}}; // one half
294 // U+00AB left-pointing double angle quote
295 const PrintableSubEntry kU00AB[] = {
296 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
297 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_6}};
299 // U+00B0 degree
300 const PrintableSubEntry kU00B0[] = {
301 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_2},
302 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
304 // U+00BA masculine ordinal indicator
305 const PrintableSubEntry kU00BA[] = {
306 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7},
307 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_OEM_5}};
309 // U+00E0 a grave
310 const PrintableSubEntry kU00E0[] = {
311 {DomCode::DIGIT0, 0, 0, kAny, kAny, VKEY_0},
312 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5},
313 {DomCode::QUOTE, 1, 0, 0x00B0, kAny, VKEY_OEM_7}, // degree
314 {DomCode::QUOTE, 1, 0, 0x00E4, kAny, VKEY_OEM_5}}; // a diaeresis
316 // U+00E1 a acute
317 const PrintableSubEntry kU00E1[] = {
318 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
319 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
321 // U+00E2 a circumflex
322 const PrintableSubEntry kU00E2[] = {
323 {DomCode::DIGIT2, 0, 0, kAny, kAny, VKEY_2},
324 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5}};
326 // U+00E4 a diaeresis
327 const PrintableSubEntry kU00E4[] = {
328 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6},
329 {DomCode::QUOTE, 1, 0, 0x00E0, kAny, VKEY_OEM_5}, // a grave
330 {DomCode::QUOTE, 1, 1, 0x00C4, kNone, VKEY_OEM_7}, // A dia., NoSymbol
331 {DomCode::QUOTE, 1, 1, 0x00C4, 0x015A, VKEY_OEM_7}, // A dia., S acute
332 {DomCode::QUOTE, 1, 1, 0x00C4, 0x0159, VKEY_OEM_7}}; // A dia., r caron
334 // U+00E6 ae
335 const PrintableSubEntry kU00E6[] = {
336 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_3},
337 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
339 // U+00E7 c cedilla
340 const PrintableSubEntry kU00E7[] = {
341 {DomCode::DIGIT9, 0, 0, kAny, kAny, VKEY_9},
342 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_4},
343 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6},
344 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7},
345 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_2},
346 {DomCode::COMMA, 0, 0, kAny, kAny, VKEY_OEM_COMMA},
347 {DomCode::SEMICOLON, 1, 1, 0x00C7, kNone, VKEY_OEM_1}, // C ced., NoSy
348 {DomCode::SEMICOLON, 1, 1, 0x00C7, 0x00DE, VKEY_OEM_3}}; // C ced., Thorn
350 // U+00E8 e grave
351 const PrintableSubEntry kU00E8[] = {
352 {DomCode::DIGIT7, 0, 0, kAny, kAny, VKEY_7},
353 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_1},
354 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_3}};
356 // U+00E9 e acute
357 const PrintableSubEntry kU00E9[] = {
358 {DomCode::DIGIT2, 0, 0, kAny, kAny, VKEY_2},
359 {DomCode::DIGIT0, 0, 0, kAny, kAny, VKEY_0},
360 {DomCode::SLASH, 0, 0, kAny, kAny, VKEY_OEM_2},
361 {DomCode::SEMICOLON, 1, 0, 0x00C9, kAny, VKEY_OEM_1}, // E acute
362 {DomCode::SEMICOLON, 1, 0, 0x00F6, kAny, VKEY_OEM_7}}; // o diaeresis
364 // U+00ED i acute
365 const PrintableSubEntry kU00ED[] = {
366 {DomCode::DIGIT9, 0, 0, kAny, kAny, VKEY_9},
367 {DomCode::BACKQUOTE, 0, 0, kAny, kAny, VKEY_0}};
369 // U+00F0 eth
370 const PrintableSubEntry kU00F0[] = {
371 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_6},
372 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_1}};
374 // U+00F3 o acute
375 const PrintableSubEntry kU00F3[] = {
376 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
377 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5}};
379 // U+00F4 o circumflex
380 const PrintableSubEntry kU00F4[] = {
381 {DomCode::DIGIT4, 0, 0, kAny, kAny, VKEY_4},
382 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_1}};
384 // U+00F6 o diaeresis
385 const PrintableSubEntry kU00F6[] = {
386 {DomCode::DIGIT0, 0, 0, kAny, kAny, VKEY_OEM_3},
387 {DomCode::MINUS, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
388 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_4},
389 {DomCode::SEMICOLON, 1, 0, 0x00E9, kAny, VKEY_OEM_7}, // e acute
390 {DomCode::SEMICOLON, 1, 1, 0x00D6, kNone, VKEY_OEM_3}, // O dia., NoSy
391 {DomCode::SEMICOLON, 1, 1, 0x00D6, 0x0162, VKEY_OEM_3}}; // O dia., T ced.
393 // U+00F8 o stroke
394 const PrintableSubEntry kU00F8[] = {
395 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_3},
396 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
398 // U+00F9 u grave
399 const PrintableSubEntry kU00F9[] = {
400 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_3},
401 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_2}};
403 // U+00FA u acute
404 const PrintableSubEntry kU00FA[] = {
405 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_4},
406 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6}};
408 // U+00FC u diaeresis
409 const PrintableSubEntry kU00FC[] = {
410 {DomCode::KEY_W, 0, 0, kAny, kAny, VKEY_W},
411 {DomCode::BRACKET_LEFT, 1, 0, 0x00E8, kAny, VKEY_OEM_1}, // e grave
412 {DomCode::MINUS, 1, 1, 0x00DC, kNone, VKEY_OEM_2}, // U dia., NoSy
413 {DomCode::BRACKET_LEFT, 1, 1, 0x00DC, kNone, VKEY_OEM_1}, // U dia., NoSy
414 {DomCode::BRACKET_LEFT, 1, 1, 0x00DC, 0x0141, VKEY_OEM_3}}; // U dia., L-
416 // U+0103 a breve
417 const PrintableSubEntry kU0103[] = {
418 {DomCode::DIGIT1, 0, 0, kAny, kAny, VKEY_1},
419 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_4}};
421 // U+0105 a ogonek
422 const PrintableSubEntry kU0105[] = {
423 {DomCode::DIGIT1, 0, 0, kAny, kAny, VKEY_1},
424 {DomCode::KEY_Q, 0, 0, kAny, kAny, VKEY_Q},
425 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
427 // U+010D c caron
428 const PrintableSubEntry kU010D[] = {
429 {DomCode::DIGIT2, 0, 0, kAny, kAny, VKEY_2},
430 {DomCode::DIGIT4, 0, 0, kAny, kAny, VKEY_4},
431 {DomCode::KEY_P, 0, 0, kAny, kAny, VKEY_X},
432 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_1},
433 {DomCode::COMMA, 0, 0, kAny, kAny, VKEY_OEM_COMMA}};
435 // U+0111 d stroke
436 const PrintableSubEntry kU0111[] = {
437 {DomCode::DIGIT0, 0, 0, kAny, kAny, VKEY_0},
438 {DomCode::BRACKET_RIGHT, 0, 0, kAny, kAny, VKEY_OEM_6}};
440 // U+0117 e dot above
441 const PrintableSubEntry kU0117[] = {
442 {DomCode::DIGIT4, 0, 0, kAny, kAny, VKEY_4},
443 {DomCode::QUOTE, 0, 0, kAny, kAny, VKEY_OEM_7}};
445 // U+0119 e ogonek
446 const PrintableSubEntry kU0119[] = {
447 {DomCode::DIGIT3, 0, 0, kAny, kAny, VKEY_3},
448 {DomCode::SLASH, 1, 1, 0x0118, kNone, VKEY_OEM_MINUS}, // E ogonek, NoSy
449 {DomCode::SLASH, 1, 1, 0x0118, 0x006E, VKEY_OEM_2}}; // E ogonek, n
451 // U+012F i ogonek
452 const PrintableSubEntry kU012F[] = {
453 {DomCode::DIGIT5, 0, 0, kAny, kAny, VKEY_5},
454 {DomCode::BRACKET_LEFT, 1, 1, 0x012E, kNone, VKEY_OEM_4}}; // Iogonek, NoSy
456 // U+0142 l stroke
457 const PrintableSubEntry kU0142[] = {
458 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_1},
459 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_2}};
461 // U+015F s cedilla
462 const PrintableSubEntry kU015F[] = {
463 {DomCode::SEMICOLON, 0, 0, kAny, kAny, VKEY_OEM_1},
464 {DomCode::PERIOD, 0, 0, kAny, kAny, VKEY_OEM_PERIOD}};
466 // U+0161 s caron
467 const PrintableSubEntry kU0161[] = {
468 {DomCode::DIGIT3, 0, 0, kAny, kAny, VKEY_3},
469 {DomCode::DIGIT6, 0, 0, kAny, kAny, VKEY_6},
470 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_4},
471 {DomCode::KEY_A, 0, 0, kAny, kAny, VKEY_OEM_1},
472 {DomCode::KEY_F, 0, 0, kAny, kAny, VKEY_F},
473 {DomCode::PERIOD, 0, 0, kAny, kAny, VKEY_OEM_PERIOD}};
475 // U+016B u macron
476 const PrintableSubEntry kU016B[] = {
477 {DomCode::DIGIT8, 0, 0, kAny, kAny, VKEY_8},
478 {DomCode::KEY_Q, 0, 0, kAny, kAny, VKEY_Q},
479 {DomCode::KEY_X, 0, 0, kAny, kAny, VKEY_X}};
481 // U+0173 u ogonek
482 const PrintableSubEntry kU0173[] = {
483 {DomCode::DIGIT7, 0, 0, kAny, kAny, VKEY_7},
484 {DomCode::SEMICOLON, 1, 1, 0x0172, kNone, VKEY_OEM_3}, // U ogo., NoSy
485 {DomCode::SEMICOLON, 1, 1, 0x0172, 0x0162, VKEY_OEM_1}}; // U ogo., T ced.
487 // U+017C z dot above
488 const PrintableSubEntry kU017C[] = {
489 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_OEM_4},
490 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5}};
492 // U+017E z caron
493 const PrintableSubEntry kU017E[] = {
494 {DomCode::DIGIT6, 0, 0, kAny, kAny, VKEY_6},
495 {DomCode::EQUAL, 0, 0, kAny, kAny, VKEY_OEM_PLUS},
496 {DomCode::KEY_W, 0, 0, kAny, kAny, VKEY_W},
497 {DomCode::BRACKET_LEFT, 0, 0, kAny, kAny, VKEY_Y},
498 {DomCode::BACKSLASH, 0, 0, kAny, kAny, VKEY_OEM_5}};
500 // Table mapping unshifted characters to PrintableSubEntry tables.
501 struct PrintableMultiEntry {
502 base::char16 plain_character;
503 const PrintableSubEntry* subtable;
504 size_t subtable_size;
507 // Entries are ordered by character value.
508 const PrintableMultiEntry kMultiMap[] = {
509 {0x0021, kU0021, arraysize(kU0021)}, // exclamation mark
510 {0x0022, kU0022, arraysize(kU0022)}, // quotation mark
511 {0x0023, kU0023, arraysize(kU0023)}, // number sign
512 {0x0024, kU0024, arraysize(kU0024)}, // dollar sign
513 {0x0027, kU0027, arraysize(kU0027)}, // apostrophe
514 {0x0028, kU0028, arraysize(kU0028)}, // left parenthesis
515 {0x0029, kU0029, arraysize(kU0029)}, // right parenthesis
516 {0x002A, kU002A, arraysize(kU002A)}, // asterisk
517 {0x002B, kU002B, arraysize(kU002B)}, // plus sign
518 {0x002C, kU002C, arraysize(kU002C)}, // comma
519 {0x002D, kU002D, arraysize(kU002D)}, // hyphen-minus
520 {0x002E, kU002E, arraysize(kU002E)}, // full stop
521 {0x002F, kU002F, arraysize(kU002F)}, // solidus
522 {0x003A, kU003A, arraysize(kU003A)}, // colon
523 {0x003B, kU003B, arraysize(kU003B)}, // semicolon
524 {0x003D, kU003D, arraysize(kU003D)}, // equals sign
525 {0x003F, kU003F, arraysize(kU003F)}, // question mark
526 {0x0040, kU0040, arraysize(kU0040)}, // commercial at
527 {0x005B, kU005B, arraysize(kU005B)}, // left square bracket
528 {0x005C, kU005C, arraysize(kU005C)}, // reverse solidus
529 {0x005D, kU005D, arraysize(kU005D)}, // right square bracket
530 {0x005F, kU005F, arraysize(kU005F)}, // low line
531 {0x0060, kU0060, arraysize(kU0060)}, // grave accent
532 {0x00A7, kU00A7, arraysize(kU00A7)}, // section sign
533 {0x00AB, kU00AB, arraysize(kU00AB)}, // left double angle quotation mark
534 {0x00B0, kU00B0, arraysize(kU00B0)}, // degree sign
535 {0x00BA, kU00BA, arraysize(kU00BA)}, // masculine ordinal indicator
536 {0x00E0, kU00E0, arraysize(kU00E0)}, // a grave
537 {0x00E1, kU00E1, arraysize(kU00E1)}, // a acute
538 {0x00E2, kU00E2, arraysize(kU00E2)}, // a circumflex
539 {0x00E4, kU00E4, arraysize(kU00E4)}, // a diaeresis
540 {0x00E6, kU00E6, arraysize(kU00E6)}, // ae
541 {0x00E7, kU00E7, arraysize(kU00E7)}, // c cedilla
542 {0x00E8, kU00E8, arraysize(kU00E8)}, // e grave
543 {0x00E9, kU00E9, arraysize(kU00E9)}, // e acute
544 {0x00ED, kU00ED, arraysize(kU00ED)}, // i acute
545 {0x00F0, kU00F0, arraysize(kU00F0)}, // eth
546 {0x00F3, kU00F3, arraysize(kU00F3)}, // o acute
547 {0x00F4, kU00F4, arraysize(kU00F4)}, // o circumflex
548 {0x00F6, kU00F6, arraysize(kU00F6)}, // o diaeresis
549 {0x00F8, kU00F8, arraysize(kU00F8)}, // o stroke
550 {0x00F9, kU00F9, arraysize(kU00F9)}, // u grave
551 {0x00FA, kU00FA, arraysize(kU00FA)}, // u acute
552 {0x00FC, kU00FC, arraysize(kU00FC)}, // u diaeresis
553 {0x0103, kU0103, arraysize(kU0103)}, // a breve
554 {0x0105, kU0105, arraysize(kU0105)}, // a ogonek
555 {0x010D, kU010D, arraysize(kU010D)}, // c caron
556 {0x0111, kU0111, arraysize(kU0111)}, // d stroke
557 {0x0117, kU0117, arraysize(kU0117)}, // e dot above
558 {0x0119, kU0119, arraysize(kU0119)}, // e ogonek
559 {0x012F, kU012F, arraysize(kU012F)}, // i ogonek
560 {0x0142, kU0142, arraysize(kU0142)}, // l stroke
561 {0x015F, kU015F, arraysize(kU015F)}, // s cedilla
562 {0x0161, kU0161, arraysize(kU0161)}, // s caron
563 {0x016B, kU016B, arraysize(kU016B)}, // u macron
564 {0x0173, kU0173, arraysize(kU0173)}, // u ogonek
565 {0x017C, kU017C, arraysize(kU017C)}, // z dot above
566 {0x017E, kU017E, arraysize(kU017E)}, // z caron
569 // Table mapping unshifted characters to VKEY values.
570 struct PrintableSimpleEntry {
571 base::char16 plain_character;
572 KeyboardCode key_code;
575 // Entries are ordered by character value.
576 const PrintableSimpleEntry kSimpleMap[] = {
577 {0x0025, VKEY_5}, // percent sign
578 {0x0026, VKEY_1}, // ampersand
579 {0x003C, VKEY_OEM_5}, // less-than sign
580 {0x007B, VKEY_OEM_7}, // left curly bracket
581 {0x007C, VKEY_OEM_5}, // vertical line
582 {0x007D, VKEY_OEM_2}, // right curly bracket
583 {0x007E, VKEY_OEM_5}, // tilde
584 {0x00A1, VKEY_OEM_6}, // inverted exclamation mark
585 {0x00AD, VKEY_OEM_3}, // soft hyphen
586 {0x00B2, VKEY_OEM_7}, // superscript two
587 {0x00B5, VKEY_OEM_5}, // micro sign
588 {0x00BB, VKEY_9}, // right-pointing double angle quotation mark
589 {0x00BD, VKEY_OEM_5}, // vulgar fraction one half
590 {0x00BF, VKEY_OEM_6}, // inverted question mark
591 {0x00DF, VKEY_OEM_4}, // sharp s
592 {0x00E5, VKEY_OEM_6}, // a ring above
593 {0x00EA, VKEY_3}, // e circumflex
594 {0x00EB, VKEY_OEM_1}, // e diaeresis
595 {0x00EC, VKEY_OEM_6}, // i grave
596 {0x00EE, VKEY_OEM_6}, // i circumflex
597 {0x00F1, VKEY_OEM_3}, // n tilde
598 {0x00F2, VKEY_OEM_3}, // o grave
599 {0x00F5, VKEY_OEM_4}, // o tilde
600 {0x00F7, VKEY_OEM_6}, // division sign
601 {0x00FD, VKEY_7}, // y acute
602 {0x00FE, VKEY_OEM_MINUS}, // thorn
603 {0x0101, VKEY_OEM_8}, // a macron
604 {0x0107, VKEY_OEM_7}, // c acute
605 {0x010B, VKEY_OEM_3}, // c dot above
606 {0x0113, VKEY_W}, // e macron
607 {0x011B, VKEY_2}, // e caron
608 {0x011F, VKEY_OEM_6}, // g breve
609 {0x0121, VKEY_OEM_4}, // g dot above
610 {0x0127, VKEY_OEM_6}, // h stroke
611 {0x012B, VKEY_OEM_6}, // i macron
612 {0x0131, VKEY_OEM_1}, // dotless i
613 {0x0137, VKEY_OEM_5}, // k cedilla
614 {0x013C, VKEY_OEM_2}, // l cedilla
615 {0x013E, VKEY_2}, // l caron
616 {0x0146, VKEY_OEM_4}, // n cedilla
617 {0x0148, VKEY_OEM_5}, // n caron
618 {0x0151, VKEY_OEM_4}, // o double acute
619 {0x0159, VKEY_5}, // r caron
620 {0x0163, VKEY_OEM_7}, // t cedilla
621 {0x0165, VKEY_5}, // t caron
622 {0x016F, VKEY_OEM_1}, // u ring above
623 {0x0171, VKEY_OEM_5}, // u double acute
624 {0x01A1, VKEY_OEM_6}, // o horn
625 {0x01B0, VKEY_OEM_4}, // u horn
626 {0x01B6, VKEY_OEM_6}, // z stroke
627 {0x0259, VKEY_OEM_3}, // schwa
630 #if defined(OS_CHROMEOS)
631 void LoadKeymap(const std::string& layout_name,
632 scoped_refptr<base::SingleThreadTaskRunner> reply_runner,
633 const LoadKeymapCallback& reply_callback) {
634 std::string layout_id;
635 std::string layout_variant;
636 XkbKeyboardLayoutEngine::ParseLayoutName(layout_name, &layout_id,
637 &layout_variant);
638 xkb_rule_names names = {.rules = NULL,
639 .model = "pc101",
640 .layout = layout_id.c_str(),
641 .variant = layout_variant.c_str(),
642 .options = ""};
643 scoped_ptr<xkb_context, XkbContextDeleter> context;
644 context.reset(xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES));
645 xkb_context_include_path_append(context.get(), "/usr/share/X11/xkb");
646 scoped_ptr<xkb_keymap, XkbKeymapDeleter> keymap;
647 keymap.reset(xkb_keymap_new_from_names(context.get(), &names,
648 XKB_KEYMAP_COMPILE_NO_FLAGS));
649 if (keymap) {
650 scoped_ptr<char, base::FreeDeleter> keymap_str(
651 xkb_keymap_get_as_string(keymap.get(), XKB_KEYMAP_FORMAT_TEXT_V1));
652 reply_runner->PostTask(FROM_HERE, base::Bind(reply_callback, layout_name,
653 base::Passed(&keymap_str)));
654 } else {
655 LOG(FATAL) << "Keymap file failed to load: " << layout_name;
658 #endif
660 } // anonymous namespace
662 XkbKeyCodeConverter::XkbKeyCodeConverter() {
665 XkbKeyCodeConverter::~XkbKeyCodeConverter() {
668 XkbKeyboardLayoutEngine::XkbKeyboardLayoutEngine(
669 const XkbKeyCodeConverter& converter)
670 : num_lock_mod_mask_(0),
671 key_code_converter_(converter),
672 weak_ptr_factory_(this) {
673 // TODO: add XKB_CONTEXT_NO_ENVIRONMENT_NAMES
674 xkb_context_.reset(xkb_context_new(XKB_CONTEXT_NO_DEFAULT_INCLUDES));
675 xkb_context_include_path_append(xkb_context_.get(),
676 "/usr/share/X11/xkb");
679 XkbKeyboardLayoutEngine::~XkbKeyboardLayoutEngine() {
680 for (const auto& entry : xkb_keymaps_) {
681 xkb_keymap_unref(entry.keymap);
685 bool XkbKeyboardLayoutEngine::CanSetCurrentLayout() const {
686 #if defined(OS_CHROMEOS)
687 return true;
688 #else
689 return false;
690 #endif
693 bool XkbKeyboardLayoutEngine::SetCurrentLayoutByName(
694 const std::string& layout_name) {
695 #if defined(OS_CHROMEOS)
696 current_layout_name_ = layout_name;
697 for (const auto& entry : xkb_keymaps_) {
698 if (entry.layout_name == layout_name) {
699 SetKeymap(entry.keymap);
700 return true;
703 LoadKeymapCallback reply_callback = base::Bind(
704 &XkbKeyboardLayoutEngine::OnKeymapLoaded, weak_ptr_factory_.GetWeakPtr());
705 base::WorkerPool::PostTask(
706 FROM_HERE,
707 base::Bind(&LoadKeymap, layout_name, base::ThreadTaskRunnerHandle::Get(),
708 reply_callback),
709 true);
710 #else
711 xkb_keymap* keymap = xkb_map_new_from_string(
712 xkb_context_.get(), layout_name.c_str(), XKB_KEYMAP_FORMAT_TEXT_V1,
713 XKB_KEYMAP_COMPILE_NO_FLAGS);
714 if (!keymap)
715 return false;
716 SetKeymap(keymap);
717 #endif // defined(OS_CHROMEOS)
718 return true;
721 void XkbKeyboardLayoutEngine::OnKeymapLoaded(
722 const std::string& layout_name,
723 scoped_ptr<char, base::FreeDeleter> keymap_str) {
724 if (keymap_str) {
725 xkb_keymap* keymap = xkb_map_new_from_string(
726 xkb_context_.get(), keymap_str.get(), XKB_KEYMAP_FORMAT_TEXT_V1,
727 XKB_KEYMAP_COMPILE_NO_FLAGS);
728 XkbKeymapEntry entry = {layout_name, keymap};
729 xkb_keymaps_.push_back(entry);
730 if (layout_name == current_layout_name_)
731 SetKeymap(keymap);
732 } else {
733 LOG(FATAL) << "Keymap file failed to load: " << layout_name;
737 bool XkbKeyboardLayoutEngine::UsesISOLevel5Shift() const {
738 // NOTIMPLEMENTED();
739 return false;
742 bool XkbKeyboardLayoutEngine::UsesAltGr() const {
743 // NOTIMPLEMENTED();
744 return false;
747 bool XkbKeyboardLayoutEngine::Lookup(DomCode dom_code,
748 int flags,
749 DomKey* dom_key,
750 base::char16* character,
751 KeyboardCode* key_code,
752 uint32* platform_keycode) const {
753 if (dom_code == DomCode::NONE)
754 return false;
755 // Convert DOM physical key to XKB representation.
756 xkb_keycode_t xkb_keycode = key_code_converter_.DomCodeToXkbKeyCode(dom_code);
757 if (xkb_keycode == key_code_converter_.InvalidXkbKeyCode()) {
758 LOG(ERROR) << "No XKB keycode for DomCode 0x" << std::hex
759 << static_cast<int>(dom_code) << " '"
760 << KeycodeConverter::DomCodeToCodeString(dom_code) << "'";
761 return false;
763 xkb_mod_mask_t xkb_flags = EventFlagsToXkbFlags(flags);
764 // Obtain keysym and character.
765 xkb_keysym_t xkb_keysym;
766 if (!XkbLookup(xkb_keycode, xkb_flags, &xkb_keysym, character))
767 return false;
768 *platform_keycode = xkb_keysym;
769 // Classify the keysym and convert to DOM and VKEY representations.
770 *dom_key = NonPrintableXkbKeySymToDomKey(xkb_keysym);
771 if (*dom_key == DomKey::NONE) {
772 *dom_key = CharacterToDomKey(*character);
773 *key_code = AlphanumericKeyboardCode(*character);
774 if (*key_code == VKEY_UNKNOWN) {
775 *key_code = DifficultKeyboardCode(dom_code, flags, xkb_keycode, xkb_flags,
776 xkb_keysym, *dom_key, *character);
777 if (*key_code == VKEY_UNKNOWN)
778 *key_code = DomCodeToNonLocatedKeyboardCode(dom_code);
781 if ((flags & EF_CONTROL_DOWN) == EF_CONTROL_DOWN) {
782 // Use GetCharacterFromKeyCode() to set |character| to 0x0 for key codes
783 // that we do not care about.
784 *character = GetCharacterFromKeyCode(*key_code, flags);
786 } else if (*dom_key == DomKey::DEAD) {
787 *character = DeadXkbKeySymToCombiningCharacter(xkb_keysym);
788 *key_code = DomCodeToNonLocatedKeyboardCode(dom_code);
789 } else {
790 *key_code = NonPrintableDomKeyToKeyboardCode(*dom_key);
791 if (*key_code == VKEY_UNKNOWN)
792 *key_code = DomCodeToNonLocatedKeyboardCode(dom_code);
794 return true;
797 void XkbKeyboardLayoutEngine::SetKeymap(xkb_keymap* keymap) {
798 xkb_state_.reset(xkb_state_new(keymap));
799 // Update flag map.
800 static const struct {
801 int ui_flag;
802 const char* xkb_name;
803 } flags[] = {{ui::EF_CONTROL_DOWN, XKB_MOD_NAME_CTRL},
804 {ui::EF_SHIFT_DOWN, XKB_MOD_NAME_SHIFT},
805 {ui::EF_ALT_DOWN, XKB_MOD_NAME_ALT},
806 {ui::EF_CAPS_LOCK_DOWN, XKB_MOD_NAME_CAPS},
807 {ui::EF_COMMAND_DOWN, XKB_MOD_NAME_LOGO},
808 {ui::EF_MOD3_DOWN, "Mod3"},
809 {ui::EF_ALTGR_DOWN, "Mod5"}};
810 xkb_flag_map_.clear();
811 xkb_flag_map_.resize(arraysize(flags));
812 for (size_t i = 0; i < arraysize(flags); ++i) {
813 xkb_mod_index_t index = xkb_keymap_mod_get_index(keymap, flags[i].xkb_name);
814 if (index == XKB_MOD_INVALID) {
815 DVLOG(3) << "XKB keyboard layout does not contain " << flags[i].xkb_name;
816 } else {
817 xkb_mod_mask_t flag = static_cast<xkb_mod_mask_t>(1) << index;
818 XkbFlagMapEntry e = {flags[i].ui_flag, flag};
819 xkb_flag_map_.push_back(e);
823 // Update num lock mask.
824 num_lock_mod_mask_ = 0;
825 xkb_mod_index_t num_mod_index =
826 xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
827 if (num_mod_index != XKB_MOD_INVALID)
828 num_lock_mod_mask_ = static_cast<xkb_mod_mask_t>(1) << num_mod_index;
831 xkb_mod_mask_t XkbKeyboardLayoutEngine::EventFlagsToXkbFlags(
832 int ui_flags) const {
833 xkb_mod_mask_t xkb_flags = 0;
834 for (const auto& entry : xkb_flag_map_) {
835 if (ui_flags & entry.ui_flag)
836 xkb_flags |= entry.xkb_flag;
838 // NumLock is always on.
839 xkb_flags |= num_lock_mod_mask_;
840 return xkb_flags;
843 bool XkbKeyboardLayoutEngine::XkbLookup(xkb_keycode_t xkb_keycode,
844 xkb_mod_mask_t xkb_flags,
845 xkb_keysym_t* xkb_keysym,
846 base::char16* character) const {
847 if (!xkb_state_) {
848 LOG(ERROR) << "No current XKB state";
849 return false;
851 xkb_state_update_mask(xkb_state_.get(), xkb_flags, 0, 0, 0, 0, 0);
852 *xkb_keysym = xkb_state_key_get_one_sym(xkb_state_.get(), xkb_keycode);
853 if (*xkb_keysym == XKB_KEY_NoSymbol)
854 return false;
855 uint32_t c = xkb_state_key_get_utf32(xkb_state_.get(), xkb_keycode);
856 DLOG_IF(ERROR, c != (c & 0xFFFF)) << "Non-BMP character:" << c;
857 *character = static_cast<base::char16>(c);
858 return true;
861 KeyboardCode XkbKeyboardLayoutEngine::DifficultKeyboardCode(
862 DomCode dom_code,
863 int ui_flags,
864 xkb_keycode_t xkb_keycode,
865 xkb_mod_mask_t xkb_flags,
866 xkb_keysym_t xkb_keysym,
867 DomKey dom_key,
868 base::char16 character) const {
869 // Get the layout interpretation without modifiers, so that
870 // e.g. Ctrl+D correctly generates VKEY_D.
871 xkb_keysym_t plain_keysym;
872 base::char16 plain_character;
873 if (!XkbLookup(xkb_keycode, 0, &plain_keysym, &plain_character))
874 return VKEY_UNKNOWN;
876 // If the plain key is non-printable, that determines the VKEY.
877 DomKey plain_key = NonPrintableXkbKeySymToDomKey(plain_keysym);
878 if (plain_key != ui::DomKey::NONE)
879 return NonPrintableDomKeyToKeyboardCode(dom_key);
881 // Plain ASCII letters and digits map directly to VKEY values.
882 KeyboardCode key_code = AlphanumericKeyboardCode(plain_character);
883 if (key_code != VKEY_UNKNOWN)
884 return key_code;
886 // Check the multi-character tables.
887 const PrintableMultiEntry* multi_end = kMultiMap + arraysize(kMultiMap);
888 const PrintableMultiEntry* multi =
889 std::lower_bound(kMultiMap, multi_end, plain_character,
890 [](const PrintableMultiEntry& e, base::char16 c) {
891 return e.plain_character < c;
893 if ((multi != multi_end) && (multi->plain_character == plain_character)) {
894 const base::char16 kNonCharacter = kAny;
895 base::char16 shift_character = kNonCharacter;
896 base::char16 altgr_character = kNonCharacter;
897 for (size_t i = 0; i < multi->subtable_size; ++i) {
898 if (multi->subtable[i].dom_code != dom_code)
899 continue;
900 if (multi->subtable[i].test_shift) {
901 if (shift_character == kNonCharacter) {
902 shift_character = XkbSubCharacter(xkb_keycode, xkb_flags, character,
903 ui::EF_SHIFT_DOWN);
905 if (shift_character != multi->subtable[i].shift_character)
906 continue;
908 if (multi->subtable[i].test_altgr) {
909 if (altgr_character == kNonCharacter) {
910 altgr_character = XkbSubCharacter(xkb_keycode, xkb_flags, character,
911 ui::EF_ALTGR_DOWN);
913 if (altgr_character != multi->subtable[i].altgr_character)
914 continue;
916 return multi->subtable[i].key_code;
920 // Check the simple character table.
921 const PrintableSimpleEntry* simple_end = kSimpleMap + arraysize(kSimpleMap);
922 const PrintableSimpleEntry* simple =
923 std::lower_bound(kSimpleMap, simple_end, plain_character,
924 [](const PrintableSimpleEntry& e, base::char16 c) {
925 return e.plain_character < c;
927 if ((simple != simple_end) && (simple->plain_character == plain_character))
928 return simple->key_code;
930 return VKEY_UNKNOWN;
933 base::char16 XkbKeyboardLayoutEngine::XkbSubCharacter(
934 xkb_keycode_t xkb_keycode,
935 xkb_mod_mask_t base_flags,
936 base::char16 base_character,
937 int ui_flags) const {
938 xkb_mod_mask_t flags = EventFlagsToXkbFlags(ui_flags);
939 if (flags == base_flags)
940 return base_character;
941 xkb_keysym_t keysym;
942 base::char16 character = 0;
943 if (!XkbLookup(xkb_keycode, flags, &keysym, &character))
944 character = kNone;
945 return character;
948 void XkbKeyboardLayoutEngine::ParseLayoutName(const std::string& layout_name,
949 std::string* layout_id,
950 std::string* layout_variant) {
951 size_t dash_index = layout_name.find('-');
952 size_t parentheses_index = layout_name.find('(');
953 *layout_id = layout_name;
954 *layout_variant = "";
955 if (parentheses_index != std::string::npos) {
956 *layout_id = layout_name.substr(0, parentheses_index);
957 size_t close_index = layout_name.find(')', parentheses_index);
958 if (close_index == std::string::npos)
959 close_index = layout_name.size();
960 *layout_variant = layout_name.substr(parentheses_index + 1,
961 close_index - parentheses_index - 1);
962 } else if (dash_index != std::string::npos) {
963 *layout_id = layout_name.substr(0, dash_index);
964 *layout_variant = layout_name.substr(dash_index + 1);
967 } // namespace ui