summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsuzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-27 21:17:57 +0000
committersuzhe@chromium.org <suzhe@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-27 21:17:57 +0000
commit853300a85cf5390d7e7e25fcf5acf391306c94f8 (patch)
tree00d89c84c2855562fed93e64f04a3180eb70d99b
parent7fdad3a542e60dd9426e103b813421f3d1b37b40 (diff)
downloadchromium_src-853300a85cf5390d7e7e25fcf5acf391306c94f8.zip
chromium_src-853300a85cf5390d7e7e25fcf5acf391306c94f8.tar.gz
chromium_src-853300a85cf5390d7e7e25fcf5acf391306c94f8.tar.bz2
[Mac]Port browser_keyevents_browsertest.cc and browser_focus_uitest.cc to Mac.
This CL includes: 1. Implementation of ui_test_utils_mac.mm 2. Fix for ui_controls_mac.mm 3. Port browser_keyevents_browsertest.cc to Mac and add some new tests for Mac. 4. Partially port browser_focus_uitest.cc to Mac, now can be compiled and run on Mac but some tests fail. 5. Add two functions into ui_test_utils.h: HideNativeWindow() and ShowAndFocusNativeWindow(). The latter one shows a window and grabs the input focus, which is useful for tests depending on fake keyboard/mouse events. Because browser_keyevents_browsertests.cc and browser_focus_uitest.cc belong to interactive_ui_tests, which is not available on Mac (see http://crbug.com/21276), in order to test them on Mac, you may want to move them into browser_tests locally. But it won't work on build and try bots, because these tests must be run with screen unlocked. This CL depends on CL: http://codereview.chromium.org/2973004 and http://codereview.chromium.org/2805075 BUG=22515 Keyboard handling needs unit tests BUG=48671 interactive_ui_test: BrowserKeyEventsTest.NormalKeyEvents is flaky BUG=48936 Browser window is opened inactivated when running an InProcessBrowserTest. TEST=none Review URL: http://codereview.chromium.org/2986004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53840 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/base.gypi2
-rw-r--r--base/keyboard_code_conversion_gtk.cc7
-rw-r--r--base/keyboard_code_conversion_mac.h34
-rw-r--r--base/keyboard_code_conversion_mac.mm293
-rw-r--r--chrome/browser/automation/ui_controls.h4
-rw-r--r--chrome/browser/automation/ui_controls_internal.h40
-rw-r--r--chrome/browser/automation/ui_controls_linux.cc22
-rw-r--r--chrome/browser/automation/ui_controls_mac.mm270
-rw-r--r--chrome/browser/browser_focus_uitest.cc102
-rw-r--r--chrome/browser/browser_keyevents_browsertest.cc485
-rw-r--r--chrome/chrome_browser.gypi1
-rw-r--r--chrome/chrome_tests.gypi4
-rw-r--r--chrome/test/data/keyevents_test.html25
-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.cc8
-rw-r--r--chrome/test/ui_test_utils_mac.cc31
-rw-r--r--chrome/test/ui_test_utils_mac.mm66
-rw-r--r--chrome/test/ui_test_utils_win.cc12
19 files changed, 1121 insertions, 294 deletions
diff --git a/base/base.gypi b/base/base.gypi
index ff05d2a..2553ab5 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -421,6 +421,8 @@
'json/string_escape.h',
'keyboard_code_conversion_gtk.cc',
'keyboard_code_conversion_gtk.h',
+ 'keyboard_code_conversion_mac.mm',
+ 'keyboard_code_conversion_mac.h',
'keyboard_codes.h',
'keyboard_codes_win.h',
'keyboard_codes_posix.h',
diff --git a/base/keyboard_code_conversion_gtk.cc b/base/keyboard_code_conversion_gtk.cc
index 91de891..9e6bfd1 100644
--- a/base/keyboard_code_conversion_gtk.cc
+++ b/base/keyboard_code_conversion_gtk.cc
@@ -33,9 +33,6 @@
// WindowsKeyCodeForGdkKeyCode is copied from platform/gtk/KeyEventGtk.cpp
-#ifndef BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
-#define BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
-
#include "base/keyboard_code_conversion_gtk.h"
#include <gdk/gdkkeysyms.h>
@@ -615,6 +612,4 @@ int GdkKeyCodeForWindowsKeyCode(base::KeyboardCode keycode, bool shift) {
}
}
-} // namespace
-
-#endif // BASE_KEYBOARD_CODE_CONVERSION_GTK_H_
+} // namespace base
diff --git a/base/keyboard_code_conversion_mac.h b/base/keyboard_code_conversion_mac.h
new file mode 100644
index 0000000..9db6e47
--- /dev/null
+++ b/base/keyboard_code_conversion_mac.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_KEYBOARD_CODE_CONVERSION_MAC_H_
+#define BASE_KEYBOARD_CODE_CONVERSION_MAC_H_
+
+#import <Cocoa/Cocoa.h>
+#include "basictypes.h"
+#include "base/keyboard_codes_posix.h"
+
+namespace base {
+
+// We use windows virtual keycodes throughout our keyboard event related code,
+// including unit tests. But Mac uses a different set of virtual keycodes.
+// This function converts a windows virtual keycode into Mac's virtual key code
+// and corresponding unicode character. |flags| is the modifiers mask such
+// as NSControlKeyMask, NSShiftKeyMask, etc.
+// When success, the corresponding Mac's virtual key code will be returned.
+// The corresponding unicode character will be stored in |character|, and the
+// corresponding unicode character ignoring the modifiers will be stored in
+// |characterIgnoringModifiers|.
+// -1 will be returned if the keycode can't be converted.
+// This function is mainly for simulating keyboard events in unit tests.
+// See third_party/WebKit/WebKit/chromium/src/mac/WebInputEventFactory.mm for
+// reverse conversion.
+int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode,
+ NSUInteger flags,
+ unichar* character,
+ unichar* characterIgnoringModifiers);
+
+} // namespace base
+
+#endif // BASE_KEYBOARD_CODE_CONVERSION_MAC_H_
diff --git a/base/keyboard_code_conversion_mac.mm b/base/keyboard_code_conversion_mac.mm
new file mode 100644
index 0000000..79c1b19
--- /dev/null
+++ b/base/keyboard_code_conversion_mac.mm
@@ -0,0 +1,293 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/keyboard_code_conversion_mac.h"
+
+#include <algorithm>
+#import <Carbon/Carbon.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace {
+
+// A struct to hold a Windows keycode to Mac virtual keycode mapping.
+struct KeyCodeMap {
+ KeyboardCode keycode;
+ int macKeycode;
+ unichar characterIgnoringModifiers;
+};
+
+// Customized less operator for using std::lower_bound() on a KeyCodeMap array.
+bool operator<(const KeyCodeMap& a, const KeyCodeMap& b) {
+ return a.keycode < b.keycode;
+}
+
+// This array must keep sorted ascending according to the value of |keycode|,
+// so that we can binary search it.
+// TODO(suzhe): This map is not complete, missing entries have macKeycode == -1.
+const KeyCodeMap kKeyCodesMap[] = {
+ { VKEY_BACK /* 0x08 */, kVK_Delete, kBackspaceCharCode },
+ { VKEY_TAB /* 0x09 */, kVK_Tab, kTabCharCode },
+ { VKEY_CLEAR /* 0x0C */, kVK_ANSI_KeypadClear, kClearCharCode },
+ { VKEY_RETURN /* 0x0D */, kVK_Return, kReturnCharCode },
+ { VKEY_SHIFT /* 0x10 */, kVK_Shift, 0 },
+ { VKEY_CONTROL /* 0x11 */, kVK_Control, 0 },
+ { VKEY_MENU /* 0x12 */, kVK_Option, 0 },
+ { VKEY_PAUSE /* 0x13 */, -1, NSPauseFunctionKey },
+ { VKEY_CAPITAL /* 0x14 */, kVK_CapsLock, 0 },
+ { VKEY_KANA /* 0x15 */, kVK_JIS_Kana, 0 },
+ { VKEY_HANGUL /* 0x15 */, -1, 0 },
+ { VKEY_JUNJA /* 0x17 */, -1, 0 },
+ { VKEY_FINAL /* 0x18 */, -1, 0 },
+ { VKEY_HANJA /* 0x19 */, -1, 0 },
+ { VKEY_KANJI /* 0x19 */, -1, 0 },
+ { VKEY_ESCAPE /* 0x1B */, kVK_Escape, kEscapeCharCode },
+ { VKEY_CONVERT /* 0x1C */, -1, 0 },
+ { VKEY_NONCONVERT /* 0x1D */, -1, 0 },
+ { VKEY_ACCEPT /* 0x1E */, -1, 0 },
+ { VKEY_MODECHANGE /* 0x1F */, -1, 0 },
+ { VKEY_SPACE /* 0x20 */, kVK_Space, kSpaceCharCode },
+ { VKEY_PRIOR /* 0x21 */, kVK_PageUp, NSPageUpFunctionKey },
+ { VKEY_NEXT /* 0x22 */, kVK_PageDown, NSPageDownFunctionKey },
+ { VKEY_END /* 0x23 */, kVK_End, NSEndFunctionKey },
+ { VKEY_HOME /* 0x24 */, kVK_Home, NSHomeFunctionKey },
+ { VKEY_LEFT /* 0x25 */, kVK_LeftArrow, NSLeftArrowFunctionKey },
+ { VKEY_UP /* 0x26 */, kVK_UpArrow, NSUpArrowFunctionKey },
+ { VKEY_RIGHT /* 0x27 */, kVK_RightArrow, NSRightArrowFunctionKey },
+ { VKEY_DOWN /* 0x28 */, kVK_DownArrow, NSDownArrowFunctionKey },
+ { VKEY_SELECT /* 0x29 */, -1, 0 },
+ { VKEY_PRINT /* 0x2A */, -1, NSPrintFunctionKey },
+ { VKEY_EXECUTE /* 0x2B */, -1, NSExecuteFunctionKey },
+ { VKEY_SNAPSHOT /* 0x2C */, -1, NSPrintScreenFunctionKey },
+ { VKEY_INSERT /* 0x2D */, -1, NSInsertFunctionKey },
+ { VKEY_DELETE /* 0x2E */, kVK_ForwardDelete, kDeleteCharCode },
+ { VKEY_HELP /* 0x2F */, kVK_Help, kHelpCharCode },
+ { VKEY_0 /* 0x30 */, kVK_ANSI_0, '0' },
+ { VKEY_1 /* 0x31 */, kVK_ANSI_1, '1' },
+ { VKEY_2 /* 0x32 */, kVK_ANSI_2, '2' },
+ { VKEY_3 /* 0x33 */, kVK_ANSI_3, '3' },
+ { VKEY_4 /* 0x34 */, kVK_ANSI_4, '4' },
+ { VKEY_5 /* 0x35 */, kVK_ANSI_5, '5' },
+ { VKEY_6 /* 0x36 */, kVK_ANSI_6, '6' },
+ { VKEY_7 /* 0x37 */, kVK_ANSI_7, '7' },
+ { VKEY_8 /* 0x38 */, kVK_ANSI_8, '8' },
+ { VKEY_9 /* 0x39 */, kVK_ANSI_9, '9' },
+ { VKEY_A /* 0x41 */, kVK_ANSI_A, 'a' },
+ { VKEY_B /* 0x42 */, kVK_ANSI_B, 'b' },
+ { VKEY_C /* 0x43 */, kVK_ANSI_C, 'c' },
+ { VKEY_D /* 0x44 */, kVK_ANSI_D, 'd' },
+ { VKEY_E /* 0x45 */, kVK_ANSI_E, 'e' },
+ { VKEY_F /* 0x46 */, kVK_ANSI_F, 'f' },
+ { VKEY_G /* 0x47 */, kVK_ANSI_G, 'g' },
+ { VKEY_H /* 0x48 */, kVK_ANSI_H, 'h' },
+ { VKEY_I /* 0x49 */, kVK_ANSI_I, 'i' },
+ { VKEY_J /* 0x4A */, kVK_ANSI_J, 'j' },
+ { VKEY_K /* 0x4B */, kVK_ANSI_K, 'k' },
+ { VKEY_L /* 0x4C */, kVK_ANSI_L, 'l' },
+ { VKEY_M /* 0x4D */, kVK_ANSI_M, 'm' },
+ { VKEY_N /* 0x4E */, kVK_ANSI_N, 'n' },
+ { VKEY_O /* 0x4F */, kVK_ANSI_O, 'o' },
+ { VKEY_P /* 0x50 */, kVK_ANSI_P, 'p' },
+ { VKEY_Q /* 0x51 */, kVK_ANSI_Q, 'q' },
+ { VKEY_R /* 0x52 */, kVK_ANSI_R, 'r' },
+ { VKEY_S /* 0x53 */, kVK_ANSI_S, 's' },
+ { VKEY_T /* 0x54 */, kVK_ANSI_T, 't' },
+ { VKEY_U /* 0x55 */, kVK_ANSI_U, 'u' },
+ { VKEY_V /* 0x56 */, kVK_ANSI_V, 'v' },
+ { VKEY_W /* 0x57 */, kVK_ANSI_W, 'w' },
+ { VKEY_X /* 0x58 */, kVK_ANSI_X, 'x' },
+ { VKEY_Y /* 0x59 */, kVK_ANSI_Y, 'y' },
+ { VKEY_Z /* 0x5A */, kVK_ANSI_Z, 'z' },
+ { VKEY_LWIN /* 0x5B */, kVK_Command, 0 },
+ { VKEY_RWIN /* 0x5C */, 0x36, 0 },
+ { VKEY_APPS /* 0x5D */, 0x36, 0 },
+ { VKEY_SLEEP /* 0x5F */, -1, 0 },
+ { VKEY_NUMPAD0 /* 0x60 */, kVK_ANSI_Keypad0, '0' },
+ { VKEY_NUMPAD1 /* 0x61 */, kVK_ANSI_Keypad1, '1' },
+ { VKEY_NUMPAD2 /* 0x62 */, kVK_ANSI_Keypad2, '2' },
+ { VKEY_NUMPAD3 /* 0x63 */, kVK_ANSI_Keypad3, '3' },
+ { VKEY_NUMPAD4 /* 0x64 */, kVK_ANSI_Keypad4, '4' },
+ { VKEY_NUMPAD5 /* 0x65 */, kVK_ANSI_Keypad5, '5' },
+ { VKEY_NUMPAD6 /* 0x66 */, kVK_ANSI_Keypad6, '6' },
+ { VKEY_NUMPAD7 /* 0x67 */, kVK_ANSI_Keypad7, '7' },
+ { VKEY_NUMPAD8 /* 0x68 */, kVK_ANSI_Keypad8, '8' },
+ { VKEY_NUMPAD9 /* 0x69 */, kVK_ANSI_Keypad9, '9' },
+ { VKEY_MULTIPLY /* 0x6A */, kVK_ANSI_KeypadMultiply, '*' },
+ { VKEY_ADD /* 0x6B */, kVK_ANSI_KeypadPlus, '+' },
+ { VKEY_SEPARATOR /* 0x6C */, -1, 0 },
+ { VKEY_SUBTRACT /* 0x6D */, kVK_ANSI_KeypadMinus, '-' },
+ { VKEY_DECIMAL /* 0x6E */, kVK_ANSI_KeypadDecimal, '.' },
+ { VKEY_DIVIDE /* 0x6F */, kVK_ANSI_KeypadDivide, '/' },
+ { VKEY_F1 /* 0x70 */, kVK_F1, NSF1FunctionKey },
+ { VKEY_F2 /* 0x71 */, kVK_F2, NSF2FunctionKey },
+ { VKEY_F3 /* 0x72 */, kVK_F3, NSF3FunctionKey },
+ { VKEY_F4 /* 0x73 */, kVK_F4, NSF4FunctionKey },
+ { VKEY_F5 /* 0x74 */, kVK_F5, NSF5FunctionKey },
+ { VKEY_F6 /* 0x75 */, kVK_F6, NSF6FunctionKey },
+ { VKEY_F7 /* 0x76 */, kVK_F7, NSF7FunctionKey },
+ { VKEY_F8 /* 0x77 */, kVK_F8, NSF8FunctionKey },
+ { VKEY_F9 /* 0x78 */, kVK_F9, NSF9FunctionKey },
+ { VKEY_F10 /* 0x79 */, kVK_F10, NSF10FunctionKey },
+ { VKEY_F11 /* 0x7A */, kVK_F11, NSF11FunctionKey },
+ { VKEY_F12 /* 0x7B */, kVK_F12, NSF12FunctionKey },
+ { VKEY_F13 /* 0x7C */, kVK_F13, NSF13FunctionKey },
+ { VKEY_F14 /* 0x7D */, kVK_F14, NSF14FunctionKey },
+ { VKEY_F15 /* 0x7E */, kVK_F15, NSF15FunctionKey },
+ { VKEY_F16 /* 0x7F */, kVK_F16, NSF16FunctionKey },
+ { VKEY_F17 /* 0x80 */, kVK_F17, NSF17FunctionKey },
+ { VKEY_F18 /* 0x81 */, kVK_F18, NSF18FunctionKey },
+ { VKEY_F19 /* 0x82 */, kVK_F19, NSF19FunctionKey },
+ { VKEY_F20 /* 0x83 */, kVK_F20, NSF20FunctionKey },
+ { VKEY_F21 /* 0x84 */, -1, NSF21FunctionKey },
+ { VKEY_F22 /* 0x85 */, -1, NSF22FunctionKey },
+ { VKEY_F23 /* 0x86 */, -1, NSF23FunctionKey },
+ { VKEY_F24 /* 0x87 */, -1, NSF24FunctionKey },
+ { VKEY_NUMLOCK /* 0x90 */, -1, 0 },
+ { VKEY_SCROLL /* 0x91 */, -1, NSScrollLockFunctionKey },
+ { VKEY_LSHIFT /* 0xA0 */, kVK_Shift, 0 },
+ { VKEY_RSHIFT /* 0xA1 */, kVK_Shift, 0 },
+ { VKEY_LCONTROL /* 0xA2 */, kVK_Control, 0 },
+ { VKEY_RCONTROL /* 0xA3 */, kVK_Control, 0 },
+ { VKEY_LMENU /* 0xA4 */, -1, 0 },
+ { VKEY_RMENU /* 0xA5 */, -1, 0 },
+ { VKEY_BROWSER_BACK /* 0xA6 */, -1, 0 },
+ { VKEY_BROWSER_FORWARD /* 0xA7 */, -1, 0 },
+ { VKEY_BROWSER_REFRESH /* 0xA8 */, -1, 0 },
+ { VKEY_BROWSER_STOP /* 0xA9 */, -1, 0 },
+ { VKEY_BROWSER_SEARCH /* 0xAA */, -1, 0 },
+ { VKEY_BROWSER_FAVORITES /* 0xAB */, -1, 0 },
+ { VKEY_BROWSER_HOME /* 0xAC */, -1, 0 },
+ { VKEY_VOLUME_MUTE /* 0xAD */, -1, 0 },
+ { VKEY_VOLUME_DOWN /* 0xAE */, -1, 0 },
+ { VKEY_VOLUME_UP /* 0xAF */, -1, 0 },
+ { VKEY_MEDIA_NEXT_TRACK /* 0xB0 */, -1, 0 },
+ { VKEY_MEDIA_PREV_TRACK /* 0xB1 */, -1, 0 },
+ { VKEY_MEDIA_STOP /* 0xB2 */, -1, 0 },
+ { VKEY_MEDIA_PLAY_PAUSE /* 0xB3 */, -1, 0 },
+ { VKEY_MEDIA_LAUNCH_MAIL /* 0xB4 */, -1, 0 },
+ { VKEY_MEDIA_LAUNCH_MEDIA_SELECT /* 0xB5 */, -1, 0 },
+ { VKEY_MEDIA_LAUNCH_APP1 /* 0xB6 */, -1, 0 },
+ { VKEY_MEDIA_LAUNCH_APP2 /* 0xB7 */, -1, 0 },
+ { VKEY_OEM_1 /* 0xBA */, kVK_ANSI_Semicolon, ';' },
+ { VKEY_OEM_PLUS /* 0xBB */, kVK_ANSI_Equal, '=' },
+ { VKEY_OEM_COMMA /* 0xBC */, kVK_ANSI_Comma, ',' },
+ { VKEY_OEM_MINUS /* 0xBD */, kVK_ANSI_Minus, '-' },
+ { VKEY_OEM_PERIOD /* 0xBE */, kVK_ANSI_Period, '.' },
+ { VKEY_OEM_2 /* 0xBF */, kVK_ANSI_Slash, '/' },
+ { VKEY_OEM_3 /* 0xC0 */, kVK_ANSI_Grave, '`' },
+ { VKEY_OEM_4 /* 0xDB */, kVK_ANSI_LeftBracket, '[' },
+ { VKEY_OEM_5 /* 0xDC */, kVK_ANSI_Backslash, '\\' },
+ { VKEY_OEM_6 /* 0xDD */, kVK_ANSI_RightBracket, ']' },
+ { VKEY_OEM_7 /* 0xDE */, kVK_ANSI_Quote, '\'' },
+ { VKEY_OEM_8 /* 0xDF */, -1, 0 },
+ { VKEY_OEM_102 /* 0xE2 */, -1, 0 },
+ { VKEY_PROCESSKEY /* 0xE5 */, -1, 0 },
+ { VKEY_PACKET /* 0xE7 */, -1, 0 },
+ { VKEY_ATTN /* 0xF6 */, -1, 0 },
+ { VKEY_CRSEL /* 0xF7 */, -1, 0 },
+ { VKEY_EXSEL /* 0xF8 */, -1, 0 },
+ { VKEY_EREOF /* 0xF9 */, -1, 0 },
+ { VKEY_PLAY /* 0xFA */, -1, 0 },
+ { VKEY_ZOOM /* 0xFB */, -1, 0 },
+ { VKEY_NONAME /* 0xFC */, -1, 0 },
+ { VKEY_PA1 /* 0xFD */, -1, 0 },
+ { VKEY_OEM_CLEAR /* 0xFE */, kVK_ANSI_KeypadClear, kClearCharCode }
+};
+
+// A convenient array for getting symbol characters on the number keys.
+const char kShiftCharsForNumberKeys[] = ")!@#$%^&*(";
+
+} // anonymous namespace
+
+int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode,
+ NSUInteger flags,
+ unichar* character,
+ unichar* characterIgnoringModifiers) {
+ KeyCodeMap from;
+ from.keycode = keycode;
+
+ const KeyCodeMap* ptr = std::lower_bound(
+ kKeyCodesMap, kKeyCodesMap + arraysize(kKeyCodesMap), from);
+
+ if (ptr >= kKeyCodesMap + arraysize(kKeyCodesMap) ||
+ ptr->keycode != keycode || ptr->macKeycode == -1) {
+ NOTREACHED() << "Unsupported keycode:" << keycode;
+ return -1;
+ }
+
+ int macKeycode = ptr->macKeycode;
+ if (characterIgnoringModifiers)
+ *characterIgnoringModifiers = ptr->characterIgnoringModifiers;
+
+ if (!character)
+ return macKeycode;
+
+ *character = ptr->characterIgnoringModifiers;
+
+ // Fill in |character| according to flags.
+ if (flags & NSShiftKeyMask) {
+ if (keycode >= VKEY_0 && keycode <= VKEY_9) {
+ *character = kShiftCharsForNumberKeys[keycode - VKEY_0];
+ } else if (keycode >= VKEY_A && keycode <= VKEY_Z) {
+ *character = 'A' + (keycode - VKEY_A);
+ } else {
+ switch (macKeycode) {
+ case kVK_ANSI_Grave:
+ *character = '~';
+ break;
+ case kVK_ANSI_Minus:
+ *character = '_';
+ break;
+ case kVK_ANSI_Equal:
+ *character = '+';
+ break;
+ case kVK_ANSI_LeftBracket:
+ *character = '{';
+ break;
+ case kVK_ANSI_RightBracket:
+ *character = '}';
+ break;
+ case kVK_ANSI_Backslash:
+ *character = '|';
+ break;
+ case kVK_ANSI_Semicolon:
+ *character = ':';
+ break;
+ case kVK_ANSI_Quote:
+ *character = '\"';
+ break;
+ case kVK_ANSI_Comma:
+ *character = '<';
+ break;
+ case kVK_ANSI_Period:
+ *character = '>';
+ break;
+ case kVK_ANSI_Slash:
+ *character = '?';
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Control characters.
+ if (flags & NSControlKeyMask) {
+ if (keycode >= VKEY_A && keycode <= VKEY_Z)
+ *character = 1 + keycode - VKEY_A;
+ else if (macKeycode == kVK_ANSI_LeftBracket)
+ *character = 27;
+ else if (macKeycode == kVK_ANSI_Backslash)
+ *character = 28;
+ else if (macKeycode == kVK_ANSI_RightBracket)
+ *character = 29;
+ }
+
+ // TODO(suzhe): Support characters for Option key bindings.
+ return macKeycode;
+}
+
+} // namespace base
diff --git a/chrome/browser/automation/ui_controls.h b/chrome/browser/automation/ui_controls.h
index 9c47f8d..63ba677 100644
--- a/chrome/browser/automation/ui_controls.h
+++ b/chrome/browser/automation/ui_controls.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -90,7 +90,7 @@ void MoveMouseToCenterAndPress(
#elif defined(TOOLKIT_GTK)
GtkWidget* widget,
#elif defined(OS_MACOSX)
- NSWindow* window,
+ NSView* view,
#endif
MouseButton button,
int state,
diff --git a/chrome/browser/automation/ui_controls_internal.h b/chrome/browser/automation/ui_controls_internal.h
new file mode 100644
index 0000000..88631c9
--- /dev/null
+++ b/chrome/browser/automation/ui_controls_internal.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_AUTOMATION_UI_CONTROLS_INTERNAL_H_
+#define CHROME_BROWSER_AUTOMATION_UI_CONTROLS_INTERNAL_H_
+
+#include "base/message_loop.h"
+#include "chrome/browser/automation/ui_controls.h"
+
+namespace ui_controls {
+
+// A utility class to send a mouse click event in a task.
+// It's shared by ui_controls_linux.cc and ui_controls_mac.cc
+class ClickTask : public Task {
+ public:
+ // A |followup| Task can be specified to notify the caller when the mouse
+ // click event is sent. If can be NULL if the caller does not care about it.
+ ClickTask(MouseButton button, int state, Task* followup)
+ : button_(button), state_(state), followup_(followup) {
+ }
+
+ virtual ~ClickTask() {}
+
+ virtual void Run() {
+ if (followup_)
+ SendMouseEventsNotifyWhenDone(button_, state_, followup_);
+ else
+ SendMouseEvents(button_, state_);
+ }
+
+ private:
+ MouseButton button_;
+ int state_;
+ Task* followup_;
+};
+
+} // ui_controls
+
+#endif // CHROME_BROWSER_AUTOMATION_UI_CONTROLS_INTERNAL_H_
diff --git a/chrome/browser/automation/ui_controls_linux.cc b/chrome/browser/automation/ui_controls_linux.cc
index c9dca78..4c19b7d 100644
--- a/chrome/browser/automation/ui_controls_linux.cc
+++ b/chrome/browser/automation/ui_controls_linux.cc
@@ -12,6 +12,7 @@
#include "base/keyboard_code_conversion_gtk.h"
#include "base/logging.h"
#include "base/message_loop.h"
+#include "chrome/browser/automation/ui_controls_internal.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/test/automation/automation_constants.h"
@@ -62,27 +63,6 @@ class EventWaiter : public MessageLoopForUI::Observer {
int count_;
};
-class ClickTask : public Task {
- public:
- ClickTask(ui_controls::MouseButton button, int state, Task* followup)
- : button_(button), state_(state), followup_(followup) {
- }
-
- virtual ~ClickTask() {}
-
- virtual void Run() {
- if (followup_)
- ui_controls::SendMouseEventsNotifyWhenDone(button_, state_, followup_);
- else
- ui_controls::SendMouseEvents(button_, state_);
- }
-
- private:
- ui_controls::MouseButton button_;
- int state_;
- Task* followup_;
-};
-
void FakeAMouseMotionEvent(gint x, gint y) {
GdkEvent* event = gdk_event_new(GDK_MOTION_NOTIFY);
diff --git a/chrome/browser/automation/ui_controls_mac.mm b/chrome/browser/automation/ui_controls_mac.mm
index 715135c1..d95dbc2 100644
--- a/chrome/browser/automation/ui_controls_mac.mm
+++ b/chrome/browser/automation/ui_controls_mac.mm
@@ -6,8 +6,11 @@
#import <Cocoa/Cocoa.h>
#include <mach/mach_time.h>
+#include <vector>
+#include "base/keyboard_code_conversion_mac.h"
#include "base/message_loop.h"
+#include "chrome/browser/automation/ui_controls_internal.h"
#include "chrome/browser/chrome_thread.h"
// Implementation details: We use [NSApplication sendEvent:] instead
@@ -22,6 +25,23 @@
// into the event queue. (I can post other kinds of tasks but can't
// guarantee their order with regards to events).
+// But [NSApplication sendEvent:] causes a problem when sending mouse click
+// events. Because in order to handle mouse drag, when processing a mouse
+// click event, the application may want to retrieve the next event
+// synchronously by calling NSApplication's nextEventMatchingMask method.
+// In this case, [NSApplication sendEvent:] causes deadlock.
+// So we need to use [NSApplication postEvent:atStart:] for mouse click
+// events. In order to notify the caller correctly after all events has been
+// processed, we setup a task to watch for the event queue time to time and
+// notify the caller as soon as there is no event in the queue.
+//
+// TODO(suzhe):
+// 1. Investigate why using [NSApplication postEvent:atStart:] for keyboard
+// events causes BrowserKeyEventsTest.CommandKeyEvents to fail.
+// See http://crbug.com/49270
+// 2. On OSX 10.6, [NSEvent addLocalMonitorForEventsMatchingMask:handler:] may
+// be used, so that we don't need to poll the event queue time to time.
+
namespace {
// From
@@ -53,6 +73,148 @@ NSTimeInterval TimeIntervalSinceSystemStartup() {
return UpTimeInNanoseconds() / 1000000000.0;
}
+// Creates and returns an autoreleased key event.
+NSEvent* SynthesizeKeyEvent(NSWindow* window,
+ bool keyDown,
+ base::KeyboardCode keycode,
+ NSUInteger flags) {
+ unichar character;
+ unichar characterIgnoringModifiers;
+ int macKeycode = base::MacKeyCodeForWindowsKeyCode(
+ keycode, flags, &character, &characterIgnoringModifiers);
+
+ if (macKeycode < 0)
+ return nil;
+
+ NSString* charactersIgnoringModifiers =
+ [[[NSString alloc] initWithCharacters:&characterIgnoringModifiers
+ length:1]
+ autorelease];
+ NSString* characters =
+ [[[NSString alloc] initWithCharacters:&character length:1] autorelease];
+
+ NSEventType type = (keyDown ? NSKeyDown : NSKeyUp);
+
+ // Modifier keys generate NSFlagsChanged event rather than
+ // NSKeyDown/NSKeyUp events.
+ if (keycode == base::VKEY_CONTROL || keycode == base::VKEY_SHIFT ||
+ keycode == base::VKEY_MENU || keycode == base::VKEY_COMMAND)
+ type = NSFlagsChanged;
+
+ // For events other than mouse moved, [event locationInWindow] is
+ // UNDEFINED if the event is not NSMouseMoved. Thus, the (0,0)
+ // location should be fine.
+ NSEvent* event =
+ [NSEvent keyEventWithType:type
+ location:NSMakePoint(0, 0)
+ modifierFlags:flags
+ timestamp:TimeIntervalSinceSystemStartup()
+ windowNumber:[window windowNumber]
+ context:nil
+ characters:characters
+ charactersIgnoringModifiers:charactersIgnoringModifiers
+ isARepeat:NO
+ keyCode:(unsigned short)macKeycode];
+
+ return event;
+}
+
+// Creates the proper sequence of autoreleased key events for a key down + up.
+void SynthesizeKeyEventsSequence(NSWindow* window,
+ base::KeyboardCode keycode,
+ bool control,
+ bool shift,
+ bool alt,
+ bool command,
+ std::vector<NSEvent*>* events) {
+ NSEvent* event = nil;
+ NSUInteger flags = 0;
+ if (control) {
+ flags |= NSControlKeyMask;
+ event = SynthesizeKeyEvent(window, true, base::VKEY_CONTROL, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (shift) {
+ flags |= NSShiftKeyMask;
+ event = SynthesizeKeyEvent(window, true, base::VKEY_SHIFT, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (alt) {
+ flags |= NSAlternateKeyMask;
+ event = SynthesizeKeyEvent(window, true, base::VKEY_MENU, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (command) {
+ flags |= NSCommandKeyMask;
+ event = SynthesizeKeyEvent(window, true, base::VKEY_COMMAND, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+
+ event = SynthesizeKeyEvent(window, true, keycode, flags);
+ DCHECK(event);
+ events->push_back(event);
+ event = SynthesizeKeyEvent(window, false, keycode, flags);
+ DCHECK(event);
+ events->push_back(event);
+
+ if (command) {
+ flags &= ~NSCommandKeyMask;
+ event = SynthesizeKeyEvent(window, false, base::VKEY_COMMAND, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (alt) {
+ flags &= ~NSAlternateKeyMask;
+ event = SynthesizeKeyEvent(window, false, base::VKEY_MENU, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (shift) {
+ flags &= ~NSShiftKeyMask;
+ event = SynthesizeKeyEvent(window, false, base::VKEY_SHIFT, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+ if (control) {
+ flags &= ~NSControlKeyMask;
+ event = SynthesizeKeyEvent(window, false, base::VKEY_CONTROL, flags);
+ DCHECK(event);
+ events->push_back(event);
+ }
+}
+
+// A task class to watch for the event queue. The specific task will be fired
+// when there is no more event in the queue.
+class EventQueueWatcher : public Task {
+ public:
+ EventQueueWatcher(Task* task) : task_(task) {}
+
+ virtual ~EventQueueWatcher() {}
+
+ virtual void Run() {
+ NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue:NO];
+ // If there is still event in the queue, then we need to check again.
+ if (event)
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task_));
+ else
+ MessageLoop::current()->PostTask(FROM_HERE, task_);
+ }
+
+ private:
+ Task* task_;
+};
+
+// Stores the current mouse location on the screen. So that we can use it
+// when firing keyboard and mouse click events.
+NSPoint g_mouse_location = { 0, 0 };
+
} // anonymous namespace
@@ -71,8 +233,6 @@ bool SendKeyPress(gfx::NativeWindow window,
// Win and Linux implement a SendKeyPress() this as a
// SendKeyPressAndRelease(), so we should as well (despite the name).
-//
-// TODO(jrg): handle "characters" better (e.g. apply shift?)
bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
base::KeyboardCode key,
bool control,
@@ -81,55 +241,23 @@ bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
bool command,
Task* task) {
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
- NSUInteger flags = 0;
- if (control)
- flags |= NSControlKeyMask;
- if (shift)
- flags |= NSShiftKeyMask;
- if (alt)
- flags |= NSAlternateKeyMask;
- if (command)
- flags |= NSCommandKeyMask;
- unsigned char keycode = key;
- NSString* charactersIgnoringModifiers = [[[NSString alloc]
- initWithBytes:&keycode
- length:1
- encoding:NSUTF8StringEncoding]
- autorelease];
- NSString* characters = charactersIgnoringModifiers;
- // For events other than mouse moved, [event locationInWindow] is
- // UNDEFINED if the event is not NSMouseMoved. Thus, the (0,0)
- // locaiton should be fine.
- // First a key down...
- NSEvent* event =
- [NSEvent keyEventWithType:NSKeyDown
- location:NSMakePoint(0,0)
- modifierFlags:flags
- timestamp:TimeIntervalSinceSystemStartup()
- windowNumber:[window windowNumber]
- context:nil
- characters:characters
- charactersIgnoringModifiers:charactersIgnoringModifiers
- isARepeat:NO
- keyCode:key];
- [[NSApplication sharedApplication] sendEvent:event];
- // Then a key up.
- event =
- [NSEvent keyEventWithType:NSKeyUp
- location:NSMakePoint(0,0)
- modifierFlags:flags
- timestamp:TimeIntervalSinceSystemStartup()
- windowNumber:[window windowNumber]
- context:nil
- characters:characters
- charactersIgnoringModifiers:charactersIgnoringModifiers
- isARepeat:NO
- keyCode:key];
- [[NSApplication sharedApplication] sendEvent:event];
+ std::vector<NSEvent*> events;
+ SynthesizeKeyEventsSequence(
+ window, key, control, shift, alt, command, &events);
+
+ // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes
+ // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270
+ // But using [NSApplication sendEvent:] should be safe for keyboard events,
+ // because until now, no code wants to retrieve the next event when handling
+ // a keyboard event.
+ for (std::vector<NSEvent*>::iterator iter = events.begin();
+ iter != events.end(); ++iter)
+ [[NSApplication sharedApplication] sendEvent:*iter];
if (task)
- MessageLoop::current()->PostTask(FROM_HERE, task);
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task));
+
return true;
}
@@ -144,7 +272,8 @@ bool SendMouseMove(long x, long y) {
bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) {
NSWindow* window = [[NSApplication sharedApplication] keyWindow];
CGFloat screenHeight = [[NSScreen mainScreen] frame].size.height;
- NSPoint pointInWindow = NSMakePoint(x, screenHeight - y); // flip!
+ g_mouse_location = NSMakePoint(x, screenHeight - y); // flip!
+ NSPoint pointInWindow = g_mouse_location;
if (window)
pointInWindow = [window convertScreenToBase:pointInWindow];
NSTimeInterval timestamp = TimeIntervalSinceSystemStartup();
@@ -160,8 +289,10 @@ bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) {
clickCount:0
pressure:0.0];
[[NSApplication sharedApplication] postEvent:event atStart:NO];
+
if (task)
- MessageLoop::current()->PostTask(FROM_HERE, task);
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task));
+
return true;
}
@@ -176,7 +307,6 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) {
return (SendMouseEventsNotifyWhenDone(type, DOWN, NULL) &&
SendMouseEventsNotifyWhenDone(type, UP, task));
}
-
NSEventType etype = 0;
if (type == LEFT) {
if (state == UP) {
@@ -200,8 +330,7 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) {
return false;
}
NSWindow* window = [[NSApplication sharedApplication] keyWindow];
- NSPoint location = [NSEvent mouseLocation];
- NSPoint pointInWindow = location;
+ NSPoint pointInWindow = g_mouse_location;
if (window)
pointInWindow = [window convertScreenToBase:pointInWindow];
@@ -213,11 +342,13 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) {
windowNumber:[window windowNumber]
context:nil
eventNumber:0
- clickCount:0
- pressure:0.0];
- [[NSApplication sharedApplication] sendEvent:event];
+ clickCount:1
+ pressure:(state == DOWN ? 1.0 : 0.0 )];
+ [[NSApplication sharedApplication] postEvent:event atStart:NO];
+
if (task)
- MessageLoop::current()->PostTask(FROM_HERE, task);
+ MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task));
+
return true;
}
@@ -225,18 +356,27 @@ bool SendMouseClick(MouseButton type) {
return SendMouseEventsNotifyWhenDone(type, UP|DOWN, NULL);
}
-// This appears to only be used by a function in test/ui_test_utils.h:
-// ui_test_utils::ClickOnView(). That is not implemented on Mac, so
-// we don't need to implement MoveMouseToCenterAndPress(). I've
-// suggested an implementation of ClickOnView() which would call Cocoa
-// directly and not need this indirection, so this may not be needed,
-// ever.
void MoveMouseToCenterAndPress(
- NSWindow* window,
+ NSView* view,
MouseButton button,
int state,
Task* task) {
- NOTIMPLEMENTED();
+ DCHECK(view);
+ NSWindow* window = [view window];
+ DCHECK(window);
+ NSScreen* screen = [window screen];
+ DCHECK(screen);
+
+ // Converts the center position of the view into the coordinates accepted
+ // by SendMouseMoveNotifyWhenDone() method.
+ NSRect bounds = [view bounds];
+ NSPoint center = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
+ center = [view convertPoint:center toView:nil];
+ center = [window convertBaseToScreen:center];
+ center = NSMakePoint(center.x, [screen frame].size.height - center.y);
+
+ SendMouseMoveNotifyWhenDone(center.x, center.y,
+ new ClickTask(button, state, task));
}
} // ui_controls
diff --git a/chrome/browser/browser_focus_uitest.cc b/chrome/browser/browser_focus_uitest.cc
index de13199..7513625 100644
--- a/chrome/browser/browser_focus_uitest.cc
+++ b/chrome/browser/browser_focus_uitest.cc
@@ -5,6 +5,7 @@
#include "build/build_config.h"
#include "base/format_macros.h"
+#include "base/logging.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "chrome/browser/automation/ui_controls.h"
@@ -19,9 +20,12 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+
+#if defined(TOOLKIT_VIEWS) || defined(OS_WIN)
#include "views/focus/focus_manager.h"
#include "views/view.h"
#include "views/window/window.h"
+#endif
#if defined(TOOLKIT_VIEWS)
#include "chrome/browser/views/frame/browser_view.h"
@@ -34,12 +38,20 @@
#endif
#if defined(OS_LINUX)
+#define MAYBE_FocusTraversal FocusTraversal
// For some reason we hit an external DNS lookup in this test in Linux but not
// on Windows. TODO(estade): investigate.
#define MAYBE_FocusTraversalOnInterstitial DISABLED_FocusTraversalOnInterstitial
// TODO(jcampan): http://crbug.com/23683
#define MAYBE_TabsRememberFocusFindInPage FAILS_TabsRememberFocusFindInPage
-#else
+#elif defined(OS_MACOSX)
+// TODO(suzhe): http://crbug.com/49738 (following two tests)
+#define MAYBE_FocusTraversal FAILS_FocusTraversal
+#define MAYBE_FocusTraversalOnInterstitial FAILS_FocusTraversalOnInterstitial
+// TODO(suzhe): http://crbug.com/49737
+#define MAYBE_TabsRememberFocusFindInPage FAILS_TabsRememberFocusFindInPage
+#elif defined(OS_WIN)
+#define MAYBE_FocusTraversal FocusTraversal
#define MAYBE_FocusTraversalOnInterstitial FocusTraversalOnInterstitial
#define MAYBE_TabsRememberFocusFindInPage TabsRememberFocusFindInPage
#endif
@@ -70,28 +82,9 @@ class BrowserFocusTest : public InProcessBrowserTest {
ui_test_utils::ClickOnView(browser(), vid);
}
- static void HideNativeWindow(gfx::NativeWindow window) {
-#if defined(OS_WIN)
- // TODO(jcampan): retrieve the WidgetWin and show/hide on it instead of
- // using Windows API.
- ::ShowWindow(window, SW_HIDE);
-#elif defined(TOOLKIT_USES_GTK)
- gtk_widget_hide(GTK_WIDGET(window));
-#else
- NOTIMPLEMENTED();
-#endif
- }
-
- static void ShowNativeWindow(gfx::NativeWindow window) {
-#if defined(OS_WIN)
- // TODO(jcampan): retrieve the WidgetWin and show/hide on it instead of
- // using Windows API.
- ::ShowWindow(window, SW_SHOW);
-#elif defined(TOOLKIT_USES_GTK)
- gtk_widget_hide(GTK_WIDGET(window));
-#else
- NOTIMPLEMENTED();
-#endif
+ void BringBrowserWindowToFront() {
+ ui_test_utils::ShowAndFocusNativeWindow(
+ browser()->window()->GetNativeHandle());
}
};
@@ -170,7 +163,8 @@ class TestInterstitialPage : public InterstitialPage {
} // namespace
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, ClickingMovesFocus) {
-#if defined(USE_X11)
+ BringBrowserWindowToFront();
+#if defined(USE_X11) || defined(OS_MACOSX)
// It seems we have to wait a little bit for the widgets to spin up before
// we can start clicking on them.
MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -189,7 +183,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, ClickingMovesFocus) {
}
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// First we navigate to our test page.
GURL url = server->TestServerPage(kSimplePage);
@@ -200,15 +196,15 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) {
// The focus should be on the Tab contents.
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);
+ ui_test_utils::HideNativeWindow(window);
+ ui_test_utils::ShowAndFocusNativeWindow(window);
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
browser()->FocusLocationBar();
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// Hide the window, show it again, the focus should not have changed.
- HideNativeWindow(window);
- ShowNativeWindow(window);
+ ui_test_utils::HideNativeWindow(window);
+ ui_test_utils::ShowAndFocusNativeWindow(window);
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// The rest of this test does not make sense on Linux because the behavior
@@ -252,7 +248,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BrowsersRememberFocus) {
// Tabs remember focus.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// First we navigate to our test page.
GURL url = server->TestServerPage(kSimplePage);
@@ -326,7 +324,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabsRememberFocus) {
// Tabs remember focus with find-in-page box.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// First we navigate to our test page.
GURL url = server->TestServerPage(kSimplePage);
@@ -364,7 +364,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_TabsRememberFocusFindInPage) {
// Background window does not steal focus.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// First we navigate to our test page.
GURL url = server->TestServerPage(kSimplePage);
@@ -393,6 +395,10 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) {
#elif defined(OS_WIN)
focused_browser = browser();
unfocused_browser = browser2;
+#elif defined(OS_MACOSX)
+ // On Mac, the newly created window always gets the focus.
+ focused_browser = browser2;
+ unfocused_browser = browser();
#endif
GURL steal_focus_url = server->TestServerPage(kStealFocusPage);
@@ -415,7 +421,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, BackgroundBrowserDontStealFocus) {
// Page cannot steal focus when focus is on location bar.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// Open the page that steals focus.
GURL url = server->TestServerPage(kStealFocusPage);
@@ -435,8 +443,10 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, LocationBarLockFocus) {
// focus has changed in the page. The notification in the renderer may change
// at which point this test would fail (see comment in
// RenderWidget::didFocus()).
-IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) {
+IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversal) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// First we navigate to our test page.
GURL url = server->TestServerPage(kTypicalPage);
@@ -528,7 +538,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusTraversal) {
// Focus traversal while an interstitial is showing.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// First we navigate to our test page.
GURL url = server->TestServerPage(kSimplePage);
@@ -618,7 +630,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusTraversalOnInterstitial) {
// Focus stays on page with interstitials.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// First we navigate to our test page.
GURL url = server->TestServerPage(kSimplePage);
@@ -653,7 +667,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, InterstitialFocus) {
// Make sure Find box can request focus, even when it is already open.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// Open some page (any page that doesn't steal focus).
GURL url = server->TestServerPage(kTypicalPage);
@@ -661,10 +677,17 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
gfx::NativeWindow window = browser()->window()->GetNativeHandle();
+#if defined(OS_MACOSX)
+ // Press Cmd+F, which will make the Find box open and request focus.
+ ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, false,
+ false, false, true,
+ new MessageLoop::QuitTask());
+#else
// Press Ctrl+F, which will make the Find box open and request focus.
ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true,
false, false, false,
new MessageLoop::QuitTask());
+#endif
ui_test_utils::RunMessageLoop();
// Ideally, we wouldn't sleep here and instead would intercept the
@@ -682,9 +705,15 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
ASSERT_TRUE(IsViewFocused(VIEW_ID_LOCATION_BAR));
// Now press Ctrl+F again and focus should move to the Find box.
+#if defined(OS_MACOSX)
+ ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, false,
+ false, false, true,
+ new MessageLoop::QuitTask());
+#else
ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true,
false, false, false,
new MessageLoop::QuitTask());
+#endif
ui_test_utils::RunMessageLoop();
ASSERT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
@@ -693,9 +722,15 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
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,
- false, false,
+#if defined(OS_MACOSX)
+ ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, false,
+ false, false, true,
+ new MessageLoop::QuitTask());
+#else
+ ui_controls::SendKeyPressNotifyWhenDone(window, base::VKEY_F, true,
+ false, false, false,
new MessageLoop::QuitTask());
+#endif
ui_test_utils::RunMessageLoop();
// See remark above on why we wait.
@@ -708,6 +743,7 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FindFocusTest) {
// Makes sure the focus is in the right location when opening the different
// types of tabs.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabInitialFocus) {
+ BringBrowserWindowToFront();
// Open the history tab, focus should be on the tab contents.
browser()->ShowHistoryTab();
@@ -732,7 +768,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, TabInitialFocus) {
// Tests that focus goes where expected when using reload.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// Open the new tab, reload.
browser()->NewTab();
@@ -765,7 +803,9 @@ IN_PROC_BROWSER_TEST_F(BrowserFocusTest, FocusOnReload) {
// Tests that focus goes where expected when using reload on a crashed tab.
IN_PROC_BROWSER_TEST_F(BrowserFocusTest, MAYBE_FocusOnReloadCrashedTab) {
+ BringBrowserWindowToFront();
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
// Open a regular page, crash, reload.
ui_test_utils::NavigateToURL(browser(), server->TestServerPage(kSimplePage));
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc
index 0b6e8fb..d3aae77 100644
--- a/chrome/browser/browser_keyevents_browsertest.cc
+++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -41,8 +41,11 @@ const wchar_t kSetFocusedElementJS[] =
const wchar_t kGetTextBoxValueJS[] =
L"window.domAutomationController.send("
L"document.getElementById('%ls').value);";
+const wchar_t kSetTextBoxValueJS[] =
+ L"window.domAutomationController.send("
+ L"document.getElementById('%ls').value = '%ls');";
const wchar_t kStartTestJS[] =
- L"window.domAutomationController.send(startTest());";
+ L"window.domAutomationController.send(startTest(%d));";
// Maximum lenght of the result array in KeyEventTestData structure.
const size_t kMaxResultLength = 10;
@@ -51,10 +54,10 @@ const size_t kMaxResultLength = 10;
// 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>
+// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
// 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.
+// <ctrlKey>, <shiftKey> <altKey> and <commandKey> 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.
@@ -63,6 +66,7 @@ struct KeyEventTestData {
bool ctrl;
bool shift;
bool alt;
+ bool command;
bool suppress_keydown;
bool suppress_keypress;
@@ -131,12 +135,21 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
ASSERT_TRUE(*native_window);
}
- void SendKey(base::KeyboardCode key, bool control, bool shift, bool alt) {
+ void BringBrowserWindowToFront() {
+ gfx::NativeWindow window = NULL;
+ ASSERT_NO_FATAL_FAILURE(GetNativeWindow(&window));
+ ui_test_utils::ShowAndFocusNativeWindow(window);
+ }
+
+ void SendKey(base::KeyboardCode key,
+ bool control,
+ bool shift,
+ bool alt,
+ bool command) {
gfx::NativeWindow window = NULL;
ASSERT_NO_FATAL_FAILURE(GetNativeWindow(&window));
EXPECT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
- window, key, control, shift, alt,
- false /* command, */,
+ window, key, control, shift, alt, command,
new MessageLoop::QuitTask()));
ui_test_utils::RunMessageLoop();
}
@@ -238,12 +251,24 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
ASSERT_EQ(WideToUTF8(value), actual);
}
- void StartTest(int tab_index) {
+ void SetTextBoxValue(int tab_index, const wchar_t* id,
+ const wchar_t* value) {
+ ASSERT_LT(tab_index, browser()->tab_count());
+ std::string actual;
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetTabContentsAt(tab_index)->render_view_host(),
+ L"",
+ StringPrintf(kSetTextBoxValueJS, id, value),
+ &actual));
+ ASSERT_EQ(WideToUTF8(value), actual);
+ }
+
+ void StartTest(int tab_index, int result_length) {
ASSERT_LT(tab_index, browser()->tab_count());
bool actual;
ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
browser()->GetTabContentsAt(tab_index)->render_view_host(),
- L"", kStartTestJS, &actual));
+ L"", StringPrintf(kStartTestJS, result_length), &actual));
ASSERT_TRUE(actual);
}
@@ -253,7 +278,7 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
// 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(StartTest(tab_index, test.result_length));
ASSERT_NO_FATAL_FAILURE(SuppressEvents(
tab_index, test.suppress_keydown, test.suppress_keypress,
test.suppress_keyup, test.suppress_textinput));
@@ -264,7 +289,8 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
TestFinishObserver finish_observer(
browser()->GetTabContentsAt(tab_index)->render_view_host());
- ASSERT_NO_FATAL_FAILURE(SendKey(test.key, test.ctrl, test.shift, test.alt));
+ ASSERT_NO_FATAL_FAILURE(
+ SendKey(test.key, test.ctrl, test.shift, test.alt, test.command));
ASSERT_TRUE(finish_observer.WaitForFinish());
ASSERT_NO_FATAL_FAILURE(CheckResult(
tab_index, test.result_length, test.result));
@@ -272,10 +298,10 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
std::string GetTestDataDescription(const KeyEventTestData& data) {
std::string desc = StringPrintf(
- " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d\n"
+ " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d, command:%d\n"
" Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n"
" Expected results(%d):\n",
- data.key, data.ctrl, data.shift, data.alt,
+ data.key, data.ctrl, data.shift, data.alt, data.command,
data.suppress_keydown, data.suppress_keypress, data.suppress_keyup,
data.suppress_textinput, data.result_length);
for (int i = 0; i < data.result_length; ++i) {
@@ -289,69 +315,70 @@ class BrowserKeyEventsTest : public InProcessBrowserTest {
} // namespace
-// Flaky since r51395. See crbug.com/48671.
-IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FLAKY_NormalKeyEvents) {
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, NormalKeyEvents) {
static const KeyEventTestData kTestNoInput[] = {
// a
- { base::VKEY_A, false, false, false,
+ { base::VKEY_A, false, 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" } },
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
+ "U 65 0 false false false false" } },
// shift-a
- { base::VKEY_A, false, true, false,
+ { base::VKEY_A, false, true, false, 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" } },
+ { "D 16 0 false true false false",
+ "D 65 0 false true false false",
+ "P 65 65 false true false false",
+ "U 65 0 false true false false",
+ "U 16 0 false true false false" } },
// a, suppress keydown
- { base::VKEY_A, false, false, false,
+ { base::VKEY_A, false, false, false, false,
true, false, false, false, 2,
- { "D 65 0 false false false",
- "U 65 0 false false false" } },
+ { "D 65 0 false false false false",
+ "U 65 0 false false false false" } },
};
static const KeyEventTestData kTestWithInput[] = {
// a
- { base::VKEY_A, false, false, false,
+ { base::VKEY_A, false, false, false, false,
false, false, false, false, 4,
- { "D 65 0 false false false",
- "P 97 97 false false false",
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
"T a",
- "U 65 0 false false false" } },
+ "U 65 0 false false false false" } },
// shift-a
- { base::VKEY_A, false, true, false,
+ { base::VKEY_A, false, true, false, false,
false, false, false, false, 6,
- { "D 16 0 false true false",
- "D 65 0 false true false",
- "P 65 65 false true false",
+ { "D 16 0 false true false false",
+ "D 65 0 false true false false",
+ "P 65 65 false true false false",
"T A",
- "U 65 0 false true false",
- "U 16 0 false true false" } },
+ "U 65 0 false true false false",
+ "U 16 0 false true false false" } },
// a, suppress keydown
- { base::VKEY_A, false, false, false,
+ { base::VKEY_A, false, false, false, false,
true, false, false, false, 2,
- { "D 65 0 false false false",
- "U 65 0 false false false" } },
+ { "D 65 0 false false false false",
+ "U 65 0 false false false false" } },
// a, suppress keypress
- { base::VKEY_A, false, false, false,
+ { base::VKEY_A, false, 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" } },
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
+ "U 65 0 false false false false" } },
// a, suppress textInput
- { base::VKEY_A, false, false, false,
+ { base::VKEY_A, false, false, false, false,
false, false, false, true, 4,
- { "D 65 0 false false false",
- "P 97 97 false false false",
+ { "D 65 0 false false false false",
+ "P 97 97 false false false false",
"T a",
- "U 65 0 false false false" } },
+ "U 65 0 false false false false" } },
};
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
+ BringBrowserWindowToFront();
GURL url = server->TestServerPage(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
@@ -365,67 +392,79 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FLAKY_NormalKeyEvents) {
<< GetTestDataDescription(kTestNoInput[i]);
}
+ // Input in normal text box.
ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
- << "kTestWithInput[" << i << "] failed:\n"
+ << "kTestWithInput[" << i << "] in text box failed:\n"
<< GetTestDataDescription(kTestWithInput[i]);
}
-
EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA"));
+
+ // Input in password box.
+ ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"B"));
+ for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
+ << "kTestWithInput[" << i << "] in password box failed:\n"
+ << GetTestDataDescription(kTestWithInput[i]);
+ }
+ EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"B", L"aA"));
}
+#if defined(OS_WIN) || defined(OS_LINUX)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
static const KeyEventTestData kTestCtrlF = {
- base::VKEY_F, true, false, false,
+ base::VKEY_F, true, false, false, false,
false, false, false, false, 2,
- { "D 17 0 true false false",
- "D 70 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 70 0 true false false false" }
};
static const KeyEventTestData kTestCtrlFSuppressKeyDown = {
- base::VKEY_F, true, false, false,
+ base::VKEY_F, true, false, 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" }
+ { "D 17 0 true false false false",
+ "D 70 0 true false false false",
+ "U 70 0 true false false false",
+ "U 17 0 true false false false" }
};
// Ctrl+Z doesn't bind to any accelerators, which then should generate a
// keypress event with charCode=26.
static const KeyEventTestData kTestCtrlZ = {
- base::VKEY_Z, true, false, false,
+ base::VKEY_Z, true, false, 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" }
+ { "D 17 0 true false false false",
+ "D 90 0 true false false false",
+ "P 26 26 true false false false",
+ "U 90 0 true false false false",
+ "U 17 0 true false false false" }
};
static const KeyEventTestData kTestCtrlZSuppressKeyDown = {
- base::VKEY_Z, true, false, false,
+ base::VKEY_Z, true, false, 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" }
+ { "D 17 0 true false false false",
+ "D 90 0 true false false false",
+ "U 90 0 true false false false",
+ "U 17 0 true false false false" }
};
// Ctrl+Enter shall generate a keypress event with charCode=10 (LF).
static const KeyEventTestData kTestCtrlEnter = {
- base::VKEY_RETURN, true, false, false,
+ base::VKEY_RETURN, true, false, 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" }
+ { "D 17 0 true false false false",
+ "D 13 0 true false false false",
+ "P 10 10 true false false false",
+ "U 13 0 true false false false",
+ "U 17 0 true false false false" }
};
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
+ BringBrowserWindowToFront();
GURL url = server->TestServerPage(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
@@ -438,7 +477,8 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
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_NO_FATAL_FAILURE(
+ SendKey(base::VKEY_ESCAPE, false, false, false, false));
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
// Press Ctrl+F with keydown suppressed shall not open the find box.
@@ -449,6 +489,49 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZSuppressKeyDown));
EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlEnter));
}
+#elif defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CommandKeyEvents) {
+ static const KeyEventTestData kTestCmdF = {
+ base::VKEY_F, false, false, false, true,
+ false, false, false, false, 2,
+ { "D 91 0 false false false true",
+ "D 70 0 false false false true" }
+ };
+
+ // On Mac we don't send key up events when command modifier is down.
+ static const KeyEventTestData kTestCmdFSuppressKeyDown = {
+ base::VKEY_F, false, false, false, true,
+ true, false, false, false, 3,
+ { "D 91 0 false false false true",
+ "D 70 0 false false false true",
+ "U 91 0 false false false true" }
+ };
+
+ HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
+
+ BringBrowserWindowToFront();
+ GURL url = server->TestServerPage(kTestingPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ int tab_index = browser()->selected_index();
+ // Press Cmd+F, which will make the Find box open and request focus.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdF));
+ EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
+
+ // Press Escape to close the Find box and move the focus back to the web page.
+ ASSERT_NO_FATAL_FAILURE(
+ SendKey(base::VKEY_ESCAPE, false, false, false, false));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ // Press Cmd+F with keydown suppressed shall not open the find box.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdFSuppressKeyDown));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+}
+#endif
#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
// See http://crbug.com/40037 for details.
@@ -458,42 +541,80 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, CtrlKeyEvents) {
#endif
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
- static const KeyEventTestData kTestAltA = {
- base::VKEY_A, false, false, true,
+#if defined(OS_MACOSX)
+ // On Mac, access keys use ctrl+alt modifiers.
+ static const KeyEventTestData kTestAccessA = {
+ base::VKEY_A, true, false, true, false,
+ false, false, false, false, 6,
+ { "D 17 0 true false false false",
+ "D 18 0 true false true false",
+ "D 65 0 true false true false",
+ "U 65 0 true false true false",
+ "U 18 0 true false true false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestAccessDSuppress = {
+ base::VKEY_D, true, false, true, false,
+ true, true, true, false, 6,
+ { "D 17 0 true false false false",
+ "D 18 0 true false true false",
+ "D 68 0 true false true false",
+ "U 68 0 true false true false",
+ "U 18 0 true false true false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestAccess1 = {
+ base::VKEY_1, true, false, true, false,
+ false, false, false, false, 6,
+ { "D 17 0 true false false false",
+ "D 18 0 true false true false",
+ "D 49 0 true false true false",
+ "U 49 0 true false true false",
+ "U 18 0 true false true false",
+ "U 17 0 true false false false" }
+ };
+#else
+ static const KeyEventTestData kTestAccessA = {
+ base::VKEY_A, false, false, true, false,
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" }
+ { "D 18 0 false false true false",
+ "D 65 0 false false true false",
+ "U 65 0 false false true false",
+ "U 18 0 false false true false" }
};
- static const KeyEventTestData kTestAltD = {
- base::VKEY_D, false, false, true,
+ static const KeyEventTestData kTestAccessD = {
+ base::VKEY_D, false, false, true, false,
false, false, false, false, 2,
- { "D 18 0 false false true",
- "D 68 0 false false true" }
+ { "D 18 0 false false true false",
+ "D 68 0 false false true false" }
};
- static const KeyEventTestData kTestAltDSuppress = {
- base::VKEY_D, false, false, true,
+ static const KeyEventTestData kTestAccessDSuppress = {
+ base::VKEY_D, false, false, true, false,
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" }
+ { "D 18 0 false false true false",
+ "D 68 0 false false true false",
+ "U 68 0 false false true false",
+ "U 18 0 false false true false" }
};
- static const KeyEventTestData kTestAlt1 = {
- base::VKEY_1, false, false, true,
+ static const KeyEventTestData kTestAccess1 = {
+ base::VKEY_1, false, false, true, false,
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" }
+ { "D 18 0 false false true false",
+ "D 49 0 false false true false",
+ "U 49 0 false false true false",
+ "U 18 0 false false true false" }
};
+#endif
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
+ BringBrowserWindowToFront();
GURL url = server->TestServerPage(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
@@ -505,15 +626,17 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
// 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(TestKeyEvent(tab_index, kTestAccessA));
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"A"));
// Blur the focused element.
EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
// Make sure no element is focused.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
+
+#if !defined(OS_MACOSX)
// Alt+D should move the focus to the location entry.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltD));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessD));
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""));
@@ -524,11 +647,13 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
// Make sure no element is focused.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
+#endif
+
// If the keydown event is suppressed, then Alt+D should be handled as an
// accesskey rather than an accelerator key. Activation of an accesskey is not
// a part of the default action of the key event, so it should not be
// suppressed at all.
- EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltDSuppress));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessDSuppress));
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"D"));
@@ -536,30 +661,32 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
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));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccess1));
#if defined(TOOLKIT_GTK)
// On GTK, alt-0..9 are assigned as tab selection accelerators, so they can
// not be used as accesskeys.
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
-#elif defined(OS_WIN)
+#else
EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1"));
#endif
}
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, ReservedAccelerators) {
HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
+ BringBrowserWindowToFront();
GURL url = server->TestServerPage(kTestingPage);
ui_test_utils::NavigateToURL(browser(), url);
ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(TOOLKIT_VIEWS)
static const KeyEventTestData kTestCtrlT = {
- base::VKEY_T, true, false, false,
+ base::VKEY_T, true, false, false, false,
true, false, false, false, 1,
- { "D 17 0 true false false" }
+ { "D 17 0 true false false false" }
};
ASSERT_EQ(1, browser()->tab_count());
@@ -576,46 +703,68 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, ReservedAccelerators) {
// Reserved accelerators can't be suppressed.
ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
// Press Ctrl+W, which will close the tab.
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_W, true, false, false));
+ ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_W, true, false, false, false));
EXPECT_EQ(1, browser()->tab_count());
+#elif defined(OS_MACOSX)
+ static const KeyEventTestData kTestCmdT = {
+ base::VKEY_T, false, false, false, true,
+ true, false, false, false, 1,
+ { "D 91 0 false false false true" }
+ };
+
+ ASSERT_EQ(1, browser()->tab_count());
+ // Press Cmd+T, which will open a new tab.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCmdT));
+ EXPECT_EQ(2, browser()->tab_count());
+ browser()->SelectNumberedTab(0);
+ ASSERT_EQ(0, browser()->selected_index());
+
+ int result_length;
+ ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
+ EXPECT_EQ(1, result_length);
+ // Reserved accelerators can't be suppressed.
+ ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
+ // Press Cmd+W, which will close the tab.
+ ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_W, false, false, false, true));
+ EXPECT_EQ(1, browser()->tab_count());
#elif defined(TOOLKIT_GTK)
// Ctrl-[a-z] are not treated as reserved accelerators on GTK.
static const KeyEventTestData kTestCtrlT = {
- base::VKEY_T, true, false, false,
+ base::VKEY_T, true, false, false, false,
false, false, false, false, 2,
- { "D 17 0 true false false",
- "D 84 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 84 0 true false false false" }
};
static const KeyEventTestData kTestCtrlPageDown = {
- base::VKEY_NEXT, true, false, false,
+ base::VKEY_NEXT, true, false, false, false,
true, false, false, false, 1,
- { "D 17 0 true false false" }
+ { "D 17 0 true false false false" }
};
static const KeyEventTestData kTestCtrlTab = {
- base::VKEY_TAB, true, false, false,
+ base::VKEY_TAB, true, false, false, false,
true, false, false, false, 1,
- { "D 17 0 true false false" }
+ { "D 17 0 true false false false" }
};
static const KeyEventTestData kTestCtrlTBlocked = {
- base::VKEY_T, true, false, false,
+ base::VKEY_T, true, false, false, false,
true, false, false, false, 4,
- { "D 17 0 true false false",
- "D 84 0 true false false",
- "U 84 0 true false false",
- "U 17 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 84 0 true false false false",
+ "U 84 0 true false false false",
+ "U 17 0 true false false false" }
};
static const KeyEventTestData kTestCtrlWBlocked = {
- base::VKEY_W, true, false, false,
+ base::VKEY_W, true, false, false, false,
true, false, false, false, 4,
- { "D 17 0 true false false",
- "D 87 0 true false false",
- "U 87 0 true false false",
- "U 17 0 true false false" }
+ { "D 17 0 true false false false",
+ "D 87 0 true false false false",
+ "U 87 0 true false false false",
+ "U 17 0 true false false false" }
};
ASSERT_EQ(1, browser()->tab_count());
@@ -647,7 +796,91 @@ IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, ReservedAccelerators) {
// Ctrl+F4 to close the tab.
ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(0, true));
- ASSERT_NO_FATAL_FAILURE(SendKey(base::VKEY_F4, true, false, false));
+ ASSERT_NO_FATAL_FAILURE( SendKey(base::VKEY_F4, true, false, false, false));
ASSERT_EQ(1, browser()->tab_count());
#endif
}
+
+#if defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) {
+ static const KeyEventTestData kTestCtrlA = {
+ base::VKEY_A, true, false, false, false,
+ false, false, false, false, 4,
+ { "D 17 0 true false false false",
+ "D 65 0 true false false false",
+ "U 65 0 true false false false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestCtrlF = {
+ base::VKEY_F, true, false, false, false,
+ false, false, false, false, 4,
+ { "D 17 0 true false false false",
+ "D 70 0 true false false false",
+ "U 70 0 true false false false",
+ "U 17 0 true false false false" }
+ };
+
+ static const KeyEventTestData kTestCtrlK = {
+ base::VKEY_K, true, false, false, false,
+ false, false, false, false, 4,
+ { "D 17 0 true false false false",
+ "D 75 0 true false false false",
+ "U 75 0 true false false false",
+ "U 17 0 true false false false" }
+ };
+
+ HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
+
+ BringBrowserWindowToFront();
+ GURL url = server->TestServerPage(kTestingPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ int tab_index = browser()->selected_index();
+ ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
+ ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index, L"A", L"Hello"));
+ // Move the caret to the beginning of the line.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlA));
+ // Forward one character
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
+ // Delete to the end of the line.
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlK));
+ EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"H"));
+}
+#endif
+
+IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, PageUpDownKeys) {
+ static const KeyEventTestData kTestPageUp = {
+ base::VKEY_PRIOR, false, false, false, false,
+ false, false, false, false, 2,
+ { "D 33 0 false false false false",
+ "U 33 0 false false false false" }
+ };
+
+ static const KeyEventTestData kTestPageDown = {
+ base::VKEY_NEXT, false, false, false, false,
+ false, false, false, false, 2,
+ { "D 34 0 false false false false",
+ "U 34 0 false false false false" }
+ };
+
+ HTTPTestServer* server = StartHTTPServer();
+ ASSERT_TRUE(server);
+
+ BringBrowserWindowToFront();
+ GURL url = server->TestServerPage(kTestingPage);
+ ui_test_utils::NavigateToURL(browser(), url);
+
+ ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
+ ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW));
+
+ int tab_index = browser()->selected_index();
+ ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageUp));
+ EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageDown));
+ EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L""));
+}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 1e6b896..6e280d4 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -222,6 +222,7 @@
'browser/automation/automation_window_tracker.h',
'browser/automation/extension_port_container.cc',
'browser/automation/extension_port_container.h',
+ 'browser/automation/ui_controls_internal.h',
'browser/automation/ui_controls_linux.cc',
'browser/automation/ui_controls_mac.mm',
'browser/automation/ui_controls_win.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index da22578..d2207d4 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -124,7 +124,7 @@
'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_mac.mm',
'test/ui_test_utils_win.cc',
],
'conditions': [
@@ -2164,7 +2164,7 @@
'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_mac.mm',
'test/ui_test_utils_win.cc',
'test/data/resource.h',
'test/data/resource.rc',
diff --git a/chrome/test/data/keyevents_test.html b/chrome/test/data/keyevents_test.html
index 140fad0..88ba7a8 100644
--- a/chrome/test/data/keyevents_test.html
+++ b/chrome/test/data/keyevents_test.html
@@ -11,7 +11,10 @@ var keyEventResult = [];
var focusedElement = "";
var lastFocusedElement = "";
var testStarted = false;
-var keyEventCount = 0;
+var expectedEventCount = 0;
+var eventCount = 0;
+var keyDownCount = 0;
+var keyUpCount = 0;
function init() {
document.addEventListener("keydown", handleEvent, false);
@@ -31,10 +34,11 @@ function setDefaultAction(type, value) {
return defaultActions[type];
}
-function startTest() {
+function startTest(count) {
if (!testStarted) {
clearResult();
testStarted = true;
+ expectedEventCount = count;
log("Start test.");
return true;
}
@@ -72,17 +76,19 @@ function handleEvent(e) {
result += (evt.keyCode + ' ' + evt.charCode + ' ' +
(keyId == 'Control' ? true : evt.ctrlKey) + ' ' +
(keyId == 'Shift' ? true : evt.shiftKey) + ' ' +
- (keyId == 'Alt' ? true : evt.altKey));
+ (keyId == 'Alt' ? true : evt.altKey) + ' ' +
+ (keyId == 'Meta' ? true : evt.metaKey));
}
keyEventResult.push(result);
log(result);
if (testStarted) {
+ ++eventCount;
if (evt.type == "keydown") {
- ++keyEventCount;
+ ++keyDownCount;
} else if (evt.type == "keyup") {
- --keyEventCount;
- if (keyEventCount == 0)
+ ++keyUpCount;
+ if (keyDownCount == keyUpCount || (eventCount >= expectedEventCount))
finishTest();
}
}
@@ -102,7 +108,10 @@ function handleWindowBlur() {
function clearResult() {
keyEventResult = [];
testStarted = false;
- keyEventCount = 0;
+ expectedEventCount = 0;
+ eventCount = 0;
+ keyDownCount = 0;
+ keyUpCount = 0;
document.getElementById('log').innerHTML = "";
return true;
}
@@ -157,7 +166,7 @@ function onClick(element) {
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"
+ <input type="password" id="B" accesskey="B"
onfocus="onFocus(this)" onblur="onBlur(this)"/>
<button id="clear" accesskey='C' onclick="clearResult()">Clear</button>
<p id="log"></p>
diff --git a/chrome/test/interactive_ui/interactive_ui_tests.gypi b/chrome/test/interactive_ui/interactive_ui_tests.gypi
index 4a6c841..33529d5 100644
--- a/chrome/test/interactive_ui/interactive_ui_tests.gypi
+++ b/chrome/test/interactive_ui/interactive_ui_tests.gypi
@@ -88,8 +88,6 @@
'sources!': [
# 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/views/find_bar_host_interactive_uitest.cc',
diff --git a/chrome/test/ui_test_utils.h b/chrome/test/ui_test_utils.h
index 5949f51..8173348 100644
--- a/chrome/test/ui_test_utils.h
+++ b/chrome/test/ui_test_utils.h
@@ -10,6 +10,7 @@
#include <string>
#include <set>
+#include "gfx/native_widget_types.h"
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/scoped_temp_dir.h"
@@ -417,6 +418,12 @@ class WindowedNotificationObserverWithDetails
DISALLOW_COPY_AND_ASSIGN(WindowedNotificationObserverWithDetails);
};
+// Hide a native window.
+void HideNativeWindow(gfx::NativeWindow window);
+
+// Show and focus a native window.
+void ShowAndFocusNativeWindow(gfx::NativeWindow window);
+
} // namespace ui_test_utils
#endif // CHROME_TEST_UI_TEST_UTILS_H_
diff --git a/chrome/test/ui_test_utils_linux.cc b/chrome/test/ui_test_utils_linux.cc
index 5878086..e9d29dc 100644
--- a/chrome/test/ui_test_utils_linux.cc
+++ b/chrome/test/ui_test_utils_linux.cc
@@ -85,4 +85,12 @@ void ClickOnView(const Browser* browser, ViewID vid) {
RunMessageLoop();
}
+void HideNativeWindow(gfx::NativeWindow window) {
+ gtk_widget_hide(GTK_WIDGET(window));
+}
+
+void ShowAndFocusNativeWindow(gfx::NativeWindow window) {
+ gtk_window_present(GTK_WINDOW(window));
+}
+
} // namespace ui_test_utils
diff --git a/chrome/test/ui_test_utils_mac.cc b/chrome/test/ui_test_utils_mac.cc
deleted file mode 100644
index c763a10..0000000
--- a/chrome/test/ui_test_utils_mac.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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 {
-
-// Details on why these are unimplemented: ViewIDs are defined in
-// chrome/browser/view_ids.h. For Cocoa (unlike Views GTK) we don't
-// associate ViewIDs with NSViews.
-//
-// Here's an idea on how to implement.
-// - associate the correct ViewID with an NSView on construction (the most work)
-// - create a mapping table, such as chrome/browser/gtk/view_id_util.h
-// - IsViewFocused() then becomes
-// [browser->window()->GetNativeHandle() firstResponder]
-// - ClickOnView() becomes a normal NSMouseDown event forge at the right coords
-
-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_mac.mm b/chrome/test/ui_test_utils_mac.mm
new file mode 100644
index 0000000..6e3689b
--- /dev/null
+++ b/chrome/test/ui_test_utils_mac.mm
@@ -0,0 +1,66 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/ui_test_utils.h"
+
+#include <Carbon/Carbon.h>
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "chrome/browser/automation/ui_controls.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_window.h"
+#import "chrome/browser/cocoa/view_id_util.h"
+
+namespace ui_test_utils {
+
+bool IsViewFocused(const Browser* browser, ViewID vid) {
+ NSWindow* window = browser->window()->GetNativeHandle();
+ DCHECK(window);
+ NSView* view = view_id_util::GetView(window, vid);
+ if (!view)
+ return false;
+
+ NSResponder* firstResponder = [window firstResponder];
+ if (firstResponder == static_cast<NSResponder*>(view))
+ return true;
+
+ // Handle the special case of focusing a TextField.
+ if ([firstResponder isKindOfClass:[NSTextView class]]) {
+ NSView* delegate = [(NSTextView*)firstResponder delegate];
+ if (delegate == view)
+ return true;
+ }
+
+ return false;
+}
+
+void ClickOnView(const Browser* browser, ViewID vid) {
+ NSWindow* window = browser->window()->GetNativeHandle();
+ DCHECK(window);
+ NSView* view = view_id_util::GetView(window, vid);
+ DCHECK(view);
+ ui_controls::MoveMouseToCenterAndPress(
+ view,
+ ui_controls::LEFT,
+ ui_controls::DOWN | ui_controls::UP,
+ new MessageLoop::QuitTask());
+ RunMessageLoop();
+}
+
+void HideNativeWindow(gfx::NativeWindow window) {
+ [window orderOut:nil];
+}
+
+void ShowAndFocusNativeWindow(gfx::NativeWindow window) {
+ // Make sure an unbundled program can get the input focus.
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+ TransformProcessType(&psn,kProcessTransformToForegroundApplication);
+ SetFrontProcess(&psn);
+
+ [window makeKeyAndOrderFront:nil];
+}
+
+} // namespace ui_test_utils
diff --git a/chrome/test/ui_test_utils_win.cc b/chrome/test/ui_test_utils_win.cc
index 22fa003..8c45ee3 100644
--- a/chrome/test/ui_test_utils_win.cc
+++ b/chrome/test/ui_test_utils_win.cc
@@ -39,4 +39,16 @@ void ClickOnView(const Browser* browser, ViewID vid) {
RunMessageLoop();
}
+void HideNativeWindow(gfx::NativeWindow window) {
+ // TODO(jcampan): retrieve the WidgetWin and show/hide on it instead of
+ // using Windows API.
+ ::ShowWindow(window, SW_HIDE);
+}
+
+void ShowAndFocusNativeWindow(gfx::NativeWindow window) {
+ // TODO(jcampan): retrieve the WidgetWin and show/hide on it instead of
+ // using Windows API.
+ ::ShowWindow(window, SW_SHOW);
+}
+
} // namespace ui_test_utils