1 // Copyright (c) 2013 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 "chrome/test/chromedriver/keycode_text_conversion.h"
8 #include <X11/keysym.h>
9 #include <X11/XKBlib.h>
11 #include <X11/Xutil.h>
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/test/chromedriver/chrome/ui_events.h"
15 #include "ui/base/x/x11_util.h"
16 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
20 struct KeyCodeAndXKeyCode
{
21 ui::KeyboardCode key_code
;
25 // Contains a list of keyboard codes, in order, with their corresponding
26 // X key code. This list is not complete.
27 // TODO(kkania): Merge this table with the existing one in
28 // keyboard_code_conversion_x.cc.
29 KeyCodeAndXKeyCode kKeyCodeToXKeyCode
[] = {
30 { ui::VKEY_BACK
, 22 },
32 { ui::VKEY_RETURN
, 36 },
33 { ui::VKEY_SHIFT
, 50 },
34 { ui::VKEY_CONTROL
, 37 },
35 { ui::VKEY_MENU
, 64 },
36 { ui::VKEY_CAPITAL
, 66 },
37 { ui::VKEY_HANGUL
, 130 },
38 { ui::VKEY_HANJA
, 131 },
39 { ui::VKEY_ESCAPE
, 9 },
40 { ui::VKEY_SPACE
, 65 },
41 { ui::VKEY_PRIOR
, 112 },
42 { ui::VKEY_NEXT
, 117 },
43 { ui::VKEY_END
, 115 },
44 { ui::VKEY_HOME
, 110 },
45 { ui::VKEY_LEFT
, 113 },
47 { ui::VKEY_RIGHT
, 114 },
48 { ui::VKEY_DOWN
, 116 },
49 { ui::VKEY_INSERT
, 118 },
50 { ui::VKEY_DELETE
, 119 },
87 { ui::VKEY_LWIN
, 133 },
88 { ui::VKEY_NUMPAD0
, 90 },
89 { ui::VKEY_NUMPAD1
, 87 },
90 { ui::VKEY_NUMPAD2
, 88 },
91 { ui::VKEY_NUMPAD3
, 89 },
92 { ui::VKEY_NUMPAD4
, 83 },
93 { ui::VKEY_NUMPAD5
, 84 },
94 { ui::VKEY_NUMPAD6
, 85 },
95 { ui::VKEY_NUMPAD7
, 79 },
96 { ui::VKEY_NUMPAD8
, 80 },
97 { ui::VKEY_NUMPAD9
, 81 },
98 { ui::VKEY_MULTIPLY
, 63 },
100 { ui::VKEY_SUBTRACT
, 82 },
101 { ui::VKEY_DECIMAL
, 129 },
102 { ui::VKEY_DIVIDE
, 106 },
112 { ui::VKEY_F10
, 76 },
113 { ui::VKEY_F11
, 95 },
114 { ui::VKEY_F12
, 96 },
115 { ui::VKEY_NUMLOCK
, 77 },
116 { ui::VKEY_SCROLL
, 78 },
117 { ui::VKEY_OEM_1
, 47 },
118 { ui::VKEY_OEM_PLUS
, 21 },
119 { ui::VKEY_OEM_COMMA
, 59 },
120 { ui::VKEY_OEM_MINUS
, 20 },
121 { ui::VKEY_OEM_PERIOD
, 60 },
122 { ui::VKEY_OEM_2
, 61 },
123 { ui::VKEY_OEM_3
, 49 },
124 { ui::VKEY_OEM_4
, 34 },
125 { ui::VKEY_OEM_5
, 51 },
126 { ui::VKEY_OEM_6
, 35 },
127 { ui::VKEY_OEM_7
, 48 }
130 // Uses to compare two KeyCodeAndXKeyCode structs based on their key code.
131 bool operator<(const KeyCodeAndXKeyCode
& a
, const KeyCodeAndXKeyCode
& b
) {
132 return a
.key_code
< b
.key_code
;
135 // Returns the equivalent X key code for the given key code. Returns -1 if
136 // no X equivalent was found.
137 int KeyboardCodeToXKeyCode(ui::KeyboardCode key_code
) {
138 KeyCodeAndXKeyCode find
;
139 find
.key_code
= key_code
;
140 const KeyCodeAndXKeyCode
* found
= std::lower_bound(
141 kKeyCodeToXKeyCode
, kKeyCodeToXKeyCode
+ arraysize(kKeyCodeToXKeyCode
),
143 if (found
>= kKeyCodeToXKeyCode
+ arraysize(kKeyCodeToXKeyCode
) ||
144 found
->key_code
!= key_code
)
146 return found
->x_key_code
;
149 // Gets the X modifier mask (Mod1Mask through Mod5Mask) for the given
150 // modifier. Only checks the alt, meta, and num lock keys currently.
151 // Returns true on success.
152 bool GetXModifierMask(Display
* display
, int modifier
, int* x_modifier
) {
153 XModifierKeymap
* mod_map
= XGetModifierMapping(display
);
155 int max_mod_keys
= mod_map
->max_keypermod
;
156 for (int mod_index
= 0; mod_index
<= 8; ++mod_index
) {
157 for (int key_index
= 0; key_index
< max_mod_keys
; ++key_index
) {
158 int key
= mod_map
->modifiermap
[mod_index
* max_mod_keys
+ key_index
];
159 int keysym
= XkbKeycodeToKeysym(display
, key
, 0, 0);
160 if (modifier
== kAltKeyModifierMask
)
161 found
= keysym
== XK_Alt_L
|| keysym
== XK_Alt_R
;
162 else if (modifier
== kMetaKeyModifierMask
)
163 found
= keysym
== XK_Meta_L
|| keysym
== XK_Meta_R
;
164 else if (modifier
== kNumLockKeyModifierMask
)
165 found
= keysym
== XK_Num_Lock
;
167 *x_modifier
= 1 << mod_index
;
174 XFreeModifiermap(mod_map
);
180 bool ConvertKeyCodeToText(
181 ui::KeyboardCode key_code
, int modifiers
, std::string
* text
,
182 std::string
* error_msg
) {
183 *error_msg
= std::string();
184 int x_key_code
= KeyboardCodeToXKeyCode(key_code
);
185 if (x_key_code
== -1) {
186 *text
= std::string();
191 memset(&event
, 0, sizeof(XEvent
));
192 XKeyEvent
* key_event
= &event
.xkey
;
193 XDisplay
* display
= gfx::GetXDisplay();
196 "an X display is required for keycode conversions, consider using Xvfb";
197 *text
= std::string();
200 key_event
->display
= display
;
201 key_event
->keycode
= x_key_code
;
202 if (modifiers
& kShiftKeyModifierMask
)
203 key_event
->state
|= ShiftMask
;
204 if (modifiers
& kControlKeyModifierMask
)
205 key_event
->state
|= ControlMask
;
207 // Make a best attempt for non-standard modifiers.
209 if (modifiers
& kAltKeyModifierMask
&&
210 GetXModifierMask(display
, kAltKeyModifierMask
, &x_modifier
)) {
211 key_event
->state
|= x_modifier
;
213 if (modifiers
& kMetaKeyModifierMask
&&
214 GetXModifierMask(display
, kMetaKeyModifierMask
, &x_modifier
)) {
215 key_event
->state
|= x_modifier
;
217 if (modifiers
& kNumLockKeyModifierMask
&&
218 GetXModifierMask(display
, kNumLockKeyModifierMask
, &x_modifier
)) {
219 key_event
->state
|= x_modifier
;
221 key_event
->type
= KeyPress
;
222 uint16 character
= ui::GetCharacterFromXEvent(&event
);
225 *text
= std::string();
227 *text
= base::UTF16ToUTF8(base::string16(1, character
));
231 bool ConvertCharToKeyCode(
233 ui::KeyboardCode
* key_code
,
234 int* necessary_modifiers
,
235 std::string
* error_msg
) {
236 std::string
key_string(base::UTF16ToUTF8(base::string16(1, key
)));
238 ui::KeyboardCode test_code
;
240 *error_msg
= std::string();
241 std::string conv_string
;
242 for (size_t i
= 0; i
< arraysize(kKeyCodeToXKeyCode
); ++i
) {
243 test_code
= kKeyCodeToXKeyCode
[i
].key_code
;
244 // Skip the numpad keys.
245 if (test_code
>= ui::VKEY_NUMPAD0
&& test_code
<= ui::VKEY_DIVIDE
)
248 if (!ConvertKeyCodeToText(
249 test_code
, test_modifiers
, &conv_string
, error_msg
))
251 if (conv_string
== key_string
) {
255 test_modifiers
= kShiftKeyModifierMask
;
256 if (!ConvertKeyCodeToText(
257 test_code
, test_modifiers
, &conv_string
, error_msg
))
259 if (conv_string
== key_string
) {
265 *key_code
= test_code
;
266 *necessary_modifiers
= test_modifiers
;