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

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: Fix build break pulling in TOT 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/macros.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/apps/app_browsertest_util.h"
10 #include "chrome/browser/extensions/extension_test_message_listener.h"
11 #include "chrome/test/base/interactive_test_utils.h"
12 #include "testing/gtest/include/gtest/gtest-spi.h"
13
14 using apps::NativeAppWindow;
15
16 class AppWindowInterceptAllKeysTest
17 : public extensions::PlatformAppBrowserTest {
18 public:
19 // Send key to window but does not wait till the key is actually in the input
20 // queue (like ui_test_utils::SendKeyPressToWindowSync()) as key will not be
21 // sent to hook when keyboard is intercepted.
22 bool SimulateKeyPress(ui::KeyboardCode key,
23 bool control,
24 bool shift,
25 bool alt,
26 bool command) {
27 LOG(INFO) << "Sending: " << key << " control = " << control << " shift = "
benwells 2014/07/30 02:50:25 Please remove logging here and elsewhere, LOG(INFO
Sriram 2014/07/31 17:00:06 Is LOG(INFO) not allowed even in tests? What is th
benwells 2014/08/01 00:32:43 Yes, DVLOG(1) or VLOG(1) is fine.
28 << shift << " alt = " << alt << " command = " << command;
29 if (!ui_controls::SendKeyPressNotifyWhenDone(
30 GetFirstAppWindow()->GetNativeWindow(),
31 key,
32 control,
33 shift,
34 alt,
35 command,
36 null_callback_)) {
37 LOG(INFO) << "Failed to send key to app";
benwells 2014/07/30 02:50:25 You can use LOG(WARNING) here, but LOG(INFO) shoul
Sriram 2014/07/31 17:00:05 Done.
38 message_ = "Failed to send key to app.";
39 return false;
40 }
41
42 base::RunLoop().RunUntilIdle();
43 return !testing::Test::HasFatalFailure();
44 }
45
46 bool SimulateKeyPress(ui::KeyboardCode key) {
47 return SimulateKeyPress(key, false, false, false, false);
48 }
49
50 bool SendReply(const char* message) {
benwells 2014/07/30 02:50:25 Can you explain what this is for? There is already
Sriram 2014/07/31 17:00:05 It is using ExtensionTestMessageListener to send t
benwells 2014/08/01 00:32:43 I'm unsure how this is working. In the .js it uses
51 return SendKeyEvent(ui::VKEY_A, message);
52 }
53
54 bool SendKeyEvent(ui::KeyboardCode code, const char* message) {
55 std::string key_event = base::StringPrintf("KeyReceived: %d", code);
56 ExtensionTestMessageListener key_listener(key_event, (message != NULL));
57 if (!key_listener.was_satisfied()) {
benwells 2014/07/30 02:50:25 Why do you have to check this here? You have just
Sriram 2014/07/31 17:00:05 Done.
58 if (!SimulateKeyPress(code)) {
59 message_ = "Failed to send key to app";
60 return false;
61 }
62 key_listener.WaitUntilSatisfied();
63 if (message) {
64 key_listener.Reply(message);
65 }
66 }
67 base::RunLoop().RunUntilIdle();
benwells 2014/07/30 02:50:25 Why do you run the message loop here?
Sriram 2014/07/31 17:00:06 Done.
68 LOG(INFO) << "Application ACK-ed keypress";
69 return true;
70 }
71
72 bool WaitForKeyEvent(ui::KeyboardCode code) {
73 return SendKeyEvent(code, NULL);
74 }
75
76 // This method will wait until the application is able to ack a key event.
77 bool WaitUntilKeyFocus() { return WaitForKeyEvent(ui::VKEY_Z); }
benwells 2014/07/30 02:50:25 I'm not sure how this causes focus to be given to
Sriram 2014/07/31 17:00:06 Intermediate iteration changed focus but not any m
78
79 ExtensionTestMessageListener* LoadApplication(const char* app_path) {
80 LOG(INFO) << "Launching app = " << app_path;
81 scoped_ptr<ExtensionTestMessageListener> launched_listener(
benwells 2014/07/30 02:50:24 Why is this a scoped_ptr? Oh, now I see. This cod
Sriram 2014/07/31 17:00:06 Done.
82 new ExtensionTestMessageListener("Launched", true));
83 LoadAndLaunchPlatformApp(app_path, launched_listener.get());
84
85 LOG(INFO) << "Waiting for 'Launched' response";
86
87 if (!launched_listener->WaitUntilSatisfied()) {
88 message_ = "Did not get the 'Launched' message.";
89 return NULL;
90 }
91
92 LOG(INFO) << "Validating that application is in focus";
93 // We start by making sure the window is actually focused.
94 if (!ui_test_utils::ShowAndFocusNativeWindow(
95 GetFirstAppWindow()->GetNativeWindow())) {
96 message_ = "App did not get focus.";
97 return NULL;
98 }
99
100 LOG(INFO) << "Launched application";
101 return launched_listener.release();
102 }
103
104 void SendTaskSwitchKeys() {
105 // Send switch sequence (currently just for windows - will have to update as
106 // more platform support is added).
107
108 // Use null closure keys cannot be intercepted to validate.
109 ui_controls::SendKeyPressNotifyWhenDone(
benwells 2014/07/30 02:50:25 Can you use SimulateKeyPress here?
Sriram 2014/07/31 17:00:05 Done.
110 GetFirstAppWindow()->GetNativeWindow(),
111 ui::VKEY_TAB,
112 false,
113 false,
114 true,
115 false,
116 null_callback_);
117 base::RunLoop().RunUntilIdle();
118 }
119
120 void ValidateCannotInterceptKeys(const char* app_path,
121 bool change_intercept,
122 bool enable_intercept) {
123 scoped_ptr<ExtensionTestMessageListener> launch_listener(
124 LoadApplication(app_path));
125
126 const char* message = "";
127 if (change_intercept) {
128 message = enable_intercept ? "enable" : "disable";
129 }
130 launch_listener->Reply(message);
131
132 ASSERT_TRUE(WaitUntilKeyFocus()) << message_;
133
134 SendTaskSwitchKeys();
135
136 // Send key and check if it is received.
137 ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << message_;
benwells 2014/07/30 02:50:25 Where exactly does this fail? Does it timeout?
Sriram 2014/07/31 17:00:06 SendKeyPressNotifyWhenDone() will fail if the wind
138 }
139
140 void ValidateInterceptKeys() {
141 scoped_ptr<ExtensionTestMessageListener> launch_listener(
142 LoadApplication(app_with_permission_));
143
144 // setInterceptAllKeys() is asynchronous so wait for response and receiving
145 // a key back.
146 launch_listener->Reply("enable");
147
148 ASSERT_TRUE(WaitUntilKeyFocus()) << message_;
149
150 SendTaskSwitchKeys();
151
152 // Send key and check if it is received.
153 ASSERT_TRUE(SimulateKeyPress(ui::VKEY_Z)) << message_;
154
155 ASSERT_TRUE(WaitUntilKeyFocus()) << message_;
156 }
157
158 protected:
159 std::string message_;
160 base::Callback<void(void)> null_callback_;
161 const char* app_with_permission_ =
162 "window_api_intercept_all_keys/has_permission";
163 const char* app_without_permission_ =
164 "window_api_intercept_all_keys/no_permission";
165 };
166
167 // Currently this is implemented only for Windows.
168 #if defined(OS_WIN)
169 #define MAYBE_GetKeysAfterSwitchSequence GetKeysAfterSwitchSequence
170 #else
171 #define MAYBE_GetKeysAfterSwitchSequence DISABLED_GetKeysAfterSwitchSequence
172 #endif
173
174 // Tests a window continues to keep focus even after application switch key
175 // sequence is sent when setInterceptAllKeys() is enabled.
176 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
177 MAYBE_GetKeysAfterSwitchSequence) {
178 ValidateInterceptKeys();
179 }
180
181 // Test to make sure that keys not received after disable.
182 #if defined(OS_WIN)
183 #define MAYBE_NoKeysAfterDisableIsCalled NoKeysAfterDisableIsCalled
184 #else
185 #define MAYBE_NoKeysAfterDisableIsCalled DISABLED_NoKeysAfterDisableIsCalled
186 #endif
187
188 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
189 MAYBE_NoKeysAfterDisableIsCalled) {
190 ValidateInterceptKeys();
191
192 LOG(INFO) << "Disabling key intercept";
193 SendReply("disable");
194
195 ASSERT_TRUE(WaitUntilKeyFocus()) << message_;
196
197 SendTaskSwitchKeys();
198
199 // Send key and check if it is received.
200 ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << message_;
201 }
202
203 // Test that calling just disable has no effect in retaining keyboard intercept.
204 // Currently this is implemented only for Windows.
205 #if defined(OS_WIN)
206 #define MAYBE_NoopCallingDisableInterceptAllKeys \
207 NoopCallingDisableInterceptAllKeys
208 #else
209 #define MAYBE_NoopCallingDisableInterceptAllKeys \
210 DISABLED_NoopCallingDisableInterceptAllKeys
211 #endif
212
213 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
214 MAYBE_NoopCallingDisableInterceptAllKeys) {
215 ValidateCannotInterceptKeys(app_with_permission_, true, false);
216 }
217
218 // Test no effect when called without permissions
219 // Currently this is implemented only for Windows.
220 #if defined(OS_WIN)
221 #define MAYBE_NoopCallingEnableWithoutPermission \
222 NoopCallingEnableWithoutPermission
223 #else
224 #define MAYBE_NoopCallingEnableWithoutPermission \
225 DISABLED_NoopCallingEnableWithoutPermission
226 #endif
227
228 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
229 MAYBE_NoopCallingEnableWithoutPermission) {
230 ValidateCannotInterceptKeys(app_without_permission_, true, true);
231 }
232
233 // Test that intercept is disabled by default
234 #if defined(OS_WIN)
235 #define MAYBE_InterceptDisabledByDefault InterceptDisabledByDefault
236 #else
237 #define MAYBE_InterceptDisabledByDefault DISABLED_InterceptDisabledByDefault
238 #endif
239
240 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
241 MAYBE_InterceptDisabledByDefault) {
242 ValidateCannotInterceptKeys(app_with_permission_, false, false);
243 }
244
245 // Tests that the application cannot be loaded in stable.
246 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, CannotLoadOtherThanDev) {
247 chrome::VersionInfo::Channel version_info[] = {
248 chrome::VersionInfo::CHANNEL_BETA, chrome::VersionInfo::CHANNEL_STABLE};
249 for (unsigned int index = 0; index < arraysize(version_info); index++) {
250 extensions::ScopedCurrentChannel channel(version_info[index]);
251 const extensions::Extension* extension;
252 EXPECT_NONFATAL_FAILURE(
253 extension = LoadExtension(test_data_dir_.AppendASCII("platform_apps")
254 .AppendASCII(app_with_permission_)),
255 "");
256
257 LOG(INFO) << "Finished loading extension";
258
259 ASSERT_TRUE(extension == NULL) << "Application loaded in"
260 << version_info[index]
261 << " while permission does not exist";
262 }
263 }
264
265 // Inject different keyboard combos and make sure that the app get them all.
266 #if defined(OS_WIN)
267 #define MAYBE_ValidateKeyEvent ValidateKeyEvent
268 #else
269 #define MAYBE_ValidateKeyEvent DISABLED_ValidateKeyEvent
270 #endif
271
272 namespace {
273 // Maximum lenght of the result array in KeyEventTestData structure.
274 const size_t kMaxResultLength = 10;
275
276 // A structure holding test data of a keyboard event.
277 // Each keyboard event may generate multiple result strings representing
278 // the result of keydown, keypress, keyup and textInput events.
279 // For keydown, keypress and keyup events, the format of the result string is:
280 // <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
281 // where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
282 // <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
283 // the state of corresponding modifier key.
284 struct KeyEventTestData {
285 ui::KeyboardCode key;
286 bool control;
287 bool shift;
288 bool alt;
289 bool command;
290
291 int result_length;
292 const char* const result[kMaxResultLength];
293 };
294 } // namespace
295
296 IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, MAYBE_ValidateKeyEvent) {
297 // Launch the app
298 ValidateInterceptKeys();
299
300 static const KeyEventTestData kValidateKeyEvents[] = {
301 // a
302 {ui::VKEY_A,
303 false,
304 false,
305 false,
306 false,
307 3,
308 {"D 65 0 false false false false",
309 "P 97 97 false false false false",
310 "U 65 0 false false false false"}},
311 // shift+a
312 {ui::VKEY_A,
313 false,
314 true,
315 false,
316 false,
317 5,
318 {"D 16 0 false true false false",
319 "D 65 0 false true false false",
320 "P 65 65 false true false false",
321 "U 65 0 false true false false",
322 "U 16 0 false true false false"}},
benwells 2014/07/30 02:50:25 Can this data be inferred before checking instead
Sriram 2014/07/31 17:00:06 Not sure if there is a clean way as the only way I
323 // ctrl+f which has aceelerator binding should also reuslt in all keys
benwells 2014/07/30 02:50:25 Nit: spelling (aceelerator, reuslt).
Sriram 2014/07/31 17:00:05 Done.
324 // being
325 // sent.
326 {ui::VKEY_F,
327 true,
328 false,
329 false,
330 false,
331 5,
332 {"D 17 0 true false false false",
333 "D 70 0 true false false false",
334 "P 6 6 true false false false",
335 "U 70 0 true false false false",
336 "U 17 0 true false false false"}},
337 // ctrl+z
338 {ui::VKEY_Z,
339 true,
340 false,
341 false,
342 false,
343 5,
344 {"D 17 0 true false false false",
345 "D 90 0 true false false false",
346 "P 26 26 true false false false",
347 "U 90 0 true false false false",
348 "U 17 0 true false false false"}},
349 // alt+f
350 {ui::VKEY_F,
351 false,
352 false,
353 true,
354 false,
355 4,
356 {"D 18 0 false false true false",
357 "D 70 0 false false true false",
358 "U 70 0 false false true false",
359 "U 18 0 false false true false"}},
360 // make sure both left and right shift makes it across
361 {ui::VKEY_RSHIFT,
362 false,
363 false,
364 false,
365 false,
366 2,
367 {"D 16 0 false true false false",
368 "U 16 0 false true false false"}},
369 };
370
371 LOG(INFO) << "Starting keyboard input test";
372
373 for (unsigned int index = 0; index < arraysize(kValidateKeyEvents); index++) {
374 // create all the event listeners needed
375 const KeyEventTestData* current_event = &kValidateKeyEvents[index];
376 scoped_ptr<ExtensionTestMessageListener> listeners[kMaxResultLength];
377 for (int i = 0; i < current_event->result_length; i++) {
378 listeners[i].reset(
379 new ExtensionTestMessageListener(current_event->result[i], false));
380 }
381 ASSERT_TRUE(SimulateKeyPress(current_event->key,
382 current_event->control,
383 current_event->shift,
384 current_event->alt,
385 current_event->command));
386 for (int i = 0; i < current_event->result_length; i++) {
387 EXPECT_TRUE(listeners[i]->WaitUntilSatisfied());
388 }
389 }
390 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698