Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_commands_global_registry_apitest.cc
blobd961bd72c1f0d56618673931b88ce57da9d13ca4
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/extension_apitest.h"
6 #include "chrome/browser/extensions/window_controller.h"
7 #include "chrome/browser/ui/browser_window.h"
8 #include "chrome/browser/ui/tabs/tab_strip_model.h"
9 #include "chrome/test/base/interactive_test_utils.h"
10 #include "content/public/test/browser_test_utils.h"
11 #include "extensions/test/result_catcher.h"
12 #include "ui/base/base_window.h"
13 #include "ui/base/test/ui_controls.h"
15 #if defined(OS_LINUX) && defined(USE_X11)
16 #include <X11/Xlib.h>
17 #include <X11/extensions/XTest.h>
18 #include <X11/keysym.h>
20 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
21 #include "ui/gfx/x/x11_types.h"
22 #endif
24 #if defined(OS_MACOSX)
25 #include <Carbon/Carbon.h>
27 #include "base/mac/scoped_cftyperef.h"
28 #endif
30 namespace extensions {
32 typedef ExtensionApiTest GlobalCommandsApiTest;
34 #if defined(OS_LINUX) && defined(USE_X11)
35 // Send a simulated key press and release event, where |control|, |shift| or
36 // |alt| indicates whether the key is struck with corresponding modifier.
37 void SendNativeKeyEventToXDisplay(ui::KeyboardCode key,
38 bool control,
39 bool shift,
40 bool alt) {
41 Display* display = gfx::GetXDisplay();
42 KeyCode ctrl_key_code = XKeysymToKeycode(display, XK_Control_L);
43 KeyCode shift_key_code = XKeysymToKeycode(display, XK_Shift_L);
44 KeyCode alt_key_code = XKeysymToKeycode(display, XK_Alt_L);
46 // Release modifiers first of all to make sure this function can work as
47 // expected. For example, when |control| is false, but the status of Ctrl key
48 // is down, we will generate a keyboard event with unwanted Ctrl key.
49 XTestFakeKeyEvent(display, ctrl_key_code, False, CurrentTime);
50 XTestFakeKeyEvent(display, shift_key_code, False, CurrentTime);
51 XTestFakeKeyEvent(display, alt_key_code, False, CurrentTime);
53 typedef std::vector<KeyCode> KeyCodes;
54 KeyCodes key_codes;
55 if (control)
56 key_codes.push_back(ctrl_key_code);
57 if (shift)
58 key_codes.push_back(shift_key_code);
59 if (alt)
60 key_codes.push_back(alt_key_code);
62 key_codes.push_back(XKeysymToKeycode(display,
63 XKeysymForWindowsKeyCode(key, false)));
65 // Simulate the keys being pressed.
66 for (KeyCodes::iterator it = key_codes.begin(); it != key_codes.end(); it++)
67 XTestFakeKeyEvent(display, *it, True, CurrentTime);
69 // Simulate the keys being released.
70 for (KeyCodes::iterator it = key_codes.begin(); it != key_codes.end(); it++)
71 XTestFakeKeyEvent(display, *it, False, CurrentTime);
73 XFlush(display);
75 #endif // OS_LINUX && USE_X11
77 #if defined(OS_MACOSX)
78 using base::ScopedCFTypeRef;
80 void SendNativeCommandShift(int key_code) {
81 CGEventSourceRef event_source =
82 CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
83 CGEventTapLocation event_tap_location = kCGHIDEventTap;
85 // Create the keyboard press events.
86 ScopedCFTypeRef<CGEventRef> command_down(CGEventCreateKeyboardEvent(
87 event_source, kVK_Command, true));
88 ScopedCFTypeRef<CGEventRef> shift_down(CGEventCreateKeyboardEvent(
89 event_source, kVK_Shift, true));
90 ScopedCFTypeRef<CGEventRef> key_down(CGEventCreateKeyboardEvent(
91 event_source, key_code, true));
92 CGEventSetFlags(key_down, kCGEventFlagMaskCommand | kCGEventFlagMaskShift);
94 // Create the keyboard release events.
95 ScopedCFTypeRef<CGEventRef> command_up(CGEventCreateKeyboardEvent(
96 event_source, kVK_Command, false));
97 ScopedCFTypeRef<CGEventRef> shift_up(CGEventCreateKeyboardEvent(
98 event_source, kVK_Shift, false));
99 ScopedCFTypeRef<CGEventRef> key_up(CGEventCreateKeyboardEvent(
100 event_source, key_code, false));
101 CGEventSetFlags(key_up, kCGEventFlagMaskCommand | kCGEventFlagMaskShift);
103 // Post all of the events.
104 CGEventPost(event_tap_location, command_down);
105 CGEventPost(event_tap_location, shift_down);
106 CGEventPost(event_tap_location, key_down);
107 CGEventPost(event_tap_location, key_up);
108 CGEventPost(event_tap_location, shift_up);
109 CGEventPost(event_tap_location, command_up);
111 CFRelease(event_source);
113 #endif
115 // Test the basics of global commands and make sure they work when Chrome
116 // doesn't have focus. Also test that non-global commands are not treated as
117 // global and that keys beyond Ctrl+Shift+[0..9] cannot be auto-assigned by an
118 // extension.
119 IN_PROC_BROWSER_TEST_F(GlobalCommandsApiTest, GlobalCommand) {
120 // Load the extension in the non-incognito browser.
121 ResultCatcher catcher;
122 ASSERT_TRUE(RunExtensionTest("keybinding/global")) << message_;
123 ASSERT_TRUE(catcher.GetNextResult());
125 #if defined(OS_WIN) || defined(OS_CHROMEOS)
126 // Our infrastructure for sending keys expects a browser to send them to, but
127 // to properly test global shortcuts you need to send them to another target.
128 // So, create an incognito browser to use as a target to send the shortcuts
129 // to. It will ignore all of them and allow us test whether the global
130 // shortcut really is global in nature and also that the non-global shortcut
131 // is non-global.
132 Browser* incognito_browser = CreateIncognitoBrowser();
134 // Try to activate the non-global shortcut (Ctrl+Shift+1) and the
135 // non-assignable shortcut (Ctrl+Shift+A) by sending the keystrokes to the
136 // incognito browser. Both shortcuts should have no effect (extension is not
137 // loaded there).
138 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
139 incognito_browser, ui::VKEY_1, true, true, false, false));
140 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
141 incognito_browser, ui::VKEY_A, true, true, false, false));
143 // Activate the shortcut (Ctrl+Shift+8). This should have an effect.
144 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
145 incognito_browser, ui::VKEY_8, true, true, false, false));
146 #elif defined(OS_LINUX) && defined(USE_X11)
147 // Create an incognito browser to capture the focus.
148 CreateIncognitoBrowser();
150 // On Linux, our infrastructure for sending keys just synthesize keyboard
151 // event and send them directly to the specified window, without notifying the
152 // X root window. It didn't work while testing global shortcut because the
153 // stuff of global shortcut on Linux need to be notified when KeyPress event
154 // is happening on X root window. So we simulate the keyboard input here.
155 SendNativeKeyEventToXDisplay(ui::VKEY_1, true, true, false);
156 SendNativeKeyEventToXDisplay(ui::VKEY_A, true, true, false);
157 SendNativeKeyEventToXDisplay(ui::VKEY_8, true, true, false);
158 #elif defined(OS_MACOSX)
159 // Create an incognito browser to capture the focus.
160 CreateIncognitoBrowser();
162 // Send some native mac key events.
163 SendNativeCommandShift(kVK_ANSI_1);
164 SendNativeCommandShift(kVK_ANSI_A);
165 SendNativeCommandShift(kVK_ANSI_8);
166 #endif
168 // If this fails, it might be because the global shortcut failed to work,
169 // but it might also be because the non-global shortcuts unexpectedly
170 // worked.
171 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
174 #if defined(OS_WIN)
175 // Feature only fully implemented on Windows, other platforms coming.
176 // TODO(smus): On mac, SendKeyPress must first support media keys.
177 // Test occasionally times out on Windows. http://crbug.com/428813
178 #define MAYBE_GlobalDuplicatedMediaKey DISABLED_GlobalDuplicatedMediaKey
179 #else
180 #define MAYBE_GlobalDuplicatedMediaKey DISABLED_GlobalDuplicatedMediaKey
181 #endif
183 IN_PROC_BROWSER_TEST_F(GlobalCommandsApiTest, MAYBE_GlobalDuplicatedMediaKey) {
184 ResultCatcher catcher;
185 ASSERT_TRUE(RunExtensionTest("keybinding/global_media_keys_0")) << message_;
186 ASSERT_TRUE(catcher.GetNextResult());
187 ASSERT_TRUE(RunExtensionTest("keybinding/global_media_keys_1")) << message_;
188 ASSERT_TRUE(catcher.GetNextResult());
190 Browser* incognito_browser = CreateIncognitoBrowser(); // Ditto.
191 WindowController* controller =
192 incognito_browser->extension_window_controller();
194 ui_controls::SendKeyPress(controller->window()->GetNativeWindow(),
195 ui::VKEY_MEDIA_NEXT_TRACK,
196 false,
197 false,
198 false,
199 false);
201 // We should get two success results.
202 ASSERT_TRUE(catcher.GetNextResult());
203 ASSERT_TRUE(catcher.GetNextResult());
206 } // namespace extensions