diff options
-rw-r--r-- | base/keyboard_code_conversion_gtk.cc | 74 | ||||
-rw-r--r-- | base/keyboard_code_conversion_gtk.h | 2 | ||||
-rw-r--r-- | chrome/browser/automation/ui_controls_linux.cc | 9 | ||||
-rw-r--r-- | chrome/browser/browser_focus_uitest.cc | 133 | ||||
-rw-r--r-- | chrome/browser/browser_keyevents_browsertest.cc | 570 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 9 | ||||
-rw-r--r-- | chrome/test/data/keyevents_test.html | 165 | ||||
-rw-r--r-- | chrome/test/interactive_ui/interactive_ui_tests.gypi | 2 | ||||
-rw-r--r-- | chrome/test/ui_test_utils.h | 7 | ||||
-rw-r--r-- | chrome/test/ui_test_utils_linux.cc | 72 | ||||
-rw-r--r-- | chrome/test/ui_test_utils_mac.cc | 20 | ||||
-rw-r--r-- | chrome/test/ui_test_utils_win.cc | 42 |
12 files changed, 958 insertions, 147 deletions
diff --git a/base/keyboard_code_conversion_gtk.cc b/base/keyboard_code_conversion_gtk.cc index b56461f..28727c4 100644 --- a/base/keyboard_code_conversion_gtk.cc +++ b/base/keyboard_code_conversion_gtk.cc @@ -411,7 +411,7 @@ base::KeyboardCode WindowsKeyCodeForGdkKeyCode(int keycode) { } // TODO(jcampan): this method might be incomplete. -int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode) { +int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode, bool shift) { switch (keycode) { case VKEY_NUMPAD0: return GDK_KP_0; @@ -447,7 +447,7 @@ int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode) { case VKEY_BACK: return GDK_BackSpace; case VKEY_TAB: - return GDK_Tab; + return shift ? GDK_ISO_Left_Tab : GDK_Tab; case VKEY_CLEAR: return GDK_Clear; case VKEY_RETURN: @@ -500,78 +500,54 @@ int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode) { case VKEY_HELP: return GDK_Help; case VKEY_0: - return GDK_0; + return shift ? GDK_parenright : GDK_0; case VKEY_1: - return GDK_1; + return shift ? GDK_exclam : GDK_1; case VKEY_2: - return GDK_2; + return shift ? GDK_at : GDK_2; case VKEY_3: - return GDK_3; + return shift ? GDK_numbersign : GDK_3; case VKEY_4: - return GDK_4; + return shift ? GDK_dollar : GDK_4; case VKEY_5: - return GDK_5; + return shift ? GDK_percent : GDK_5; case VKEY_6: - return GDK_6; + return shift ? GDK_asciicircum : GDK_6; case VKEY_7: - return GDK_7; + return shift ? GDK_ampersand : GDK_7; case VKEY_8: - return GDK_8; + return shift ? GDK_asterisk : GDK_8; case VKEY_9: - return GDK_9; + return shift ? GDK_parenleft : GDK_9; case VKEY_A: - return GDK_a; case VKEY_B: - return GDK_b; case VKEY_C: - return GDK_c; case VKEY_D: - return GDK_d; case VKEY_E: - return GDK_e; case VKEY_F: - return GDK_f; case VKEY_G: - return GDK_g; case VKEY_H: - return GDK_h; case VKEY_I: - return GDK_i; case VKEY_J: - return GDK_j; case VKEY_K: - return GDK_k; case VKEY_L: - return GDK_l; case VKEY_M: - return GDK_m; case VKEY_N: - return GDK_n; case VKEY_O: - return GDK_o; case VKEY_P: - return GDK_p; case VKEY_Q: - return GDK_q; case VKEY_R: - return GDK_r; case VKEY_S: - return GDK_s; case VKEY_T: - return GDK_t; case VKEY_U: - return GDK_u; case VKEY_V: - return GDK_v; case VKEY_W: - return GDK_w; case VKEY_X: - return GDK_x; case VKEY_Y: - return GDK_y; case VKEY_Z: - return GDK_z; + return (shift ? GDK_A : GDK_a) + (keycode - VKEY_A); + case VKEY_LWIN: return GDK_Meta_L; case VKEY_RWIN: @@ -584,27 +560,27 @@ int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode) { return GDK_Scroll_Lock; case VKEY_OEM_1: - return GDK_semicolon; + return shift ? GDK_colon : GDK_semicolon; case VKEY_OEM_PLUS: - return GDK_plus; + return shift ? GDK_plus : GDK_equal; case VKEY_OEM_COMMA: - return GDK_comma; + return shift ? GDK_less : GDK_comma; case VKEY_OEM_MINUS: - return GDK_minus; + return shift ? GDK_underscore : GDK_minus; case VKEY_OEM_PERIOD: - return GDK_period; + return shift ? GDK_greater : GDK_period; case VKEY_OEM_2: - return GDK_slash; + return shift ? GDK_question : GDK_slash; case VKEY_OEM_3: - return GDK_asciitilde; + return shift ? GDK_asciitilde : GDK_quoteleft; case VKEY_OEM_4: - return GDK_bracketleft; + return shift ? GDK_braceleft : GDK_bracketleft; case VKEY_OEM_5: - return GDK_backslash; + return shift ? GDK_bar : GDK_backslash; case VKEY_OEM_6: - return GDK_bracketright; + return shift ? GDK_braceright : GDK_bracketright; case VKEY_OEM_7: - return GDK_quoteright; + return shift ? GDK_quotedbl : GDK_quoteright; case VKEY_F1: case VKEY_F2: diff --git a/base/keyboard_code_conversion_gtk.h b/base/keyboard_code_conversion_gtk.h index 1f1e3b6..2ad6b12 100644 --- a/base/keyboard_code_conversion_gtk.h +++ b/base/keyboard_code_conversion_gtk.h @@ -42,7 +42,7 @@ namespace base { base::KeyboardCode WindowsKeyCodeForGdkKeyCode(int keycode); -int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode); +int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode, bool shift); } // namespace diff --git a/chrome/browser/automation/ui_controls_linux.cc b/chrome/browser/automation/ui_controls_linux.cc index 544816b..f0e04a1 100644 --- a/chrome/browser/automation/ui_controls_linux.cc +++ b/chrome/browser/automation/ui_controls_linux.cc @@ -197,23 +197,24 @@ bool SendKeyPress(gfx::NativeWindow window, (shift ? GDK_SHIFT_MASK : 0) | (alt ? GDK_MOD1_MASK : 0); - guint gdk_key = base::GdkKeyCodeForWindowsKeyCode(key); + guint gdk_key = base::GdkKeyCodeForWindowsKeyCode(key, shift); rv = rv && SendKeyEvent(event_window, true, gdk_key, state); rv = rv && SendKeyEvent(event_window, false, gdk_key, state); if (alt) { guint state = (control ? GDK_CONTROL_MASK : 0) | - (shift ? GDK_SHIFT_MASK : 0); + (shift ? GDK_SHIFT_MASK : 0) | GDK_MOD1_MASK; rv = rv && SendKeyEvent(event_window, false, GDK_Alt_L, state); } if (shift) { rv = rv && SendKeyEvent(event_window, false, GDK_Shift_L, - control ? GDK_CONTROL_MASK : 0); + (control ? GDK_CONTROL_MASK : 0) | GDK_SHIFT_MASK); } if (control) - rv = rv && SendKeyEvent(event_window, false, GDK_Control_L, 0); + rv = rv && SendKeyEvent(event_window, false, GDK_Control_L, + GDK_CONTROL_MASK); return rv; } diff --git a/chrome/browser/browser_focus_uitest.cc b/chrome/browser/browser_focus_uitest.cc index d9d9ebf..7a07b1e 100644 --- a/chrome/browser/browser_focus_uitest.cc +++ b/chrome/browser/browser_focus_uitest.cc @@ -58,45 +58,12 @@ class BrowserFocusTest : public InProcessBrowserTest { EnableDOMAutomation(); } - void CheckViewHasFocus(ViewID vid) { - BrowserWindow* browser_window = browser()->window(); - ASSERT_TRUE(browser_window); - gfx::NativeWindow window = browser_window->GetNativeHandle(); - ASSERT_TRUE(window); -#if defined(OS_WIN) - views::FocusManager* focus_manager = - views::FocusManager::GetFocusManagerForNativeView(window); - ASSERT_TRUE(focus_manager); - EXPECT_EQ(vid, focus_manager->GetFocusedView()->GetID()) << - "For view id " << vid; -#elif defined(OS_LINUX) - GtkWidget* widget = ViewIDUtil::GetWidget(GTK_WIDGET(window), vid); - ASSERT_TRUE(widget); - EXPECT_TRUE(WidgetInFocusChain(GTK_WIDGET(window), widget)) << - "For view id " << vid; -#else - NOTIMPLEMENTED(); -#endif + bool IsViewFocused(ViewID vid) { + return ui_test_utils::IsViewFocused(browser(), vid); } void ClickOnView(ViewID vid) { - BrowserWindow* browser_window = browser()->window(); - ASSERT_TRUE(browser_window); -#if defined(TOOLKIT_VIEWS) - views::View* view = - reinterpret_cast<BrowserView*>(browser_window)->GetViewByID(vid); -#elif defined(OS_LINUX) - gfx::NativeWindow window = browser_window->GetNativeHandle(); - ASSERT_TRUE(window); - GtkWidget* view = ViewIDUtil::GetWidget(GTK_WIDGET(window), vid); -#endif - ASSERT_TRUE(view); - ui_controls::MoveMouseToCenterAndPress( - view, - ui_controls::LEFT, - ui_controls::DOWN | ui_controls::UP, - new MessageLoop::QuitTask()); - ui_test_utils::RunMessageLoop(); + ui_test_utils::ClickOnView(browser(), vid); } static void HideNativeWindow(gfx::NativeWindow window) { @@ -122,26 +89,6 @@ class BrowserFocusTest : public InProcessBrowserTest { NOTIMPLEMENTED(); #endif } - - private: -#if defined(OS_LINUX) - // Check if the focused widget for |root| is |target| or a child of |target|. - static bool WidgetInFocusChain(GtkWidget* root, GtkWidget* target) { - GtkWidget* iter = root; - - while (iter) { - if (iter == target) - return true; - - if (!GTK_IS_CONTAINER(iter)) - return false; - - iter = GTK_CONTAINER(iter)->focus_child; - } - - return false; - } -#endif }; class TestInterstitialPage : public InterstitialPage { @@ -228,13 +175,13 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, ClickingMovesFocus) { ui_test_utils::RunMessageLoop(); #endif - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); ClickOnView(VIEW_ID_TAB_CONTAINER); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); ClickOnView(VIEW_ID_LOCATION_BAR); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); } IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) { @@ -247,18 +194,18 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) { gfx::NativeWindow window = browser()->window()->GetNativeHandle(); // The focus should be on the Tab contents. - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Now hide the window, show it again, the focus should not have changed. HideNativeWindow(window); ShowNativeWindow(window); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); browser()->FocusLocationBar(); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Hide the window, show it again, the focus should not have changed. HideNativeWindow(window); ShowNativeWindow(window); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // The rest of this test does not make sense on Linux because the behavior // of Activate() is not well defined and can vary by window manager. @@ -283,7 +230,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) { // Switch to the 1st browser window, focus should still be on the location // bar and the second browser should have nothing focused. browser()->window()->Activate(); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); EXPECT_EQ(NULL, focus_manager2->GetFocusedView()); // Switch back to the second browser, focus should still be on the page. @@ -340,7 +287,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) { ViewID vid = kFocusPage[i][j] ? VIEW_ID_TAB_CONTAINER_FOCUS_VIEW : VIEW_ID_LOCATION_BAR; - CheckViewHasFocus(vid); + ASSERT_TRUE(IsViewFocused(vid)); } } } @@ -357,7 +304,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabsRememberFocusFindInPage) { browser()->Find(); ui_test_utils::FindInPage(browser()->GetSelectedTabContents(), ASCIIToUTF16("a"), true, false, NULL); - CheckViewHasFocus(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); + ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); // Focus the location bar. browser()->FocusLocationBar(); @@ -367,21 +314,21 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, DISABLED_TabsRememberFocusFindInPage) { false, NULL); // Focus should be on the recently opened tab page. - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Select 1st tab, focus should still be on the location-bar. // (bug http://crbug.com/23296) browser()->SelectTabContentsAt(0, true); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Now open the find box again, switch to another tab and come back, the focus // should return to the find box. browser()->Find(); - CheckViewHasFocus(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); + ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); browser()->SelectTabContentsAt(1, true); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); browser()->SelectTabContentsAt(0, true); - CheckViewHasFocus(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); + ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); } // Background window does not steal focus. @@ -447,7 +394,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) { PlatformThread::Sleep(2000); // Make sure the location bar is still focused. - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); } // Focus traversal on a regular page. @@ -476,7 +423,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) { // Test forward focus traversal. for (int i = 0; i < 3; ++i) { // Location bar should be focused. - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Now let's press tab to move the focus. for (size_t j = 0; j < arraysize(kExpElementIDs); ++j) { @@ -510,7 +457,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) { // Now let's try reverse focus traversal. for (int i = 0; i < 3; ++i) { // Location bar should be focused. - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Now let's press shift-tab to move the focus in reverse. for (size_t j = 0; j < 7; ++j) { @@ -551,7 +498,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) { ui_test_utils::NavigateToURL(browser(), url); // Focus should be on the page. - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Let's show an interstitial. TestInterstitialPage* interstitial_page = @@ -578,7 +525,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) { // Test forward focus traversal. for (int i = 0; i < 2; ++i) { // Location bar should be focused. - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Now let's press tab to move the focus. for (size_t j = 0; j < 7; ++j) { @@ -606,7 +553,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) { // Now let's try reverse focus traversal. for (int i = 0; i < 2; ++i) { // Location bar should be focused. - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Now let's press shift-tab to move the focus in reverse. for (size_t j = 0; j < 7; ++j) { @@ -641,7 +588,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) { ui_test_utils::NavigateToURL(browser(), url); // Page should have focus. - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); EXPECT_TRUE(browser()->GetSelectedTabContents()->render_view_host()->view()-> HasFocus()); @@ -657,14 +604,14 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) { ui_test_utils::RunMessageLoop(); // The interstitial should have focus now. - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); EXPECT_TRUE(interstitial_page->HasFocus()); // Hide the interstitial. interstitial_page->DontProceed(); // Focus should be back on the original page. - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); } // Make sure Find box can request focus, even when it is already open. @@ -692,21 +639,21 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) { FROM_HERE, new MessageLoop::QuitTask(), kActionDelayMs); ui_test_utils::RunMessageLoop(); - CheckViewHasFocus(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); + ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); browser()->FocusLocationBar(); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Now press Ctrl+F again and focus should move to the Find box. ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true, false, false, new MessageLoop::QuitTask()); ui_test_utils::RunMessageLoop(); - CheckViewHasFocus(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); + ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); // Set focus to the page. ClickOnView(VIEW_ID_TAB_CONTAINER); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Now press Ctrl+F again and focus should move to the Find box. ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true, false, @@ -717,7 +664,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) { MessageLoop::current()->PostDelayedTask( FROM_HERE, new MessageLoop::QuitTask(), kActionDelayMs); ui_test_utils::RunMessageLoop(); - CheckViewHasFocus(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD); + ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD)); } // Makes sure the focus is in the right location when opening the different @@ -725,20 +672,20 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) { IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabInitialFocus) { // Open the history tab, focus should be on the tab contents. browser()->ShowHistoryTab(); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Open the new tab, focus should be on the location bar. browser()->NewTab(); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Open the download tab, focus should be on the tab contents. browser()->ShowDownloadsTab(); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); // Open about:blank, focus should be on the location bar. browser()->AddTabWithURL(GURL("about:blank"), GURL(), PageTransition::LINK, true, -1, false, NULL); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); } // Tests that focus goes where expected when using reload. @@ -750,17 +697,17 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) { browser()->Reload(); ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); // Focus should stay on the location bar. - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); // Open a regular page, focus the location bar, reload. ui_test_utils::NavigateToURL(browser(), server->TestServerPageW(kSimplePage)); browser()->FocusLocationBar(); - CheckViewHasFocus(VIEW_ID_LOCATION_BAR); + ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR)); browser()->Reload(); ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); // Focus should now be on the tab contents. browser()->ShowDownloadsTab(); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); } // Tests that focus goes where expected when using reload on a crashed tab. @@ -774,5 +721,5 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReloadCrashedTab) { ASSERT_TRUE(ui_test_utils::WaitForNavigationInCurrentTab(browser())); // Focus should now be on the tab contents. browser()->ShowDownloadsTab(); - CheckViewHasFocus(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW); + ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW)); } diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc new file mode 100644 index 0000000..64f9be5 --- /dev/null +++ b/chrome/browser/browser_keyevents_browsertest.cc @@ -0,0 +1,570 @@ +// Copyright (c) 2009 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 "base/basictypes.h" +#include "base/keyboard_codes.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/automation/ui_controls.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.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" + +namespace { + +const wchar_t kTestingPage[] = L"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 kStartTestJS[] = + L"window.domAutomationController.send(startTest());"; + +// 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: +// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> +// where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup). +// <ctrlKey>, <shiftKey> and <altKey> are boolean value indicating the state of +// corresponding modifier key. +// For textInput event, the format is: T <text>, where <text> is the text to be +// input. +// Please refer to chrome/test/data/keyevents_test.html for details. +struct KeyEventTestData { + base::KeyboardCode key; + bool ctrl; + bool shift; + bool alt; + + 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<RenderViewHost>(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<DomOperationNotificationDetails> 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(); + } + + void GetNativeWindow(gfx::NativeWindow* native_window) { + BrowserWindow* window = browser()->window(); + ASSERT_TRUE(window); + *native_window = window->GetNativeHandle(); + ASSERT_TRUE(*native_window); + } + + void SendKey(base::KeyboardCode key, bool control, bool shift, bool alt) { + gfx::NativeWindow window = NULL; + ASSERT_NO_FATAL_FAILURE(GetNativeWindow(&window)); + ui_controls::SendKeyPressNotifyWhenDone(window, key, control, shift, alt, + new MessageLoop::QuitTask()); + ui_test_utils::RunMessageLoop(); + } + + 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 StartTest(int tab_index) { + ASSERT_LT(tab_index, browser()->tab_count()); + bool actual; + ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser()->GetTabContentsAt(tab_index)->render_view_host(), + L"", kStartTestJS, &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)); + 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 SendKey() method. + TestFinishObserver finish_observer( + browser()->GetTabContentsAt(tab_index)->render_view_host()); + + ASSERT_NO_FATAL_FAILURE(SendKey(test.key, test.ctrl, test.shift, test.alt)); + 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\n" + " Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n" + " Expected results(%d):\n", + data.key, data.ctrl, data.shift, data.alt, + 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; + } +}; + +} // namespace + +IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, NormalKeyEvents) { + static const KeyEventTestData kTestNoInput[] = { + // a + { base::VKEY_A, false, false, false, + false, false, false, false, 3, + { "D 65 0 false false false", + "P 97 97 false false false", + "U 65 0 false false false" } }, + // shift-a + { base::VKEY_A, false, true, false, + false, false, false, false, 5, + { "D 16 0 false true false", + "D 65 0 false true false", + "P 65 65 false true false", + "U 65 0 false true false", + "U 16 0 false true false" } }, + // a, suppress keydown + { base::VKEY_A, false, false, false, + true, false, false, false, 2, + { "D 65 0 false false false", + "U 65 0 false false false" } }, + }; + + static const KeyEventTestData kTestWithInput[] = { + // a + { base::VKEY_A, false, false, false, + false, false, false, false, 4, + { "D 65 0 false false false", + "P 97 97 false false false", + "T a", + "U 65 0 false false false" } }, + // shift-a + { base::VKEY_A, false, true, false, + false, false, false, false, 6, + { "D 16 0 false true false", + "D 65 0 false true false", + "P 65 65 false true false", + "T A", + "U 65 0 false true false", + "U 16 0 false true false" } }, + // a, suppress keydown + { base::VKEY_A, false, false, false, + true, false, false, false, 2, + { "D 65 0 false false false", + "U 65 0 false false false" } }, + // a, suppress keypress + { base::VKEY_A, false, false, false, + false, true, false, false, 3, + { "D 65 0 false false false", + "P 97 97 false false false", + "U 65 0 false false false" } }, + // a, suppress textInput + { base::VKEY_A, false, false, false, + false, false, false, true, 4, + { "D 65 0 false false false", + "P 97 97 false false false", + "T a", + "U 65 0 false false false" } }, + }; + + HTTPTestServer* server = StartHTTPServer(); + + GURL url = server->TestServerPageW(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]); + } + + 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 << "] failed:\n" + << GetTestDataDescription(kTestWithInput[i]); + } + + EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA")); +} + +IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) { + static const KeyEventTestData kTestCtrlF = { + base::VKEY_F, true, false, false, + false, false, false, false, 2, + { "D 17 0 true false false", + "D 70 0 true false false" } + }; + + static const KeyEventTestData kTestCtrlFSuppressKeyDown = { + base::VKEY_F, true, false, false, + true, false, false, false, 4, + { "D 17 0 true false false", + "D 70 0 true false false", + "U 70 0 true false false", + "U 17 0 true false false" } + }; + + // Ctrl+Z doesn't bind to any accelerators, which then should generate a + // keypress event with charCode=26. + static const KeyEventTestData kTestCtrlZ = { + base::VKEY_Z, true, false, false, + false, false, false, false, 5, + { "D 17 0 true false false", + "D 90 0 true false false", + "P 26 26 true false false", + "U 90 0 true false false", + "U 17 0 true false false" } + }; + + static const KeyEventTestData kTestCtrlZSuppressKeyDown = { + base::VKEY_Z, true, false, false, + true, false, false, false, 4, + { "D 17 0 true false false", + "D 90 0 true false false", + "U 90 0 true false false", + "U 17 0 true false false" } + }; + + // Ctrl+Enter shall generate a keypress event with charCode=10 (LF). + static const KeyEventTestData kTestCtrlEnter = { + base::VKEY_RETURN, true, false, false, + false, false, false, false, 5, + { "D 17 0 true false false", + "D 13 0 true false false", + "P 10 10 true false false", + "U 13 0 true false false", + "U 17 0 true false false" } + }; + + HTTPTestServer* server = StartHTTPServer(); + + GURL url = server->TestServerPageW(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_NO_FATAL_FAILURE(SendKey(base::VKEY_ESCAPE, 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)); +} + +IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, AccessKeys) { + static const KeyEventTestData kTestAltA = { + base::VKEY_A, false, false, true, + false, false, false, false, 4, + { "D 18 0 false false true", + "D 65 0 false false true", + "U 65 0 false false true", + "U 18 0 false false true" } + }; + + static const KeyEventTestData kTestAltD = { + base::VKEY_D, false, false, true, + false, false, false, false, 2, + { "D 18 0 false false true", + "D 68 0 false false true" } + }; + + static const KeyEventTestData kTestAltDSuppress = { + base::VKEY_D, false, false, true, + true, true, true, false, 4, + { "D 18 0 false false true", + "D 68 0 false false true", + "U 68 0 false false true", + "U 18 0 false false true" } + }; + + static const KeyEventTestData kTestAlt1 = { + base::VKEY_1, false, false, true, + false, false, false, false, 4, + { "D 18 0 false false true", + "D 49 0 false false true", + "U 49 0 false false true", + "U 18 0 false false true" } + }; + + HTTPTestServer* server = StartHTTPServer(); + + GURL url = server->TestServerPageW(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(); + // 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, kTestAltA)); + 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"")); + // Alt+D should move the focus to the location entry. + EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltD)); + 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"")); + // 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, kTestAltDSuppress)); + 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, kTestAlt1)); +#if defined(OS_LINUX) + // On Linux, 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"")); +#elif defined(OS_WIN) + EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1")); +#endif +} + +IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, ReservedAccelerators) { + static const KeyEventTestData kTestCtrlT = { + base::VKEY_T, true, false, false, + false, false, false, false, 1, + { "D 17 0 true false false" } + }; + + HTTPTestServer* server = StartHTTPServer(); + + GURL url = server->TestServerPageW(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_EQ(1, browser()->tab_count()); + // Press Ctrl+T, which will open a new tab. + EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlT)); + EXPECT_EQ(2, browser()->tab_count()); + browser()->SelectNumberedTab(tab_index); + ASSERT_EQ(tab_index, browser()->selected_index()); + + int result_length; + ASSERT_NO_FATAL_FAILURE(GetResultLength(tab_index, &result_length)); + EXPECT_EQ(1, result_length); + + // Reserved accelerators can't be suppressed. + ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(tab_index, true)); + // Press Ctrl+W, which will close the tab. + ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_W, true, false, false)); + EXPECT_EQ(1, browser()->tab_count()); +} diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 7a3f5b9..c22cdf0 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -3958,6 +3958,9 @@ 'test/testing_profile.h', 'test/ui_test_utils.cc', 'test/ui_test_utils.h', + 'test/ui_test_utils_linux.cc', + 'test/ui_test_utils_mac.cc', + 'test/ui_test_utils_win.cc', ], 'conditions': [ ['OS=="linux"', { @@ -6154,6 +6157,9 @@ 'test/test_notification_tracker.cc', 'test/test_notification_tracker.h', 'test/testing_browser_process.h', + 'test/ui_test_utils_linux.cc', + 'test/ui_test_utils_mac.cc', + 'test/ui_test_utils_win.cc', 'test/data/resource.h', 'test/data/resource.rc', '<(SHARED_INTERMEDIATE_DIR)/chrome/browser_resources.rc', @@ -6240,6 +6246,9 @@ 'test/test_launcher/run_all_unittests.cc', 'test/unit/chrome_test_suite.h', 'test/ui_test_utils.cc', + 'test/ui_test_utils_linux.cc', + 'test/ui_test_utils_mac.cc', + 'test/ui_test_utils_win.cc', 'app/chrome_dll.rc', 'app/chrome_dll_resource.h', 'app/chrome_dll_version.rc.version', diff --git a/chrome/test/data/keyevents_test.html b/chrome/test/data/keyevents_test.html new file mode 100644 index 0000000..140fad0 --- /dev/null +++ b/chrome/test/data/keyevents_test.html @@ -0,0 +1,165 @@ +<html><head> +<meta http-equiv="content-type" content="text/html; charset=utf-8"> +<script type="text/javascript"> +var defaultActions = { + 'keydown': true, + 'keypress': true, + 'keyup': true, + 'textInput': true, +}; +var keyEventResult = []; +var focusedElement = ""; +var lastFocusedElement = ""; +var testStarted = false; +var keyEventCount = 0; + +function init() { + document.addEventListener("keydown", handleEvent, false); + document.addEventListener("keypress", handleEvent, false); + document.addEventListener("keyup", handleEvent, false); + document.addEventListener("textInput", handleEvent, false); + window.addEventListener("blur", handleWindowBlur, false); +} + +function log(text) { + document.getElementById('log').innerHTML += text + '<br/>'; +} + +function setDefaultAction(type, value) { + defaultActions[type] = value; + document.getElementById(type).checked = !value; + return defaultActions[type]; +} + +function startTest() { + if (!testStarted) { + clearResult(); + testStarted = true; + log("Start test."); + return true; + } + return false; +} + +function finishTest() { + testStarted = false; + window.domAutomationController.setAutomationId(0); + window.domAutomationController.send("FINISHED"); + log("Finish test."); +} + +function handleEvent(e) { + var prefixes = { + 'keydown': 'D', + 'keypress': 'P', + 'keyup': 'U', + 'textInput': 'T', + }; + + var evt = e || window.event; + var result = prefixes[evt.type] + ' '; + if (evt.type == 'textInput') { + result += evt.data; + } else { + // On Linux, the keydown event of a modifier key doesn't have the + // corresponding modifier attribute set, while the keyup event does have, + // eg. pressing and releasing ctrl may generate a keydown event with + // ctrlKey=false and a keyup event with ctrlKey=true. + // But Windows and Mac have opposite behavior than Linux. + // To make the C++ testing code simpler, if it's a modifier key event, + // then ignores the corresponding modifier attribute by setting it to true. + var keyId = evt.keyIdentifier; + result += (evt.keyCode + ' ' + evt.charCode + ' ' + + (keyId == 'Control' ? true : evt.ctrlKey) + ' ' + + (keyId == 'Shift' ? true : evt.shiftKey) + ' ' + + (keyId == 'Alt' ? true : evt.altKey)); + } + keyEventResult.push(result); + log(result); + + if (testStarted) { + if (evt.type == "keydown") { + ++keyEventCount; + } else if (evt.type == "keyup") { + --keyEventCount; + if (keyEventCount == 0) + finishTest(); + } + } + + if (!defaultActions[evt.type]) { + if (evt.preventDefault) evt.preventDefault(); + if (evt.stopPropagation) evt.stopPropagation(); + } + return defaultActions[evt.type]; +} + +function handleWindowBlur() { + if (testStarted) + finishTest(); +} + +function clearResult() { + keyEventResult = []; + testStarted = false; + keyEventCount = 0; + document.getElementById('log').innerHTML = ""; + return true; +} + +function setFocusedElement(id) { + if (id == "" && focusedElement != "") { + var elem = document.getElementById(focusedElement); + if (elem) { + elem.blur(); + return true; + } + } else { + var elem = document.getElementById(id); + if (elem) { + elem.focus(); + return true; + } + } + return false; +} + +function onFocus(element) { + focusedElement = element.id; + log("Focus: " + focusedElement); +} + +function onBlur(element) { + focusedElement = ""; + lastFocusedElement = element.id; + log("Blur: " + element.id); +} + +function onClick(element) { + if (defaultActions[element.id] != undefined) + defaultActions[element.id] = !element.checked; +} +</script> +</head> +<body onload="init()"> + <input type="checkbox" id="keydown" onclick="onClick(this)">keydown</input> + <input type="checkbox" id="keypress" onclick="onClick(this)">keypress</input> + <input type="checkbox" id="keyup" onclick="onClick(this)">keyup</input> + <input type="checkbox" id="textInput" onclick="onClick(this)">textInput</input> + <br/> + <input type="checkbox" id="1" accesskey='1' + onfocus="onFocus(this)" onblur="onBlur(this)"/> + <input type="checkbox" id="2" accesskey='2' + onfocus="onFocus(this)" onblur="onBlur(this)"/> + <input type="checkbox" id="3" accesskey='3' + onfocus="onFocus(this)" onblur="onBlur(this)"/> + <input type="checkbox" id="D" accesskey='D' + onfocus="onFocus(this)" onblur="onBlur(this)"/> + <input type="text" id="A" accesskey="A" + onfocus="onFocus(this)" onblur="onBlur(this)"/> + <input type="text" id="B" accesskey="B" + onfocus="onFocus(this)" onblur="onBlur(this)"/> + <button id="clear" accesskey='C' onclick="clearResult()">Clear</button> + <p id="log"></p> +</body> +</html> diff --git a/chrome/test/interactive_ui/interactive_ui_tests.gypi b/chrome/test/interactive_ui/interactive_ui_tests.gypi index fa1f846..3e0ed2f 100644 --- a/chrome/test/interactive_ui/interactive_ui_tests.gypi +++ b/chrome/test/interactive_ui/interactive_ui_tests.gypi @@ -30,6 +30,7 @@ 'sources': [ '<(DEPTH)/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc', '<(DEPTH)/chrome/browser/browser_focus_uitest.cc', + '<(DEPTH)/chrome/browser/browser_keyevents_browsertest.cc', '<(DEPTH)/chrome/browser/debugger/devtools_sanity_unittest.cc', '<(DEPTH)/chrome/browser/views/bookmark_bar_view_test.cc', '<(DEPTH)/chrome/browser/blocked_popup_container_interactive_uitest.cc', @@ -73,6 +74,7 @@ # TODO(port) '<(DEPTH)/chrome/browser/autocomplete/autocomplete_edit_view_browsertest.cc', '<(DEPTH)/chrome/browser/browser_focus_uitest.cc', + '<(DEPTH)/chrome/browser/browser_keyevents_browsertest.cc', '<(DEPTH)/chrome/browser/debugger/devtools_sanity_unittest.cc', '<(DEPTH)/chrome/browser/views/bookmark_bar_view_test.cc', '<(DEPTH)/chrome/browser/blocked_popup_container_interactive_uitest.cc', diff --git a/chrome/test/ui_test_utils.h b/chrome/test/ui_test_utils.h index 59f32b1b..ae0d44e 100644 --- a/chrome/test/ui_test_utils.h +++ b/chrome/test/ui_test_utils.h @@ -9,6 +9,7 @@ #include "base/basictypes.h" #include "base/string16.h" +#include "chrome/browser/view_ids.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_type.h" @@ -122,6 +123,12 @@ int FindInPage(TabContents* tab, bool case_sensitive, int* ordinal); +// Returns true if the View is focused. +bool IsViewFocused(const Browser* browser, ViewID vid); + +// Simulates a mouse click on a View in the browser. +void ClickOnView(const Browser* browser, ViewID vid); + // Register |observer| for the given |type| and run the message loop until // either the observer posts a quit task or we timeout. void RegisterAndWait(NotificationType::Type type, diff --git a/chrome/test/ui_test_utils_linux.cc b/chrome/test/ui_test_utils_linux.cc new file mode 100644 index 0000000..95f757e --- /dev/null +++ b/chrome/test/ui_test_utils_linux.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2009 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 "chrome/test/ui_test_utils.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/automation/ui_controls.h" +#if defined(TOOLKIT_VIEWS) +#include "chrome/browser/views/frame/browser_view.h" +#endif + +#include "chrome/browser/gtk/view_id_util.h" + +namespace ui_test_utils { + +namespace { + +// Check if the focused widget for |root| is |target| or a child of |target|. +static bool IsWidgetInFocusChain(GtkWidget* root, GtkWidget* target) { + GtkWidget* iter = root; + + while (iter) { + if (iter == target) + return true; + + if (!GTK_IS_CONTAINER(iter)) + return false; + + iter = GTK_CONTAINER(iter)->focus_child; + } + + return false; +} + +} // namespace + +bool IsViewFocused(const Browser* browser, ViewID vid) { + BrowserWindow* browser_window = browser->window(); + DCHECK(browser_window); + gfx::NativeWindow window = browser_window->GetNativeHandle(); + DCHECK(window); + GtkWidget* widget = ViewIDUtil::GetWidget(GTK_WIDGET(window), vid); + DCHECK(widget); + return IsWidgetInFocusChain(GTK_WIDGET(window), widget); +} + +void ClickOnView(const Browser* browser, ViewID vid) { + BrowserWindow* browser_window = browser->window(); + DCHECK(browser_window); +#if defined(TOOLKIT_VIEWS) + views::View* view = + reinterpret_cast<BrowserView*>(browser_window)->GetViewByID(vid); +#else + gfx::NativeWindow window = browser_window->GetNativeHandle(); + DCHECK(window); + GtkWidget* view = ViewIDUtil::GetWidget(GTK_WIDGET(window), vid); +#endif + + DCHECK(view); + ui_controls::MoveMouseToCenterAndPress( + view, + ui_controls::LEFT, + ui_controls::DOWN | ui_controls::UP, + new MessageLoop::QuitTask()); + RunMessageLoop(); +} + +} // namespace ui_test_utils diff --git a/chrome/test/ui_test_utils_mac.cc b/chrome/test/ui_test_utils_mac.cc new file mode 100644 index 0000000..1e40666 --- /dev/null +++ b/chrome/test/ui_test_utils_mac.cc @@ -0,0 +1,20 @@ +// Copyright (c) 2009 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 "chrome/test/ui_test_utils.h" + +#include "base/logging.h" + +namespace ui_test_utils { + +bool IsViewFocused(const Browser* browser, ViewID vid) { + NOTIMPLEMENTED(); + return false; +} + +void ClickOnView(const Browser* browser, ViewID vid) { + NOTIMPLEMENTED(); +} + +} // namespace ui_test_utils diff --git a/chrome/test/ui_test_utils_win.cc b/chrome/test/ui_test_utils_win.cc new file mode 100644 index 0000000..22fa003 --- /dev/null +++ b/chrome/test/ui_test_utils_win.cc @@ -0,0 +1,42 @@ +// Copyright (c) 2009 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 "chrome/test/ui_test_utils.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_window.h" +#include "chrome/browser/automation/ui_controls.h" +#include "chrome/browser/views/frame/browser_view.h" +#include "views/focus/focus_manager.h" + +namespace ui_test_utils { + +bool IsViewFocused(const Browser* browser, ViewID vid) { + BrowserWindow* browser_window = browser->window(); + DCHECK(browser_window); + gfx::NativeWindow window = browser_window->GetNativeHandle(); + DCHECK(window); + views::FocusManager* focus_manager = + views::FocusManager::GetFocusManagerForNativeView(window); + DCHECK(focus_manager); + return focus_manager->GetFocusedView()->GetID() == vid; +} + +void ClickOnView(const Browser* browser, ViewID vid) { + BrowserWindow* browser_window = browser->window(); + DCHECK(browser_window); + views::View* view = + reinterpret_cast<BrowserView*>(browser_window)->GetViewByID(vid); + DCHECK(view); + ui_controls::MoveMouseToCenterAndPress( + view, + ui_controls::LEFT, + ui_controls::DOWN | ui_controls::UP, + new MessageLoop::QuitTask()); + RunMessageLoop(); +} + +} // namespace ui_test_utils |