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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/apps/app_window_intercept_all_keys_uitest.cc
diff --git a/chrome/browser/apps/app_window_intercept_all_keys_uitest.cc b/chrome/browser/apps/app_window_intercept_all_keys_uitest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a70f0cd12380d167ca51beb3edc2d69923547cb3
--- /dev/null
+++ b/chrome/browser/apps/app_window_intercept_all_keys_uitest.cc
@@ -0,0 +1,358 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "apps/ui/native_app_window.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+
+using apps::NativeAppWindow;
+
+class AppWindowInterceptAllKeysTest
+ : public extensions::PlatformAppBrowserTest {
+ public:
+ // Send key to window but does not wait till the key is actually in the input
+ // queue (like ui_test_utils::SendKeyPressToWindowSync()) as key will not be
+ // sent to hook when keyboard is intercepted.
+ bool SimulateKeyPress(ui::KeyboardCode key,
+ bool control,
+ bool shift,
+ bool alt,
+ bool command) {
+ DVLOG(1) << "Sending: " << key << " control = " << control
+ << " shift = " << shift << " alt = " << alt
+ << " command = " << command;
+ if (!ui_controls::SendKeyPressNotifyWhenDone(
+ GetFirstAppWindow()->GetNativeWindow(),
+ key,
+ control,
+ shift,
+ alt,
+ command,
+ null_callback_)) {
+ LOG(WARNING) << "Failed to send key to app";
+ message_ = "Failed to send key to app.";
+ return false;
+ }
+
+ base::RunLoop().RunUntilIdle();
+ return !testing::Test::HasFatalFailure();
+ }
+
+ bool SimulateKeyPress(ui::KeyboardCode key) {
+ return SimulateKeyPress(key, false, false, false, false);
+ }
+
+ bool SendReply(const char* message) {
+ 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
+ }
+
+ bool SendKeyEvent(ui::KeyboardCode code, const char* message) {
+ std::string key_event = base::StringPrintf("KeyReceived: %d", code);
+ ExtensionTestMessageListener key_listener(key_event, (message != NULL));
+
+ if (!SimulateKeyPress(code)) {
+ message_ = "Failed to send key to app";
+ return false;
+ }
+
+ key_listener.WaitUntilSatisfied();
+ if (message) {
+ key_listener.Reply(message);
+ }
+
+ DVLOG(1) << "Application ACK-ed keypress";
+ return true;
+ }
+
+ bool WaitForKeyEvent(ui::KeyboardCode code) {
+ return SendKeyEvent(code, NULL);
+ }
+
+ bool LoadApplication(const char* app_path) {
+ DVLOG(1) << "Launching app = " << app_path;
+ LoadAndLaunchPlatformApp(app_path, "Launched");
+
+ DVLOG(1) << "Validating that application is in focus";
+ // We start by making sure the window is actually focused.
+ if (!ui_test_utils::ShowAndFocusNativeWindow(
+ GetFirstAppWindow()->GetNativeWindow())) {
+ message_ = "App did not get focus.";
+ return false;
+ }
+
+ DVLOG(1) << "Launched application";
+ return true;
+ }
+
+ void SendTaskSwitchKeys() {
+ // Send switch sequence (currently just for windows - will have to update as
+ // more platform support is added).
+ SimulateKeyPress(ui::VKEY_TAB, false, false, true, false);
+ }
+
+ void ValidateCannotInterceptKeys(const char* app_path,
+ bool change_intercept,
+ bool enable_intercept) {
+ ASSERT_TRUE(LoadApplication(app_path)) << message_;
+
+ const char* message = "";
+ if (change_intercept) {
+ message = enable_intercept ? "enable" : "disable";
+ }
+ SendReply(message);
+
+ ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << message_;
+
+ SendTaskSwitchKeys();
+
+ // Send key and check if it is received.
+ ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << message_;
+ }
+
+ void ValidateInterceptKeys() {
+ ASSERT_TRUE(LoadApplication(app_with_permission_)) << message_;
+
+ // setInterceptAllKeys() is asynchronous so wait for response and receiving
+ // a key back.
+ SendReply("enable");
+
+ ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << message_;
+
+ SendTaskSwitchKeys();
+
+ // Send key and check if it is received.
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_Z)) << message_;
+
+ ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << message_;
+ }
+
+ protected:
+ std::string message_;
+ base::Callback<void(void)> null_callback_;
+ const char* app_with_permission_ =
+ "window_api_intercept_all_keys/has_permission";
+ const char* app_without_permission_ =
+ "window_api_intercept_all_keys/no_permission";
+};
+
+// Currently this is implemented only for Windows.
+#if defined(OS_WIN)
+#define MAYBE_GetKeysAfterSwitchSequence GetKeysAfterSwitchSequence
+#else
+#define MAYBE_GetKeysAfterSwitchSequence DISABLED_GetKeysAfterSwitchSequence
+#endif
+
+// Tests a window continues to keep focus even after application switch key
+// sequence is sent when setInterceptAllKeys() is enabled.
+IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
+ MAYBE_GetKeysAfterSwitchSequence) {
+ ValidateInterceptKeys();
+}
+
+// Test to make sure that keys not received after disable.
+#if defined(OS_WIN)
+#define MAYBE_NoKeysAfterDisableIsCalled NoKeysAfterDisableIsCalled
+#else
+#define MAYBE_NoKeysAfterDisableIsCalled DISABLED_NoKeysAfterDisableIsCalled
+#endif
+
+IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
+ MAYBE_NoKeysAfterDisableIsCalled) {
+ ValidateInterceptKeys();
+
+ DVLOG(1) << "Disabling key intercept";
+ SendReply("disable");
+
+ ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << message_;
+
+ SendTaskSwitchKeys();
+
+ // Send key and check if it is received.
+ ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << message_;
+}
+
+// Test that calling just disable has no effect in retaining keyboard intercept.
+// Currently this is implemented only for Windows.
+#if defined(OS_WIN)
+#define MAYBE_NoopCallingDisableInterceptAllKeys \
+ NoopCallingDisableInterceptAllKeys
+#else
+#define MAYBE_NoopCallingDisableInterceptAllKeys \
+ DISABLED_NoopCallingDisableInterceptAllKeys
+#endif
+
+IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
+ MAYBE_NoopCallingDisableInterceptAllKeys) {
+ ValidateCannotInterceptKeys(app_with_permission_, true, false);
+}
+
+// Test no effect when called without permissions
+// Currently this is implemented only for Windows.
+#if defined(OS_WIN)
+#define MAYBE_NoopCallingEnableWithoutPermission \
+ NoopCallingEnableWithoutPermission
+#else
+#define MAYBE_NoopCallingEnableWithoutPermission \
+ DISABLED_NoopCallingEnableWithoutPermission
+#endif
+
+IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
+ MAYBE_NoopCallingEnableWithoutPermission) {
+ ValidateCannotInterceptKeys(app_without_permission_, true, true);
+}
+
+// Test that intercept is disabled by default
+#if defined(OS_WIN)
+#define MAYBE_InterceptDisabledByDefault InterceptDisabledByDefault
+#else
+#define MAYBE_InterceptDisabledByDefault DISABLED_InterceptDisabledByDefault
+#endif
+
+IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest,
+ MAYBE_InterceptDisabledByDefault) {
+ ValidateCannotInterceptKeys(app_with_permission_, false, false);
+}
+
+// Tests that the application cannot be loaded in stable.
+IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, CannotLoadOtherThanDev) {
+ chrome::VersionInfo::Channel version_info[] = {
+ chrome::VersionInfo::CHANNEL_BETA, chrome::VersionInfo::CHANNEL_STABLE};
+ for (unsigned int index = 0; index < arraysize(version_info); index++) {
+ extensions::ScopedCurrentChannel channel(version_info[index]);
+ const extensions::Extension* extension;
+ EXPECT_NONFATAL_FAILURE(
+ extension = LoadExtension(test_data_dir_.AppendASCII("platform_apps")
+ .AppendASCII(app_with_permission_)),
+ "");
+
+ DVLOG(1) << "Finished loading extension";
+
+ ASSERT_TRUE(extension == NULL) << "Application loaded in"
+ << version_info[index]
+ << " while permission does not exist";
+ }
+}
+
+// Inject different keyboard combos and make sure that the app get them all.
+#if defined(OS_WIN)
+#define MAYBE_ValidateKeyEvent ValidateKeyEvent
+#else
+#define MAYBE_ValidateKeyEvent DISABLED_ValidateKeyEvent
+#endif
+
+namespace {
+// Maximum lenght of the result array in KeyEventTestData structure.
+const size_t kMaxResultLength = 10;
+
+// A structure holding test data of a keyboard event.
+// Each keyboard event may generate multiple result strings representing
+// the result of keydown, keypress, keyup and textInput events.
+// For keydown, keypress and keyup events, the format of the result string is:
+// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
+// where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
+// <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
+// the state of corresponding modifier key.
+struct KeyEventTestData {
+ ui::KeyboardCode key;
+ bool control;
+ bool shift;
+ bool alt;
+ bool command;
+
+ int result_length;
+ const char* const result[kMaxResultLength];
+};
+} // namespace
+
+IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, MAYBE_ValidateKeyEvent) {
+ // Launch the app
+ ValidateInterceptKeys();
+
+ static const KeyEventTestData kValidateKeyEvents[] = {
+ // a
+ {ui::VKEY_A,
+ false,
+ false,
+ false,
+ false,
+ 3,
+ {"D 65 0 false false false false", "P 97 97 false false false false",
+ "U 65 0 false false false false"}},
+ // shift+a
+ {ui::VKEY_A,
+ false,
+ true,
+ false,
+ false,
+ 5,
+ {"D 16 0 false true false false", "D 65 0 false true false false",
+ "P 65 65 false true false false", "U 65 0 false true false false",
+ "U 16 0 false true false false"}},
+ // ctrl+f which has accelerator binding should also result in all keys
+ // being
+ // sent.
+ {ui::VKEY_F,
+ true,
+ false,
+ false,
+ false,
+ 5,
+ {"D 17 0 true false false false", "D 70 0 true false false false",
+ "P 6 6 true false false false", "U 70 0 true false false false",
+ "U 17 0 true false false false"}},
+ // ctrl+z
+ {ui::VKEY_Z,
+ true,
+ false,
+ false,
+ false,
+ 5,
+ {"D 17 0 true false false false", "D 90 0 true false false false",
+ "P 26 26 true false false false", "U 90 0 true false false false",
+ "U 17 0 true false false false"}},
+ // alt+f
+ {ui::VKEY_F,
+ false,
+ false,
+ true,
+ false,
+ 4,
+ {"D 18 0 false false true false", "D 70 0 false false true false",
+ "U 70 0 false false true false", "U 18 0 false false true false"}},
+ // make sure both left and right shift makes it across
+ {ui::VKEY_RSHIFT,
+ false,
+ false,
+ false,
+ false,
+ 2,
+ {"D 16 0 false true false false", "U 16 0 false true false false"}},
+ };
+
+ DVLOG(1) << "Starting keyboard input test";
+
+ for (unsigned int index = 0; index < arraysize(kValidateKeyEvents); index++) {
+ // create all the event listeners needed
+ const KeyEventTestData* current_event = &kValidateKeyEvents[index];
+ scoped_ptr<ExtensionTestMessageListener> listeners[kMaxResultLength];
+ for (int i = 0; i < current_event->result_length; i++) {
+ listeners[i].reset(
+ new ExtensionTestMessageListener(current_event->result[i], false));
+ }
+ ASSERT_TRUE(SimulateKeyPress(current_event->key,
+ current_event->control,
+ current_event->shift,
+ current_event->alt,
+ current_event->command));
+ for (int i = 0; i < current_event->result_length; i++) {
+ EXPECT_TRUE(listeners[i]->WaitUntilSatisfied());
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698