Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: chrome/test/webdriver/webdriver_key_converter.cc

Issue 6482014: Implement sendKeys webdriver API in ChromeDriver. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/webdriver_key_converter.h"
6
7 #include "base/utf_string_conversions.h"
8 #include "chrome/common/automation_constants.h"
9
10 namespace {
11
12 // TODO(kkania): Use this in KeyMap.
13 // Ordered list of all the key codes corresponding to special WebDriver keys.
14 // These WebDriver keys are defined in the Unicode Private Use Area.
15 // http://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/e lement/:id/value
16 const ui::KeyboardCode kSpecialWebDriverKeys[] = {
17 ui::VKEY_UNKNOWN,
18 ui::VKEY_UNKNOWN,
19 ui::VKEY_HELP,
20 ui::VKEY_BACK,
21 ui::VKEY_TAB,
22 ui::VKEY_CLEAR,
23 ui::VKEY_RETURN,
24 ui::VKEY_RETURN,
25 ui::VKEY_SHIFT,
26 ui::VKEY_CONTROL,
27 ui::VKEY_MENU,
28 ui::VKEY_PAUSE,
29 ui::VKEY_ESCAPE,
30 ui::VKEY_SPACE,
31 ui::VKEY_PRIOR, // page up
32 ui::VKEY_NEXT, // page down
33 ui::VKEY_END,
34 ui::VKEY_HOME,
35 ui::VKEY_LEFT,
36 ui::VKEY_UP,
37 ui::VKEY_RIGHT,
38 ui::VKEY_DOWN,
39 ui::VKEY_INSERT,
40 ui::VKEY_DELETE,
41 ui::VKEY_OEM_1, // semicolon
42 ui::VKEY_OEM_PLUS, // equals
43 ui::VKEY_NUMPAD0,
44 ui::VKEY_NUMPAD1,
45 ui::VKEY_NUMPAD2,
46 ui::VKEY_NUMPAD3,
47 ui::VKEY_NUMPAD4,
48 ui::VKEY_NUMPAD5,
49 ui::VKEY_NUMPAD6,
50 ui::VKEY_NUMPAD7,
51 ui::VKEY_NUMPAD8,
52 ui::VKEY_NUMPAD9,
53 ui::VKEY_MULTIPLY,
54 ui::VKEY_ADD,
55 ui::VKEY_OEM_COMMA,
56 ui::VKEY_SUBTRACT,
57 ui::VKEY_DECIMAL,
58 ui::VKEY_DIVIDE,
59 ui::VKEY_UNKNOWN,
60 ui::VKEY_UNKNOWN,
61 ui::VKEY_UNKNOWN,
62 ui::VKEY_UNKNOWN,
63 ui::VKEY_UNKNOWN,
64 ui::VKEY_UNKNOWN,
65 ui::VKEY_UNKNOWN,
66 ui::VKEY_F1,
67 ui::VKEY_F2,
68 ui::VKEY_F3,
69 ui::VKEY_F4,
70 ui::VKEY_F5,
71 ui::VKEY_F6,
72 ui::VKEY_F7,
73 ui::VKEY_F8,
74 ui::VKEY_F9,
75 ui::VKEY_F10,
76 ui::VKEY_F11,
77 ui::VKEY_F12};
78
79 const char16 kWebDriverNullKey = 0xE000U;
80 const char16 kWebDriverShiftKey = 0xE008U;
81 const char16 kWebDriverControlKey = 0xE009U;
82 const char16 kWebDriverAltKey = 0xE00AU;
83 const char16 kWebDriverCommandKey = 0xE03DU;
84
85 // Returns whether the given key is a WebDriver key modifier.
86 bool IsModifierKey(char16 key) {
87 switch (key) {
88 case kWebDriverShiftKey:
89 case kWebDriverControlKey:
90 case kWebDriverAltKey:
91 case kWebDriverCommandKey:
92 return true;
93 default:
94 return false;
95 }
96 }
97
98 // Gets the key code associated with |key|, if it is a special WebDriver key.
99 // Returns whether |key| is a special WebDriver key. If true, |key_code| will
100 // be set.
101 bool KeyCodeFromSpecialWebDriverKey(char16 key, ui::KeyboardCode* key_code) {
102 int index = static_cast<int>(key) - 0xE000U;
103 bool is_special_key = index >= 0 &&
104 index < static_cast<int>(arraysize(kSpecialWebDriverKeys));
105 if (is_special_key)
106 *key_code = kSpecialWebDriverKeys[index];
107 return is_special_key;
108 }
109
110 // Converts a character to the key code and modifier set that would
111 // produce the character using the given keyboard layout.
112 bool ConvertCharToKeyCode(
113 char16 key, ui::KeyboardCode* key_code, int *necessary_modifiers) {
114 #if defined(OS_WIN)
115 short vkey_and_modifiers = ::VkKeyScanW(key);
116 bool translated = vkey_and_modifiers != -1 &&
117 LOBYTE(vkey_and_modifiers) != -1 &&
118 HIBYTE(vkey_and_modifiers) != -1;
119 if (translated) {
120 *key_code = static_cast<ui::KeyboardCode>(LOBYTE(vkey_and_modifiers));
121 *necessary_modifiers = HIBYTE(vkey_and_modifiers);
122 }
123 return translated;
124 #else
125 // TODO(kkania): Implement.
126 return false;
127 #endif
128 }
129
130 // Returns the character that would be produced from the given key code and
131 // modifier set, or "" if no character would be produced.
132 std::string ConvertKeyCodeToText(ui::KeyboardCode key_code, int modifiers) {
133 #if defined(OS_WIN)
134 UINT scan_code = ::MapVirtualKeyW(key_code, MAPVK_VK_TO_VSC);
135 BYTE keyboard_state[256];
136 ::GetKeyboardState(keyboard_state);
137 if (modifiers & automation::kShiftKeyMask)
138 keyboard_state[VK_SHIFT] |= 0x80;
139 wchar_t chars[5];
140 int code = ::ToUnicode(key_code, scan_code, keyboard_state, chars, 4, 0);
141 if (code <= 0) {
142 return "";
143 } else {
144 std::string text;
145 WideToUTF8(chars, code, &text);
146 return text;
147 }
148 #else
149 // TODO(kkania): Implement
150 return "";
151 #endif
152 }
153
154 } // namespace
155
156 namespace webdriver {
157
158 WebKeyEvent CreateKeyDownEvent(ui::KeyboardCode key_code, int modifiers) {
159 return WebKeyEvent(automation::kRawKeyDownType, key_code, "", "", modifiers);
160 }
161
162 WebKeyEvent CreateKeyUpEvent(ui::KeyboardCode key_code, int modifiers) {
163 return WebKeyEvent(automation::kKeyUpType, key_code, "", "", modifiers);
164 }
165
166 WebKeyEvent CreateCharEvent(const std::string& unmodified_text,
167 const std::string& modified_text,
168 int modifiers) {
169 return WebKeyEvent(automation::kCharType,
170 ui::VKEY_UNKNOWN,
171 unmodified_text,
172 modified_text,
173 modifiers);
174 }
175
176 void ConvertKeysToWebKeyEvents(const string16& client_keys,
177 std::vector<WebKeyEvent>* key_events) {
178 // Add an implicit NULL character to the end of the input to depress all
179 // modifiers.
180 string16 keys = client_keys;
181 keys.push_back(kWebDriverNullKey);
182
183 int sticky_modifiers = 0;
184 for (size_t i = 0; i < keys.size(); ++i) {
185 char16 key = keys[i];
186
187 if (key == kWebDriverNullKey) {
188 // Release all modifier keys and clear |stick_modifiers|.
189 if (sticky_modifiers & automation::kShiftKeyMask)
190 key_events->push_back(CreateKeyUpEvent(ui::VKEY_SHIFT, 0));
191 if (sticky_modifiers & automation::kControlKeyMask)
192 key_events->push_back(CreateKeyUpEvent(ui::VKEY_CONTROL, 0));
193 if (sticky_modifiers & automation::kAltKeyMask)
194 key_events->push_back(CreateKeyUpEvent(ui::VKEY_MENU, 0));
195 if (sticky_modifiers & automation::kMetaKeyMask)
196 key_events->push_back(CreateKeyUpEvent(ui::VKEY_COMMAND, 0));
197 sticky_modifiers = 0;
198 continue;
199 }
200 if (IsModifierKey(key)) {
201 // Press or release the modifier, and adjust |sticky_modifiers|.
202 bool modifier_down = false;
203 ui::KeyboardCode key_code;
204 if (key == kWebDriverShiftKey) {
205 sticky_modifiers ^= automation::kShiftKeyMask;
206 modifier_down = sticky_modifiers & automation::kShiftKeyMask;
207 key_code = ui::VKEY_SHIFT;
208 } else if (key == kWebDriverControlKey) {
209 sticky_modifiers ^= automation::kControlKeyMask;
210 modifier_down = sticky_modifiers & automation::kControlKeyMask;
211 key_code = ui::VKEY_CONTROL;
212 } else if (key == kWebDriverAltKey) {
213 sticky_modifiers ^= automation::kAltKeyMask;
214 modifier_down = sticky_modifiers & automation::kAltKeyMask;
215 key_code = ui::VKEY_MENU;
216 } else if (key == kWebDriverCommandKey) {
217 sticky_modifiers ^= automation::kMetaKeyMask;
218 modifier_down = sticky_modifiers & automation::kMetaKeyMask;
219 key_code = ui::VKEY_COMMAND;
220 }
221 if (modifier_down)
222 key_events->push_back(CreateKeyDownEvent(key_code, sticky_modifiers));
223 else
224 key_events->push_back(CreateKeyUpEvent(key_code, sticky_modifiers));
225 continue;
226 }
227
228 ui::KeyboardCode key_code = ui::VKEY_UNKNOWN;
229 std::string unmodified_text, modified_text;
230 int all_modifiers = sticky_modifiers;
231
232 bool is_special_key = KeyCodeFromSpecialWebDriverKey(key, &key_code);
233 if (is_special_key && key_code == ui::VKEY_UNKNOWN) {
234 LOG(ERROR) << "Unknown WebDriver key: " << static_cast<int>(key);
235 continue;
236 }
237 if (!is_special_key) {
238 int necessary_modifiers = 0;
239 ConvertCharToKeyCode(key, &key_code, &necessary_modifiers);
240 all_modifiers |= necessary_modifiers;
241 }
242 if (key_code != ui::VKEY_UNKNOWN) {
243 unmodified_text = ConvertKeyCodeToText(key_code, 0);
244 modified_text = ConvertKeyCodeToText(key_code, all_modifiers);
245 }
246 if (!is_special_key && (unmodified_text.empty() || modified_text.empty())) {
247 // Do a best effort and use the raw key we were given.
248 LOG(WARNING) << "No translation for key code. Code point: "
249 << static_cast<int>(key);
250 if (unmodified_text.empty())
251 unmodified_text = UTF16ToUTF8(keys.substr(i, 1));
252 if (modified_text.empty())
253 modified_text = UTF16ToUTF8(keys.substr(i, 1));
254 }
255
256 // Create the key events.
257 bool need_shift_key =
258 all_modifiers & automation::kShiftKeyMask &&
259 !(sticky_modifiers & automation::kShiftKeyMask);
260 if (need_shift_key) {
261 key_events->push_back(
262 CreateKeyDownEvent(ui::VKEY_SHIFT, sticky_modifiers));
263 }
264
265 key_events->push_back(CreateKeyDownEvent(key_code, all_modifiers));
266 if (unmodified_text.length() || modified_text.length()) {
267 key_events->push_back(
268 CreateCharEvent(unmodified_text, modified_text, all_modifiers));
269 }
270 key_events->push_back(CreateKeyUpEvent(key_code, all_modifiers));
271
272 if (need_shift_key) {
273 key_events->push_back(
274 CreateKeyUpEvent(ui::VKEY_SHIFT, sticky_modifiers));
275 }
276 }
277 }
278
279 } // namespace webdriver
OLDNEW
« no previous file with comments | « chrome/test/webdriver/webdriver_key_converter.h ('k') | chrome/test/webdriver/webdriver_key_converter_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698