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.
4
5 #include <stddef.h>
6
7 #include <string>
8
9 #include "base/stl_util.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "chrome/test/chromedriver/chrome/status.h"
14 #include "chrome/test/chromedriver/chrome/ui_events.h"
15 #include "chrome/test/chromedriver/key_converter.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "ui/events/test/keyboard_layout.h"
18
19 namespace {
20
CheckEvents(const base::string16 & keys,const std::vector<KeyEvent> & expected_events,bool release_modifiers,int expected_modifiers)21 void CheckEvents(const base::string16& keys,
22 const std::vector<KeyEvent>& expected_events,
23 bool release_modifiers,
24 int expected_modifiers) {
25 int modifiers = 0;
26 std::vector<KeyEvent> events;
27 EXPECT_EQ(kOk, ConvertKeysToKeyEvents(keys, release_modifiers,
28 &modifiers, &events).code());
29 EXPECT_EQ(expected_events.size(), events.size());
30 auto expected = expected_events.begin();
31 std::vector<KeyEvent>::const_iterator actual = events.begin();
32 while (expected != expected_events.end() && actual != events.end()) {
33 EXPECT_EQ(expected->type, actual->type);
34 EXPECT_EQ(expected->modifiers, actual->modifiers);
35 EXPECT_EQ(expected->modified_text, actual->modified_text);
36 EXPECT_EQ(expected->unmodified_text, actual->unmodified_text);
37 EXPECT_EQ(expected->key_code, actual->key_code);
38
39 ++expected;
40 ++actual;
41 }
42 EXPECT_EQ(expected_modifiers, modifiers);
43 }
44
CheckEventsReleaseModifiers(const base::string16 & keys,const std::vector<KeyEvent> & expected_events)45 void CheckEventsReleaseModifiers(const base::string16& keys,
46 const std::vector<KeyEvent>& expected_events) {
47 CheckEvents(keys, expected_events, true /* release_modifier */,
48 0 /* expected_modifiers */);
49 }
50
CheckEventsReleaseModifiers(const std::string & keys,std::vector<KeyEvent> & expected_events)51 void CheckEventsReleaseModifiers(const std::string& keys,
52 std::vector<KeyEvent>& expected_events) {
53 CheckEventsReleaseModifiers(base::UTF8ToUTF16(keys), expected_events);
54 }
55
CheckNonShiftChar(ui::KeyboardCode key_code,char character)56 void CheckNonShiftChar(ui::KeyboardCode key_code, char character) {
57 int modifiers = 0;
58 std::string char_string;
59 char_string.push_back(character);
60 std::vector<KeyEvent> events;
61 EXPECT_EQ(kOk, ConvertKeysToKeyEvents(base::ASCIIToUTF16(char_string),
62 true /* release_modifiers*/,
63 &modifiers, &events).code());
64 ASSERT_EQ(3u, events.size()) << "Char: " << character;
65 std::vector<KeyEvent>::const_iterator it = events.begin();
66 EXPECT_EQ(key_code, it->key_code) << "Char: " << character;
67 ++it; // Move to the second event.
68 ASSERT_EQ(1u, it->modified_text.length()) << "Char: " << character;
69 ASSERT_EQ(1u, it->unmodified_text.length()) << "Char: " << character;
70 EXPECT_EQ(character, it->modified_text[0]) << "Char: " << character;
71 EXPECT_EQ(character, it->unmodified_text[0]) << "Char: " << character;
72 ++it; // Move to the third event.
73 EXPECT_EQ(key_code, it->key_code) << "Char: " << character;
74 }
75
CheckShiftChar(ui::KeyboardCode key_code,char character,char lower)76 void CheckShiftChar(ui::KeyboardCode key_code, char character, char lower) {
77 int modifiers = 0;
78 std::string char_string;
79 char_string.push_back(character);
80 std::vector<KeyEvent> events;
81 EXPECT_EQ(kOk, ConvertKeysToKeyEvents(base::ASCIIToUTF16(char_string),
82 true /* release_modifiers*/,
83 &modifiers, &events).code());
84 ASSERT_EQ(5u, events.size()) << "Char: " << character;
85 std::vector<KeyEvent>::const_iterator it = events.begin();
86 EXPECT_EQ(ui::VKEY_SHIFT, it->key_code) << "Char: " << character;
87 ++it; // Move to second event.
88 EXPECT_EQ(key_code, it->key_code) << "Char: " << character;
89 ++it; // Move to third event.
90 ASSERT_EQ(1u, it->modified_text.length()) << "Char: " << character;
91 ASSERT_EQ(1u, it->unmodified_text.length()) << "Char: " << character;
92 EXPECT_EQ(character, it->modified_text[0]) << "Char: " << character;
93 EXPECT_EQ(lower, it->unmodified_text[0]) << "Char: " << character;
94 ++it; // Move to fourth event.
95 EXPECT_EQ(key_code, it->key_code) << "Char: " << character;
96 ++it; // Move to fifth event.
97 EXPECT_EQ(ui::VKEY_SHIFT, it->key_code) << "Char: " << character;
98 }
99
100 } // namespace
101
TEST(KeyConverter,SingleChar)102 TEST(KeyConverter, SingleChar) {
103 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
104 KeyEventBuilder builder;
105 std::vector<KeyEvent> key_events;
106 builder.SetText("h", "h")->SetKeyCode(ui::VKEY_H)->Generate(&key_events);
107 CheckEventsReleaseModifiers("h", key_events);
108 }
109
TEST(KeyConverter,SingleNumber)110 TEST(KeyConverter, SingleNumber) {
111 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
112 KeyEventBuilder builder;
113 std::vector<KeyEvent> key_events;
114 builder.SetText("1", "1")->SetKeyCode(ui::VKEY_1)->Generate(&key_events);
115 CheckEventsReleaseModifiers("1", key_events);
116 }
117
TEST(KeyConverter,MultipleChars)118 TEST(KeyConverter, MultipleChars) {
119 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
120 KeyEventBuilder builder;
121 std::vector<KeyEvent> key_events;
122 builder.SetText("h", "h")->SetKeyCode(ui::VKEY_H)->Generate(&key_events);
123 builder.SetText("e", "e")->SetKeyCode(ui::VKEY_E)->Generate(&key_events);
124 builder.SetText("y", "y")->SetKeyCode(ui::VKEY_Y)->Generate(&key_events);
125 CheckEventsReleaseModifiers("hey", key_events);
126 }
127
TEST(KeyConverter,WebDriverSpecialChar)128 TEST(KeyConverter, WebDriverSpecialChar) {
129 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
130 KeyEventBuilder builder;
131 std::vector<KeyEvent> key_events;
132 builder.SetKeyCode(ui::VKEY_SPACE)->SetText(" ", " ")->Generate(&key_events);
133 base::string16 keys;
134 keys.push_back(static_cast<base::char16>(0xE00DU));
135 CheckEventsReleaseModifiers(keys, key_events);
136 }
137
TEST(KeyConverter,WebDriverSpecialNonCharKey)138 TEST(KeyConverter, WebDriverSpecialNonCharKey) {
139 KeyEventBuilder builder;
140 std::vector<KeyEvent> key_events;
141 builder.SetKeyCode(ui::VKEY_F1)->Generate(&key_events);
142 base::string16 keys;
143 keys.push_back(static_cast<base::char16>(0xE031U));
144 CheckEventsReleaseModifiers(keys, key_events);
145 }
146
TEST(KeyConverter,FrenchKeyOnEnglishLayout)147 TEST(KeyConverter, FrenchKeyOnEnglishLayout) {
148 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
149 KeyEventBuilder builder;
150 std::string e_acute = base::WideToUTF8(L"\u00E9");
151 std::vector<KeyEvent> key_events;
152 builder.SetText(e_acute, e_acute)->Generate(&key_events);
153 CheckEventsReleaseModifiers(base::WideToUTF16(L"\u00E9"), key_events);
154 }
155
156 #if defined(OS_WIN)
TEST(KeyConverter,NeedsCtrlAndAlt)157 TEST(KeyConverter, NeedsCtrlAndAlt) {
158 KeyEventBuilder ctrl_builder;
159 ctrl_builder.SetKeyCode(ui::VKEY_CONTROL);
160
161 KeyEventBuilder alt_builder;
162 alt_builder.SetKeyCode(ui::VKEY_MENU);
163
164 KeyEventBuilder q_builder;
165 q_builder.SetModifiers(kControlKeyModifierMask | kAltKeyModifierMask)
166 ->SetKeyCode(ui::VKEY_Q)
167 ->SetText("q", "@");
168
169 std::vector<KeyEvent> key_events;
170 key_events.push_back(ctrl_builder.SetType(kRawKeyDownEventType)->Build());
171 key_events.push_back(alt_builder.SetType(kRawKeyDownEventType)->Build());
172 q_builder.Generate(&key_events);
173 key_events.push_back(alt_builder.SetType(kKeyUpEventType)->Build());
174 key_events.push_back(ctrl_builder.SetType(kKeyUpEventType)->Build());
175
176 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_GERMAN);
177 CheckEventsReleaseModifiers("@", key_events);
178 }
179 #endif
180
TEST(KeyConverter,UppercaseCharDoesShift)181 TEST(KeyConverter, UppercaseCharDoesShift) {
182 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
183 KeyEventBuilder shift_builder;
184 shift_builder.SetKeyCode(ui::VKEY_SHIFT);
185 KeyEventBuilder a_builder;
186 a_builder.SetKeyCode(ui::VKEY_A)
187 ->SetModifiers(kShiftKeyModifierMask)
188 ->SetText("a", "A");
189 std::vector<KeyEvent> key_events;
190 key_events.push_back(shift_builder.SetType(kRawKeyDownEventType)->Build());
191 a_builder.Generate(&key_events);
192 key_events.push_back(shift_builder.SetType(kKeyUpEventType)->Build());
193 CheckEventsReleaseModifiers("A", key_events);
194 }
195
TEST(KeyConverter,UppercaseSymbolCharDoesShift)196 TEST(KeyConverter, UppercaseSymbolCharDoesShift) {
197 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
198 KeyEventBuilder shift_builder;
199 shift_builder.SetKeyCode(ui::VKEY_SHIFT);
200 KeyEventBuilder one_builder;
201 one_builder.SetModifiers(kShiftKeyModifierMask)
202 ->SetKeyCode(ui::VKEY_1)
203 ->SetText("1", "!");
204 std::vector<KeyEvent> key_events;
205 key_events.push_back(shift_builder.SetType(kRawKeyDownEventType)->Build());
206 one_builder.Generate(&key_events);
207 key_events.push_back(shift_builder.SetType(kKeyUpEventType)->Build());
208 CheckEventsReleaseModifiers("!", key_events);
209 }
210
TEST(KeyConverter,UppercaseCharUsesShiftOnlyIfNecessary)211 TEST(KeyConverter, UppercaseCharUsesShiftOnlyIfNecessary) {
212 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
213 std::vector<KeyEvent> key_events;
214 KeyEventBuilder shift_builder;
215 key_events.push_back(shift_builder.SetType(kRawKeyDownEventType)
216 ->SetKeyCode(ui::VKEY_SHIFT)
217 ->SetModifiers(kShiftKeyModifierMask)
218 ->Build());
219 KeyEventBuilder builder;
220 builder.SetModifiers(kShiftKeyModifierMask);
221 builder.SetKeyCode(ui::VKEY_A)->SetText("a", "A")->Generate(&key_events);
222 builder.SetKeyCode(ui::VKEY_B)->SetText("b", "B")->Generate(&key_events);
223 builder.SetKeyCode(ui::VKEY_C)->SetText("c", "C")->Generate(&key_events);
224 key_events.push_back(
225 shift_builder.SetType(kKeyUpEventType)->SetModifiers(0)->Build());
226 base::string16 keys;
227 keys.push_back(static_cast<base::char16>(0xE008U));
228 keys.append(base::UTF8ToUTF16("aBc"));
229 CheckEventsReleaseModifiers(keys, key_events);
230 }
231
TEST(KeyConverter,ToggleModifiers)232 TEST(KeyConverter, ToggleModifiers) {
233 std::vector<KeyEvent> key_events;
234 KeyEventBuilder builder;
235 key_events.push_back(builder.SetType(kRawKeyDownEventType)
236 ->SetKeyCode(ui::VKEY_SHIFT)
237 ->SetModifiers(kShiftKeyModifierMask)
238 ->Build());
239 key_events.push_back(
240 builder.SetType(kKeyUpEventType)->SetModifiers(0)->Build());
241 key_events.push_back(builder.SetType(kRawKeyDownEventType)
242 ->SetKeyCode(ui::VKEY_CONTROL)
243 ->SetModifiers(kControlKeyModifierMask)
244 ->Build());
245 key_events.push_back(
246 builder.SetType(kKeyUpEventType)->SetModifiers(0)->Build());
247 key_events.push_back(builder.SetType(kRawKeyDownEventType)
248 ->SetKeyCode(ui::VKEY_MENU)
249 ->SetModifiers(kAltKeyModifierMask)
250 ->Build());
251 key_events.push_back(
252 builder.SetType(kKeyUpEventType)->SetModifiers(0)->Build());
253 key_events.push_back(builder.SetType(kRawKeyDownEventType)
254 ->SetKeyCode(ui::VKEY_COMMAND)
255 ->SetModifiers(kMetaKeyModifierMask)
256 ->Build());
257 key_events.push_back(
258 builder.SetType(kKeyUpEventType)->SetModifiers(0)->Build());
259 base::string16 keys;
260 keys.push_back(static_cast<base::char16>(0xE008U));
261 keys.push_back(static_cast<base::char16>(0xE008U));
262 keys.push_back(static_cast<base::char16>(0xE009U));
263 keys.push_back(static_cast<base::char16>(0xE009U));
264 keys.push_back(static_cast<base::char16>(0xE00AU));
265 keys.push_back(static_cast<base::char16>(0xE00AU));
266 keys.push_back(static_cast<base::char16>(0xE03DU));
267 keys.push_back(static_cast<base::char16>(0xE03DU));
268 CheckEventsReleaseModifiers(keys, key_events);
269 }
270
TEST(KeyConverter,AllShorthandKeys)271 TEST(KeyConverter, AllShorthandKeys) {
272 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
273 KeyEventBuilder builder;
274 std::vector<KeyEvent> key_events;
275 builder.SetKeyCode(ui::VKEY_RETURN)
276 ->SetText("\r", "\r")
277 ->Generate(&key_events);
278 builder.Generate(&key_events);
279 builder.SetKeyCode(ui::VKEY_TAB);
280 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
281 builder.SetText("\t", "\t")->Generate(&key_events);
282 #else
283 builder.SetText(std::string(), std::string());
284 key_events.push_back(builder.SetType(kRawKeyDownEventType)->Build());
285 key_events.push_back(builder.SetType(kKeyUpEventType)->Build());
286 #endif
287 builder.SetKeyCode(ui::VKEY_BACK);
288 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
289 builder.SetText("\b", "\b")->Generate(&key_events);
290 #else
291 builder.SetText(std::string(), std::string());
292 key_events.push_back(builder.SetType(kRawKeyDownEventType)->Build());
293 key_events.push_back(builder.SetType(kKeyUpEventType)->Build());
294 #endif
295 builder.SetKeyCode(ui::VKEY_SPACE)->SetText(" ", " ")->Generate(&key_events);
296 CheckEventsReleaseModifiers("\n\r\n\t\b ", key_events);
297 }
298
299 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
300 // Fails on bots: crbug.com/174962
301 #define MAYBE_AllEnglishKeyboardSymbols DISABLED_AllEnglishKeyboardSymbols
302 #else
303 #define MAYBE_AllEnglishKeyboardSymbols AllEnglishKeyboardSymbols
304 #endif
305
TEST(KeyConverter,MAYBE_AllEnglishKeyboardSymbols)306 TEST(KeyConverter, MAYBE_AllEnglishKeyboardSymbols) {
307 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
308 base::string16 keys;
309 const ui::KeyboardCode kSymbolKeyCodes[] = {
310 ui::VKEY_OEM_3,
311 ui::VKEY_OEM_MINUS,
312 ui::VKEY_OEM_PLUS,
313 ui::VKEY_OEM_4,
314 ui::VKEY_OEM_6,
315 ui::VKEY_OEM_5,
316 ui::VKEY_OEM_1,
317 ui::VKEY_OEM_7,
318 ui::VKEY_OEM_COMMA,
319 ui::VKEY_OEM_PERIOD,
320 ui::VKEY_OEM_2};
321 std::string kLowerSymbols = "`-=[]\\;',./";
322 std::string kUpperSymbols = "~_+{}|:\"<>?";
323 for (size_t i = 0; i < kLowerSymbols.length(); ++i)
324 CheckNonShiftChar(kSymbolKeyCodes[i], kLowerSymbols[i]);
325 for (size_t i = 0; i < kUpperSymbols.length(); ++i)
326 CheckShiftChar(kSymbolKeyCodes[i], kUpperSymbols[i], kLowerSymbols[i]);
327 }
328
TEST(KeyConverter,AllEnglishKeyboardTextChars)329 TEST(KeyConverter, AllEnglishKeyboardTextChars) {
330 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
331 std::string kLowerChars = "0123456789abcdefghijklmnopqrstuvwxyz";
332 std::string kUpperChars = ")!@#$%^&*(ABCDEFGHIJKLMNOPQRSTUVWXYZ";
333 for (size_t i = 0; i < kLowerChars.length(); ++i) {
334 int offset = 0;
335 if (i < 10)
336 offset = ui::VKEY_0;
337 else
338 offset = ui::VKEY_0 + 7;
339 ui::KeyboardCode expected_code = static_cast<ui::KeyboardCode>(offset + i);
340 CheckNonShiftChar(expected_code, kLowerChars[i]);
341 }
342 for (size_t i = 0; i < kUpperChars.length(); ++i) {
343 int offset = 0;
344 if (i < 10)
345 offset = ui::VKEY_0;
346 else
347 offset = ui::VKEY_0 + 7;
348 ui::KeyboardCode expected_code = static_cast<ui::KeyboardCode>(offset + i);
349 CheckShiftChar(expected_code, kUpperChars[i], kLowerChars[i]);
350 }
351 }
352
TEST(KeyConverter,AllSpecialWebDriverKeysOnEnglishKeyboard)353 TEST(KeyConverter, AllSpecialWebDriverKeysOnEnglishKeyboard) {
354 ui::ScopedKeyboardLayout keyboard_layout(ui::KEYBOARD_LAYOUT_ENGLISH_US);
355 const char kTextForKeys[] = {
356 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
357 0, 0, 0, 0, '\t', 0, '\r', '\r', 0, 0, 0, 0, 0,
358 #else
359 0, 0, 0, 0, 0, 0, '\r', '\r', 0, 0, 0, 0, 0,
360 #endif
361 ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ';', '=',
362 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
363 '*', '+', ',', '-', '.', '/'};
364 for (size_t i = 0; i <= 0x3D; ++i) {
365 if (i > 0x29 && i < 0x31)
366 continue;
367 base::string16 keys;
368 int modifiers = 0;
369 keys.push_back(0xE000U + i);
370 std::vector<KeyEvent> events;
371 EXPECT_EQ(kOk, ConvertKeysToKeyEvents(keys,
372 true /* release_modifiers */,
373 &modifiers, &events).code())
374 << "Index: " << i;
375 if (i == 0) {
376 EXPECT_EQ(0u, events.size()) << "Index: " << i;
377 } else if (i >= base::size(kTextForKeys) || kTextForKeys[i] == 0) {
378 EXPECT_EQ(2u, events.size()) << "Index: " << i;
379 } else {
380 ASSERT_EQ(3u, events.size()) << "Index: " << i;
381 std::vector<KeyEvent>::const_iterator it = events.begin();
382 ++it; // Move to the second event.
383 ASSERT_EQ(1u, it->unmodified_text.length()) << "Index: " << i;
384 EXPECT_EQ(kTextForKeys[i], it->unmodified_text[0])
385 << "Index: " << i;
386 }
387 }
388 }
389
TEST(KeyConverter,ModifiersState)390 TEST(KeyConverter, ModifiersState) {
391 KeyEventBuilder builder;
392 builder.SetType(kRawKeyDownEventType);
393 std::vector<KeyEvent> key_events;
394 key_events.push_back(builder.SetKeyCode(ui::VKEY_SHIFT)
395 ->AddModifiers(kShiftKeyModifierMask)
396 ->Build());
397 key_events.push_back(builder.SetKeyCode(ui::VKEY_CONTROL)
398 ->AddModifiers(kControlKeyModifierMask)
399 ->Build());
400 key_events.push_back(builder.SetKeyCode(ui::VKEY_MENU)
401 ->AddModifiers(kAltKeyModifierMask)
402 ->Build());
403 key_events.push_back(builder.SetKeyCode(ui::VKEY_COMMAND)
404 ->AddModifiers(kMetaKeyModifierMask)
405 ->Build());
406
407 base::string16 keys;
408 keys.push_back(static_cast<base::char16>(0xE008U));
409 keys.push_back(static_cast<base::char16>(0xE009U));
410 keys.push_back(static_cast<base::char16>(0xE00AU));
411 keys.push_back(static_cast<base::char16>(0xE03DU));
412
413 CheckEvents(keys, key_events, false /* release_modifiers */,
414 kShiftKeyModifierMask | kControlKeyModifierMask |
415 kAltKeyModifierMask | kMetaKeyModifierMask);
416 }
417
TEST(KeyConverter,ReleaseModifiers)418 TEST(KeyConverter, ReleaseModifiers) {
419 std::vector<KeyEvent> key_events;
420 KeyEventBuilder builder;
421 key_events.push_back(builder.SetType(kRawKeyDownEventType)
422 ->SetKeyCode(ui::VKEY_SHIFT)
423 ->AddModifiers(kShiftKeyModifierMask)
424 ->Build());
425 key_events.push_back(builder.SetKeyCode(ui::VKEY_CONTROL)
426 ->AddModifiers(kControlKeyModifierMask)
427 ->Build());
428 key_events.push_back(builder.SetType(kKeyUpEventType)
429 ->SetKeyCode(ui::VKEY_SHIFT)
430 ->SetModifiers(0)
431 ->Build());
432 key_events.push_back(builder.SetKeyCode(ui::VKEY_CONTROL)->Build());
433 base::string16 keys;
434 keys.push_back(static_cast<base::char16>(0xE008U));
435 keys.push_back(static_cast<base::char16>(0xE009U));
436
437 CheckEvents(keys, key_events, true /* release_modifiers */, 0);
438 }
439