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 "build/build_config.h"
6
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/dom_operation_notification_details.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/common/chrome_paths.h"
16 #include "chrome/test/in_process_browser_test.h"
17 #include "chrome/test/ui_test_utils.h"
18 #include "content/browser/renderer_host/render_view_host.h"
19 #include "content/browser/renderer_host/render_widget_host_view.h"
20 #include "content/browser/tab_contents/tab_contents.h"
21 #include "content/browser/tab_contents/tab_contents_view.h"
22 #include "content/common/notification_registrar.h"
23 #include "content/common/notification_service.h"
24 #include "net/test/test_server.h"
25 #include "ui/base/keycodes/keyboard_codes.h"
26
27 namespace {
28
29 const char kTestingPage[] = "files/keyevents_test.html";
30 const wchar_t kSuppressEventJS[] =
31 L"window.domAutomationController.send(setDefaultAction('%ls', %ls));";
32 const wchar_t kGetResultJS[] =
33 L"window.domAutomationController.send(keyEventResult[%d]);";
34 const wchar_t kGetResultLengthJS[] =
35 L"window.domAutomationController.send(keyEventResult.length);";
36 const wchar_t kGetFocusedElementJS[] =
37 L"window.domAutomationController.send(focusedElement);";
38 const wchar_t kSetFocusedElementJS[] =
39 L"window.domAutomationController.send(setFocusedElement('%ls'));";
40 const wchar_t kGetTextBoxValueJS[] =
41 L"window.domAutomationController.send("
42 L"document.getElementById('%ls').value);";
43 const wchar_t kSetTextBoxValueJS[] =
44 L"window.domAutomationController.send("
45 L"document.getElementById('%ls').value = '%ls');";
46 const wchar_t kStartTestJS[] =
47 L"window.domAutomationController.send(startTest(%d));";
48
49 // Maximum lenght of the result array in KeyEventTestData structure.
50 const size_t kMaxResultLength = 10;
51
52 // A structure holding test data of a keyboard event.
53 // Each keyboard event may generate multiple result strings representing
54 // the result of keydown, keypress, keyup and textInput events.
55 // For keydown, keypress and keyup events, the format of the result string is:
56 // <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
57 // where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
58 // <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
59 // the state of corresponding modifier key.
60 // For textInput event, the format is: T <text>, where <text> is the text to be
61 // input.
62 // Please refer to chrome/test/data/keyevents_test.html for details.
63 struct KeyEventTestData {
64 ui::KeyboardCode key;
65 bool ctrl;
66 bool shift;
67 bool alt;
68 bool command;
69
70 bool suppress_keydown;
71 bool suppress_keypress;
72 bool suppress_keyup;
73 bool suppress_textinput;
74
75 int result_length;
76 const char* const result[kMaxResultLength];
77 };
78
GetBoolString(bool value)79 const wchar_t* GetBoolString(bool value) {
80 return value ? L"true" : L"false";
81 }
82
83 // A class to help wait for the finish of a key event test.
84 class TestFinishObserver : public NotificationObserver {
85 public:
TestFinishObserver(RenderViewHost * render_view_host)86 explicit TestFinishObserver(RenderViewHost* render_view_host)
87 : finished_(false), waiting_(false) {
88 registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE,
89 Source<RenderViewHost>(render_view_host));
90 }
91
WaitForFinish()92 bool WaitForFinish() {
93 if (!finished_) {
94 waiting_ = true;
95 ui_test_utils::RunMessageLoop();
96 waiting_ = false;
97 }
98 return finished_;
99 }
100
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)101 virtual void Observe(NotificationType type,
102 const NotificationSource& source,
103 const NotificationDetails& details) {
104 DCHECK(type == NotificationType::DOM_OPERATION_RESPONSE);
105 Details<DomOperationNotificationDetails> dom_op_details(details);
106 // We might receive responses for other script execution, but we only
107 // care about the test finished message.
108 if (dom_op_details->json() == "\"FINISHED\"") {
109 finished_ = true;
110 if (waiting_)
111 MessageLoopForUI::current()->Quit();
112 }
113 }
114
115 private:
116 bool finished_;
117 bool waiting_;
118 NotificationRegistrar registrar_;
119
120 DISALLOW_COPY_AND_ASSIGN(TestFinishObserver);
121 };
122
123 class BrowserKeyEventsTest : public InProcessBrowserTest {
124 public:
BrowserKeyEventsTest()125 BrowserKeyEventsTest() {
126 set_show_window(true);
127 EnableDOMAutomation();
128 }
129
IsViewFocused(ViewID vid)130 bool IsViewFocused(ViewID vid) {
131 return ui_test_utils::IsViewFocused(browser(), vid);
132 }
133
ClickOnView(ViewID vid)134 void ClickOnView(ViewID vid) {
135 ui_test_utils::ClickOnView(browser(), vid);
136 }
137
138 // Set the suppress flag of an event specified by |type|. If |suppress| is
139 // true then the web page will suppress all events with |type|. Following
140 // event types are supported: keydown, keypress, keyup and textInput.
SuppressEventByType(int tab_index,const wchar_t * type,bool suppress)141 void SuppressEventByType(int tab_index, const wchar_t* type, bool suppress) {
142 ASSERT_LT(tab_index, browser()->tab_count());
143 bool actual;
144 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
145 browser()->GetTabContentsAt(tab_index)->render_view_host(),
146 L"",
147 StringPrintf(kSuppressEventJS, type, GetBoolString(!suppress)),
148 &actual));
149 ASSERT_EQ(!suppress, actual);
150 }
151
SuppressEvents(int tab_index,bool keydown,bool keypress,bool keyup,bool textinput)152 void SuppressEvents(int tab_index, bool keydown, bool keypress,
153 bool keyup, bool textinput) {
154 ASSERT_NO_FATAL_FAILURE(
155 SuppressEventByType(tab_index, L"keydown", keydown));
156 ASSERT_NO_FATAL_FAILURE(
157 SuppressEventByType(tab_index, L"keypress", keypress));
158 ASSERT_NO_FATAL_FAILURE(
159 SuppressEventByType(tab_index, L"keyup", keyup));
160 ASSERT_NO_FATAL_FAILURE(
161 SuppressEventByType(tab_index, L"textInput", textinput));
162 }
163
SuppressAllEvents(int tab_index,bool suppress)164 void SuppressAllEvents(int tab_index, bool suppress) {
165 SuppressEvents(tab_index, suppress, suppress, suppress, suppress);
166 }
167
GetResultLength(int tab_index,int * length)168 void GetResultLength(int tab_index, int* length) {
169 ASSERT_LT(tab_index, browser()->tab_count());
170 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt(
171 browser()->GetTabContentsAt(tab_index)->render_view_host(),
172 L"", kGetResultLengthJS, length));
173 }
174
CheckResult(int tab_index,int length,const char * const result[])175 void CheckResult(int tab_index, int length, const char* const result[]) {
176 ASSERT_LT(tab_index, browser()->tab_count());
177 int actual_length;
178 ASSERT_NO_FATAL_FAILURE(GetResultLength(tab_index, &actual_length));
179 ASSERT_GE(actual_length, length);
180 for (int i = 0; i < actual_length; ++i) {
181 std::string actual;
182 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
183 browser()->GetTabContentsAt(tab_index)->render_view_host(),
184 L"", StringPrintf(kGetResultJS, i), &actual));
185
186 // If more events were received than expected, then the additional events
187 // must be keyup events.
188 if (i < length)
189 ASSERT_STREQ(result[i], actual.c_str());
190 else
191 ASSERT_EQ('U', actual[0]);
192 }
193 }
194
CheckFocusedElement(int tab_index,const wchar_t * focused)195 void CheckFocusedElement(int tab_index, const wchar_t* focused) {
196 ASSERT_LT(tab_index, browser()->tab_count());
197 std::string actual;
198 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
199 browser()->GetTabContentsAt(tab_index)->render_view_host(),
200 L"", kGetFocusedElementJS, &actual));
201 ASSERT_EQ(WideToUTF8(focused), actual);
202 }
203
SetFocusedElement(int tab_index,const wchar_t * focused)204 void SetFocusedElement(int tab_index, const wchar_t* focused) {
205 ASSERT_LT(tab_index, browser()->tab_count());
206 bool actual;
207 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
208 browser()->GetTabContentsAt(tab_index)->render_view_host(),
209 L"",
210 StringPrintf(kSetFocusedElementJS, focused),
211 &actual));
212 ASSERT_TRUE(actual);
213 }
214
CheckTextBoxValue(int tab_index,const wchar_t * id,const wchar_t * value)215 void CheckTextBoxValue(int tab_index, const wchar_t* id,
216 const wchar_t* value) {
217 ASSERT_LT(tab_index, browser()->tab_count());
218 std::string actual;
219 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
220 browser()->GetTabContentsAt(tab_index)->render_view_host(),
221 L"",
222 StringPrintf(kGetTextBoxValueJS, id),
223 &actual));
224 ASSERT_EQ(WideToUTF8(value), actual);
225 }
226
SetTextBoxValue(int tab_index,const wchar_t * id,const wchar_t * value)227 void SetTextBoxValue(int tab_index, const wchar_t* id,
228 const wchar_t* value) {
229 ASSERT_LT(tab_index, browser()->tab_count());
230 std::string actual;
231 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
232 browser()->GetTabContentsAt(tab_index)->render_view_host(),
233 L"",
234 StringPrintf(kSetTextBoxValueJS, id, value),
235 &actual));
236 ASSERT_EQ(WideToUTF8(value), actual);
237 }
238
StartTest(int tab_index,int result_length)239 void StartTest(int tab_index, int result_length) {
240 ASSERT_LT(tab_index, browser()->tab_count());
241 bool actual;
242 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
243 browser()->GetTabContentsAt(tab_index)->render_view_host(),
244 L"", StringPrintf(kStartTestJS, result_length), &actual));
245 ASSERT_TRUE(actual);
246 }
247
TestKeyEvent(int tab_index,const KeyEventTestData & test)248 void TestKeyEvent(int tab_index, const KeyEventTestData& test) {
249 ASSERT_LT(tab_index, browser()->tab_count());
250 ASSERT_EQ(tab_index, browser()->active_index());
251
252 // Inform our testing web page that we are about to start testing a key
253 // event.
254 ASSERT_NO_FATAL_FAILURE(StartTest(tab_index, test.result_length));
255 ASSERT_NO_FATAL_FAILURE(SuppressEvents(
256 tab_index, test.suppress_keydown, test.suppress_keypress,
257 test.suppress_keyup, test.suppress_textinput));
258
259 // We need to create a finish observer before sending the key event,
260 // because the test finished message might be arrived before returning
261 // from the SendKeyPressSync() method.
262 TestFinishObserver finish_observer(
263 browser()->GetTabContentsAt(tab_index)->render_view_host());
264
265 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
266 browser(), test.key, test.ctrl, test.shift, test.alt, test.command));
267 ASSERT_TRUE(finish_observer.WaitForFinish());
268 ASSERT_NO_FATAL_FAILURE(CheckResult(
269 tab_index, test.result_length, test.result));
270 }
271
GetTestDataDescription(const KeyEventTestData & data)272 std::string GetTestDataDescription(const KeyEventTestData& data) {
273 std::string desc = StringPrintf(
274 " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d, command:%d\n"
275 " Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n"
276 " Expected results(%d):\n",
277 data.key, data.ctrl, data.shift, data.alt, data.command,
278 data.suppress_keydown, data.suppress_keypress, data.suppress_keyup,
279 data.suppress_textinput, data.result_length);
280 for (int i = 0; i < data.result_length; ++i) {
281 desc.append(" ");
282 desc.append(data.result[i]);
283 desc.append("\n");
284 }
285 return desc;
286 }
287 };
288
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,NormalKeyEvents)289 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, NormalKeyEvents) {
290 static const KeyEventTestData kTestNoInput[] = {
291 // a
292 { ui::VKEY_A, false, false, false, false,
293 false, false, false, false, 3,
294 { "D 65 0 false false false false",
295 "P 97 97 false false false false",
296 "U 65 0 false false false false" } },
297 // shift-a
298 { ui::VKEY_A, false, true, false, false,
299 false, false, false, false, 5,
300 { "D 16 0 false true false false",
301 "D 65 0 false true false false",
302 "P 65 65 false true false false",
303 "U 65 0 false true false false",
304 "U 16 0 false true false false" } },
305 // a, suppress keydown
306 { ui::VKEY_A, false, false, false, false,
307 true, false, false, false, 2,
308 { "D 65 0 false false false false",
309 "U 65 0 false false false false" } },
310 };
311
312 static const KeyEventTestData kTestWithInput[] = {
313 // a
314 { ui::VKEY_A, false, false, false, false,
315 false, false, false, false, 4,
316 { "D 65 0 false false false false",
317 "P 97 97 false false false false",
318 "T a",
319 "U 65 0 false false false false" } },
320 // shift-a
321 { ui::VKEY_A, false, true, false, false,
322 false, false, false, false, 6,
323 { "D 16 0 false true false false",
324 "D 65 0 false true false false",
325 "P 65 65 false true false false",
326 "T A",
327 "U 65 0 false true false false",
328 "U 16 0 false true false false" } },
329 // a, suppress keydown
330 { ui::VKEY_A, false, false, false, false,
331 true, false, false, false, 2,
332 { "D 65 0 false false false false",
333 "U 65 0 false false false false" } },
334 // a, suppress keypress
335 { ui::VKEY_A, false, false, false, false,
336 false, true, false, false, 3,
337 { "D 65 0 false false false false",
338 "P 97 97 false false false false",
339 "U 65 0 false false false false" } },
340 // a, suppress textInput
341 { ui::VKEY_A, false, false, false, false,
342 false, false, false, true, 4,
343 { "D 65 0 false false false false",
344 "P 97 97 false false false false",
345 "T a",
346 "U 65 0 false false false false" } },
347 };
348
349 ASSERT_TRUE(test_server()->Start());
350
351 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
352 GURL url = test_server()->GetURL(kTestingPage);
353 ui_test_utils::NavigateToURL(browser(), url);
354
355 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
356 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
357
358 int tab_index = browser()->active_index();
359 for (size_t i = 0; i < arraysize(kTestNoInput); ++i) {
360 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestNoInput[i]))
361 << "kTestNoInput[" << i << "] failed:\n"
362 << GetTestDataDescription(kTestNoInput[i]);
363 }
364
365 // Input in normal text box.
366 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
367 for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
368 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
369 << "kTestWithInput[" << i << "] in text box failed:\n"
370 << GetTestDataDescription(kTestWithInput[i]);
371 }
372 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA"));
373
374 // Input in password box.
375 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"B"));
376 for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
377 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
378 << "kTestWithInput[" << i << "] in password box failed:\n"
379 << GetTestDataDescription(kTestWithInput[i]);
380 }
381 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"B", L"aA"));
382 }
383
384 #if defined(OS_WIN) || defined(OS_LINUX)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,CtrlKeyEvents)385 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
386 static const KeyEventTestData kTestCtrlF = {
387 ui::VKEY_F, true, false, false, false,
388 false, false, false, false, 2,
389 { "D 17 0 true false false false",
390 "D 70 0 true false false false" }
391 };
392
393 static const KeyEventTestData kTestCtrlFSuppressKeyDown = {
394 ui::VKEY_F, true, false, false, false,
395 true, false, false, false, 4,
396 { "D 17 0 true false false false",
397 "D 70 0 true false false false",
398 "U 70 0 true false false false",
399 "U 17 0 true false false false" }
400 };
401
402 // Ctrl+Z doesn't bind to any accelerators, which then should generate a
403 // keypress event with charCode=26.
404 static const KeyEventTestData kTestCtrlZ = {
405 ui::VKEY_Z, true, false, false, false,
406 false, false, false, false, 5,
407 { "D 17 0 true false false false",
408 "D 90 0 true false false false",
409 "P 26 26 true false false false",
410 "U 90 0 true false false false",
411 "U 17 0 true false false false" }
412 };
413
414 static const KeyEventTestData kTestCtrlZSuppressKeyDown = {
415 ui::VKEY_Z, true, false, false, false,
416 true, false, false, false, 4,
417 { "D 17 0 true false false false",
418 "D 90 0 true false false false",
419 "U 90 0 true false false false",
420 "U 17 0 true false false false" }
421 };
422
423 // Ctrl+Enter shall generate a keypress event with charCode=10 (LF).
424 static const KeyEventTestData kTestCtrlEnter = {
425 ui::VKEY_RETURN, true, false, false, false,
426 false, false, false, false, 5,
427 { "D 17 0 true false false false",
428 "D 13 0 true false false false",
429 "P 10 10 true false false false",
430 "U 13 0 true false false false",
431 "U 17 0 true false false false" }
432 };
433
434 ASSERT_TRUE(test_server()->Start());
435
436 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
437 GURL url = test_server()->GetURL(kTestingPage);
438 ui_test_utils::NavigateToURL(browser(), url);
439
440 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
441 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
442
443 int tab_index = browser()->active_index();
444 // Press Ctrl+F, which will make the Find box open and request focus.
445 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
446 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
447
448 // Press Escape to close the Find box and move the focus back to the web page.
449 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
450 browser(), ui::VKEY_ESCAPE, false, false, false, false));
451 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
452
453 // Press Ctrl+F with keydown suppressed shall not open the find box.
454 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlFSuppressKeyDown));
455 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
456
457 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZ));
458 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZSuppressKeyDown));
459 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlEnter));
460 }
461 #elif defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,CommandKeyEvents)462 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CommandKeyEvents) {
463 static const KeyEventTestData kTestCmdF = {
464 ui::VKEY_F, false, false, false, true,
465 false, false, false, false, 2,
466 { "D 91 0 false false false true",
467 "D 70 0 false false false true" }
468 };
469
470 // On Mac we don't send key up events when command modifier is down.
471 static const KeyEventTestData kTestCmdFSuppressKeyDown = {
472 ui::VKEY_F, false, false, false, true,
473 true, false, false, false, 3,
474 { "D 91 0 false false false true",
475 "D 70 0 false false false true",
476 "U 91 0 false false false true" }
477 };
478
479 ASSERT_TRUE(test_server()->Start());
480
481 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
482 GURL url = test_server()->GetURL(kTestingPage);
483 ui_test_utils::NavigateToURL(browser(), url);
484
485 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
486 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
487
488 int tab_index = browser()->active_index();
489 // Press Cmd+F, which will make the Find box open and request focus.
490 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdF));
491 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
492
493 // Press Escape to close the Find box and move the focus back to the web page.
494 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
495 browser(), ui::VKEY_ESCAPE, false, false, false, false));
496 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
497
498 // Press Cmd+F with keydown suppressed shall not open the find box.
499 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdFSuppressKeyDown));
500 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
501 }
502 #endif
503
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,AccessKeys)504 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, AccessKeys) {
505 #if defined(OS_MACOSX)
506 // On Mac, access keys use ctrl+alt modifiers.
507 static const KeyEventTestData kTestAccessA = {
508 ui::VKEY_A, true, false, true, false,
509 false, false, false, false, 6,
510 { "D 17 0 true false false false",
511 "D 18 0 true false true false",
512 "D 65 0 true false true false",
513 "U 65 0 true false true false",
514 "U 18 0 true false true false",
515 "U 17 0 true false false false" }
516 };
517
518 static const KeyEventTestData kTestAccessDSuppress = {
519 ui::VKEY_D, true, false, true, false,
520 true, true, true, false, 6,
521 { "D 17 0 true false false false",
522 "D 18 0 true false true false",
523 "D 68 0 true false true false",
524 "U 68 0 true false true false",
525 "U 18 0 true false true false",
526 "U 17 0 true false false false" }
527 };
528
529 static const KeyEventTestData kTestAccess1 = {
530 ui::VKEY_1, true, false, true, false,
531 false, false, false, false, 6,
532 { "D 17 0 true false false false",
533 "D 18 0 true false true false",
534 "D 49 0 true false true false",
535 "U 49 0 true false true false",
536 "U 18 0 true false true false",
537 "U 17 0 true false false false" }
538 };
539 #else
540 static const KeyEventTestData kTestAccessA = {
541 ui::VKEY_A, false, false, true, false,
542 false, false, false, false, 4,
543 { "D 18 0 false false true false",
544 "D 65 0 false false true false",
545 "U 65 0 false false true false",
546 "U 18 0 false false true false" }
547 };
548
549 static const KeyEventTestData kTestAccessD = {
550 ui::VKEY_D, false, false, true, false,
551 false, false, false, false, 2,
552 { "D 18 0 false false true false",
553 "D 68 0 false false true false" }
554 };
555
556 static const KeyEventTestData kTestAccessDSuppress = {
557 ui::VKEY_D, false, false, true, false,
558 true, true, true, false, 4,
559 { "D 18 0 false false true false",
560 "D 68 0 false false true false",
561 "U 68 0 false false true false",
562 "U 18 0 false false true false" }
563 };
564
565 static const KeyEventTestData kTestAccess1 = {
566 ui::VKEY_1, false, false, true, false,
567 false, false, false, false, 4,
568 { "D 18 0 false false true false",
569 "D 49 0 false false true false",
570 "U 49 0 false false true false",
571 "U 18 0 false false true false" }
572 };
573 #endif
574
575 ASSERT_TRUE(test_server()->Start());
576
577 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
578 GURL url = test_server()->GetURL(kTestingPage);
579 ui_test_utils::NavigateToURL(browser(), url);
580
581 ui_test_utils::RunAllPendingInMessageLoop();
582 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
583 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
584
585 int tab_index = browser()->active_index();
586 // Make sure no element is focused.
587 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
588 // Alt+A should focus the element with accesskey = "A".
589 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessA));
590 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"A"));
591
592 // Blur the focused element.
593 EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
594 // Make sure no element is focused.
595 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
596
597 #if !defined(OS_MACOSX)
598 // Alt+D should move the focus to the location entry.
599 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessD));
600
601 // TODO(isherman): This is an experimental change to help diagnose
602 // http://crbug.com/55713
603 ui_test_utils::RunAllPendingInMessageLoop();
604
605 EXPECT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
606 // No element should be focused, as Alt+D was handled by the browser.
607 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
608
609 // Move the focus back to the web page.
610 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
611 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
612
613 // Make sure no element is focused.
614 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
615 #endif
616
617 // If the keydown event is suppressed, then Alt+D should be handled as an
618 // accesskey rather than an accelerator key. Activation of an accesskey is not
619 // a part of the default action of the key event, so it should not be
620 // suppressed at all.
621 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessDSuppress));
622 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
623 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"D"));
624
625 // Blur the focused element.
626 EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
627 // Make sure no element is focused.
628 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
629 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccess1));
630 #if defined(TOOLKIT_GTK)
631 // On GTK, alt-0..9 are assigned as tab selection accelerators, so they can
632 // not be used as accesskeys.
633 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
634 #else
635 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1"));
636 #endif
637 }
638
639 // Disabled, http://crbug.com/69475.
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,DISABLED_ReservedAccelerators)640 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_ReservedAccelerators) {
641 ASSERT_TRUE(test_server()->Start());
642
643 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
644 GURL url = test_server()->GetURL(kTestingPage);
645 ui_test_utils::NavigateToURL(browser(), url);
646
647 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
648 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
649
650 ASSERT_EQ(1, browser()->tab_count());
651
652 static const KeyEventTestData kTestCtrlOrCmdT = {
653 #if defined(OS_MACOSX)
654 ui::VKEY_T, false, false, false, true,
655 true, false, false, false, 1,
656 { "D 91 0 false false false true" }
657 #else
658 ui::VKEY_T, true, false, false, false,
659 true, false, false, false, 1,
660 { "D 17 0 true false false false" }
661 #endif
662 };
663
664 ui_test_utils::WindowedNotificationObserver wait_for_new_tab(
665 NotificationType::TAB_PARENTED,
666 NotificationService::AllSources());
667
668 // Press Ctrl/Cmd+T, which will open a new tab. It cannot be suppressed.
669 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlOrCmdT));
670
671 ASSERT_NO_FATAL_FAILURE(
672 wait_for_new_tab.WaitFor(Source<NavigationController>(
673 &browser()->GetTabContentsAt(1)->controller())));
674
675 int result_length;
676 ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
677 EXPECT_EQ(1, result_length);
678
679 EXPECT_EQ(2, browser()->tab_count());
680 ASSERT_EQ(1, browser()->active_index());
681
682 // Because of issue http://crbug.com/65375, switching back to the first tab
683 // may cause the focus to be grabbed by omnibox. So instead, we load our
684 // testing page in the newly created tab and try Cmd-W here.
685 ui_test_utils::NavigateToURL(browser(), url);
686
687 // Make sure the focus is in the testing page.
688 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
689 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
690
691 // Reserved accelerators can't be suppressed.
692 ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(1, true));
693
694 ui_test_utils::WindowedNotificationObserver wait_for_tab_closed(
695 NotificationType::TAB_CLOSED, Source<NavigationController>(
696 &browser()->GetTabContentsAt(1)->controller()));
697
698 // Press Ctrl/Cmd+W, which will close the tab.
699 #if defined(OS_MACOSX)
700 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
701 browser(), ui::VKEY_W, false, false, false, true));
702 #else
703 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
704 browser(), ui::VKEY_W, true, false, false, false));
705 #endif
706
707 ASSERT_NO_FATAL_FAILURE(wait_for_tab_closed.Wait());
708
709 EXPECT_EQ(1, browser()->tab_count());
710 }
711
712 #if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,EditorKeyBindings)713 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) {
714 static const KeyEventTestData kTestCtrlA = {
715 ui::VKEY_A, true, false, false, false,
716 false, false, false, false, 4,
717 { "D 17 0 true false false false",
718 "D 65 0 true false false false",
719 "U 65 0 true false false false",
720 "U 17 0 true false false false" }
721 };
722
723 static const KeyEventTestData kTestCtrlF = {
724 ui::VKEY_F, true, false, false, false,
725 false, false, false, false, 4,
726 { "D 17 0 true false false false",
727 "D 70 0 true false false false",
728 "U 70 0 true false false false",
729 "U 17 0 true false false false" }
730 };
731
732 static const KeyEventTestData kTestCtrlK = {
733 ui::VKEY_K, true, false, false, false,
734 false, false, false, false, 4,
735 { "D 17 0 true false false false",
736 "D 75 0 true false false false",
737 "U 75 0 true false false false",
738 "U 17 0 true false false false" }
739 };
740
741 ASSERT_TRUE(test_server()->Start());
742
743 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
744 GURL url = test_server()->GetURL(kTestingPage);
745 ui_test_utils::NavigateToURL(browser(), url);
746
747 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
748 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
749
750 int tab_index = browser()->active_index();
751 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
752 ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index, L"A", L"Hello"));
753 // Move the caret to the beginning of the line.
754 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlA));
755 // Forward one character
756 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
757 // Delete to the end of the line.
758 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlK));
759 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"H"));
760 }
761 #endif
762
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,PageUpDownKeys)763 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, PageUpDownKeys) {
764 static const KeyEventTestData kTestPageUp = {
765 ui::VKEY_PRIOR, false, false, false, false,
766 false, false, false, false, 2,
767 { "D 33 0 false false false false",
768 "U 33 0 false false false false" }
769 };
770
771 static const KeyEventTestData kTestPageDown = {
772 ui::VKEY_NEXT, false, false, false, false,
773 false, false, false, false, 2,
774 { "D 34 0 false false false false",
775 "U 34 0 false false false false" }
776 };
777
778 ASSERT_TRUE(test_server()->Start());
779
780 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
781 GURL url = test_server()->GetURL(kTestingPage);
782 ui_test_utils::NavigateToURL(browser(), url);
783
784 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
785 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
786
787 int tab_index = browser()->active_index();
788 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
789 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageUp));
790 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageDown));
791 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L""));
792 }
793
794 #if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,FocusMenuBarByAltKey)795 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FocusMenuBarByAltKey) {
796 static const KeyEventTestData kTestAltKey = {
797 ui::VKEY_MENU, false, false, false, false,
798 false, false, false, false, 2,
799 { "D 18 0 false false true false",
800 "U 18 0 false false true false" }
801 };
802
803 static const KeyEventTestData kTestAltKeySuppress = {
804 ui::VKEY_MENU, false, false, false, false,
805 true, false, false, false, 2,
806 { "D 18 0 false false true false",
807 "U 18 0 false false true false" }
808 };
809
810 static const KeyEventTestData kTestCtrlAltKey = {
811 ui::VKEY_MENU, true, false, false, false,
812 false, false, false, false, 4,
813 { "D 17 0 true false false false",
814 "D 18 0 true false true false",
815 "U 18 0 true false true false",
816 "U 17 0 true false false false" }
817 };
818
819 ASSERT_TRUE(test_server()->Start());
820
821 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
822 GURL url = test_server()->GetURL(kTestingPage);
823 ui_test_utils::NavigateToURL(browser(), url);
824
825 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
826 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
827
828 int tab_index = browser()->active_index();
829 // Press and release Alt key to focus wrench menu button.
830 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKey));
831 EXPECT_TRUE(IsViewFocused(VIEW_ID_APP_MENU));
832
833 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
834 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
835
836 // Alt key can be suppressed.
837 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKeySuppress));
838 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
839
840 // Ctrl+Alt should have no effect.
841 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlAltKey));
842 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
843 }
844 #endif
845
846 } // namespace
847