OLD | NEW |
| (Empty) |
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 "chrome/test/webdriver/keycode_text_conversion.h" | |
6 | |
7 #include <algorithm> | |
8 #include <X11/keysym.h> | |
9 #include <X11/XKBlib.h> | |
10 #include <X11/Xlib.h> | |
11 #include <X11/Xutil.h> | |
12 | |
13 #include "base/strings/utf_string_conversions.h" | |
14 #include "chrome/common/automation_constants.h" | |
15 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | |
16 #include "ui/base/x/x11_util.h" | |
17 | |
18 namespace webdriver { | |
19 | |
20 namespace { | |
21 | |
22 struct KeyCodeAndXKeyCode { | |
23 ui::KeyboardCode key_code; | |
24 int x_key_code; | |
25 }; | |
26 | |
27 // Contains a list of keyboard codes, in order, with their corresponding | |
28 // X key code. This list is not complete. | |
29 // TODO(kkania): Merge this table with the existing one in | |
30 // keyboard_code_conversion_x.cc. | |
31 KeyCodeAndXKeyCode kKeyCodeToXKeyCode[] = { | |
32 { ui::VKEY_BACK, 22 }, | |
33 { ui::VKEY_TAB, 23 }, | |
34 { ui::VKEY_RETURN, 36 }, | |
35 { ui::VKEY_SHIFT, 50 }, | |
36 { ui::VKEY_CONTROL, 37 }, | |
37 { ui::VKEY_MENU, 64 }, | |
38 { ui::VKEY_CAPITAL, 66 }, | |
39 { ui::VKEY_HANGUL, 130 }, | |
40 { ui::VKEY_HANJA, 131 }, | |
41 { ui::VKEY_ESCAPE, 9 }, | |
42 { ui::VKEY_SPACE, 65 }, | |
43 { ui::VKEY_PRIOR, 112 }, | |
44 { ui::VKEY_NEXT, 117 }, | |
45 { ui::VKEY_END, 115 }, | |
46 { ui::VKEY_HOME, 110 }, | |
47 { ui::VKEY_LEFT, 113 }, | |
48 { ui::VKEY_UP, 111 }, | |
49 { ui::VKEY_RIGHT, 114 }, | |
50 { ui::VKEY_DOWN, 116 }, | |
51 { ui::VKEY_INSERT, 118 }, | |
52 { ui::VKEY_DELETE, 119 }, | |
53 { ui::VKEY_0, 19 }, | |
54 { ui::VKEY_1, 10 }, | |
55 { ui::VKEY_2, 11 }, | |
56 { ui::VKEY_3, 12 }, | |
57 { ui::VKEY_4, 13 }, | |
58 { ui::VKEY_5, 14 }, | |
59 { ui::VKEY_6, 15 }, | |
60 { ui::VKEY_7, 16 }, | |
61 { ui::VKEY_8, 17 }, | |
62 { ui::VKEY_9, 18 }, | |
63 { ui::VKEY_A, 38 }, | |
64 { ui::VKEY_B, 56 }, | |
65 { ui::VKEY_C, 54 }, | |
66 { ui::VKEY_D, 40 }, | |
67 { ui::VKEY_E, 26 }, | |
68 { ui::VKEY_F, 41 }, | |
69 { ui::VKEY_G, 42 }, | |
70 { ui::VKEY_H, 43 }, | |
71 { ui::VKEY_I, 31 }, | |
72 { ui::VKEY_J, 44 }, | |
73 { ui::VKEY_K, 45 }, | |
74 { ui::VKEY_L, 46 }, | |
75 { ui::VKEY_M, 58 }, | |
76 { ui::VKEY_N, 57 }, | |
77 { ui::VKEY_O, 32 }, | |
78 { ui::VKEY_P, 33 }, | |
79 { ui::VKEY_Q, 24 }, | |
80 { ui::VKEY_R, 27 }, | |
81 { ui::VKEY_S, 39 }, | |
82 { ui::VKEY_T, 28 }, | |
83 { ui::VKEY_U, 30 }, | |
84 { ui::VKEY_V, 55 }, | |
85 { ui::VKEY_W, 25 }, | |
86 { ui::VKEY_X, 53 }, | |
87 { ui::VKEY_Y, 29 }, | |
88 { ui::VKEY_Z, 52 }, | |
89 { ui::VKEY_LWIN, 133 }, | |
90 { ui::VKEY_NUMPAD0, 90 }, | |
91 { ui::VKEY_NUMPAD1, 87 }, | |
92 { ui::VKEY_NUMPAD2, 88 }, | |
93 { ui::VKEY_NUMPAD3, 89 }, | |
94 { ui::VKEY_NUMPAD4, 83 }, | |
95 { ui::VKEY_NUMPAD5, 84 }, | |
96 { ui::VKEY_NUMPAD6, 85 }, | |
97 { ui::VKEY_NUMPAD7, 79 }, | |
98 { ui::VKEY_NUMPAD8, 80 }, | |
99 { ui::VKEY_NUMPAD9, 81 }, | |
100 { ui::VKEY_MULTIPLY, 63 }, | |
101 { ui::VKEY_ADD, 86 }, | |
102 { ui::VKEY_SUBTRACT, 82 }, | |
103 { ui::VKEY_DECIMAL, 129 }, | |
104 { ui::VKEY_DIVIDE, 106 }, | |
105 { ui::VKEY_F1, 67 }, | |
106 { ui::VKEY_F2, 68 }, | |
107 { ui::VKEY_F3, 69 }, | |
108 { ui::VKEY_F4, 70 }, | |
109 { ui::VKEY_F5, 71 }, | |
110 { ui::VKEY_F6, 72 }, | |
111 { ui::VKEY_F7, 73 }, | |
112 { ui::VKEY_F8, 74 }, | |
113 { ui::VKEY_F9, 75 }, | |
114 { ui::VKEY_F10, 76 }, | |
115 { ui::VKEY_F11, 95 }, | |
116 { ui::VKEY_F12, 96 }, | |
117 { ui::VKEY_NUMLOCK, 77 }, | |
118 { ui::VKEY_SCROLL, 78 }, | |
119 { ui::VKEY_OEM_1, 47 }, | |
120 { ui::VKEY_OEM_PLUS, 21 }, | |
121 { ui::VKEY_OEM_COMMA, 59 }, | |
122 { ui::VKEY_OEM_MINUS, 20 }, | |
123 { ui::VKEY_OEM_PERIOD, 60 }, | |
124 { ui::VKEY_OEM_2, 61 }, | |
125 { ui::VKEY_OEM_3, 49 }, | |
126 { ui::VKEY_OEM_4, 34 }, | |
127 { ui::VKEY_OEM_5, 51 }, | |
128 { ui::VKEY_OEM_6, 35 }, | |
129 { ui::VKEY_OEM_7, 48 } | |
130 }; | |
131 | |
132 // Uses to compare two KeyCodeAndXKeyCode structs based on their key code. | |
133 bool operator<(const KeyCodeAndXKeyCode& a, const KeyCodeAndXKeyCode& b) { | |
134 return a.key_code < b.key_code; | |
135 } | |
136 | |
137 // Returns the equivalent X key code for the given key code. Returns -1 if | |
138 // no X equivalent was found. | |
139 int KeyboardCodeToXKeyCode(ui::KeyboardCode key_code) { | |
140 KeyCodeAndXKeyCode find; | |
141 find.key_code = key_code; | |
142 const KeyCodeAndXKeyCode* found = std::lower_bound( | |
143 kKeyCodeToXKeyCode, kKeyCodeToXKeyCode + arraysize(kKeyCodeToXKeyCode), | |
144 find); | |
145 if (found >= kKeyCodeToXKeyCode + arraysize(kKeyCodeToXKeyCode) || | |
146 found->key_code != key_code) | |
147 return -1; | |
148 return found->x_key_code; | |
149 } | |
150 | |
151 // Gets the X modifier mask (Mod1Mask through Mod5Mask) for the given automation | |
152 // modifier. Only checks the alt, meta, and num lock keys currently. | |
153 // Returns true on success. | |
154 bool GetXModifierMask(Display* display, int modifier, int* x_modifier) { | |
155 XModifierKeymap* mod_map = XGetModifierMapping(display); | |
156 bool found = false; | |
157 int max_mod_keys = mod_map->max_keypermod; | |
158 for (int mod_index = 0; mod_index <= 8; ++mod_index) { | |
159 for (int key_index = 0; key_index < max_mod_keys; ++key_index) { | |
160 int key = mod_map->modifiermap[mod_index * max_mod_keys + key_index]; | |
161 int keysym = XkbKeycodeToKeysym(display, key, 0, 0); | |
162 if (modifier == automation::kAltKeyMask) | |
163 found = keysym == XK_Alt_L || keysym == XK_Alt_R; | |
164 else if (modifier == automation::kMetaKeyMask) | |
165 found = keysym == XK_Meta_L || keysym == XK_Meta_R; | |
166 else if (modifier == automation::kNumLockKeyMask) | |
167 found = keysym == XK_Num_Lock; | |
168 if (found) { | |
169 *x_modifier = 1 << mod_index; | |
170 break; | |
171 } | |
172 } | |
173 if (found) | |
174 break; | |
175 } | |
176 XFreeModifiermap(mod_map); | |
177 return found; | |
178 } | |
179 | |
180 } // namespace | |
181 | |
182 std::string ConvertKeyCodeToText(ui::KeyboardCode key_code, int modifiers) { | |
183 int x_key_code = KeyboardCodeToXKeyCode(key_code); | |
184 if (x_key_code == -1) | |
185 return ""; | |
186 | |
187 XEvent event; | |
188 memset(&event, 0, sizeof(XEvent)); | |
189 XKeyEvent* key_event = &event.xkey; | |
190 Display* display = ui::GetXDisplay(); | |
191 key_event->display = display; | |
192 key_event->keycode = x_key_code; | |
193 if (modifiers & automation::kShiftKeyMask) | |
194 key_event->state |= ShiftMask; | |
195 if (modifiers & automation::kControlKeyMask) | |
196 key_event->state |= ControlMask; | |
197 | |
198 // Make a best attempt for non-standard modifiers. | |
199 int x_modifier; | |
200 if (modifiers & automation::kAltKeyMask && | |
201 GetXModifierMask(display, automation::kAltKeyMask, &x_modifier)) { | |
202 key_event->state |= x_modifier; | |
203 } | |
204 if (modifiers & automation::kMetaKeyMask && | |
205 GetXModifierMask(display, automation::kMetaKeyMask, &x_modifier)) { | |
206 key_event->state |= x_modifier; | |
207 } | |
208 if (modifiers & automation::kNumLockKeyMask && | |
209 GetXModifierMask(display, automation::kNumLockKeyMask, &x_modifier)) { | |
210 key_event->state |= x_modifier; | |
211 } | |
212 key_event->type = KeyPress; | |
213 uint16 character = ui::GetCharacterFromXEvent(&event); | |
214 | |
215 if (!character) | |
216 return ""; | |
217 return UTF16ToUTF8(string16(1, character)); | |
218 } | |
219 | |
220 bool ConvertCharToKeyCode( | |
221 char16 key, | |
222 ui::KeyboardCode* key_code, | |
223 int* necessary_modifiers) { | |
224 std::string key_string(UTF16ToUTF8(string16(1, key))); | |
225 bool found = false; | |
226 ui::KeyboardCode test_code; | |
227 int test_modifiers; | |
228 for (size_t i = 0; i < arraysize(kKeyCodeToXKeyCode); ++i) { | |
229 test_code = kKeyCodeToXKeyCode[i].key_code; | |
230 // Skip the numpad keys. | |
231 if (test_code >= ui::VKEY_NUMPAD0 && test_code <= ui::VKEY_DIVIDE) | |
232 continue; | |
233 test_modifiers = 0; | |
234 if (ConvertKeyCodeToText(test_code, test_modifiers) == key_string) { | |
235 found = true; | |
236 break; | |
237 } | |
238 test_modifiers = automation::kShiftKeyMask; | |
239 if (ConvertKeyCodeToText(test_code, test_modifiers) == key_string) { | |
240 found = true; | |
241 break; | |
242 } | |
243 } | |
244 if (found) { | |
245 *key_code = test_code; | |
246 *necessary_modifiers = test_modifiers; | |
247 } | |
248 return found; | |
249 } | |
250 | |
251 } // namespace webdriver | |
OLD | NEW |