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>
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"
28 typedef base::Callback
<void(const std::string
&,
29 scoped_ptr
<char, base::FreeDeleter
>)>
32 DomKey
CharacterToDomKey(base::char16 character
) {
35 return DomKey::BACKSPACE
;
42 return DomKey::ESCAPE
;
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');
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
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
{
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
}};
91 const PrintableSubEntry kU0022
[] = {
92 {DomCode::DIGIT2
, 0, 0, kAny
, kAny
, VKEY_2
},
93 {DomCode::DIGIT3
, 0, 0, kAny
, kAny
, VKEY_3
}};
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
}};
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
}};
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
}};
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''
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
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
}};
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
}}; // ?
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
}};
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
}};
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
}}; // %, -
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
}};
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
}};
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
}};
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''
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
}};
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
}};
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
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
335 const PrintableSubEntry kU00E6
[] = {
336 {DomCode::SEMICOLON
, 0, 0, kAny
, kAny
, VKEY_OEM_3
},
337 {DomCode::QUOTE
, 0, 0, kAny
, kAny
, VKEY_OEM_7
}};
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
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
}};
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
365 const PrintableSubEntry kU00ED
[] = {
366 {DomCode::DIGIT9
, 0, 0, kAny
, kAny
, VKEY_9
},
367 {DomCode::BACKQUOTE
, 0, 0, kAny
, kAny
, VKEY_0
}};
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
}};
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.
394 const PrintableSubEntry kU00F8
[] = {
395 {DomCode::SEMICOLON
, 0, 0, kAny
, kAny
, VKEY_OEM_3
},
396 {DomCode::QUOTE
, 0, 0, kAny
, kAny
, VKEY_OEM_7
}};
399 const PrintableSubEntry kU00F9
[] = {
400 {DomCode::QUOTE
, 0, 0, kAny
, kAny
, VKEY_OEM_3
},
401 {DomCode::BACKSLASH
, 0, 0, kAny
, kAny
, VKEY_OEM_2
}};
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-
417 const PrintableSubEntry kU0103
[] = {
418 {DomCode::DIGIT1
, 0, 0, kAny
, kAny
, VKEY_1
},
419 {DomCode::BRACKET_LEFT
, 0, 0, kAny
, kAny
, VKEY_OEM_4
}};
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
}};
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
}};
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
}};
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
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
457 const PrintableSubEntry kU0142
[] = {
458 {DomCode::SEMICOLON
, 0, 0, kAny
, kAny
, VKEY_OEM_1
},
459 {DomCode::BACKSLASH
, 0, 0, kAny
, kAny
, VKEY_OEM_2
}};
462 const PrintableSubEntry kU015F
[] = {
463 {DomCode::SEMICOLON
, 0, 0, kAny
, kAny
, VKEY_OEM_1
},
464 {DomCode::PERIOD
, 0, 0, kAny
, kAny
, VKEY_OEM_PERIOD
}};
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
}};
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
}};
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
}};
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
,
638 xkb_rule_names names
= {.rules
= NULL
,
640 .layout
= layout_id
.c_str(),
641 .variant
= layout_variant
.c_str(),
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
));
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
)));
655 LOG(FATAL
) << "Keymap file failed to load: " << layout_name
;
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)
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
);
703 LoadKeymapCallback reply_callback
= base::Bind(
704 &XkbKeyboardLayoutEngine::OnKeymapLoaded
, weak_ptr_factory_
.GetWeakPtr());
705 base::WorkerPool::PostTask(
707 base::Bind(&LoadKeymap
, layout_name
, base::ThreadTaskRunnerHandle::Get(),
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
);
717 #endif // defined(OS_CHROMEOS)
721 void XkbKeyboardLayoutEngine::OnKeymapLoaded(
722 const std::string
& layout_name
,
723 scoped_ptr
<char, base::FreeDeleter
> 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_
)
733 LOG(FATAL
) << "Keymap file failed to load: " << layout_name
;
737 bool XkbKeyboardLayoutEngine::UsesISOLevel5Shift() const {
742 bool XkbKeyboardLayoutEngine::UsesAltGr() const {
747 bool XkbKeyboardLayoutEngine::Lookup(DomCode dom_code
,
750 base::char16
* character
,
751 KeyboardCode
* key_code
,
752 uint32
* platform_keycode
) const {
753 if (dom_code
== DomCode::NONE
)
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
) << "'";
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
))
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
);
790 *key_code
= NonPrintableDomKeyToKeyboardCode(*dom_key
);
791 if (*key_code
== VKEY_UNKNOWN
)
792 *key_code
= DomCodeToNonLocatedKeyboardCode(dom_code
);
797 void XkbKeyboardLayoutEngine::SetKeymap(xkb_keymap
* keymap
) {
798 xkb_state_
.reset(xkb_state_new(keymap
));
800 static const struct {
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
;
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_
;
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 {
848 LOG(ERROR
) << "No current XKB state";
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
)
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
);
861 KeyboardCode
XkbKeyboardLayoutEngine::DifficultKeyboardCode(
864 xkb_keycode_t xkb_keycode
,
865 xkb_mod_mask_t xkb_flags
,
866 xkb_keysym_t xkb_keysym
,
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
))
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
)
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
)
900 if (multi
->subtable
[i
].test_shift
) {
901 if (shift_character
== kNonCharacter
) {
902 shift_character
= XkbSubCharacter(xkb_keycode
, xkb_flags
, character
,
905 if (shift_character
!= multi
->subtable
[i
].shift_character
)
908 if (multi
->subtable
[i
].test_altgr
) {
909 if (altgr_character
== kNonCharacter
) {
910 altgr_character
= XkbSubCharacter(xkb_keycode
, xkb_flags
, character
,
913 if (altgr_character
!= multi
->subtable
[i
].altgr_character
)
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
;
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
;
942 base::char16 character
= 0;
943 if (!XkbLookup(xkb_keycode
, flags
, &keysym
, &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);