summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/keyboard_code_conversion_gtk.cc74
-rw-r--r--base/keyboard_code_conversion_gtk.h2
-rw-r--r--chrome/browser/automation/ui_controls_linux.cc9
-rw-r--r--chrome/browser/browser_focus_uitest.cc133
-rw-r--r--chrome/browser/browser_keyevents_browsertest.cc570
-rwxr-xr-xchrome/chrome.gyp9
-rw-r--r--chrome/test/data/keyevents_test.html165
-rw-r--r--chrome/test/interactive_ui/interactive_ui_tests.gypi2
-rw-r--r--chrome/test/ui_test_utils.h7
-rw-r--r--chrome/test/ui_test_utils_linux.cc72
-rw-r--r--chrome/test/ui_test_utils_mac.cc20
-rw-r--r--chrome/test/ui_test_utils_win.cc42
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