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.
5 #include "build/build_config.h"
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/stringprintf.h"
11 #include "base/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "chrome/common/chrome_paths.h"
17 #include "chrome/test/base/in_process_browser_test.h"
18 #include "chrome/test/base/interactive_test_utils.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/dom_operation_notification_details.h"
21 #include "content/public/browser/notification_registrar.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/render_widget_host_view.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/browser/web_contents_view.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "net/test/spawned_test_server/spawned_test_server.h"
29 #include "ui/base/keycodes/keyboard_codes.h"
30 #include "ui/views/controls/textfield/textfield.h"
32 // TODO(kbr): remove: http://crbug.com/222296
33 #if defined(OS_MACOSX)
34 #import "base/mac/mac_util.h"
37 using content::DomOperationNotificationDetails
;
38 using content::NavigationController
;
39 using content::RenderViewHost
;
43 const char kTestingPage
[] = "files/keyevents_test.html";
44 const char kSuppressEventJS
[] =
45 "window.domAutomationController.send(setDefaultAction('%ls', %ls));";
46 const char kGetResultJS
[] =
47 "window.domAutomationController.send(keyEventResult[%d]);";
48 const char kGetResultLengthJS
[] =
49 "window.domAutomationController.send(keyEventResult.length);";
50 const char kGetFocusedElementJS
[] =
51 "window.domAutomationController.send(focusedElement);";
52 const char kSetFocusedElementJS
[] =
53 "window.domAutomationController.send(setFocusedElement('%ls'));";
54 const char kGetTextBoxValueJS
[] =
55 "window.domAutomationController.send("
56 " document.getElementById('%ls').value);";
57 const char kSetTextBoxValueJS
[] =
58 "window.domAutomationController.send("
59 " document.getElementById('%ls').value = '%ls');";
60 const char kStartTestJS
[] =
61 "window.domAutomationController.send(startTest(%d));";
63 // Maximum lenght of the result array in KeyEventTestData structure.
64 const size_t kMaxResultLength
= 10;
66 // A structure holding test data of a keyboard event.
67 // Each keyboard event may generate multiple result strings representing
68 // the result of keydown, keypress, keyup and textInput events.
69 // For keydown, keypress and keyup events, the format of the result string is:
70 // <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
71 // where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
72 // <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
73 // the state of corresponding modifier key.
74 // For textInput event, the format is: T <text>, where <text> is the text to be
76 // Please refer to chrome/test/data/keyevents_test.html for details.
77 struct KeyEventTestData
{
84 bool suppress_keydown
;
85 bool suppress_keypress
;
87 bool suppress_textinput
;
90 const char* const result
[kMaxResultLength
];
93 const wchar_t* GetBoolString(bool value
) {
94 return value
? L
"true" : L
"false";
97 // A class to help wait for the finish of a key event test.
98 class TestFinishObserver
: public content::NotificationObserver
{
100 explicit TestFinishObserver(RenderViewHost
* render_view_host
)
101 : finished_(false), waiting_(false) {
102 registrar_
.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE
,
103 content::Source
<RenderViewHost
>(render_view_host
));
106 bool WaitForFinish() {
109 content::RunMessageLoop();
115 virtual void Observe(int type
,
116 const content::NotificationSource
& source
,
117 const content::NotificationDetails
& details
) OVERRIDE
{
118 DCHECK(type
== content::NOTIFICATION_DOM_OPERATION_RESPONSE
);
119 content::Details
<DomOperationNotificationDetails
> dom_op_details(details
);
120 // We might receive responses for other script execution, but we only
121 // care about the test finished message.
122 if (dom_op_details
->json
== "\"FINISHED\"") {
125 MessageLoopForUI::current()->Quit();
132 content::NotificationRegistrar registrar_
;
134 DISALLOW_COPY_AND_ASSIGN(TestFinishObserver
);
137 class BrowserKeyEventsTest
: public InProcessBrowserTest
{
139 BrowserKeyEventsTest() {}
141 bool IsViewFocused(ViewID vid
) {
142 return ui_test_utils::IsViewFocused(browser(), vid
);
145 void ClickOnView(ViewID vid
) {
146 ui_test_utils::ClickOnView(browser(), vid
);
149 // Set the suppress flag of an event specified by |type|. If |suppress| is
150 // true then the web page will suppress all events with |type|. Following
151 // event types are supported: keydown, keypress, keyup and textInput.
152 void SuppressEventByType(int tab_index
, const wchar_t* type
, bool suppress
) {
153 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
155 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
156 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
157 base::StringPrintf(kSuppressEventJS
, type
, GetBoolString(!suppress
)),
159 ASSERT_EQ(!suppress
, actual
);
162 void SuppressEvents(int tab_index
, bool keydown
, bool keypress
,
163 bool keyup
, bool textinput
) {
164 ASSERT_NO_FATAL_FAILURE(
165 SuppressEventByType(tab_index
, L
"keydown", keydown
));
166 ASSERT_NO_FATAL_FAILURE(
167 SuppressEventByType(tab_index
, L
"keypress", keypress
));
168 ASSERT_NO_FATAL_FAILURE(
169 SuppressEventByType(tab_index
, L
"keyup", keyup
));
170 ASSERT_NO_FATAL_FAILURE(
171 SuppressEventByType(tab_index
, L
"textInput", textinput
));
174 void SuppressAllEvents(int tab_index
, bool suppress
) {
175 SuppressEvents(tab_index
, suppress
, suppress
, suppress
, suppress
);
178 void GetResultLength(int tab_index
, int* length
) {
179 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
180 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
181 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
186 void CheckResult(int tab_index
, int length
, const char* const result
[]) {
187 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
189 ASSERT_NO_FATAL_FAILURE(GetResultLength(tab_index
, &actual_length
));
190 ASSERT_GE(actual_length
, length
);
191 for (int i
= 0; i
< actual_length
; ++i
) {
193 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
194 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
195 base::StringPrintf(kGetResultJS
, i
),
198 // If more events were received than expected, then the additional events
199 // must be keyup events.
201 ASSERT_STREQ(result
[i
], actual
.c_str());
203 ASSERT_EQ('U', actual
[0]);
207 void CheckFocusedElement(int tab_index
, const wchar_t* focused
) {
208 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
210 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
211 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
212 kGetFocusedElementJS
,
214 ASSERT_EQ(WideToUTF8(focused
), actual
);
217 void SetFocusedElement(int tab_index
, const wchar_t* focused
) {
218 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
220 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
221 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
222 base::StringPrintf(kSetFocusedElementJS
, focused
),
227 void CheckTextBoxValue(int tab_index
, const wchar_t* id
,
228 const wchar_t* value
) {
229 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
231 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
232 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
233 base::StringPrintf(kGetTextBoxValueJS
, id
),
235 ASSERT_EQ(WideToUTF8(value
), actual
);
238 void SetTextBoxValue(int tab_index
, const wchar_t* id
,
239 const wchar_t* value
) {
240 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
242 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
243 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
244 base::StringPrintf(kSetTextBoxValueJS
, id
, value
),
246 ASSERT_EQ(WideToUTF8(value
), actual
);
249 void StartTest(int tab_index
, int result_length
) {
250 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
252 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
253 browser()->tab_strip_model()->GetWebContentsAt(tab_index
),
254 base::StringPrintf(kStartTestJS
, result_length
),
259 void TestKeyEvent(int tab_index
, const KeyEventTestData
& test
) {
260 ASSERT_LT(tab_index
, browser()->tab_strip_model()->count());
261 ASSERT_EQ(tab_index
, browser()->tab_strip_model()->active_index());
263 // Inform our testing web page that we are about to start testing a key
265 ASSERT_NO_FATAL_FAILURE(StartTest(tab_index
, test
.result_length
));
266 ASSERT_NO_FATAL_FAILURE(SuppressEvents(
267 tab_index
, test
.suppress_keydown
, test
.suppress_keypress
,
268 test
.suppress_keyup
, test
.suppress_textinput
));
270 // We need to create a finish observer before sending the key event,
271 // because the test finished message might be arrived before returning
272 // from the SendKeyPressSync() method.
273 TestFinishObserver
finish_observer(
274 browser()->tab_strip_model()->GetWebContentsAt(tab_index
)->
275 GetRenderViewHost());
277 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
278 browser(), test
.key
, test
.ctrl
, test
.shift
, test
.alt
, test
.command
));
279 ASSERT_TRUE(finish_observer
.WaitForFinish());
280 ASSERT_NO_FATAL_FAILURE(CheckResult(
281 tab_index
, test
.result_length
, test
.result
));
284 std::string
GetTestDataDescription(const KeyEventTestData
& data
) {
285 std::string desc
= base::StringPrintf(
286 " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d, command:%d\n"
287 " Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n"
288 " Expected results(%d):\n",
289 data
.key
, data
.ctrl
, data
.shift
, data
.alt
, data
.command
,
290 data
.suppress_keydown
, data
.suppress_keypress
, data
.suppress_keyup
,
291 data
.suppress_textinput
, data
.result_length
);
292 for (int i
= 0; i
< data
.result_length
; ++i
) {
294 desc
.append(data
.result
[i
]);
301 #if defined(OS_MACOSX)
302 // http://crbug.com/81451
303 #define MAYBE_NormalKeyEvents DISABLED_NormalKeyEvents
304 #elif defined(OS_LINUX)
305 // http://crbug.com/129235
306 #define MAYBE_NormalKeyEvents DISABLED_NormalKeyEvents
308 #define MAYBE_NormalKeyEvents NormalKeyEvents
311 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, MAYBE_NormalKeyEvents
) {
312 static const KeyEventTestData kTestNoInput
[] = {
314 { ui::VKEY_A
, false, false, false, false,
315 false, false, false, false, 3,
316 { "D 65 0 false false false false",
317 "P 97 97 false false false false",
318 "U 65 0 false false false false" } },
320 { ui::VKEY_A
, false, true, false, false,
321 false, false, false, false, 5,
322 { "D 16 0 false true false false",
323 "D 65 0 false true false false",
324 "P 65 65 false true false false",
325 "U 65 0 false true false false",
326 "U 16 0 false true false false" } },
327 // a, suppress keydown
328 { ui::VKEY_A
, false, false, false, false,
329 true, false, false, false, 2,
330 { "D 65 0 false false false false",
331 "U 65 0 false false false false" } },
334 static const KeyEventTestData kTestWithInput
[] = {
336 { ui::VKEY_A
, false, false, false, false,
337 false, false, false, false, 4,
338 { "D 65 0 false false false false",
339 "P 97 97 false false false false",
341 "U 65 0 false false false false" } },
343 { ui::VKEY_A
, false, true, false, false,
344 false, false, false, false, 6,
345 { "D 16 0 false true false false",
346 "D 65 0 false true false false",
347 "P 65 65 false true false false",
349 "U 65 0 false true false false",
350 "U 16 0 false true false false" } },
351 // a, suppress keydown
352 { ui::VKEY_A
, false, false, false, false,
353 true, false, false, false, 2,
354 { "D 65 0 false false false false",
355 "U 65 0 false false false false" } },
356 // a, suppress keypress
357 { ui::VKEY_A
, false, false, false, false,
358 false, true, false, false, 3,
359 { "D 65 0 false false false false",
360 "P 97 97 false false false false",
361 "U 65 0 false false false false" } },
362 // a, suppress textInput
363 { ui::VKEY_A
, false, false, false, false,
364 false, false, false, true, 4,
365 { "D 65 0 false false false false",
366 "P 97 97 false false false false",
368 "U 65 0 false false false false" } },
371 ASSERT_TRUE(test_server()->Start());
373 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
374 GURL url
= test_server()->GetURL(kTestingPage
);
375 ui_test_utils::NavigateToURL(browser(), url
);
377 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
378 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
380 int tab_index
= browser()->tab_strip_model()->active_index();
381 for (size_t i
= 0; i
< arraysize(kTestNoInput
); ++i
) {
382 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestNoInput
[i
]))
383 << "kTestNoInput[" << i
<< "] failed:\n"
384 << GetTestDataDescription(kTestNoInput
[i
]);
387 // Input in normal text box.
388 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index
, L
"A"));
389 for (size_t i
= 0; i
< arraysize(kTestWithInput
); ++i
) {
390 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestWithInput
[i
]))
391 << "kTestWithInput[" << i
<< "] in text box failed:\n"
392 << GetTestDataDescription(kTestWithInput
[i
]);
394 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index
, L
"A", L
"aA"));
396 // Input in password box.
397 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index
, L
"B"));
398 for (size_t i
= 0; i
< arraysize(kTestWithInput
); ++i
) {
399 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestWithInput
[i
]))
400 << "kTestWithInput[" << i
<< "] in password box failed:\n"
401 << GetTestDataDescription(kTestWithInput
[i
]);
403 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index
, L
"B", L
"aA"));
406 #if defined(OS_WIN) || defined(OS_LINUX)
408 #if defined(OS_LINUX)
409 // http://crbug.com/129235
410 #define MAYBE_CtrlKeyEvents DISABLED_CtrlKeyEvents
412 #define MAYBE_CtrlKeyEvents CtrlKeyEvents
415 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, MAYBE_CtrlKeyEvents
) {
416 static const KeyEventTestData kTestCtrlF
= {
417 ui::VKEY_F
, true, false, false, false,
418 false, false, false, false, 2,
419 { "D 17 0 true false false false",
420 "D 70 0 true false false false" }
423 static const KeyEventTestData kTestCtrlFSuppressKeyDown
= {
424 ui::VKEY_F
, true, false, false, false,
425 true, false, false, false, 4,
426 { "D 17 0 true false false false",
427 "D 70 0 true false false false",
428 "U 70 0 true false false false",
429 "U 17 0 true false false false" }
432 // Ctrl+Z doesn't bind to any accelerators, which then should generate a
433 // keypress event with charCode=26.
434 static const KeyEventTestData kTestCtrlZ
= {
435 ui::VKEY_Z
, true, false, false, false,
436 false, false, false, false, 5,
437 { "D 17 0 true false false false",
438 "D 90 0 true false false false",
439 "P 26 26 true false false false",
440 "U 90 0 true false false false",
441 "U 17 0 true false false false" }
444 static const KeyEventTestData kTestCtrlZSuppressKeyDown
= {
445 ui::VKEY_Z
, true, false, false, false,
446 true, false, false, false, 4,
447 { "D 17 0 true false false false",
448 "D 90 0 true false false false",
449 "U 90 0 true false false false",
450 "U 17 0 true false false false" }
453 // Ctrl+Enter shall generate a keypress event with charCode=10 (LF).
454 static const KeyEventTestData kTestCtrlEnter
= {
455 ui::VKEY_RETURN
, true, false, false, false,
456 false, false, false, false, 5,
457 { "D 17 0 true false false false",
458 "D 13 0 true false false false",
459 "P 10 10 true false false false",
460 "U 13 0 true false false false",
461 "U 17 0 true false false false" }
464 ASSERT_TRUE(test_server()->Start());
466 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
467 GURL url
= test_server()->GetURL(kTestingPage
);
468 ui_test_utils::NavigateToURL(browser(), url
);
470 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
471 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
473 int tab_index
= browser()->tab_strip_model()->active_index();
474 // Press Ctrl+F, which will make the Find box open and request focus.
475 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlF
));
476 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD
));
478 // Press Escape to close the Find box and move the focus back to the web page.
479 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
480 browser(), ui::VKEY_ESCAPE
, false, false, false, false));
481 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
483 // Press Ctrl+F with keydown suppressed shall not open the find box.
484 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlFSuppressKeyDown
));
485 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
487 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlZ
));
488 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlZSuppressKeyDown
));
489 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlEnter
));
491 #elif defined(OS_MACOSX)
492 // http://crbug.com/81451
493 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, DISABLED_CommandKeyEvents
) {
494 static const KeyEventTestData kTestCmdF
= {
495 ui::VKEY_F
, false, false, false, true,
496 false, false, false, false, 2,
497 { "D 91 0 false false false true",
498 "D 70 0 false false false true" }
501 // On Mac we don't send key up events when command modifier is down.
502 static const KeyEventTestData kTestCmdFSuppressKeyDown
= {
503 ui::VKEY_F
, false, false, false, true,
504 true, false, false, false, 3,
505 { "D 91 0 false false false true",
506 "D 70 0 false false false true",
507 "U 91 0 false false false true" }
510 ASSERT_TRUE(test_server()->Start());
512 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
513 GURL url
= test_server()->GetURL(kTestingPage
);
514 ui_test_utils::NavigateToURL(browser(), url
);
516 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
517 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
519 int tab_index
= browser()->tab_strip_model()->active_index();
520 // Press Cmd+F, which will make the Find box open and request focus.
521 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCmdF
));
522 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD
));
524 // Press Escape to close the Find box and move the focus back to the web page.
525 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
526 browser(), ui::VKEY_ESCAPE
, false, false, false, false));
527 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
529 // Press Cmd+F with keydown suppressed shall not open the find box.
530 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCmdFSuppressKeyDown
));
531 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
535 #if defined(OS_MACOSX)
536 // http://crbug.com/81451 for mac
537 #define MAYBE_AccessKeys DISABLED_AccessKeys
538 #elif defined(OS_LINUX)
539 // http://crbug.com/129235
540 #define MAYBE_AccessKeys DISABLED_AccessKeys
542 #define MAYBE_AccessKeys AccessKeys
545 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, MAYBE_AccessKeys
) {
546 #if defined(OS_MACOSX)
547 // On Mac, access keys use ctrl+alt modifiers.
548 static const KeyEventTestData kTestAccessA
= {
549 ui::VKEY_A
, true, false, true, false,
550 false, false, false, false, 6,
551 { "D 17 0 true false false false",
552 "D 18 0 true false true false",
553 "D 65 0 true false true false",
554 "U 65 0 true false true false",
555 "U 18 0 true false true false",
556 "U 17 0 true false false false" }
559 static const KeyEventTestData kTestAccessDSuppress
= {
560 ui::VKEY_D
, true, false, true, false,
561 true, true, true, false, 6,
562 { "D 17 0 true false false false",
563 "D 18 0 true false true false",
564 "D 68 0 true false true false",
565 "U 68 0 true false true false",
566 "U 18 0 true false true false",
567 "U 17 0 true false false false" }
570 static const KeyEventTestData kTestAccess1
= {
571 ui::VKEY_1
, true, false, true, false,
572 false, false, false, false, 6,
573 { "D 17 0 true false false false",
574 "D 18 0 true false true false",
575 "D 49 0 true false true false",
576 "U 49 0 true false true false",
577 "U 18 0 true false true false",
578 "U 17 0 true false false false" }
581 static const KeyEventTestData kTestAccessA
= {
582 ui::VKEY_A
, false, false, true, false,
583 false, false, false, false, 4,
584 { "D 18 0 false false true false",
585 "D 65 0 false false true false",
586 "U 65 0 false false true false",
587 "U 18 0 false false true false" }
590 static const KeyEventTestData kTestAccessD
= {
591 ui::VKEY_D
, false, false, true, false,
592 false, false, false, false, 2,
593 { "D 18 0 false false true false",
594 "D 68 0 false false true false" }
597 static const KeyEventTestData kTestAccessDSuppress
= {
598 ui::VKEY_D
, false, false, true, false,
599 true, true, true, false, 4,
600 { "D 18 0 false false true false",
601 "D 68 0 false false true false",
602 "U 68 0 false false true false",
603 "U 18 0 false false true false" }
606 #if !defined(USE_ASH)
607 static const KeyEventTestData kTestAccess1
= {
608 ui::VKEY_1
, false, false, true, false,
609 false, false, false, false, 4,
610 { "D 18 0 false false true false",
611 "D 49 0 false false true false",
612 "U 49 0 false false true false",
613 "U 18 0 false false true false" }
618 ASSERT_TRUE(test_server()->Start());
620 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
621 GURL url
= test_server()->GetURL(kTestingPage
);
622 ui_test_utils::NavigateToURL(browser(), url
);
624 content::RunAllPendingInMessageLoop();
625 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
626 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
628 int tab_index
= browser()->tab_strip_model()->active_index();
629 // Make sure no element is focused.
630 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
""));
631 // Alt+A should focus the element with accesskey = "A".
632 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestAccessA
));
633 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
"A"));
635 // Blur the focused element.
636 EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index
, L
""));
637 // Make sure no element is focused.
638 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
""));
640 #if !defined(OS_MACOSX)
641 // Alt+D should move the focus to the location entry.
642 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestAccessD
));
644 // TODO(isherman): This is an experimental change to help diagnose
645 // http://crbug.com/55713
646 content::RunAllPendingInMessageLoop();
647 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX
));
648 // No element should be focused, as Alt+D was handled by the browser.
649 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
""));
651 // Move the focus back to the web page.
652 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
653 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
655 // Make sure no element is focused.
656 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
""));
659 // If the keydown event is suppressed, then Alt+D should be handled as an
660 // accesskey rather than an accelerator key. Activation of an accesskey is not
661 // a part of the default action of the key event, so it should not be
662 // suppressed at all.
663 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestAccessDSuppress
));
664 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
665 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
"D"));
667 // Blur the focused element.
668 EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index
, L
""));
669 // Make sure no element is focused.
670 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
""));
671 #if !defined(USE_ASH)
672 // On Ash, alt-1..9 are assigned as window selection global accelerators, so
673 // they can not be used as accesskeys.
674 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestAccess1
));
675 #if defined(TOOLKIT_GTK)
676 // On GTK, alt-0..9 are assigned as tab selection accelerators, so they can
677 // not be used as accesskeys.
678 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
""));
680 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index
, L
"1"));
685 // Flaky, http://crbug.com/69475.
686 #if defined(OS_LINUX)
687 #define MAYBE_ReservedAccelerators DISABLED_ReservedAccelerators
689 #define MAYBE_ReservedAccelerators ReservedAccelerators
691 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, MAYBE_ReservedAccelerators
) {
692 ASSERT_TRUE(test_server()->Start());
694 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
695 GURL url
= test_server()->GetURL(kTestingPage
);
696 ui_test_utils::NavigateToURL(browser(), url
);
698 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
699 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
701 ASSERT_EQ(1, browser()->tab_strip_model()->count());
703 static const KeyEventTestData kTestCtrlOrCmdT
= {
704 #if defined(OS_MACOSX)
705 ui::VKEY_T
, false, false, false, true,
706 true, false, false, false, 1,
707 { "D 91 0 false false false true" }
709 ui::VKEY_T
, true, false, false, false,
710 true, false, false, false, 1,
711 { "D 17 0 true false false false" }
715 content::WindowedNotificationObserver
wait_for_new_tab(
716 chrome::NOTIFICATION_TAB_PARENTED
,
717 content::NotificationService::AllSources());
719 // Press Ctrl/Cmd+T, which will open a new tab. It cannot be suppressed.
720 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlOrCmdT
));
721 wait_for_new_tab
.Wait();
724 ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length
));
725 EXPECT_EQ(1, result_length
);
727 EXPECT_EQ(2, browser()->tab_strip_model()->count());
728 ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
730 // Because of issue <http://crbug.com/65375>, switching back to the first tab
731 // may cause the focus to be grabbed by omnibox. So instead, we load our
732 // testing page in the newly created tab and try Cmd-W here.
733 ui_test_utils::NavigateToURL(browser(), url
);
735 // Make sure the focus is in the testing page.
736 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
737 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
739 // Reserved accelerators can't be suppressed.
740 ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(1, true));
742 content::WindowedNotificationObserver
wait_for_tab_closed(
743 content::NOTIFICATION_WEB_CONTENTS_DESTROYED
,
744 content::Source
<content::WebContents
>(
745 browser()->tab_strip_model()->GetWebContentsAt(1)));
747 // Press Ctrl/Cmd+W, which will close the tab.
748 #if defined(OS_MACOSX)
749 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
750 browser(), ui::VKEY_W
, false, false, false, true));
752 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
753 browser(), ui::VKEY_W
, true, false, false, false));
756 ASSERT_NO_FATAL_FAILURE(wait_for_tab_closed
.Wait());
758 EXPECT_EQ(1, browser()->tab_strip_model()->count());
761 #if defined(OS_MACOSX)
762 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, EditorKeyBindings
) {
763 // TODO(kbr): re-enable: http://crbug.com/222296
764 if (base::mac::IsOSMountainLionOrLater())
767 static const KeyEventTestData kTestCtrlA
= {
768 ui::VKEY_A
, true, false, false, false,
769 false, false, false, false, 4,
770 { "D 17 0 true false false false",
771 "D 65 0 true false false false",
772 "U 65 0 true false false false",
773 "U 17 0 true false false false" }
776 static const KeyEventTestData kTestCtrlF
= {
777 ui::VKEY_F
, true, false, false, false,
778 false, false, false, false, 4,
779 { "D 17 0 true false false false",
780 "D 70 0 true false false false",
781 "U 70 0 true false false false",
782 "U 17 0 true false false false" }
785 static const KeyEventTestData kTestCtrlK
= {
786 ui::VKEY_K
, true, false, false, false,
787 false, false, false, false, 4,
788 { "D 17 0 true false false false",
789 "D 75 0 true false false false",
790 "U 75 0 true false false false",
791 "U 17 0 true false false false" }
794 ASSERT_TRUE(test_server()->Start());
796 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
797 GURL url
= test_server()->GetURL(kTestingPage
);
798 ui_test_utils::NavigateToURL(browser(), url
);
800 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
801 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
803 int tab_index
= browser()->tab_strip_model()->active_index();
804 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index
, L
"A"));
805 ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index
, L
"A", L
"Hello"));
806 // Move the caret to the beginning of the line.
807 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlA
));
808 // Forward one character
809 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlF
));
810 // Delete to the end of the line.
811 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlK
));
812 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index
, L
"A", L
"H"));
816 // See http://crbug.com/147579
817 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, DISABLED_PageUpDownKeys
) {
818 static const KeyEventTestData kTestPageUp
= {
819 ui::VKEY_PRIOR
, false, false, false, false,
820 false, false, false, false, 2,
821 { "D 33 0 false false false false",
822 "U 33 0 false false false false" }
825 static const KeyEventTestData kTestPageDown
= {
826 ui::VKEY_NEXT
, false, false, false, false,
827 false, false, false, false, 2,
828 { "D 34 0 false false false false",
829 "U 34 0 false false false false" }
832 ASSERT_TRUE(test_server()->Start());
834 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
835 GURL url
= test_server()->GetURL(kTestingPage
);
836 ui_test_utils::NavigateToURL(browser(), url
);
838 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
839 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
841 int tab_index
= browser()->tab_strip_model()->active_index();
842 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index
, L
"A"));
843 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestPageUp
));
844 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestPageDown
));
845 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index
, L
"A", L
""));
849 // AltKey is enabled only on Windows. See crbug.com/114537.
850 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest
, FocusMenuBarByAltKey
) {
851 static const KeyEventTestData kTestAltKey
= {
852 ui::VKEY_MENU
, false, false, false, false,
853 false, false, false, false, 2,
854 { "D 18 0 false false true false",
855 "U 18 0 false false true false" }
858 static const KeyEventTestData kTestAltKeySuppress
= {
859 ui::VKEY_MENU
, false, false, false, false,
860 true, false, false, false, 2,
861 { "D 18 0 false false true false",
862 "U 18 0 false false true false" }
865 static const KeyEventTestData kTestCtrlAltKey
= {
866 ui::VKEY_MENU
, true, false, false, false,
867 false, false, false, false, 4,
868 { "D 17 0 true false false false",
869 "D 18 0 true false true false",
870 "U 18 0 true false true false",
871 "U 17 0 true false false false" }
874 ASSERT_TRUE(test_server()->Start());
876 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
877 GURL url
= test_server()->GetURL(kTestingPage
);
878 ui_test_utils::NavigateToURL(browser(), url
);
880 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
881 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
883 int tab_index
= browser()->tab_strip_model()->active_index();
884 // Press and release Alt key to focus wrench menu button.
885 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestAltKey
));
886 EXPECT_TRUE(IsViewFocused(VIEW_ID_APP_MENU
));
888 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER
));
889 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
891 // Alt key can be suppressed.
892 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestAltKeySuppress
));
893 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));
895 // Ctrl+Alt should have no effect.
896 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index
, kTestCtrlAltKey
));
897 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER
));