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

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

Powered by Google App Engine
This is Rietveld 408576698