Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: chrome/browser/apps/app_window_intercept_all_keys_uitest.cc

Issue 297123002: API proposal for chrome.app.window to intercept all keys. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Return if there is no windows with keyboard focus. Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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.
4
5 #include "apps/ui/native_app_window.h"
6 #include "base/callback.h"
7 #include "base/logging.h"
8 #include "base/macros.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/apps/app_browsertest_util.h"
11 #include "chrome/browser/extensions/extension_test_message_listener.h"
12 #include "chrome/test/base/interactive_test_utils.h"
13 #include "testing/gtest/include/gtest/gtest-spi.h"
14
15 using apps::NativeAppWindow;
16
17 class AppWindowInterceptAllKeysTest
18 : public extensions::PlatformAppBrowserTest {
19 public:
20 // Send key to window but does not wait till the key is actually in the input
21 // queue (like ui_test_utils::SendKeyPressToWindowSync()) as key will not be
22 // sent to hook when keyboard is intercepted.
23 bool SimulateKeyPress(ui::KeyboardCode key,
24 bool control,
25 bool shift,
26 bool alt,
27 bool command) {
28 DVLOG(1) << "Sending: " << key << " control = " << control
29 << " shift = " << shift << " alt = " << alt
30 << " command = " << command;
31 if (!ui_controls::SendKeyPressNotifyWhenDone(
32 GetFirstAppWindow()->GetNativeWindow(),
33 key,
34 control,
35 shift,
36 alt,
37 command,
38 null_callback_)) {
39 LOG(WARNING) << "Failed to send key to app";
40 failure_message_ = "Failed to send key to app.";
41 return false;
42 }
43
44 base::RunLoop().RunUntilIdle();
45 return !testing::Test::HasFatalFailure();
46 }
47
48 bool SimulateKeyPress(ui::KeyboardCode key) {
49 return SimulateKeyPress(key, false, false, false, false);
50 }
51
52 bool WaitForKeyEvent(ui::KeyboardCode code) {
53 std::string key_event = base::StringPrintf("KeyReceived: %d", code);
54 ExtensionTestMessageListener key_listener(key_event, false);
55
56 if (!SimulateKeyPress(code)) {
57 failure_message_ = "Failed to send key to app";
58 return false;
59 }
60
61 key_listener.WaitUntilSatisfied();
62
63 DVLOG(1) << "Application ACK-ed keypress";
64 return true;
65 }
66
67 bool LoadApplication(const char* app_path) {
68 DVLOG(1) << "Launching app = " << app_path;
69 LoadAndLaunchPlatformApp(app_path, "Launched");
70
71 DVLOG(1) << "Validating that application is in focus";
72 // We start by making sure the window is actually focused.
73 if (!ui_test_utils::ShowAndFocusNativeWindow(
74 GetFirstAppWindow()->GetNativeWindow())) {
75 failure_message_ = "App did not get focus.";
76 return false;
77 }
78
79 DVLOG(1) << "Launched application";
80 return true;
81 }
82
83 void SendTaskSwitchKeys() {
84 // Send switch sequence (currently just for windows - will have to update as
85 // more platform support is added).
86 SimulateKeyPress(ui::VKEY_TAB, false, false, true, false);
87 }
88
89 void ValidateCannotInterceptKeys(const char* app_path,
90 bool change_intercept,
91 bool enable_intercept) {
92 ExtensionTestMessageListener command_listener("readyForCommand", true);
93 ASSERT_TRUE(LoadApplication(app_path)) << failure_message_;
94
95 const char* message = "";
96 if (change_intercept) {
97 message = enable_intercept ? "enable" : "disable";
98 }
99 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
100 command_listener.Reply(message);
101 command_listener.Reset();
102
103 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
104
105 SendTaskSwitchKeys();
106
107 // Send key and check if it is received.
108 ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_;
109 }
110
111 void ValidateInterceptKeys(bool disable_after_enabling) {
112 ExtensionTestMessageListener command_listener("readyForCommand", true);
113 ASSERT_TRUE(LoadApplication(app_with_permission_)) << failure_message_;
114
115 // setInterceptAllKeys() is asynchronous so wait for response and receiving
116 // a key back.
117 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
118 command_listener.Reply("enable");
119 command_listener.Reset();
120
121 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
122
123 SendTaskSwitchKeys();
124
125 // Send key and check if it is received.
126 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_;
127
128 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
129
130 if (disable_after_enabling) {
131 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
132 command_listener.Reply("disable");
133 command_listener.Reset();
134 ASSERT_TRUE(command_listener.WaitUntilSatisfied());
135 }
136 }
137
138 protected:
139 std::string failure_message_;
140 base::Callback<void(void)> null_callback_;
141 const char* app_with_permission_ =
142 "window_api_intercept_all_keys/has_permission";
143 const char* app_without_permission_ =
144 "window_api_intercept_all_keys/no_permission";
145 };
146
147 // Currently this is implemented only for Windows.
148 #if defined(OS_WIN)
149 #define MAYBE_GetKeysAfterSwitchSequence GetKeysAfterSwitchSequence
150 #else
151 #define MAYBE_GetKeysAfterSwitchSequence DISABLED_GetKeysAfterSwitchSequence
152 #endif
153
154 // Tests a window continues to keep focus even after application switch key
155 // sequence is sent when setInterceptAllKeys() is enabled.
156 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
157 MAYBE_GetKeysAfterSwitchSequence) {
158 ValidateInterceptKeys(false);
159 }
160
161 // Test to make sure that keys not received after disable.
162 #if defined(OS_WIN)
163 #define MAYBE_NoKeysAfterDisableIsCalled NoKeysAfterDisableIsCalled
164 #else
165 #define MAYBE_NoKeysAfterDisableIsCalled DISABLED_NoKeysAfterDisableIsCalled
166 #endif
167
168 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
169 MAYBE_NoKeysAfterDisableIsCalled) {
170 ValidateInterceptKeys(true);
171
172 ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_;
173
174 SendTaskSwitchKeys();
175
176 // Send key and check if it is received.
177 ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_;
178 }
179
180 // Test that calling just disable has no effect in retaining keyboard intercept.
181 // Currently this is implemented only for Windows.
182 #if defined(OS_WIN)
183 #define MAYBE_NoopCallingDisableInterceptAllKeys \
184 NoopCallingDisableInterceptAllKeys
185 #else
186 #define MAYBE_NoopCallingDisableInterceptAllKeys \
187 DISABLED_NoopCallingDisableInterceptAllKeys
188 #endif
189
190 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
191 MAYBE_NoopCallingDisableInterceptAllKeys) {
192 ValidateCannotInterceptKeys(app_with_permission_, true, false);
193 }
194
195 // Test no effect when called without permissions
196 // Currently this is implemented only for Windows.
197 #if defined(OS_WIN)
198 #define MAYBE_NoopCallingEnableWithoutPermission \
199 NoopCallingEnableWithoutPermission
200 #else
201 #define MAYBE_NoopCallingEnableWithoutPermission \
202 DISABLED_NoopCallingEnableWithoutPermission
203 #endif
204
205 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
206 MAYBE_NoopCallingEnableWithoutPermission) {
207 ValidateCannotInterceptKeys(app_without_permission_, true, true);
208 }
209
210 // Test that intercept is disabled by default
211 #if defined(OS_WIN)
212 #define MAYBE_InterceptDisabledByDefault InterceptDisabledByDefault
213 #else
214 #define MAYBE_InterceptDisabledByDefault DISABLED_InterceptDisabledByDefault
215 #endif
216
217 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
218 MAYBE_InterceptDisabledByDefault) {
219 ValidateCannotInterceptKeys(app_with_permission_, false, false);
220 }
221
222 // Tests that the application cannot be loaded in stable.
223 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, CannotLoadOtherThanDev) {
224 chrome::VersionInfo::Channel version_info[] = {
225 chrome::VersionInfo::CHANNEL_BETA, chrome::VersionInfo::CHANNEL_STABLE};
226 for (unsigned int index = 0; index < arraysize(version_info); index++) {
227 extensions::ScopedCurrentChannel channel(version_info[index]);
228 const extensions::Extension* extension;
229 EXPECT_NONFATAL_FAILURE(
230 extension = LoadExtension(test_data_dir_.AppendASCII("platform_apps")
231 .AppendASCII(app_with_permission_)),
232 "");
233
234 DVLOG(1) << "Finished loading extension";
235
236 ASSERT_TRUE(extension == NULL) << "Application loaded in"
237 << version_info[index]
238 << " while permission does not exist";
239 }
240 }
241
242 // Inject different keyboard combos and make sure that the app get them all.
243 #if defined(OS_WIN)
244 #define MAYBE_ValidateKeyEvent ValidateKeyEvent
245 #else
246 #define MAYBE_ValidateKeyEvent DISABLED_ValidateKeyEvent
247 #endif
248
249 namespace {
250 // Maximum lenght of the result array in KeyEventTestData structure.
251 const size_t kMaxResultLength = 10;
252
253 // A structure holding test data of a keyboard event.
254 // Each keyboard event may generate multiple result strings representing
255 // the result of keydown, keypress, keyup and textInput events.
256 // For keydown, keypress and keyup events, the format of the result string is:
257 // <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
258 // where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
259 // <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
260 // the state of corresponding modifier key.
261 struct KeyEventTestData {
262 ui::KeyboardCode key;
263 bool control;
264 bool shift;
265 bool alt;
266 bool command;
267
268 int result_length;
269 const char* const result[kMaxResultLength];
270 };
271 } // namespace
272
273 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, MAYBE_ValidateKeyEvent) {
274 // Launch the app
275 ValidateInterceptKeys(false);
276
277 static const KeyEventTestData kValidateKeyEvents[] = {
278 // a
279 {ui::VKEY_A,
280 false,
281 false,
282 false,
283 false,
284 3,
285 {"D 65 0 false false false false", "P 97 97 false false false false",
286 "U 65 0 false false false false"}},
287 // shift+a
288 {ui::VKEY_A,
289 false,
290 true,
291 false,
292 false,
293 5,
294 {"D 16 0 false true false false", "D 65 0 false true false false",
295 "P 65 65 false true false false", "U 65 0 false true false false",
296 "U 16 0 false true false false"}},
297 // ctrl+f which has accelerator binding should also result in all keys
298 // being
299 // sent.
300 {ui::VKEY_F,
301 true,
302 false,
303 false,
304 false,
305 5,
306 {"D 17 0 true false false false", "D 70 0 true false false false",
307 "P 6 6 true false false false", "U 70 0 true false false false",
308 "U 17 0 true false false false"}},
309 // ctrl+z
310 {ui::VKEY_Z,
311 true,
312 false,
313 false,
314 false,
315 5,
316 {"D 17 0 true false false false", "D 90 0 true false false false",
317 "P 26 26 true false false false", "U 90 0 true false false false",
318 "U 17 0 true false false false"}},
319 // alt+f
320 {ui::VKEY_F,
321 false,
322 false,
323 true,
324 false,
325 4,
326 {"D 18 0 false false true false", "D 70 0 false false true false",
327 "U 70 0 false false true false", "U 18 0 false false true false"}},
328 // make sure both left and right shift makes it across
329 {ui::VKEY_RSHIFT,
330 false,
331 false,
332 false,
333 false,
334 2,
335 {"D 16 0 false true false false", "U 16 0 false true false false"}},
336 };
337
338 DVLOG(1) << "Starting keyboard input test";
339
340 for (unsigned int index = 0; index < arraysize(kValidateKeyEvents); index++) {
341 // create all the event listeners needed
342 const KeyEventTestData* current_event = &kValidateKeyEvents[index];
343 scoped_ptr<ExtensionTestMessageListener> listeners[kMaxResultLength];
344 for (int i = 0; i < current_event->result_length; i++) {
345 listeners[i].reset(
346 new ExtensionTestMessageListener(current_event->result[i], false));
347 }
348 ASSERT_TRUE(SimulateKeyPress(current_event->key,
349 current_event->control,
350 current_event->shift,
351 current_event->alt,
352 current_event->command));
353 for (int i = 0; i < current_event->result_length; i++) {
354 EXPECT_TRUE(listeners[i]->WaitUntilSatisfied());
355 }
356 }
357 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698