summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsuzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-23 02:52:06 +0000
committersuzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-23 02:52:06 +0000
commit21abcc74837a6cb9537a8026a1b12efc9da402f0 (patch)
tree9860885689c7af40e05a14513b09a98dc8642542
parent44c8966e5995e827d0d0b3fd2d4fcee0f56bbdff (diff)
downloadchromium_src-21abcc74837a6cb9537a8026a1b12efc9da402f0.zip
chromium_src-21abcc74837a6cb9537a8026a1b12efc9da402f0.tar.gz
chromium_src-21abcc74837a6cb9537a8026a1b12efc9da402f0.tar.bz2
Implements tests for testing browser's overall key events handling behavior.
This CL implements some basic tests for testing browser's overall key events handling behavior. This CL depends on http://codereview.chromium.org/235039 and http://codereview.chromium.org/195062. Currently, only Linux and Windows are supported. The tests assume US keyboard layout is used and no IME is activated. We still need to investigate how to write tests that involving different keyboard layout and input methods. BUG=none TEST=none Review URL: http://codereview.chromium.org/268035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29866 0039d316-1c4b-4281-b951-d872f2087c98
-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