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

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

Powered by Google App Engine
This is Rietveld 408576698