keyboard_code_conversion_x.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright (c) 2012 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.
4
5#include "ui/events/keycodes/keyboard_code_conversion_x.h"
6
7#include <algorithm>
8
9#define XK_3270  // for XK_3270_BackTab
10#include <X11/XF86keysym.h>
11#include <X11/Xlib.h>
12#include <X11/Xutil.h>
13#include <X11/extensions/XInput2.h>
14#include <X11/keysym.h>
15
16#include "base/basictypes.h"
17#include "base/logging.h"
18#include "base/strings/stringprintf.h"
19#include "base/strings/sys_string_conversions.h"
20#include "base/strings/utf_string_conversions.h"
21#include "ui/events/keycodes/dom4/keycode_converter.h"
22
23#define VKEY_UNSUPPORTED VKEY_UNKNOWN
24
25namespace ui {
26
27namespace {
28
29// MAP0 - MAP3:
30// These are the generated VKEY code maps for all possible Latin keyboard
31// layouts in Windows. And the maps are only for special letter keys excluding
32// [a-z] & [0-9].
33//
34// ch0: the keysym without modifier states.
35// ch1: the keysym with shift state.
36// ch2: the keysym with altgr state.
37// sc: the hardware keycode (in Windows, it's called scan code).
38// vk: the VKEY code.
39//
40// MAP0: maps from ch0 to vk.
41// MAP1: maps from ch0+sc to vk.
42// MAP2: maps from ch0+ch1+sc to vk.
43// MAP3: maps from ch0+ch1+ch2+sc to vk.
44// MAP0 - MAP3 are all sorted, so that finding VK can be binary search.
45//
46// Reason for creating these maps is because a hard-coded mapping in
47// KeyboardCodeFromXKeysym() doesn't support non-US keyboard layouts.
48// e.g. in UK keyboard, the key between Quote and Enter keys has the VKEY code
49// VKEY_OEM_5 instead of VKEY_3.
50//
51// The key symbols which are not [a-zA-Z0-9] and functional/extend keys (e.g.
52// TAB, ENTER, BS, Arrow keys, modifier keys, F1-F12, media/app keys, etc.)
53// should go through these maps for correct VKEY codes.
54//
55// Please refer to crbug.com/386066.
56//
57const struct MAP0 {
58  KeySym ch0;
59  uint8 vk;
60  bool operator()(const MAP0& m1, const MAP0& m2) const {
61    return m1.ch0 < m2.ch0;
62  }
63} map0[] = {
64      {0x0025, 0x35},  // XK_percent: VKEY_5
65      {0x0026, 0x31},  // XK_ampersand: VKEY_1
66      {0x003C, 0xDC},  // XK_less: VKEY_OEM_5
67      {0x007B, 0xDE},  // XK_braceleft: VKEY_OEM_7
68      {0x007C, 0xDC},  // XK_bar: VKEY_OEM_5
69      {0x007D, 0xBF},  // XK_braceright: VKEY_OEM_2
70      {0x007E, 0xDC},  // XK_asciitilde: VKEY_OEM_5
71      {0x00A1, 0xDD},  // XK_exclamdown: VKEY_OEM_6
72      {0x00AD, 0xC0},  // XK_hyphen: VKEY_OEM_3
73      {0x00B2, 0xDE},  // XK_twosuperior: VKEY_OEM_7
74      {0x00B5, 0xDC},  // XK_mu: VKEY_OEM_5
75      {0x00BB, 0x39},  // XK_guillemotright: VKEY_9
76      {0x00BD, 0xDC},  // XK_onehalf: VKEY_OEM_5
77      {0x00BF, 0xDD},  // XK_questiondown: VKEY_OEM_6
78      {0x00DF, 0xDB},  // XK_ssharp: VKEY_OEM_4
79      {0x00E5, 0xDD},  // XK_aring: VKEY_OEM_6
80      {0x00EA, 0x33},  // XK_ecircumflex: VKEY_3
81      {0x00EB, 0xBA},  // XK_ediaeresis: VKEY_OEM_1
82      {0x00EC, 0xDD},  // XK_igrave: VKEY_OEM_6
83      {0x00EE, 0xDD},  // XK_icircumflex: VKEY_OEM_6
84      {0x00F1, 0xC0},  // XK_ntilde: VKEY_OEM_3
85      {0x00F2, 0xC0},  // XK_ograve: VKEY_OEM_3
86      {0x00F5, 0xDB},  // XK_otilde: VKEY_OEM_4
87      {0x00F7, 0xDD},  // XK_division: VKEY_OEM_6
88      {0x00FD, 0x37},  // XK_yacute: VKEY_7
89      {0x00FE, 0xBD},  // XK_thorn: VKEY_OEM_MINUS
90      {0x01A1, 0xDD},  // XK_ohorn: VKEY_OEM_6
91      {0x01B0, 0xDB},  // XK_uhorn: VKEY_OEM_4
92      {0x01B5, 0x32},  // XK_lcaron: VKEY_2
93      {0x01B6, 0xDD},  // XK_zstroke: VKEY_OEM_6
94      {0x01BB, 0x35},  // XK_tcaron: VKEY_5
95      {0x01E6, 0xDE},  // XK_cacute: VKEY_OEM_7
96      {0x01EC, 0x32},  // XK_ecaron: VKEY_2
97      {0x01F2, 0xDC},  // XK_ncaron: VKEY_OEM_5
98      {0x01F5, 0xDB},  // XK_odoubleacute: VKEY_OEM_4
99      {0x01F8, 0x35},  // XK_rcaron: VKEY_5
100      {0x01F9, 0xBA},  // XK_uring: VKEY_OEM_1
101      {0x01FB, 0xDC},  // XK_udoubleacute: VKEY_OEM_5
102      {0x01FE, 0xDE},  // XK_tcedilla: VKEY_OEM_7
103      {0x0259, 0xC0},  // XK_schwa: VKEY_OEM_3
104      {0x02B1, 0xDD},  // XK_hstroke: VKEY_OEM_6
105      {0x02B9, 0xBA},  // XK_idotless: VKEY_OEM_1
106      {0x02BB, 0xDD},  // XK_gbreve: VKEY_OEM_6
107      {0x02E5, 0xC0},  // XK_cabovedot: VKEY_OEM_3
108      {0x02F5, 0xDB},  // XK_gabovedot: VKEY_OEM_4
109      {0x03B6, 0xBF},  // XK_lcedilla: VKEY_OEM_2
110      {0x03BA, 0x57},  // XK_emacron: VKEY_W
111      {0x03E0, 0xDF},  // XK_amacron: VKEY_OEM_8
112      {0x03EF, 0xDD},  // XK_imacron: VKEY_OEM_6
113      {0x03F1, 0xDB},  // XK_ncedilla: VKEY_OEM_4
114      {0x03F3, 0xDC},  // XK_kcedilla: VKEY_OEM_5
115};
116
117const struct MAP1 {
118  KeySym ch0;
119  unsigned sc;
120  uint8 vk;
121  bool operator()(const MAP1& m1, const MAP1& m2) const {
122    if (m1.ch0 == m2.ch0)
123      return m1.sc < m2.sc;
124    return m1.ch0 < m2.ch0;
125  }
126} map1[] = {
127      {0x0021, 0x0A, 0x31},  // XK_exclam+AE01: VKEY_1
128      {0x0021, 0x11, 0x38},  // XK_exclam+AE08: VKEY_8
129      {0x0021, 0x3D, 0xDF},  // XK_exclam+AB10: VKEY_OEM_8
130      {0x0022, 0x0B, 0x32},  // XK_quotedbl+AE02: VKEY_2
131      {0x0022, 0x0C, 0x33},  // XK_quotedbl+AE03: VKEY_3
132      {0x0023, 0x31, 0xDE},  // XK_numbersign+TLDE: VKEY_OEM_7
133      {0x0024, 0x23, 0xBA},  // XK_dollar+AD12: VKEY_OEM_1
134      {0x0024, 0x33, 0xDF},  // XK_dollar+BKSL: VKEY_OEM_8
135      {0x0027, 0x0D, 0x34},  // XK_quoteright+AE04: VKEY_4
136      {0x0027, 0x18, 0xDE},  // XK_quoteright+AD01: VKEY_OEM_7
137      {0x0027, 0x23, 0xBA},  // XK_quoteright+AD12: VKEY_OEM_1
138      {0x0027, 0x3D, 0xDE},  // XK_quoteright+AB10: VKEY_OEM_7
139      {0x0028, 0x0E, 0x35},  // XK_parenleft+AE05: VKEY_5
140      {0x0028, 0x12, 0x39},  // XK_parenleft+AE09: VKEY_9
141      {0x0028, 0x33, 0xDC},  // XK_parenleft+BKSL: VKEY_OEM_5
142      {0x0029, 0x13, 0x30},  // XK_parenright+AE10: VKEY_0
143      {0x0029, 0x14, 0xDB},  // XK_parenright+AE11: VKEY_OEM_4
144      {0x0029, 0x23, 0xDD},  // XK_parenright+AD12: VKEY_OEM_6
145      {0x002A, 0x23, 0xBA},  // XK_asterisk+AD12: VKEY_OEM_1
146      {0x002A, 0x33, 0xDC},  // XK_asterisk+BKSL: VKEY_OEM_5
147      {0x002B, 0x0A, 0x31},  // XK_plus+AE01: VKEY_1
148      {0x002B, 0x15, 0xBB},  // XK_plus+AE12: VKEY_OEM_PLUS
149      {0x002B, 0x22, 0xBB},  // XK_plus+AD11: VKEY_OEM_PLUS
150      {0x002B, 0x23, 0xBB},  // XK_plus+AD12: VKEY_OEM_PLUS
151      {0x002B, 0x2F, 0xBB},  // XK_plus+AC10: VKEY_OEM_PLUS
152      {0x002B, 0x33, 0xBF},  // XK_plus+BKSL: VKEY_OEM_2
153      {0x002C, 0x0C, 0x33},  // XK_comma+AE03: VKEY_3
154      {0x002C, 0x0E, 0x35},  // XK_comma+AE05: VKEY_5
155      {0x002C, 0x0F, 0x36},  // XK_comma+AE06: VKEY_6
156      {0x002C, 0x12, 0x39},  // XK_comma+AE09: VKEY_9
157      {0x002C, 0x19, 0xBC},  // XK_comma+AD02: VKEY_OEM_COMMA
158      {0x002C, 0x37, 0xBC},  // XK_comma+AB04: VKEY_OEM_COMMA
159      {0x002C, 0x3A, 0xBC},  // XK_comma+AB07: VKEY_OEM_COMMA
160      {0x002C, 0x3B, 0xBC},  // XK_comma+AB08: VKEY_OEM_COMMA
161      {0x002D, 0x0B, 0x32},  // XK_minus+AE02: VKEY_2
162      {0x002D, 0x0F, 0x36},  // XK_minus+AE06: VKEY_6
163      {0x002D, 0x14, 0xBD},  // XK_minus+AE11: VKEY_OEM_MINUS
164      {0x002D, 0x26, 0xBD},  // XK_minus+AC01: VKEY_OEM_MINUS
165      {0x002D, 0x30, 0xBD},  // XK_minus+AC11: VKEY_OEM_MINUS
166      {0x002E, 0x10, 0x37},  // XK_period+AE07: VKEY_7
167      {0x002E, 0x11, 0x38},  // XK_period+AE08: VKEY_8
168      {0x002E, 0x1A, 0xBE},  // XK_period+AD03: VKEY_OEM_PERIOD
169      {0x002E, 0x1B, 0xBE},  // XK_period+AD04: VKEY_OEM_PERIOD
170      {0x002E, 0x20, 0xBE},  // XK_period+AD09: VKEY_OEM_PERIOD
171      {0x002E, 0x30, 0xDE},  // XK_period+AC11: VKEY_OEM_7
172      {0x002E, 0x3C, 0xBE},  // XK_period+AB09: VKEY_OEM_PERIOD
173      {0x002E, 0x3D, 0xBF},  // XK_period+AB10: VKEY_OEM_2
174      {0x002F, 0x14, 0xDB},  // XK_slash+AE11: VKEY_OEM_4
175      {0x002F, 0x22, 0xBF},  // XK_slash+AD11: VKEY_OEM_2
176      {0x002F, 0x31, 0xDE},  // XK_slash+TLDE: VKEY_OEM_7
177      {0x002F, 0x33, 0xDC},  // XK_slash+BKSL: VKEY_OEM_5
178      {0x002F, 0x3D, 0xBF},  // XK_slash+AB10: VKEY_OEM_2
179      {0x003A, 0x0A, 0x31},  // XK_colon+AE01: VKEY_1
180      {0x003A, 0x0E, 0x35},  // XK_colon+AE05: VKEY_5
181      {0x003A, 0x0F, 0x36},  // XK_colon+AE06: VKEY_6
182      {0x003A, 0x3C, 0xBF},  // XK_colon+AB09: VKEY_OEM_2
183      {0x003B, 0x0D, 0x34},  // XK_semicolon+AE04: VKEY_4
184      {0x003B, 0x11, 0x38},  // XK_semicolon+AE08: VKEY_8
185      {0x003B, 0x18, 0xBA},  // XK_semicolon+AD01: VKEY_OEM_1
186      {0x003B, 0x22, 0xBA},  // XK_semicolon+AD11: VKEY_OEM_1
187      {0x003B, 0x23, 0xDD},  // XK_semicolon+AD12: VKEY_OEM_6
188      {0x003B, 0x2F, 0xBA},  // XK_semicolon+AC10: VKEY_OEM_1
189      {0x003B, 0x31, 0xC0},  // XK_semicolon+TLDE: VKEY_OEM_3
190      {0x003B, 0x34, 0xBA},  // XK_semicolon+AB01: VKEY_OEM_1
191      {0x003B, 0x3B, 0xBE},  // XK_semicolon+AB08: VKEY_OEM_PERIOD
192      {0x003B, 0x3D, 0xBF},  // XK_semicolon+AB10: VKEY_OEM_2
193      {0x003D, 0x11, 0x38},  // XK_equal+AE08: VKEY_8
194      {0x003D, 0x15, 0xBB},  // XK_equal+AE12: VKEY_OEM_PLUS
195      {0x003D, 0x23, 0xBB},  // XK_equal+AD12: VKEY_OEM_PLUS
196      {0x003F, 0x0B, 0x32},  // XK_question+AE02: VKEY_2
197      {0x003F, 0x10, 0x37},  // XK_question+AE07: VKEY_7
198      {0x003F, 0x11, 0x38},  // XK_question+AE08: VKEY_8
199      {0x003F, 0x14, 0xBB},  // XK_question+AE11: VKEY_OEM_PLUS
200      {0x0040, 0x23, 0xDD},  // XK_at+AD12: VKEY_OEM_6
201      {0x0040, 0x31, 0xDE},  // XK_at+TLDE: VKEY_OEM_7
202      {0x005B, 0x0A, 0xDB},  // XK_bracketleft+AE01: VKEY_OEM_4
203      {0x005B, 0x14, 0xDB},  // XK_bracketleft+AE11: VKEY_OEM_4
204      {0x005B, 0x22, 0xDB},  // XK_bracketleft+AD11: VKEY_OEM_4
205      {0x005B, 0x23, 0xDD},  // XK_bracketleft+AD12: VKEY_OEM_6
206      {0x005B, 0x30, 0xDE},  // XK_bracketleft+AC11: VKEY_OEM_7
207      {0x005C, 0x15, 0xDB},  // XK_backslash+AE12: VKEY_OEM_4
208      {0x005D, 0x0B, 0xDD},  // XK_bracketright+AE02: VKEY_OEM_6
209      {0x005D, 0x15, 0xDD},  // XK_bracketright+AE12: VKEY_OEM_6
210      {0x005D, 0x23, 0xDD},  // XK_bracketright+AD12: VKEY_OEM_6
211      {0x005D, 0x31, 0xC0},  // XK_bracketright+TLDE: VKEY_OEM_3
212      {0x005D, 0x33, 0xDC},  // XK_bracketright+BKSL: VKEY_OEM_5
213      {0x005F, 0x11, 0x38},  // XK_underscore+AE08: VKEY_8
214      {0x005F, 0x14, 0xBD},  // XK_underscore+AE11: VKEY_OEM_MINUS
215      {0x00A7, 0x0D, 0x34},  // XK_section+AE04: VKEY_4
216      {0x00A7, 0x0F, 0x36},  // XK_section+AE06: VKEY_6
217      {0x00A7, 0x30, 0xDE},  // XK_section+AC11: VKEY_OEM_7
218      {0x00AB, 0x11, 0x38},  // XK_guillemotleft+AE08: VKEY_8
219      {0x00AB, 0x15, 0xDD},  // XK_guillemotleft+AE12: VKEY_OEM_6
220      {0x00B0, 0x15, 0xBF},  // XK_degree+AE12: VKEY_OEM_2
221      {0x00B0, 0x31, 0xDE},  // XK_degree+TLDE: VKEY_OEM_7
222      {0x00BA, 0x30, 0xDE},  // XK_masculine+AC11: VKEY_OEM_7
223      {0x00BA, 0x31, 0xDC},  // XK_masculine+TLDE: VKEY_OEM_5
224      {0x00E0, 0x13, 0x30},  // XK_agrave+AE10: VKEY_0
225      {0x00E0, 0x33, 0xDC},  // XK_agrave+BKSL: VKEY_OEM_5
226      {0x00E1, 0x11, 0x38},  // XK_aacute+AE08: VKEY_8
227      {0x00E1, 0x30, 0xDE},  // XK_aacute+AC11: VKEY_OEM_7
228      {0x00E2, 0x0B, 0x32},  // XK_acircumflex+AE02: VKEY_2
229      {0x00E2, 0x33, 0xDC},  // XK_acircumflex+BKSL: VKEY_OEM_5
230      {0x00E4, 0x23, 0xDD},  // XK_adiaeresis+AD12: VKEY_OEM_6
231      {0x00E6, 0x2F, 0xC0},  // XK_ae+AC10: VKEY_OEM_3
232      {0x00E6, 0x30, 0xDE},  // XK_ae+AC11: VKEY_OEM_7
233      {0x00E7, 0x12, 0x39},  // XK_ccedilla+AE09: VKEY_9
234      {0x00E7, 0x22, 0xDB},  // XK_ccedilla+AD11: VKEY_OEM_4
235      {0x00E7, 0x23, 0xDD},  // XK_ccedilla+AD12: VKEY_OEM_6
236      {0x00E7, 0x30, 0xDE},  // XK_ccedilla+AC11: VKEY_OEM_7
237      {0x00E7, 0x33, 0xBF},  // XK_ccedilla+BKSL: VKEY_OEM_2
238      {0x00E7, 0x3B, 0xBC},  // XK_ccedilla+AB08: VKEY_OEM_COMMA
239      {0x00E8, 0x10, 0x37},  // XK_egrave+AE07: VKEY_7
240      {0x00E8, 0x22, 0xBA},  // XK_egrave+AD11: VKEY_OEM_1
241      {0x00E8, 0x30, 0xC0},  // XK_egrave+AC11: VKEY_OEM_3
242      {0x00E9, 0x0B, 0x32},  // XK_eacute+AE02: VKEY_2
243      {0x00E9, 0x13, 0x30},  // XK_eacute+AE10: VKEY_0
244      {0x00E9, 0x3D, 0xBF},  // XK_eacute+AB10: VKEY_OEM_2
245      {0x00ED, 0x12, 0x39},  // XK_iacute+AE09: VKEY_9
246      {0x00ED, 0x31, 0x30},  // XK_iacute+TLDE: VKEY_0
247      {0x00F0, 0x22, 0xDD},  // XK_eth+AD11: VKEY_OEM_6
248      {0x00F0, 0x23, 0xBA},  // XK_eth+AD12: VKEY_OEM_1
249      {0x00F3, 0x15, 0xBB},  // XK_oacute+AE12: VKEY_OEM_PLUS
250      {0x00F3, 0x33, 0xDC},  // XK_oacute+BKSL: VKEY_OEM_5
251      {0x00F4, 0x0D, 0x34},  // XK_ocircumflex+AE04: VKEY_4
252      {0x00F4, 0x2F, 0xBA},  // XK_ocircumflex+AC10: VKEY_OEM_1
253      {0x00F6, 0x13, 0xC0},  // XK_odiaeresis+AE10: VKEY_OEM_3
254      {0x00F6, 0x14, 0xBB},  // XK_odiaeresis+AE11: VKEY_OEM_PLUS
255      {0x00F6, 0x22, 0xDB},  // XK_odiaeresis+AD11: VKEY_OEM_4
256      {0x00F8, 0x2F, 0xC0},  // XK_oslash+AC10: VKEY_OEM_3
257      {0x00F8, 0x30, 0xDE},  // XK_oslash+AC11: VKEY_OEM_7
258      {0x00F9, 0x30, 0xC0},  // XK_ugrave+AC11: VKEY_OEM_3
259      {0x00F9, 0x33, 0xBF},  // XK_ugrave+BKSL: VKEY_OEM_2
260      {0x00FA, 0x22, 0xDB},  // XK_uacute+AD11: VKEY_OEM_4
261      {0x00FA, 0x23, 0xDD},  // XK_uacute+AD12: VKEY_OEM_6
262      {0x00FC, 0x19, 0x57},  // XK_udiaeresis+AD02: VKEY_W
263      {0x01B1, 0x0A, 0x31},  // XK_aogonek+AE01: VKEY_1
264      {0x01B1, 0x18, 0x51},  // XK_aogonek+AD01: VKEY_Q
265      {0x01B1, 0x30, 0xDE},  // XK_aogonek+AC11: VKEY_OEM_7
266      {0x01B3, 0x2F, 0xBA},  // XK_lstroke+AC10: VKEY_OEM_1
267      {0x01B3, 0x33, 0xBF},  // XK_lstroke+BKSL: VKEY_OEM_2
268      {0x01B9, 0x0C, 0x33},  // XK_scaron+AE03: VKEY_3
269      {0x01B9, 0x0F, 0x36},  // XK_scaron+AE06: VKEY_6
270      {0x01B9, 0x22, 0xDB},  // XK_scaron+AD11: VKEY_OEM_4
271      {0x01B9, 0x26, 0xBA},  // XK_scaron+AC01: VKEY_OEM_1
272      {0x01B9, 0x29, 0x46},  // XK_scaron+AC04: VKEY_F
273      {0x01B9, 0x3C, 0xBE},  // XK_scaron+AB09: VKEY_OEM_PERIOD
274      {0x01BA, 0x2F, 0xBA},  // XK_scedilla+AC10: VKEY_OEM_1
275      {0x01BA, 0x3C, 0xBE},  // XK_scedilla+AB09: VKEY_OEM_PERIOD
276      {0x01BE, 0x0F, 0x36},  // XK_zcaron+AE06: VKEY_6
277      {0x01BE, 0x15, 0xBB},  // XK_zcaron+AE12: VKEY_OEM_PLUS
278      {0x01BE, 0x19, 0x57},  // XK_zcaron+AD02: VKEY_W
279      {0x01BE, 0x22, 0x59},  // XK_zcaron+AD11: VKEY_Y
280      {0x01BE, 0x33, 0xDC},  // XK_zcaron+BKSL: VKEY_OEM_5
281      {0x01BF, 0x22, 0xDB},  // XK_zabovedot+AD11: VKEY_OEM_4
282      {0x01BF, 0x33, 0xDC},  // XK_zabovedot+BKSL: VKEY_OEM_5
283      {0x01E3, 0x0A, 0x31},  // XK_abreve+AE01: VKEY_1
284      {0x01E3, 0x22, 0xDB},  // XK_abreve+AD11: VKEY_OEM_4
285      {0x01E8, 0x0B, 0x32},  // XK_ccaron+AE02: VKEY_2
286      {0x01E8, 0x0D, 0x34},  // XK_ccaron+AE04: VKEY_4
287      {0x01E8, 0x21, 0x58},  // XK_ccaron+AD10: VKEY_X
288      {0x01E8, 0x2F, 0xBA},  // XK_ccaron+AC10: VKEY_OEM_1
289      {0x01E8, 0x3B, 0xBC},  // XK_ccaron+AB08: VKEY_OEM_COMMA
290      {0x01EA, 0x0C, 0x33},  // XK_eogonek+AE03: VKEY_3
291      {0x01F0, 0x13, 0x30},  // XK_dstroke+AE10: VKEY_0
292      {0x01F0, 0x23, 0xDD},  // XK_dstroke+AD12: VKEY_OEM_6
293      {0x03E7, 0x0E, 0x35},  // XK_iogonek+AE05: VKEY_5
294      {0x03EC, 0x0D, 0x34},  // XK_eabovedot+AE04: VKEY_4
295      {0x03EC, 0x30, 0xDE},  // XK_eabovedot+AC11: VKEY_OEM_7
296      {0x03F9, 0x10, 0x37},  // XK_uogonek+AE07: VKEY_7
297      {0x03FE, 0x11, 0x38},  // XK_umacron+AE08: VKEY_8
298      {0x03FE, 0x18, 0x51},  // XK_umacron+AD01: VKEY_Q
299      {0x03FE, 0x35, 0x58},  // XK_umacron+AB02: VKEY_X
300};
301
302const struct MAP2 {
303  KeySym ch0;
304  unsigned sc;
305  KeySym ch1;
306  uint8 vk;
307  bool operator()(const MAP2& m1, const MAP2& m2) const {
308    if (m1.ch0 == m2.ch0 && m1.sc == m2.sc)
309      return m1.ch1 < m2.ch1;
310    if (m1.ch0 == m2.ch0)
311      return m1.sc < m2.sc;
312    return m1.ch0 < m2.ch0;
313  }
314} map2[] = {
315      {0x0023, 0x33, 0x0027,
316       0xBF},  // XK_numbersign+BKSL+XK_quoteright: VKEY_OEM_2
317      {0x0027, 0x30, 0x0022,
318       0xDE},  // XK_quoteright+AC11+XK_quotedbl: VKEY_OEM_7
319      {0x0027, 0x31, 0x0022,
320       0xC0},  // XK_quoteright+TLDE+XK_quotedbl: VKEY_OEM_3
321      {0x0027, 0x31, 0x00B7,
322       0xDC},  // XK_quoteright+TLDE+XK_periodcentered: VKEY_OEM_5
323      {0x0027, 0x33, 0x0000, 0xDC},  // XK_quoteright+BKSL+NoSymbol: VKEY_OEM_5
324      {0x002D, 0x3D, 0x003D, 0xBD},  // XK_minus+AB10+XK_equal: VKEY_OEM_MINUS
325      {0x002F, 0x0C, 0x0033, 0x33},  // XK_slash+AE03+XK_3: VKEY_3
326      {0x002F, 0x0C, 0x003F, 0xBF},  // XK_slash+AE03+XK_question: VKEY_OEM_2
327      {0x002F, 0x13, 0x0030, 0x30},  // XK_slash+AE10+XK_0: VKEY_0
328      {0x002F, 0x13, 0x003F, 0xBF},  // XK_slash+AE10+XK_question: VKEY_OEM_2
329      {0x003D, 0x3D, 0x0025, 0xDF},  // XK_equal+AB10+XK_percent: VKEY_OEM_8
330      {0x003D, 0x3D, 0x002B, 0xBB},  // XK_equal+AB10+XK_plus: VKEY_OEM_PLUS
331      {0x005C, 0x33, 0x002F, 0xDE},  // XK_backslash+BKSL+XK_slash: VKEY_OEM_7
332      {0x005C, 0x33, 0x007C, 0xDC},  // XK_backslash+BKSL+XK_bar: VKEY_OEM_5
333      {0x0060, 0x31, 0x0000, 0xC0},  // XK_quoteleft+TLDE+NoSymbol: VKEY_OEM_3
334      {0x0060, 0x31, 0x00AC, 0xDF},  // XK_quoteleft+TLDE+XK_notsign: VKEY_OEM_8
335      {0x00A7, 0x31, 0x00B0, 0xBF},  // XK_section+TLDE+XK_degree: VKEY_OEM_2
336      {0x00A7, 0x31, 0x00BD, 0xDC},  // XK_section+TLDE+XK_onehalf: VKEY_OEM_5
337      {0x00E0, 0x30, 0x00B0, 0xDE},  // XK_agrave+AC11+XK_degree: VKEY_OEM_7
338      {0x00E0, 0x30, 0x00E4, 0xDC},  // XK_agrave+AC11+XK_adiaeresis: VKEY_OEM_5
339      {0x00E4, 0x30, 0x00E0, 0xDC},  // XK_adiaeresis+AC11+XK_agrave: VKEY_OEM_5
340      {0x00E9, 0x2F, 0x00C9, 0xBA},  // XK_eacute+AC10+XK_Eacute: VKEY_OEM_1
341      {0x00E9, 0x2F, 0x00F6, 0xDE},  // XK_eacute+AC10+XK_odiaeresis: VKEY_OEM_7
342      {0x00F6, 0x2F, 0x00E9, 0xDE},  // XK_odiaeresis+AC10+XK_eacute: VKEY_OEM_7
343      {0x00FC, 0x22, 0x00E8, 0xBA},  // XK_udiaeresis+AD11+XK_egrave: VKEY_OEM_1
344};
345
346const struct MAP3 {
347  KeySym ch0;
348  unsigned sc;
349  KeySym ch1;
350  KeySym ch2;
351  uint8 vk;
352  bool operator()(const MAP3& m1, const MAP3& m2) const {
353    if (m1.ch0 == m2.ch0 && m1.sc == m2.sc && m1.ch1 == m2.ch1)
354      return m1.ch2 < m2.ch2;
355    if (m1.ch0 == m2.ch0 && m1.sc == m2.sc)
356      return m1.ch1 < m2.ch1;
357    if (m1.ch0 == m2.ch0)
358      return m1.sc < m2.sc;
359    return m1.ch0 < m2.ch0;
360  }
361} map3[] = {
362      {0x0023, 0x33, 0x007E, 0x0000,
363       0xDE},  // XK_numbersign+BKSL+XK_asciitilde+NoSymbol: VKEY_OEM_7
364      {0x0027, 0x14, 0x003F, 0x0000,
365       0xDB},  // XK_quoteright+AE11+XK_question+NoSymbol: VKEY_OEM_4
366      {0x0027, 0x14, 0x003F, 0x00DD,
367       0xDB},  // XK_quoteright+AE11+XK_question+XK_Yacute: VKEY_OEM_4
368      {0x0027, 0x15, 0x002A, 0x0000,
369       0xBB},  // XK_quoteright+AE12+XK_asterisk+NoSymbol: VKEY_OEM_PLUS
370      {0x0027, 0x30, 0x0040, 0x0000,
371       0xC0},  // XK_quoteright+AC11+XK_at+NoSymbol: VKEY_OEM_3
372      {0x0027, 0x33, 0x002A, 0x0000,
373       0xBF},  // XK_quoteright+BKSL+XK_asterisk+NoSymbol: VKEY_OEM_2
374      {0x0027, 0x33, 0x002A, 0x00BD,
375       0xDC},  // XK_quoteright+BKSL+XK_asterisk+XK_onehalf: VKEY_OEM_5
376      {0x0027, 0x33, 0x002A, 0x01A3,
377       0xBF},  // XK_quoteright+BKSL+XK_asterisk+XK_Lstroke: VKEY_OEM_2
378      {0x0027, 0x34, 0x0022, 0x0000,
379       0x5A},  // XK_quoteright+AB01+XK_quotedbl+NoSymbol: VKEY_Z
380      {0x0027, 0x34, 0x0022, 0x01D8,
381       0xDE},  // XK_quoteright+AB01+XK_quotedbl+XK_Rcaron: VKEY_OEM_7
382      {0x002B, 0x14, 0x003F, 0x0000,
383       0xBB},  // XK_plus+AE11+XK_question+NoSymbol: VKEY_OEM_PLUS
384      {0x002B, 0x14, 0x003F, 0x005C,
385       0xBD},  // XK_plus+AE11+XK_question+XK_backslash: VKEY_OEM_MINUS
386      {0x002B, 0x14, 0x003F, 0x01F5,
387       0xBB},  // XK_plus+AE11+XK_question+XK_odoubleacute: VKEY_OEM_PLUS
388      {0x002D, 0x15, 0x005F, 0x0000,
389       0xBD},  // XK_minus+AE12+XK_underscore+NoSymbol: VKEY_OEM_MINUS
390      {0x002D, 0x15, 0x005F, 0x03B3,
391       0xDB},  // XK_minus+AE12+XK_underscore+XK_rcedilla: VKEY_OEM_4
392      {0x002D, 0x3D, 0x005F, 0x0000,
393       0xBD},  // XK_minus+AB10+XK_underscore+NoSymbol: VKEY_OEM_MINUS
394      {0x002D, 0x3D, 0x005F, 0x002A,
395       0xBD},  // XK_minus+AB10+XK_underscore+XK_asterisk: VKEY_OEM_MINUS
396      {0x002D, 0x3D, 0x005F, 0x002F,
397       0xBF},  // XK_minus+AB10+XK_underscore+XK_slash: VKEY_OEM_2
398      {0x002D, 0x3D, 0x005F, 0x006E,
399       0xBD},  // XK_minus+AB10+XK_underscore+XK_n: VKEY_OEM_MINUS
400      {0x003D, 0x14, 0x0025, 0x0000,
401       0xBB},  // XK_equal+AE11+XK_percent+NoSymbol: VKEY_OEM_PLUS
402      {0x003D, 0x14, 0x0025, 0x002D,
403       0xBD},  // XK_equal+AE11+XK_percent+XK_minus: VKEY_OEM_MINUS
404      {0x005C, 0x31, 0x007C, 0x0031,
405       0xDC},  // XK_backslash+TLDE+XK_bar+XK_1: VKEY_OEM_5
406      {0x005C, 0x31, 0x007C, 0x03D1,
407       0xC0},  // XK_backslash+TLDE+XK_bar+XK_Ncedilla: VKEY_OEM_3
408      {0x0060, 0x31, 0x007E, 0x0000,
409       0xC0},  // XK_quoteleft+TLDE+XK_asciitilde+NoSymbol: VKEY_OEM_3
410      {0x0060, 0x31, 0x007E, 0x0031,
411       0xC0},  // XK_quoteleft+TLDE+XK_asciitilde+XK_1: VKEY_OEM_3
412      {0x0060, 0x31, 0x007E, 0x003B,
413       0xC0},  // XK_quoteleft+TLDE+XK_asciitilde+XK_semicolon: VKEY_OEM_3
414      {0x0060, 0x31, 0x007E, 0x0060,
415       0xC0},  // XK_quoteleft+TLDE+XK_asciitilde+XK_quoteleft: VKEY_OEM_3
416      {0x0060, 0x31, 0x007E, 0x00BF,
417       0xC0},  // XK_quoteleft+TLDE+XK_asciitilde+XK_questiondown: VKEY_OEM_3
418      {0x0060, 0x31, 0x007E, 0x01F5,
419       0xC0},  // XK_quoteleft+TLDE+XK_asciitilde+XK_odoubleacute: VKEY_OEM_3
420      {0x00E4, 0x30, 0x00C4, 0x0000,
421       0xDE},  // XK_adiaeresis+AC11+XK_Adiaeresis+NoSymbol: VKEY_OEM_7
422      {0x00E4, 0x30, 0x00C4, 0x01A6,
423       0xDE},  // XK_adiaeresis+AC11+XK_Adiaeresis+XK_Sacute: VKEY_OEM_7
424      {0x00E4, 0x30, 0x00C4, 0x01F8,
425       0xDE},  // XK_adiaeresis+AC11+XK_Adiaeresis+XK_rcaron: VKEY_OEM_7
426      {0x00E7, 0x2F, 0x00C7, 0x0000,
427       0xBA},  // XK_ccedilla+AC10+XK_Ccedilla+NoSymbol: VKEY_OEM_1
428      {0x00E7, 0x2F, 0x00C7, 0x00DE,
429       0xC0},  // XK_ccedilla+AC10+XK_Ccedilla+XK_Thorn: VKEY_OEM_3
430      {0x00F6, 0x2F, 0x00D6, 0x0000,
431       0xC0},  // XK_odiaeresis+AC10+XK_Odiaeresis+NoSymbol: VKEY_OEM_3
432      {0x00F6, 0x2F, 0x00D6, 0x01DE,
433       0xC0},  // XK_odiaeresis+AC10+XK_Odiaeresis+XK_Tcedilla: VKEY_OEM_3
434      {0x00FC, 0x14, 0x00DC, 0x0000,
435       0xBF},  // XK_udiaeresis+AE11+XK_Udiaeresis+NoSymbol: VKEY_OEM_2
436      {0x00FC, 0x22, 0x00DC, 0x0000,
437       0xBA},  // XK_udiaeresis+AD11+XK_Udiaeresis+NoSymbol: VKEY_OEM_1
438      {0x00FC, 0x22, 0x00DC, 0x01A3,
439       0xC0},  // XK_udiaeresis+AD11+XK_Udiaeresis+XK_Lstroke: VKEY_OEM_3
440      {0x01EA, 0x3D, 0x01CA, 0x0000,
441       0xBD},  // XK_eogonek+AB10+XK_Eogonek+NoSymbol: VKEY_OEM_MINUS
442      {0x01EA, 0x3D, 0x01CA, 0x006E,
443       0xBF},  // XK_eogonek+AB10+XK_Eogonek+XK_n: VKEY_OEM_2
444      {0x03E7, 0x22, 0x03C7, 0x0000,
445       0xDB},  // XK_iogonek+AD11+XK_Iogonek+NoSymbol: VKEY_OEM_4
446      {0x03F9, 0x2F, 0x03D9, 0x0000,
447       0xC0},  // XK_uogonek+AC10+XK_Uogonek+NoSymbol: VKEY_OEM_3
448      {0x03F9, 0x2F, 0x03D9, 0x01DE,
449       0xBA},  // XK_uogonek+AC10+XK_Uogonek+XK_Tcedilla: VKEY_OEM_1
450};
451
452template <class T_MAP>
453KeyboardCode FindVK(const T_MAP& key, const T_MAP* map, size_t size) {
454  T_MAP comp = {0};
455  const T_MAP* p = std::lower_bound(map, map + size, key, comp);
456  if (p != map + size && !comp(*p, key) && !comp(key, *p))
457    return static_cast<KeyboardCode>(p->vk);
458  return VKEY_UNKNOWN;
459}
460
461}  // namespace
462
463// Get an ui::KeyboardCode from an X keyevent
464KeyboardCode KeyboardCodeFromXKeyEvent(const XEvent* xev) {
465  // Gets correct VKEY code from XEvent is performed as the following steps:
466  // 1. Gets the keysym without modifier states.
467  // 2. For [a-z] & [0-9] cases, returns the VKEY code accordingly.
468  // 3. Find keysym in map0.
469  // 4. If not found, fallback to find keysym + hardware_code in map1.
470  // 5. If not found, fallback to find keysym + keysym_shift + hardware_code
471  //    in map2.
472  // 6. If not found, fallback to find keysym + keysym_shift + keysym_altgr +
473  //    hardware_code in map3.
474  // 7. If not found, fallback to find in KeyboardCodeFromXKeysym(), which
475  //    mainly for non-letter keys.
476  // 8. If not found, fallback to find with the hardware code in US layout.
477
478  KeySym keysym = NoSymbol;
479  XEvent xkeyevent;
480  if (xev->type == GenericEvent) {
481    // Convert the XI2 key event into a core key event so that we can
482    // continue to use XLookupString() until crbug.com/367732 is complete.
483    InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
484  } else {
485    xkeyevent.xkey = xev->xkey;
486  }
487  XKeyEvent* xkey = &xkeyevent.xkey;
488  xkey->state &= (~0xFF | Mod2Mask);  // Clears the xkey's state except numlock.
489  // XLookupKeysym does not take into consideration the state of the lock/shift
490  // etc. keys. So it is necessary to use XLookupString instead.
491  XLookupString(xkey, NULL, 0, &keysym, NULL);
492
493  // [a-z] cases.
494  if (keysym >= XK_a && keysym <= XK_z)
495    return static_cast<KeyboardCode>(VKEY_A + keysym - XK_a);
496
497  // [0-9] cases.
498  if (keysym >= XK_0 && keysym <= XK_9)
499    return static_cast<KeyboardCode>(VKEY_0 + keysym - XK_0);
500
501  KeyboardCode keycode = VKEY_UNKNOWN;
502
503  if (!IsKeypadKey(keysym) && !IsPrivateKeypadKey(keysym) &&
504      !IsCursorKey(keysym) && !IsPFKey(keysym) && !IsFunctionKey(keysym) &&
505      !IsModifierKey(keysym)) {
506    MAP0 key0 = {keysym & 0xFFFF, 0};
507    keycode = FindVK(key0, map0, arraysize(map0));
508    if (keycode != VKEY_UNKNOWN)
509      return keycode;
510
511    MAP1 key1 = {keysym & 0xFFFF, xkey->keycode, 0};
512    keycode = FindVK(key1, map1, arraysize(map1));
513    if (keycode != VKEY_UNKNOWN)
514      return keycode;
515
516    KeySym keysym_shift = NoSymbol;
517    xkey->state |= ShiftMask;
518    XLookupString(xkey, NULL, 0, &keysym_shift, NULL);
519    MAP2 key2 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0};
520    keycode = FindVK(key2, map2, arraysize(map2));
521    if (keycode != VKEY_UNKNOWN)
522      return keycode;
523
524    KeySym keysym_altgr = NoSymbol;
525    xkey->state &= ~ShiftMask;
526    xkey->state |= Mod1Mask;
527    XLookupString(xkey, NULL, 0, &keysym_altgr, NULL);
528    MAP3 key3 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF,
529                 keysym_altgr & 0xFFFF, 0};
530    keycode = FindVK(key3, map3, arraysize(map3));
531    if (keycode != VKEY_UNKNOWN)
532      return keycode;
533
534    // On Linux some keys has AltGr char but not on Windows.
535    // So if cannot find VKEY with (ch0+sc+ch1+ch2) in map3, tries to fallback
536    // to just find VKEY with (ch0+sc+ch1). This is the best we could do.
537    MAP3 key4 = {keysym & 0xFFFF, xkey->keycode, keysym_shift & 0xFFFF, 0xFFFF,
538                 0};
539    const MAP3* p =
540        std::lower_bound(map3, map3 + arraysize(map3), key4, MAP3());
541    if (p != map3 + arraysize(map3) && p->ch0 == key4.ch0 && p->sc == key4.sc &&
542        p->ch1 == key4.ch1)
543      return static_cast<KeyboardCode>(p->vk);
544  }
545
546  keycode = KeyboardCodeFromXKeysym(keysym);
547  if (keycode == VKEY_UNKNOWN)
548    keycode = DefaultKeyboardCodeFromHardwareKeycode(xkey->keycode);
549
550  return keycode;
551}
552
553KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
554  // TODO(sad): Have |keysym| go through the X map list?
555
556  switch (keysym) {
557    case XK_BackSpace:
558      return VKEY_BACK;
559    case XK_Delete:
560    case XK_KP_Delete:
561      return VKEY_DELETE;
562    case XK_Tab:
563    case XK_KP_Tab:
564    case XK_ISO_Left_Tab:
565    case XK_3270_BackTab:
566      return VKEY_TAB;
567    case XK_Linefeed:
568    case XK_Return:
569    case XK_KP_Enter:
570    case XK_ISO_Enter:
571      return VKEY_RETURN;
572    case XK_Clear:
573    case XK_KP_Begin:  // NumPad 5 without Num Lock, for crosbug.com/29169.
574      return VKEY_CLEAR;
575    case XK_KP_Space:
576    case XK_space:
577      return VKEY_SPACE;
578    case XK_Home:
579    case XK_KP_Home:
580      return VKEY_HOME;
581    case XK_End:
582    case XK_KP_End:
583      return VKEY_END;
584    case XK_Page_Up:
585    case XK_KP_Page_Up:  // aka XK_KP_Prior
586      return VKEY_PRIOR;
587    case XK_Page_Down:
588    case XK_KP_Page_Down:  // aka XK_KP_Next
589      return VKEY_NEXT;
590    case XK_Left:
591    case XK_KP_Left:
592      return VKEY_LEFT;
593    case XK_Right:
594    case XK_KP_Right:
595      return VKEY_RIGHT;
596    case XK_Down:
597    case XK_KP_Down:
598      return VKEY_DOWN;
599    case XK_Up:
600    case XK_KP_Up:
601      return VKEY_UP;
602    case XK_Escape:
603      return VKEY_ESCAPE;
604    case XK_Kana_Lock:
605    case XK_Kana_Shift:
606      return VKEY_KANA;
607    case XK_Hangul:
608      return VKEY_HANGUL;
609    case XK_Hangul_Hanja:
610      return VKEY_HANJA;
611    case XK_Kanji:
612      return VKEY_KANJI;
613    case XK_Henkan:
614      return VKEY_CONVERT;
615    case XK_Muhenkan:
616      return VKEY_NONCONVERT;
617    case XK_Zenkaku_Hankaku:
618      return VKEY_DBE_DBCSCHAR;
619
620    case XK_KP_0:
621    case XK_KP_1:
622    case XK_KP_2:
623    case XK_KP_3:
624    case XK_KP_4:
625    case XK_KP_5:
626    case XK_KP_6:
627    case XK_KP_7:
628    case XK_KP_8:
629    case XK_KP_9:
630      return static_cast<KeyboardCode>(VKEY_NUMPAD0 + (keysym - XK_KP_0));
631
632    case XK_multiply:
633    case XK_KP_Multiply:
634      return VKEY_MULTIPLY;
635    case XK_KP_Add:
636      return VKEY_ADD;
637    case XK_KP_Separator:
638      return VKEY_SEPARATOR;
639    case XK_KP_Subtract:
640      return VKEY_SUBTRACT;
641    case XK_KP_Decimal:
642      return VKEY_DECIMAL;
643    case XK_KP_Divide:
644      return VKEY_DIVIDE;
645    case XK_KP_Equal:
646    case XK_equal:
647    case XK_plus:
648      return VKEY_OEM_PLUS;
649    case XK_comma:
650    case XK_less:
651      return VKEY_OEM_COMMA;
652    case XK_minus:
653    case XK_underscore:
654      return VKEY_OEM_MINUS;
655    case XK_greater:
656    case XK_period:
657      return VKEY_OEM_PERIOD;
658    case XK_colon:
659    case XK_semicolon:
660      return VKEY_OEM_1;
661    case XK_question:
662    case XK_slash:
663      return VKEY_OEM_2;
664    case XK_asciitilde:
665    case XK_quoteleft:
666      return VKEY_OEM_3;
667    case XK_bracketleft:
668    case XK_braceleft:
669      return VKEY_OEM_4;
670    case XK_backslash:
671    case XK_bar:
672      return VKEY_OEM_5;
673    case XK_bracketright:
674    case XK_braceright:
675      return VKEY_OEM_6;
676    case XK_quoteright:
677    case XK_quotedbl:
678      return VKEY_OEM_7;
679    case XK_ISO_Level5_Shift:
680      return VKEY_OEM_8;
681    case XK_Shift_L:
682    case XK_Shift_R:
683      return VKEY_SHIFT;
684    case XK_Control_L:
685    case XK_Control_R:
686      return VKEY_CONTROL;
687    case XK_Meta_L:
688    case XK_Meta_R:
689    case XK_Alt_L:
690    case XK_Alt_R:
691      return VKEY_MENU;
692    case XK_ISO_Level3_Shift:
693    case XK_Mode_switch:
694      return VKEY_ALTGR;
695    case XK_Multi_key:
696      return VKEY_COMPOSE;
697    case XK_Pause:
698      return VKEY_PAUSE;
699    case XK_Caps_Lock:
700      return VKEY_CAPITAL;
701    case XK_Num_Lock:
702      return VKEY_NUMLOCK;
703    case XK_Scroll_Lock:
704      return VKEY_SCROLL;
705    case XK_Select:
706      return VKEY_SELECT;
707    case XK_Print:
708      return VKEY_PRINT;
709    case XK_Execute:
710      return VKEY_EXECUTE;
711    case XK_Insert:
712    case XK_KP_Insert:
713      return VKEY_INSERT;
714    case XK_Help:
715      return VKEY_HELP;
716    case XK_Super_L:
717      return VKEY_LWIN;
718    case XK_Super_R:
719      return VKEY_RWIN;
720    case XK_Menu:
721      return VKEY_APPS;
722    case XK_F1:
723    case XK_F2:
724    case XK_F3:
725    case XK_F4:
726    case XK_F5:
727    case XK_F6:
728    case XK_F7:
729    case XK_F8:
730    case XK_F9:
731    case XK_F10:
732    case XK_F11:
733    case XK_F12:
734    case XK_F13:
735    case XK_F14:
736    case XK_F15:
737    case XK_F16:
738    case XK_F17:
739    case XK_F18:
740    case XK_F19:
741    case XK_F20:
742    case XK_F21:
743    case XK_F22:
744    case XK_F23:
745    case XK_F24:
746      return static_cast<KeyboardCode>(VKEY_F1 + (keysym - XK_F1));
747    case XK_KP_F1:
748    case XK_KP_F2:
749    case XK_KP_F3:
750    case XK_KP_F4:
751      return static_cast<KeyboardCode>(VKEY_F1 + (keysym - XK_KP_F1));
752
753    case XK_guillemotleft:
754    case XK_guillemotright:
755    case XK_degree:
756    // In the case of canadian multilingual keyboard layout, VKEY_OEM_102 is
757    // assigned to ugrave key.
758    case XK_ugrave:
759    case XK_Ugrave:
760    case XK_brokenbar:
761      return VKEY_OEM_102;  // international backslash key in 102 keyboard.
762
763    // When evdev is in use, /usr/share/X11/xkb/symbols/inet maps F13-18 keys
764    // to the special XF86XK symbols to support Microsoft Ergonomic keyboards:
765    // https://bugs.freedesktop.org/show_bug.cgi?id=5783
766    // In Chrome, we map these X key symbols back to F13-18 since we don't have
767    // VKEYs for these XF86XK symbols.
768    case XF86XK_Tools:
769      return VKEY_F13;
770    case XF86XK_Launch5:
771      return VKEY_F14;
772    case XF86XK_Launch6:
773      return VKEY_F15;
774    case XF86XK_Launch7:
775      return VKEY_F16;
776    case XF86XK_Launch8:
777      return VKEY_F17;
778    case XF86XK_Launch9:
779      return VKEY_F18;
780
781    // For supporting multimedia buttons on a USB keyboard.
782    case XF86XK_Back:
783      return VKEY_BROWSER_BACK;
784    case XF86XK_Forward:
785      return VKEY_BROWSER_FORWARD;
786    case XF86XK_Reload:
787      return VKEY_BROWSER_REFRESH;
788    case XF86XK_Stop:
789      return VKEY_BROWSER_STOP;
790    case XF86XK_Search:
791      return VKEY_BROWSER_SEARCH;
792    case XF86XK_Favorites:
793      return VKEY_BROWSER_FAVORITES;
794    case XF86XK_HomePage:
795      return VKEY_BROWSER_HOME;
796    case XF86XK_AudioMute:
797      return VKEY_VOLUME_MUTE;
798    case XF86XK_AudioLowerVolume:
799      return VKEY_VOLUME_DOWN;
800    case XF86XK_AudioRaiseVolume:
801      return VKEY_VOLUME_UP;
802    case XF86XK_AudioNext:
803      return VKEY_MEDIA_NEXT_TRACK;
804    case XF86XK_AudioPrev:
805      return VKEY_MEDIA_PREV_TRACK;
806    case XF86XK_AudioStop:
807      return VKEY_MEDIA_STOP;
808    case XF86XK_AudioPlay:
809      return VKEY_MEDIA_PLAY_PAUSE;
810    case XF86XK_Mail:
811      return VKEY_MEDIA_LAUNCH_MAIL;
812    case XF86XK_LaunchA:  // F3 on an Apple keyboard.
813      return VKEY_MEDIA_LAUNCH_APP1;
814    case XF86XK_LaunchB:  // F4 on an Apple keyboard.
815    case XF86XK_Calculator:
816      return VKEY_MEDIA_LAUNCH_APP2;
817    case XF86XK_WLAN:
818      return VKEY_WLAN;
819    case XF86XK_PowerOff:
820      return VKEY_POWER;
821    case XF86XK_MonBrightnessDown:
822      return VKEY_BRIGHTNESS_DOWN;
823    case XF86XK_MonBrightnessUp:
824      return VKEY_BRIGHTNESS_UP;
825    case XF86XK_KbdBrightnessDown:
826      return VKEY_KBD_BRIGHTNESS_DOWN;
827    case XF86XK_KbdBrightnessUp:
828      return VKEY_KBD_BRIGHTNESS_UP;
829
830    // TODO(sad): some keycodes are still missing.
831  }
832  DLOG(WARNING) << "Unknown keysym: " << base::StringPrintf("0x%x", keysym);
833  return VKEY_UNKNOWN;
834}
835
836const char* CodeFromXEvent(const XEvent* xev) {
837  int keycode = (xev->type == GenericEvent)
838                    ? static_cast<XIDeviceEvent*>(xev->xcookie.data)->detail
839                    : xev->xkey.keycode;
840  return KeycodeConverter::GetInstance()->NativeKeycodeToCode(keycode);
841}
842
843uint16 GetCharacterFromXEvent(const XEvent* xev) {
844  XEvent xkeyevent;
845  const XKeyEvent* xkey = NULL;
846  char buf[6];
847  if (xev->type == GenericEvent) {
848    // Convert the XI2 key event into a core key event so that we can
849    // continue to use XLookupString() until crbug.com/367732 is complete.
850    InitXKeyEventFromXIDeviceEvent(*xev, &xkeyevent);
851    xkey = &xkeyevent.xkey;
852  } else {
853    xkey = &xev->xkey;
854  }
855  int bytes_written =
856      XLookupString(const_cast<XKeyEvent*>(xkey), buf, 6, NULL, NULL);
857  DCHECK_LE(bytes_written, 6);
858
859  if (bytes_written <= 0)
860    return 0;
861  const base::string16& result = base::WideToUTF16(
862      base::SysNativeMBToWide(base::StringPiece(buf, bytes_written)));
863  return result.length() == 1 ? result[0] : 0;
864}
865
866KeyboardCode DefaultKeyboardCodeFromHardwareKeycode(
867    unsigned int hardware_code) {
868  // This function assumes that X11 is using evdev-based keycodes.
869  static const KeyboardCode kHardwareKeycodeMap[] = {
870      // Please refer to below links for the table content:
871      // http://www.w3.org/TR/DOM-Level-3-Events-code/#keyboard-101
872      // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.keyCode
873      // http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf
874      VKEY_UNKNOWN,       // 0x00:
875      VKEY_UNKNOWN,       // 0x01:
876      VKEY_UNKNOWN,       // 0x02:
877      VKEY_UNKNOWN,       // 0x03:
878      VKEY_UNKNOWN,       // 0x04:
879      VKEY_UNKNOWN,       // 0x05:
880      VKEY_UNKNOWN,       // 0x06:
881      VKEY_UNKNOWN,       // XKB   evdev (XKB - 8)      X KeySym
882      VKEY_UNKNOWN,       // ===   ===============      ======
883      VKEY_ESCAPE,        // 0x09: KEY_ESC              Escape
884      VKEY_1,             // 0x0A: KEY_1                1
885      VKEY_2,             // 0x0B: KEY_2                2
886      VKEY_3,             // 0x0C: KEY_3                3
887      VKEY_4,             // 0x0D: KEY_4                4
888      VKEY_5,             // 0x0E: KEY_5                5
889      VKEY_6,             // 0x0F: KEY_6                6
890      VKEY_7,             // 0x10: KEY_7                7
891      VKEY_8,             // 0x11: KEY_8                8
892      VKEY_9,             // 0x12: KEY_9                9
893      VKEY_0,             // 0x13: KEY_0                0
894      VKEY_OEM_MINUS,     // 0x14: KEY_MINUS            minus
895      VKEY_OEM_PLUS,      // 0x15: KEY_EQUAL            equal
896      VKEY_BACK,          // 0x16: KEY_BACKSPACE        BackSpace
897      VKEY_TAB,           // 0x17: KEY_TAB              Tab
898      VKEY_Q,             // 0x18: KEY_Q                q
899      VKEY_W,             // 0x19: KEY_W                w
900      VKEY_E,             // 0x1A: KEY_E                e
901      VKEY_R,             // 0x1B: KEY_R                r
902      VKEY_T,             // 0x1C: KEY_T                t
903      VKEY_Y,             // 0x1D: KEY_Y                y
904      VKEY_U,             // 0x1E: KEY_U                u
905      VKEY_I,             // 0x1F: KEY_I                i
906      VKEY_O,             // 0x20: KEY_O                o
907      VKEY_P,             // 0x21: KEY_P                p
908      VKEY_OEM_4,         // 0x22: KEY_LEFTBRACE        bracketleft
909      VKEY_OEM_6,         // 0x23: KEY_RIGHTBRACE       bracketright
910      VKEY_RETURN,        // 0x24: KEY_ENTER            Return
911      VKEY_LCONTROL,      // 0x25: KEY_LEFTCTRL         Control_L
912      VKEY_A,             // 0x26: KEY_A                a
913      VKEY_S,             // 0x27: KEY_S                s
914      VKEY_D,             // 0x28: KEY_D                d
915      VKEY_F,             // 0x29: KEY_F                f
916      VKEY_G,             // 0x2A: KEY_G                g
917      VKEY_H,             // 0x2B: KEY_H                h
918      VKEY_J,             // 0x2C: KEY_J                j
919      VKEY_K,             // 0x2D: KEY_K                k
920      VKEY_L,             // 0x2E: KEY_L                l
921      VKEY_OEM_1,         // 0x2F: KEY_SEMICOLON        semicolon
922      VKEY_OEM_7,         // 0x30: KEY_APOSTROPHE       apostrophe
923      VKEY_OEM_3,         // 0x31: KEY_GRAVE            grave
924      VKEY_LSHIFT,        // 0x32: KEY_LEFTSHIFT        Shift_L
925      VKEY_OEM_5,         // 0x33: KEY_BACKSLASH        backslash
926      VKEY_Z,             // 0x34: KEY_Z                z
927      VKEY_X,             // 0x35: KEY_X                x
928      VKEY_C,             // 0x36: KEY_C                c
929      VKEY_V,             // 0x37: KEY_V                v
930      VKEY_B,             // 0x38: KEY_B                b
931      VKEY_N,             // 0x39: KEY_N                n
932      VKEY_M,             // 0x3A: KEY_M                m
933      VKEY_OEM_COMMA,     // 0x3B: KEY_COMMA            comma
934      VKEY_OEM_PERIOD,    // 0x3C: KEY_DOT              period
935      VKEY_OEM_2,         // 0x3D: KEY_SLASH            slash
936      VKEY_RSHIFT,        // 0x3E: KEY_RIGHTSHIFT       Shift_R
937      VKEY_MULTIPLY,      // 0x3F: KEY_KPASTERISK       KP_Multiply
938      VKEY_LMENU,         // 0x40: KEY_LEFTALT          Alt_L
939      VKEY_SPACE,         // 0x41: KEY_SPACE            space
940      VKEY_CAPITAL,       // 0x42: KEY_CAPSLOCK         Caps_Lock
941      VKEY_F1,            // 0x43: KEY_F1               F1
942      VKEY_F2,            // 0x44: KEY_F2               F2
943      VKEY_F3,            // 0x45: KEY_F3               F3
944      VKEY_F4,            // 0x46: KEY_F4               F4
945      VKEY_F5,            // 0x47: KEY_F5               F5
946      VKEY_F6,            // 0x48: KEY_F6               F6
947      VKEY_F7,            // 0x49: KEY_F7               F7
948      VKEY_F8,            // 0x4A: KEY_F8               F8
949      VKEY_F9,            // 0x4B: KEY_F9               F9
950      VKEY_F10,           // 0x4C: KEY_F10              F10
951      VKEY_NUMLOCK,       // 0x4D: KEY_NUMLOCK          Num_Lock
952      VKEY_SCROLL,        // 0x4E: KEY_SCROLLLOCK       Scroll_Lock
953      VKEY_NUMPAD7,       // 0x4F: KEY_KP7              KP_7
954      VKEY_NUMPAD8,       // 0x50: KEY_KP8              KP_8
955      VKEY_NUMPAD9,       // 0x51: KEY_KP9              KP_9
956      VKEY_SUBTRACT,      // 0x52: KEY_KPMINUS          KP_Subtract
957      VKEY_NUMPAD4,       // 0x53: KEY_KP4              KP_4
958      VKEY_NUMPAD5,       // 0x54: KEY_KP5              KP_5
959      VKEY_NUMPAD6,       // 0x55: KEY_KP6              KP_6
960      VKEY_ADD,           // 0x56: KEY_KPPLUS           KP_Add
961      VKEY_NUMPAD1,       // 0x57: KEY_KP1              KP_1
962      VKEY_NUMPAD2,       // 0x58: KEY_KP2              KP_2
963      VKEY_NUMPAD3,       // 0x59: KEY_KP3              KP_3
964      VKEY_NUMPAD0,       // 0x5A: KEY_KP0              KP_0
965      VKEY_DECIMAL,       // 0x5B: KEY_KPDOT            KP_Decimal
966      VKEY_UNKNOWN,       // 0x5C:
967      VKEY_DBE_DBCSCHAR,  // 0x5D: KEY_ZENKAKUHANKAKU   Zenkaku_Hankaku
968      VKEY_OEM_5,         // 0x5E: KEY_102ND            backslash
969      VKEY_F11,           // 0x5F: KEY_F11              F11
970      VKEY_F12,           // 0x60: KEY_F12              F12
971      VKEY_OEM_102,       // 0x61: KEY_RO               Romaji
972      VKEY_UNSUPPORTED,   // 0x62: KEY_KATAKANA         Katakana
973      VKEY_UNSUPPORTED,   // 0x63: KEY_HIRAGANA         Hiragana
974      VKEY_CONVERT,       // 0x64: KEY_HENKAN           Henkan
975      VKEY_UNSUPPORTED,   // 0x65: KEY_KATAKANAHIRAGANA Hiragana_Katakana
976      VKEY_NONCONVERT,    // 0x66: KEY_MUHENKAN         Muhenkan
977      VKEY_SEPARATOR,     // 0x67: KEY_KPJPCOMMA        KP_Separator
978      VKEY_RETURN,        // 0x68: KEY_KPENTER          KP_Enter
979      VKEY_RCONTROL,      // 0x69: KEY_RIGHTCTRL        Control_R
980      VKEY_DIVIDE,        // 0x6A: KEY_KPSLASH          KP_Divide
981      VKEY_PRINT,         // 0x6B: KEY_SYSRQ            Print
982      VKEY_RMENU,         // 0x6C: KEY_RIGHTALT         Alt_R
983      VKEY_RETURN,        // 0x6D: KEY_LINEFEED         Linefeed
984      VKEY_HOME,          // 0x6E: KEY_HOME             Home
985      VKEY_UP,            // 0x6F: KEY_UP               Up
986      VKEY_PRIOR,         // 0x70: KEY_PAGEUP           Page_Up
987      VKEY_LEFT,          // 0x71: KEY_LEFT             Left
988      VKEY_RIGHT,         // 0x72: KEY_RIGHT            Right
989      VKEY_END,           // 0x73: KEY_END              End
990      VKEY_DOWN,          // 0x74: KEY_DOWN             Down
991      VKEY_NEXT,          // 0x75: KEY_PAGEDOWN         Page_Down
992      VKEY_INSERT,        // 0x76: KEY_INSERT           Insert
993      VKEY_DELETE,        // 0x77: KEY_DELETE           Delete
994      VKEY_UNSUPPORTED,   // 0x78: KEY_MACRO
995      VKEY_VOLUME_MUTE,   // 0x79: KEY_MUTE             XF86AudioMute
996      VKEY_VOLUME_DOWN,   // 0x7A: KEY_VOLUMEDOWN       XF86AudioLowerVolume
997      VKEY_VOLUME_UP,     // 0x7B: KEY_VOLUMEUP         XF86AudioRaiseVolume
998      VKEY_POWER,         // 0x7C: KEY_POWER            XF86PowerOff
999      VKEY_OEM_PLUS,      // 0x7D: KEY_KPEQUAL          KP_Equal
1000      VKEY_UNSUPPORTED,   // 0x7E: KEY_KPPLUSMINUS      plusminus
1001      VKEY_PAUSE,         // 0x7F: KEY_PAUSE            Pause
1002      VKEY_MEDIA_LAUNCH_APP1,  // 0x80: KEY_SCALE            XF86LaunchA
1003      VKEY_DECIMAL,            // 0x81: KEY_KPCOMMA          KP_Decimal
1004      VKEY_HANGUL,             // 0x82: KEY_HANGUEL          Hangul
1005      VKEY_HANJA,              // 0x83: KEY_HANJA            Hangul_Hanja
1006      VKEY_OEM_5,              // 0x84: KEY_YEN              yen
1007      VKEY_LWIN,               // 0x85: KEY_LEFTMETA         Super_L
1008      VKEY_RWIN,               // 0x86: KEY_RIGHTMETA        Super_R
1009      VKEY_COMPOSE,            // 0x87: KEY_COMPOSE          Menu
1010  };
1011
1012  if (hardware_code >= arraysize(kHardwareKeycodeMap)) {
1013    // Additional keycodes used by the Chrome OS top row special function keys.
1014    switch (hardware_code) {
1015      case 0xA6:  // KEY_BACK
1016        return VKEY_BACK;
1017      case 0xA7:  // KEY_FORWARD
1018        return VKEY_BROWSER_FORWARD;
1019      case 0xB5:  // KEY_REFRESH
1020        return VKEY_BROWSER_REFRESH;
1021      case 0xD4:  // KEY_DASHBOARD
1022        return VKEY_MEDIA_LAUNCH_APP2;
1023      case 0xE8:  // KEY_BRIGHTNESSDOWN
1024        return VKEY_BRIGHTNESS_DOWN;
1025      case 0xE9:  // KEY_BRIGHTNESSUP
1026        return VKEY_BRIGHTNESS_UP;
1027    }
1028    return VKEY_UNKNOWN;
1029  }
1030  return kHardwareKeycodeMap[hardware_code];
1031}
1032
1033// TODO(jcampan): this method might be incomplete.
1034int XKeysymForWindowsKeyCode(KeyboardCode keycode, bool shift) {
1035  switch (keycode) {
1036    case VKEY_NUMPAD0:
1037      return XK_KP_0;
1038    case VKEY_NUMPAD1:
1039      return XK_KP_1;
1040    case VKEY_NUMPAD2:
1041      return XK_KP_2;
1042    case VKEY_NUMPAD3:
1043      return XK_KP_3;
1044    case VKEY_NUMPAD4:
1045      return XK_KP_4;
1046    case VKEY_NUMPAD5:
1047      return XK_KP_5;
1048    case VKEY_NUMPAD6:
1049      return XK_KP_6;
1050    case VKEY_NUMPAD7:
1051      return XK_KP_7;
1052    case VKEY_NUMPAD8:
1053      return XK_KP_8;
1054    case VKEY_NUMPAD9:
1055      return XK_KP_9;
1056    case VKEY_MULTIPLY:
1057      return XK_KP_Multiply;
1058    case VKEY_ADD:
1059      return XK_KP_Add;
1060    case VKEY_SUBTRACT:
1061      return XK_KP_Subtract;
1062    case VKEY_DECIMAL:
1063      return XK_KP_Decimal;
1064    case VKEY_DIVIDE:
1065      return XK_KP_Divide;
1066
1067    case VKEY_BACK:
1068      return XK_BackSpace;
1069    case VKEY_TAB:
1070      return shift ? XK_ISO_Left_Tab : XK_Tab;
1071    case VKEY_CLEAR:
1072      return XK_Clear;
1073    case VKEY_RETURN:
1074      return XK_Return;
1075    case VKEY_SHIFT:
1076      return XK_Shift_L;
1077    case VKEY_CONTROL:
1078      return XK_Control_L;
1079    case VKEY_MENU:
1080      return XK_Alt_L;
1081    case VKEY_APPS:
1082      return XK_Menu;
1083    case VKEY_ALTGR:
1084      return XK_ISO_Level3_Shift;
1085    case VKEY_COMPOSE:
1086      return XK_Multi_key;
1087
1088    case VKEY_PAUSE:
1089      return XK_Pause;
1090    case VKEY_CAPITAL:
1091      return XK_Caps_Lock;
1092    case VKEY_KANA:
1093      return XK_Kana_Lock;
1094    case VKEY_HANJA:
1095      return XK_Hangul_Hanja;
1096    case VKEY_CONVERT:
1097      return XK_Henkan;
1098    case VKEY_NONCONVERT:
1099      return XK_Muhenkan;
1100    case VKEY_DBE_SBCSCHAR:
1101      return XK_Zenkaku_Hankaku;
1102    case VKEY_DBE_DBCSCHAR:
1103      return XK_Zenkaku_Hankaku;
1104    case VKEY_ESCAPE:
1105      return XK_Escape;
1106    case VKEY_SPACE:
1107      return XK_space;
1108    case VKEY_PRIOR:
1109      return XK_Page_Up;
1110    case VKEY_NEXT:
1111      return XK_Page_Down;
1112    case VKEY_END:
1113      return XK_End;
1114    case VKEY_HOME:
1115      return XK_Home;
1116    case VKEY_LEFT:
1117      return XK_Left;
1118    case VKEY_UP:
1119      return XK_Up;
1120    case VKEY_RIGHT:
1121      return XK_Right;
1122    case VKEY_DOWN:
1123      return XK_Down;
1124    case VKEY_SELECT:
1125      return XK_Select;
1126    case VKEY_PRINT:
1127      return XK_Print;
1128    case VKEY_EXECUTE:
1129      return XK_Execute;
1130    case VKEY_INSERT:
1131      return XK_Insert;
1132    case VKEY_DELETE:
1133      return XK_Delete;
1134    case VKEY_HELP:
1135      return XK_Help;
1136    case VKEY_0:
1137      return shift ? XK_parenright : XK_0;
1138    case VKEY_1:
1139      return shift ? XK_exclam : XK_1;
1140    case VKEY_2:
1141      return shift ? XK_at : XK_2;
1142    case VKEY_3:
1143      return shift ? XK_numbersign : XK_3;
1144    case VKEY_4:
1145      return shift ? XK_dollar : XK_4;
1146    case VKEY_5:
1147      return shift ? XK_percent : XK_5;
1148    case VKEY_6:
1149      return shift ? XK_asciicircum : XK_6;
1150    case VKEY_7:
1151      return shift ? XK_ampersand : XK_7;
1152    case VKEY_8:
1153      return shift ? XK_asterisk : XK_8;
1154    case VKEY_9:
1155      return shift ? XK_parenleft : XK_9;
1156
1157    case VKEY_A:
1158    case VKEY_B:
1159    case VKEY_C:
1160    case VKEY_D:
1161    case VKEY_E:
1162    case VKEY_F:
1163    case VKEY_G:
1164    case VKEY_H:
1165    case VKEY_I:
1166    case VKEY_J:
1167    case VKEY_K:
1168    case VKEY_L:
1169    case VKEY_M:
1170    case VKEY_N:
1171    case VKEY_O:
1172    case VKEY_P:
1173    case VKEY_Q:
1174    case VKEY_R:
1175    case VKEY_S:
1176    case VKEY_T:
1177    case VKEY_U:
1178    case VKEY_V:
1179    case VKEY_W:
1180    case VKEY_X:
1181    case VKEY_Y:
1182    case VKEY_Z:
1183      return (shift ? XK_A : XK_a) + (keycode - VKEY_A);
1184
1185    case VKEY_LWIN:
1186      return XK_Super_L;
1187    case VKEY_RWIN:
1188      return XK_Super_R;
1189
1190    case VKEY_NUMLOCK:
1191      return XK_Num_Lock;
1192
1193    case VKEY_SCROLL:
1194      return XK_Scroll_Lock;
1195
1196    case VKEY_OEM_1:
1197      return shift ? XK_colon : XK_semicolon;
1198    case VKEY_OEM_PLUS:
1199      return shift ? XK_plus : XK_equal;
1200    case VKEY_OEM_COMMA:
1201      return shift ? XK_less : XK_comma;
1202    case VKEY_OEM_MINUS:
1203      return shift ? XK_underscore : XK_minus;
1204    case VKEY_OEM_PERIOD:
1205      return shift ? XK_greater : XK_period;
1206    case VKEY_OEM_2:
1207      return shift ? XK_question : XK_slash;
1208    case VKEY_OEM_3:
1209      return shift ? XK_asciitilde : XK_quoteleft;
1210    case VKEY_OEM_4:
1211      return shift ? XK_braceleft : XK_bracketleft;
1212    case VKEY_OEM_5:
1213      return shift ? XK_bar : XK_backslash;
1214    case VKEY_OEM_6:
1215      return shift ? XK_braceright : XK_bracketright;
1216    case VKEY_OEM_7:
1217      return shift ? XK_quotedbl : XK_quoteright;
1218    case VKEY_OEM_8:
1219      return XK_ISO_Level5_Shift;
1220    case VKEY_OEM_102:
1221      return shift ? XK_guillemotleft : XK_guillemotright;
1222
1223    case VKEY_F1:
1224    case VKEY_F2:
1225    case VKEY_F3:
1226    case VKEY_F4:
1227    case VKEY_F5:
1228    case VKEY_F6:
1229    case VKEY_F7:
1230    case VKEY_F8:
1231    case VKEY_F9:
1232    case VKEY_F10:
1233    case VKEY_F11:
1234    case VKEY_F12:
1235    case VKEY_F13:
1236    case VKEY_F14:
1237    case VKEY_F15:
1238    case VKEY_F16:
1239    case VKEY_F17:
1240    case VKEY_F18:
1241    case VKEY_F19:
1242    case VKEY_F20:
1243    case VKEY_F21:
1244    case VKEY_F22:
1245    case VKEY_F23:
1246    case VKEY_F24:
1247      return XK_F1 + (keycode - VKEY_F1);
1248
1249    case VKEY_BROWSER_BACK:
1250      return XF86XK_Back;
1251    case VKEY_BROWSER_FORWARD:
1252      return XF86XK_Forward;
1253    case VKEY_BROWSER_REFRESH:
1254      return XF86XK_Reload;
1255    case VKEY_BROWSER_STOP:
1256      return XF86XK_Stop;
1257    case VKEY_BROWSER_SEARCH:
1258      return XF86XK_Search;
1259    case VKEY_BROWSER_FAVORITES:
1260      return XF86XK_Favorites;
1261    case VKEY_BROWSER_HOME:
1262      return XF86XK_HomePage;
1263    case VKEY_VOLUME_MUTE:
1264      return XF86XK_AudioMute;
1265    case VKEY_VOLUME_DOWN:
1266      return XF86XK_AudioLowerVolume;
1267    case VKEY_VOLUME_UP:
1268      return XF86XK_AudioRaiseVolume;
1269    case VKEY_MEDIA_NEXT_TRACK:
1270      return XF86XK_AudioNext;
1271    case VKEY_MEDIA_PREV_TRACK:
1272      return XF86XK_AudioPrev;
1273    case VKEY_MEDIA_STOP:
1274      return XF86XK_AudioStop;
1275    case VKEY_MEDIA_PLAY_PAUSE:
1276      return XF86XK_AudioPlay;
1277    case VKEY_MEDIA_LAUNCH_MAIL:
1278      return XF86XK_Mail;
1279    case VKEY_MEDIA_LAUNCH_APP1:
1280      return XF86XK_LaunchA;
1281    case VKEY_MEDIA_LAUNCH_APP2:
1282      return XF86XK_LaunchB;
1283    case VKEY_WLAN:
1284      return XF86XK_WLAN;
1285    case VKEY_POWER:
1286      return XF86XK_PowerOff;
1287    case VKEY_BRIGHTNESS_DOWN:
1288      return XF86XK_MonBrightnessDown;
1289    case VKEY_BRIGHTNESS_UP:
1290      return XF86XK_MonBrightnessUp;
1291    case VKEY_KBD_BRIGHTNESS_DOWN:
1292      return XF86XK_KbdBrightnessDown;
1293    case VKEY_KBD_BRIGHTNESS_UP:
1294      return XF86XK_KbdBrightnessUp;
1295
1296    default:
1297      LOG(WARNING) << "Unknown keycode:" << keycode;
1298      return 0;
1299    }
1300}
1301
1302void InitXKeyEventFromXIDeviceEvent(const XEvent& src, XEvent* xkeyevent) {
1303  DCHECK(src.type == GenericEvent);
1304  XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(src.xcookie.data);
1305  switch (xievent->evtype) {
1306    case XI_KeyPress:
1307      xkeyevent->type = KeyPress;
1308      break;
1309    case XI_KeyRelease:
1310      xkeyevent->type = KeyRelease;
1311      break;
1312    default:
1313      NOTREACHED();
1314  }
1315  xkeyevent->xkey.serial = xievent->serial;
1316  xkeyevent->xkey.send_event = xievent->send_event;
1317  xkeyevent->xkey.display = xievent->display;
1318  xkeyevent->xkey.window = xievent->event;
1319  xkeyevent->xkey.root = xievent->root;
1320  xkeyevent->xkey.subwindow = xievent->child;
1321  xkeyevent->xkey.time = xievent->time;
1322  xkeyevent->xkey.x = xievent->event_x;
1323  xkeyevent->xkey.y = xievent->event_y;
1324  xkeyevent->xkey.x_root = xievent->root_x;
1325  xkeyevent->xkey.y_root = xievent->root_y;
1326  xkeyevent->xkey.state = xievent->mods.effective;
1327  xkeyevent->xkey.keycode = xievent->detail;
1328  xkeyevent->xkey.same_screen = 1;
1329}
1330
1331unsigned int XKeyCodeForWindowsKeyCode(ui::KeyboardCode key_code,
1332                                       int flags,
1333                                       XDisplay* display) {
1334  // SHIFT state is ignored in the call to XKeysymForWindowsKeyCode() here
1335  // because we map the XKeysym back to a keycode, i.e. a physical key position.
1336  // Using a SHIFT-modified XKeysym would sometimes yield X keycodes that,
1337  // while technically valid, may be surprising in that they do not match
1338  // the keycode of the original press, and conflict with assumptions in
1339  // other code.
1340  //
1341  // For example, in a US layout, Shift-9 has the interpretation XK_parenleft,
1342  // but the keycode KEY_9 alone does not map to XK_parenleft; instead,
1343  // XKeysymToKeycode() returns KEY_KPLEFTPAREN (keypad left parenthesis)
1344  // which does map to XK_parenleft -- notwithstanding that keyboards with
1345  // dedicated number pad parenthesis keys are currently uncommon.
1346  //
1347  // Similarly, Shift-Comma has the interpretation XK_less, but KEY_COMMA
1348  // alone does not map to XK_less; XKeysymToKeycode() returns KEY_102ND
1349  // (the '<>' key between Shift and Z on 105-key keyboards) which does.
1350  //
1351  // crbug.com/386066 and crbug.com/390263 are examples of problems
1352  // associated with this.
1353  //
1354  return XKeysymToKeycode(display, XKeysymForWindowsKeyCode(key_code, false));
1355}
1356
1357}  // namespace ui
1358