// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "build/build_config.h" #include "app/keyboard_codes.h" #include "base/basictypes.h" #include "base/logging.h" #include "base/message_loop.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser.h" #include "chrome/browser/dom_operation_notification_details.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/tab_contents/tab_contents_view.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" #include "net/test/test_server.h" namespace { const char kTestingPage[] = "files/keyevents_test.html"; const wchar_t kSuppressEventJS[] = L"window.domAutomationController.send(setDefaultAction('%ls', %ls));"; const wchar_t kGetResultJS[] = L"window.domAutomationController.send(keyEventResult[%d]);"; const wchar_t kGetResultLengthJS[] = L"window.domAutomationController.send(keyEventResult.length);"; const wchar_t kGetFocusedElementJS[] = L"window.domAutomationController.send(focusedElement);"; const wchar_t kSetFocusedElementJS[] = L"window.domAutomationController.send(setFocusedElement('%ls'));"; const wchar_t kGetTextBoxValueJS[] = L"window.domAutomationController.send(" L"document.getElementById('%ls').value);"; const wchar_t kSetTextBoxValueJS[] = L"window.domAutomationController.send(" L"document.getElementById('%ls').value = '%ls');"; const wchar_t kStartTestJS[] = L"window.domAutomationController.send(startTest(%d));"; // Maximum lenght of the result array in KeyEventTestData structure. const size_t kMaxResultLength = 10; // A structure holding test data of a keyboard event. // Each keyboard event may generate multiple result strings representing // the result of keydown, keypress, keyup and textInput events. // For keydown, keypress and keyup events, the format of the result string is: // // where may be 'D' (keydown), 'P' (keypress) or 'U' (keyup). // , and are boolean value indicating // the state of corresponding modifier key. // For textInput event, the format is: T , where is the text to be // input. // Please refer to chrome/test/data/keyevents_test.html for details. struct KeyEventTestData { app::KeyboardCode key; bool ctrl; bool shift; bool alt; bool command; bool suppress_keydown; bool suppress_keypress; bool suppress_keyup; bool suppress_textinput; int result_length; const char* const result[kMaxResultLength]; }; const wchar_t* GetBoolString(bool value) { return value ? L"true" : L"false"; } // A class to help wait for the finish of a key event test. class TestFinishObserver : public NotificationObserver { public: explicit TestFinishObserver(RenderViewHost* render_view_host) : finished_(false), waiting_(false) { registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE, Source(render_view_host)); } bool WaitForFinish() { if (!finished_) { waiting_ = true; ui_test_utils::RunMessageLoop(); waiting_ = false; } return finished_; } virtual void Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { DCHECK(type == NotificationType::DOM_OPERATION_RESPONSE); Details dom_op_details(details); // We might receive responses for other script execution, but we only // care about the test finished message. if (dom_op_details->json() == "\"FINISHED\"") { finished_ = true; if (waiting_) MessageLoopForUI::current()->Quit(); } } private: bool finished_; bool waiting_; NotificationRegistrar registrar_; DISALLOW_COPY_AND_ASSIGN(TestFinishObserver); }; class BrowserKeyEventsTest : public InProcessBrowserTest { public: BrowserKeyEventsTest() { set_show_window(true); EnableDOMAutomation(); } bool IsViewFocused(ViewID vid) { return ui_test_utils::IsViewFocused(browser(), vid); } void ClickOnView(ViewID vid) { ui_test_utils::ClickOnView(browser(), vid); } // Set the suppress flag of an event specified by |type|. If |suppress| is // true then the web page will suppress all events with |type|. Following // event types are supported: keydown, keypress, keyup and textInput. void SuppressEventByType(int tab_index, const wchar_t* type, bool suppress) { ASSERT_LT(tab_index, browser()->tab_count()); bool actual; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", StringPrintf(kSuppressEventJS, type, GetBoolString(!suppress)), &actual)); ASSERT_EQ(!suppress, actual); } void SuppressEvents(int tab_index, bool keydown, bool keypress, bool keyup, bool textinput) { ASSERT_NO_FATAL_FAILURE( SuppressEventByType(tab_index, L"keydown", keydown)); ASSERT_NO_FATAL_FAILURE( SuppressEventByType(tab_index, L"keypress", keypress)); ASSERT_NO_FATAL_FAILURE( SuppressEventByType(tab_index, L"keyup", keyup)); ASSERT_NO_FATAL_FAILURE( SuppressEventByType(tab_index, L"textInput", textinput)); } void SuppressAllEvents(int tab_index, bool suppress) { SuppressEvents(tab_index, suppress, suppress, suppress, suppress); } void GetResultLength(int tab_index, int* length) { ASSERT_LT(tab_index, browser()->tab_count()); ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractInt( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", kGetResultLengthJS, length)); } void CheckResult(int tab_index, int length, const char* const result[]) { ASSERT_LT(tab_index, browser()->tab_count()); int actual_length; ASSERT_NO_FATAL_FAILURE(GetResultLength(tab_index, &actual_length)); ASSERT_GE(actual_length, length); for (int i = 0; i < actual_length; ++i) { std::string actual; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", StringPrintf(kGetResultJS, i), &actual)); // If more events were received than expected, then the additional events // must be keyup events. if (i < length) ASSERT_STREQ(result[i], actual.c_str()); else ASSERT_EQ('U', actual[0]); } } void CheckFocusedElement(int tab_index, const wchar_t* focused) { ASSERT_LT(tab_index, browser()->tab_count()); std::string actual; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", kGetFocusedElementJS, &actual)); ASSERT_EQ(WideToUTF8(focused), actual); } void SetFocusedElement(int tab_index, const wchar_t* focused) { ASSERT_LT(tab_index, browser()->tab_count()); bool actual; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", StringPrintf(kSetFocusedElementJS, focused), &actual)); ASSERT_TRUE(actual); } void CheckTextBoxValue(int tab_index, const wchar_t* id, const wchar_t* value) { ASSERT_LT(tab_index, browser()->tab_count()); std::string actual; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", StringPrintf(kGetTextBoxValueJS, id), &actual)); ASSERT_EQ(WideToUTF8(value), actual); } void SetTextBoxValue(int tab_index, const wchar_t* id, const wchar_t* value) { ASSERT_LT(tab_index, browser()->tab_count()); std::string actual; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", StringPrintf(kSetTextBoxValueJS, id, value), &actual)); ASSERT_EQ(WideToUTF8(value), actual); } void StartTest(int tab_index, int result_length) { ASSERT_LT(tab_index, browser()->tab_count()); bool actual; ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( browser()->GetTabContentsAt(tab_index)->render_view_host(), L"", StringPrintf(kStartTestJS, result_length), &actual)); ASSERT_TRUE(actual); } void TestKeyEvent(int tab_index, const KeyEventTestData& test) { ASSERT_LT(tab_index, browser()->tab_count()); ASSERT_EQ(tab_index, browser()->selected_index()); // Inform our testing web page that we are about to start testing a key // event. ASSERT_NO_FATAL_FAILURE(StartTest(tab_index, test.result_length)); ASSERT_NO_FATAL_FAILURE(SuppressEvents( tab_index, test.suppress_keydown, test.suppress_keypress, test.suppress_keyup, test.suppress_textinput)); // We need to create a finish observer before sending the key event, // because the test finished message might be arrived before returning // from the SendKeyPressSync() method. TestFinishObserver finish_observer( browser()->GetTabContentsAt(tab_index)->render_view_host()); ASSERT_TRUE(ui_test_utils::SendKeyPressSync( browser(), test.key, test.ctrl, test.shift, test.alt, test.command)); ASSERT_TRUE(finish_observer.WaitForFinish()); ASSERT_NO_FATAL_FAILURE(CheckResult( tab_index, test.result_length, test.result)); } std::string GetTestDataDescription(const KeyEventTestData& data) { std::string desc = StringPrintf( " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d, command:%d\n" " Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n" " Expected results(%d):\n", data.key, data.ctrl, data.shift, data.alt, data.command, data.suppress_keydown, data.suppress_keypress, data.suppress_keyup, data.suppress_textinput, data.result_length); for (int i = 0; i < data.result_length; ++i) { desc.append(" "); desc.append(data.result[i]); desc.append("\n"); } return desc; } }; IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, NormalKeyEvents) { static const KeyEventTestData kTestNoInput[] = { // a { app::VKEY_A, false, false, false, false, false, false, false, false, 3, { "D 65 0 false false false false", "P 97 97 false false false false", "U 65 0 false false false false" } }, // shift-a { app::VKEY_A, false, true, false, false, false, false, false, false, 5, { "D 16 0 false true false false", "D 65 0 false true false false", "P 65 65 false true false false", "U 65 0 false true false false", "U 16 0 false true false false" } }, // a, suppress keydown { app::VKEY_A, false, false, false, false, true, false, false, false, 2, { "D 65 0 false false false false", "U 65 0 false false false false" } }, }; static const KeyEventTestData kTestWithInput[] = { // a { app::VKEY_A, false, false, false, false, false, false, false, false, 4, { "D 65 0 false false false false", "P 97 97 false false false false", "T a", "U 65 0 false false false false" } }, // shift-a { app::VKEY_A, false, true, false, false, false, false, false, false, 6, { "D 16 0 false true false false", "D 65 0 false true false false", "P 65 65 false true false false", "T A", "U 65 0 false true false false", "U 16 0 false true false false" } }, // a, suppress keydown { app::VKEY_A, false, false, false, false, true, false, false, false, 2, { "D 65 0 false false false false", "U 65 0 false false false false" } }, // a, suppress keypress { app::VKEY_A, false, false, false, false, false, true, false, false, 3, { "D 65 0 false false false false", "P 97 97 false false false false", "U 65 0 false false false false" } }, // a, suppress textInput { app::VKEY_A, false, false, false, false, false, false, false, true, 4, { "D 65 0 false false false false", "P 97 97 false false false false", "T a", "U 65 0 false false false false" } }, }; ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); int tab_index = browser()->selected_index(); for (size_t i = 0; i < arraysize(kTestNoInput); ++i) { EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestNoInput[i])) << "kTestNoInput[" << i << "] failed:\n" << GetTestDataDescription(kTestNoInput[i]); } // Input in normal text box. ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A")); for (size_t i = 0; i < arraysize(kTestWithInput); ++i) { EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i])) << "kTestWithInput[" << i << "] in text box failed:\n" << GetTestDataDescription(kTestWithInput[i]); } EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA")); // Input in password box. ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"B")); for (size_t i = 0; i < arraysize(kTestWithInput); ++i) { EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i])) << "kTestWithInput[" << i << "] in password box failed:\n" << GetTestDataDescription(kTestWithInput[i]); } EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"B", L"aA")); } #if defined(OS_WIN) || defined(OS_LINUX) IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) { static const KeyEventTestData kTestCtrlF = { app::VKEY_F, true, false, false, false, false, false, false, false, 2, { "D 17 0 true false false false", "D 70 0 true false false false" } }; static const KeyEventTestData kTestCtrlFSuppressKeyDown = { app::VKEY_F, true, false, false, false, true, false, false, false, 4, { "D 17 0 true false false false", "D 70 0 true false false false", "U 70 0 true false false false", "U 17 0 true false false false" } }; // Ctrl+Z doesn't bind to any accelerators, which then should generate a // keypress event with charCode=26. static const KeyEventTestData kTestCtrlZ = { app::VKEY_Z, true, false, false, false, false, false, false, false, 5, { "D 17 0 true false false false", "D 90 0 true false false false", "P 26 26 true false false false", "U 90 0 true false false false", "U 17 0 true false false false" } }; static const KeyEventTestData kTestCtrlZSuppressKeyDown = { app::VKEY_Z, true, false, false, false, true, false, false, false, 4, { "D 17 0 true false false false", "D 90 0 true false false false", "U 90 0 true false false false", "U 17 0 true false false false" } }; // Ctrl+Enter shall generate a keypress event with charCode=10 (LF). static const KeyEventTestData kTestCtrlEnter = { app::VKEY_RETURN, true, false, false, false, false, false, false, false, 5, { "D 17 0 true false false false", "D 13 0 true false false false", "P 10 10 true false false false", "U 13 0 true false false false", "U 17 0 true false false false" } }; ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); int tab_index = browser()->selected_index(); // Press Ctrl+F, which will make the Find box open and request focus. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF)); EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); // Press Escape to close the Find box and move the focus back to the web page. ASSERT_TRUE(ui_test_utils::SendKeyPressSync( browser(), app::VKEY_ESCAPE, false, false, false, false)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Press Ctrl+F with keydown suppressed shall not open the find box. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlFSuppressKeyDown)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZ)); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZSuppressKeyDown)); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlEnter)); } #elif defined(OS_MACOSX) IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CommandKeyEvents) { static const KeyEventTestData kTestCmdF = { app::VKEY_F, false, false, false, true, false, false, false, false, 2, { "D 91 0 false false false true", "D 70 0 false false false true" } }; // On Mac we don't send key up events when command modifier is down. static const KeyEventTestData kTestCmdFSuppressKeyDown = { app::VKEY_F, false, false, false, true, true, false, false, false, 3, { "D 91 0 false false false true", "D 70 0 false false false true", "U 91 0 false false false true" } }; ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); int tab_index = browser()->selected_index(); // Press Cmd+F, which will make the Find box open and request focus. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdF)); EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); // Press Escape to close the Find box and move the focus back to the web page. ASSERT_TRUE(ui_test_utils::SendKeyPressSync( browser(), app::VKEY_ESCAPE, false, false, false, false)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Press Cmd+F with keydown suppressed shall not open the find box. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdFSuppressKeyDown)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); } #endif #if defined(OS_WIN) // Tests may fail on windows: http://crbug.com/55713 #define MAYBE_AccessKeys FLAKY_AccessKeys #else #define MAYBE_AccessKeys AccessKeys #endif IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) { #if defined(OS_MACOSX) // On Mac, access keys use ctrl+alt modifiers. static const KeyEventTestData kTestAccessA = { app::VKEY_A, true, false, true, false, false, false, false, false, 6, { "D 17 0 true false false false", "D 18 0 true false true false", "D 65 0 true false true false", "U 65 0 true false true false", "U 18 0 true false true false", "U 17 0 true false false false" } }; static const KeyEventTestData kTestAccessDSuppress = { app::VKEY_D, true, false, true, false, true, true, true, false, 6, { "D 17 0 true false false false", "D 18 0 true false true false", "D 68 0 true false true false", "U 68 0 true false true false", "U 18 0 true false true false", "U 17 0 true false false false" } }; static const KeyEventTestData kTestAccess1 = { app::VKEY_1, true, false, true, false, false, false, false, false, 6, { "D 17 0 true false false false", "D 18 0 true false true false", "D 49 0 true false true false", "U 49 0 true false true false", "U 18 0 true false true false", "U 17 0 true false false false" } }; #else static const KeyEventTestData kTestAccessA = { app::VKEY_A, false, false, true, false, false, false, false, false, 4, { "D 18 0 false false true false", "D 65 0 false false true false", "U 65 0 false false true false", "U 18 0 false false true false" } }; static const KeyEventTestData kTestAccessD = { app::VKEY_D, false, false, true, false, false, false, false, false, 2, { "D 18 0 false false true false", "D 68 0 false false true false" } }; static const KeyEventTestData kTestAccessDSuppress = { app::VKEY_D, false, false, true, false, true, true, true, false, 4, { "D 18 0 false false true false", "D 68 0 false false true false", "U 68 0 false false true false", "U 18 0 false false true false" } }; static const KeyEventTestData kTestAccess1 = { app::VKEY_1, false, false, true, false, false, false, false, false, 4, { "D 18 0 false false true false", "D 49 0 false false true false", "U 49 0 false false true false", "U 18 0 false false true false" } }; #endif ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ui_test_utils::RunAllPendingInMessageLoop(); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); int tab_index = browser()->selected_index(); // Make sure no element is focused. EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"")); // Alt+A should focus the element with accesskey = "A". EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessA)); EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"A")); // Blur the focused element. EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"")); // Make sure no element is focused. EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"")); #if !defined(OS_MACOSX) // Alt+D should move the focus to the location entry. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessD)); // TODO(isherman): This is an experimental change to help diagnose // http://crbug.com/55713 ui_test_utils::RunAllPendingInMessageLoop(); EXPECT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // No element should be focused, as Alt+D was handled by the browser. EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"")); // Move the focus back to the web page. ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Make sure no element is focused. EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"")); #endif // If the keydown event is suppressed, then Alt+D should be handled as an // accesskey rather than an accelerator key. Activation of an accesskey is not // a part of the default action of the key event, so it should not be // suppressed at all. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessDSuppress)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"D")); // Blur the focused element. EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"")); // Make sure no element is focused. EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"")); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccess1)); #if defined(TOOLKIT_GTK) // On GTK, alt-0..9 are assigned as tab selection accelerators, so they can // not be used as accesskeys. EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"")); #else EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1")); #endif } #if defined(OS_MACOSX) // See http://crbug.com/50447 for details. #define MAYBE_ReservedAccelerators FLAKY_ReservedAccelerators #else #define MAYBE_ReservedAccelerators ReservedAccelerators #endif IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) { ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); #if defined(OS_WIN) || defined(TOOLKIT_VIEWS) static const KeyEventTestData kTestCtrlT = { app::VKEY_T, true, false, false, false, true, false, false, false, 1, { "D 17 0 true false false false" } }; ASSERT_EQ(1, browser()->tab_count()); // Press Ctrl+T, which will open a new tab. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlT)); EXPECT_EQ(2, browser()->tab_count()); browser()->SelectNumberedTab(0); ASSERT_EQ(0, browser()->selected_index()); int result_length; ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length)); EXPECT_EQ(1, result_length); // Reserved accelerators can't be suppressed. ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true)); // Press Ctrl+W, which will close the tab. ASSERT_TRUE(ui_test_utils::SendKeyPressSync( browser(), app::VKEY_W, true, false, false, false)); EXPECT_EQ(1, browser()->tab_count()); #elif defined(OS_MACOSX) static const KeyEventTestData kTestCmdT = { app::VKEY_T, false, false, false, true, true, false, false, false, 1, { "D 91 0 false false false true" } }; ASSERT_EQ(1, browser()->tab_count()); // Press Cmd+T, which will open a new tab. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCmdT)); EXPECT_EQ(2, browser()->tab_count()); browser()->SelectNumberedTab(0); ASSERT_EQ(0, browser()->selected_index()); int result_length; ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length)); EXPECT_EQ(1, result_length); // Reserved accelerators can't be suppressed. ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true)); // Press Cmd+W, which will close the tab. ASSERT_TRUE(ui_test_utils::SendKeyPressSync( browser(), app::VKEY_W, false, false, false, true)); EXPECT_EQ(1, browser()->tab_count()); #elif defined(TOOLKIT_GTK) // Ctrl-[a-z] are not treated as reserved accelerators on GTK. static const KeyEventTestData kTestCtrlT = { app::VKEY_T, true, false, false, false, false, false, false, false, 2, { "D 17 0 true false false false", "D 84 0 true false false false" } }; static const KeyEventTestData kTestCtrlPageDown = { app::VKEY_NEXT, true, false, false, false, true, false, false, false, 1, { "D 17 0 true false false false" } }; static const KeyEventTestData kTestCtrlTab = { app::VKEY_TAB, true, false, false, false, true, false, false, false, 1, { "D 17 0 true false false false" } }; static const KeyEventTestData kTestCtrlTBlocked = { app::VKEY_T, true, false, false, false, true, false, false, false, 4, { "D 17 0 true false false false", "D 84 0 true false false false", "U 84 0 true false false false", "U 17 0 true false false false" } }; static const KeyEventTestData kTestCtrlWBlocked = { app::VKEY_W, true, false, false, false, true, false, false, false, 4, { "D 17 0 true false false false", "D 87 0 true false false false", "U 87 0 true false false false", "U 17 0 true false false false" } }; ASSERT_EQ(1, browser()->tab_count()); // Ctrl+T should be blockable. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlTBlocked)); ASSERT_EQ(1, browser()->tab_count()); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlT)); ASSERT_EQ(2, browser()->tab_count()); ASSERT_EQ(1, browser()->selected_index()); browser()->SelectNumberedTab(0); ASSERT_EQ(0, browser()->selected_index()); // Ctrl+PageDown and Ctrl+Tab switches to the next tab. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlPageDown)); ASSERT_EQ(1, browser()->selected_index()); browser()->SelectNumberedTab(0); ASSERT_EQ(0, browser()->selected_index()); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlTab)); ASSERT_EQ(1, browser()->selected_index()); // Ctrl+W should be blockable. browser()->SelectNumberedTab(0); ASSERT_EQ(0, browser()->selected_index()); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlWBlocked)); ASSERT_EQ(2, browser()->tab_count()); // Ctrl+F4 to close the tab. ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true)); ASSERT_TRUE(ui_test_utils::SendKeyPressSync( browser(), app::VKEY_F4, true, false, false, false)); ASSERT_EQ(1, browser()->tab_count()); #endif } #if defined(OS_MACOSX) IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) { static const KeyEventTestData kTestCtrlA = { app::VKEY_A, true, false, false, false, false, false, false, false, 4, { "D 17 0 true false false false", "D 65 0 true false false false", "U 65 0 true false false false", "U 17 0 true false false false" } }; static const KeyEventTestData kTestCtrlF = { app::VKEY_F, true, false, false, false, false, false, false, false, 4, { "D 17 0 true false false false", "D 70 0 true false false false", "U 70 0 true false false false", "U 17 0 true false false false" } }; static const KeyEventTestData kTestCtrlK = { app::VKEY_K, true, false, false, false, false, false, false, false, 4, { "D 17 0 true false false false", "D 75 0 true false false false", "U 75 0 true false false false", "U 17 0 true false false false" } }; ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); int tab_index = browser()->selected_index(); ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A")); ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index, L"A", L"Hello")); // Move the caret to the beginning of the line. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlA)); // Forward one character EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF)); // Delete to the end of the line. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlK)); EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"H")); } #endif IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, PageUpDownKeys) { static const KeyEventTestData kTestPageUp = { app::VKEY_PRIOR, false, false, false, false, false, false, false, false, 2, { "D 33 0 false false false false", "U 33 0 false false false false" } }; static const KeyEventTestData kTestPageDown = { app::VKEY_NEXT, false, false, false, false, false, false, false, false, 2, { "D 34 0 false false false false", "U 34 0 false false false false" } }; ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); int tab_index = browser()->selected_index(); ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A")); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageUp)); EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageDown)); EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"")); } #if defined(OS_WIN) || defined(TOOLKIT_VIEWS) IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FocusMenuBarByAltKey) { static const KeyEventTestData kTestAltKey = { app::VKEY_MENU, false, false, false, false, false, false, false, false, 2, { "D 18 0 false false true false", "U 18 0 false false true false" } }; static const KeyEventTestData kTestAltKeySuppress = { app::VKEY_MENU, false, false, false, false, true, false, false, false, 2, { "D 18 0 false false true false", "U 18 0 false false true false" } }; static const KeyEventTestData kTestCtrlAltKey = { app::VKEY_MENU, true, false, false, false, false, false, false, false, 4, { "D 17 0 true false false false", "D 18 0 true false true false", "U 18 0 true false true false", "U 17 0 true false false false" } }; ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); GURL url = test_server()->GetURL(kTestingPage); ui_test_utils::NavigateToURL(browser(), url); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); int tab_index = browser()->selected_index(); // Press and release Alt key to focus wrench menu button. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKey)); EXPECT_TRUE(IsViewFocused(VIEW_ID_APP_MENU)); ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Alt key can be suppressed. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKeySuppress)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Ctrl+Alt should have no effect. EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlAltKey)); ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); } #endif } // namespace