Commit d6833856 authored by sky@chromium.org's avatar sky@chromium.org

Lands http://codereview.chromium.org/3153008 for bryeung:

Synthetic KeyEvent delivery, part I.

This delivers synthetic key events to the views hierarchy. This
currently does nothing, as nothing is listening for the event in
TOUCH_UI (or elsewhere). That part will come later.

BUG=none
TEST=unit test for key identifier conversion + manual for extension
api

Review URL: http://codereview.chromium.org/3130029

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56886 0039d316-1c4b-4281-b951-d872f2087c98
parent d8ada0c9
...@@ -95,6 +95,7 @@ ...@@ -95,6 +95,7 @@
'json/json_reader_unittest.cc', 'json/json_reader_unittest.cc',
'json/json_writer_unittest.cc', 'json/json_writer_unittest.cc',
'json/string_escape_unittest.cc', 'json/string_escape_unittest.cc',
'keyboard_code_conversion_unittest.cc',
'lazy_instance_unittest.cc', 'lazy_instance_unittest.cc',
'leak_tracker_unittest.cc', 'leak_tracker_unittest.cc',
'linked_list_unittest.cc', 'linked_list_unittest.cc',
......
...@@ -432,6 +432,8 @@ ...@@ -432,6 +432,8 @@
'hmac_win.cc', 'hmac_win.cc',
'image_util.cc', 'image_util.cc',
'image_util.h', 'image_util.h',
'keyboard_code_conversion.cc',
'keyboard_code_conversion.h',
'keyboard_code_conversion_gtk.cc', 'keyboard_code_conversion_gtk.cc',
'keyboard_code_conversion_gtk.h', 'keyboard_code_conversion_gtk.h',
'keyboard_code_conversion_mac.mm', 'keyboard_code_conversion_mac.mm',
......
This diff is collapsed.
// Copyright (c) 2010 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.
#ifndef BASE_KEYBOARD_CODE_CONVERSION_H_
#define BASE_KEYBOARD_CODE_CONVERSION_H_
#pragma once
#include "base/keyboard_codes.h"
#include <string>
namespace base {
// Convert a KeyIdentifer (see Section 6.3.3 here:
// http://www.w3.org/TR/DOM-Level-3-Events/#keyset-keyidentifiers)
// to a base::KeyboardCode.
KeyboardCode KeyCodeFromKeyIdentifier(const std::string& key_identifier);
} // namespace
#endif // BASE_KEYBOARD_CODE_CONVERSION_H_
// Copyright (c) 2010 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 "base/keyboard_code_conversion.h"
#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(KeyCodeFromKeyIdentifierTest, MatchOnIdentifier) {
EXPECT_EQ(base::VKEY_APPS, KeyCodeFromKeyIdentifier("Apps"));
EXPECT_EQ(base::VKEY_UNKNOWN, KeyCodeFromKeyIdentifier("Nonsense"));
}
TEST(KeyCodeFromKeyIdentifierTest, MatchOnCharacter) {
EXPECT_EQ(base::VKEY_A, KeyCodeFromKeyIdentifier("a"));
EXPECT_EQ(base::VKEY_A, KeyCodeFromKeyIdentifier("A"));
EXPECT_EQ(base::VKEY_OEM_PERIOD, KeyCodeFromKeyIdentifier(">"));
std::string non_printing_char(" ");
non_printing_char[0] = static_cast<char>(1);
EXPECT_EQ(base::VKEY_UNKNOWN, KeyCodeFromKeyIdentifier(non_printing_char));
}
TEST(KeyCodeFromKeyIdentifierTest, MatchOnUnicodeCodepoint) {
EXPECT_EQ(base::VKEY_A, KeyCodeFromKeyIdentifier("U+0041"));
EXPECT_EQ(base::VKEY_A, KeyCodeFromKeyIdentifier("U+0061"));
EXPECT_EQ(base::VKEY_DELETE, KeyCodeFromKeyIdentifier("U+007F"));
// this one exists in the map, but has no valid VKEY
EXPECT_EQ(base::VKEY_UNKNOWN, KeyCodeFromKeyIdentifier("U+030A"));
// this one is not in the map
EXPECT_EQ(base::VKEY_UNKNOWN, KeyCodeFromKeyIdentifier("U+0001"));
}
TEST(KeyCodeFromKeyIdentifierTest, DoesNotMatchEmptyString) {
EXPECT_EQ(base::VKEY_UNKNOWN, KeyCodeFromKeyIdentifier(""));
}
} // namespace base
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
#include "chrome/browser/extensions/extension_idle_api.h" #include "chrome/browser/extensions/extension_idle_api.h"
#include "chrome/browser/extensions/extension_i18n_api.h" #include "chrome/browser/extensions/extension_i18n_api.h"
#include "chrome/browser/extensions/extension_infobar_module.h" #include "chrome/browser/extensions/extension_infobar_module.h"
#if defined(TOOLKIT_VIEWS)
#include "chrome/browser/extensions/extension_input_api.h"
#endif
#include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/extensions/extension_metrics_module.h" #include "chrome/browser/extensions/extension_metrics_module.h"
#include "chrome/browser/extensions/extension_omnibox_api.h" #include "chrome/browser/extensions/extension_omnibox_api.h"
...@@ -54,6 +57,7 @@ ...@@ -54,6 +57,7 @@
#include "chrome/common/result_codes.h" #include "chrome/common/result_codes.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
// FactoryRegistry ------------------------------------------------------------- // FactoryRegistry -------------------------------------------------------------
namespace { namespace {
...@@ -261,6 +265,11 @@ void FactoryRegistry::ResetFunctions() { ...@@ -261,6 +265,11 @@ void FactoryRegistry::ResetFunctions() {
RegisterFunction<SetIconSidebarFunction>(); RegisterFunction<SetIconSidebarFunction>();
RegisterFunction<SetTitleSidebarFunction>(); RegisterFunction<SetTitleSidebarFunction>();
RegisterFunction<ShowSidebarFunction>(); RegisterFunction<ShowSidebarFunction>();
#if defined(TOOLKIT_VIEWS)
// Input.
RegisterFunction<SendKeyboardEventInputFunction>();
#endif
} }
void FactoryRegistry::GetAllNames(std::vector<std::string>* names) { void FactoryRegistry::GetAllNames(std::vector<std::string>* names) {
......
// Copyright (c) 2010 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 "chrome/browser/extensions/extension_input_api.h"
#include <string>
#include "base/values.h"
#include "base/keyboard_code_conversion.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "views/event.h"
#include "views/widget/root_view.h"
namespace {
// Keys.
const char kType[] = "type";
const char kKeyIdentifier[] = "keyIdentifier";
const char kAlt[] = "altKey";
const char kCtrl[] = "ctrlKey";
const char kMeta[] = "metaKey";
const char kShift[] = "shiftKey";
const char kKeyDown[] = "keydown";
const char kKeyUp[] = "keyup";
// Errors.
const char kUnknownEventTypeError[] = "Unknown event type.";
const char kUnknownOrUnsupportedKeyIdentiferError[] = "Unknown or unsupported "
"key identifier.";
const char kNoValidRecipientError[] = "No valid recipient for event.";
const char kKeyEventUnprocessedError[] = "Event was not handled.";
views::Event::EventType GetTypeFromString(const std::string& type) {
if (type == kKeyDown) {
return views::Event::ET_KEY_PRESSED;
} else if (type == kKeyUp) {
return views::Event::ET_KEY_RELEASED;
}
return views::Event::ET_UNKNOWN;
}
} // namespace
void InputFunction::Run() {
SendResponse(RunImpl());
}
views::RootView* SendKeyboardEventInputFunction::GetRootView() {
Browser* browser = GetCurrentBrowser();
if (!browser)
return NULL;
BrowserWindow* window = browser->window();
if (!window)
return NULL;
BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
window->GetNativeHandle());
if (!browser_view)
return NULL;
return browser_view->GetRootView();
}
bool SendKeyboardEventInputFunction::RunImpl() {
DictionaryValue* args;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
std::string type_name;
EXTENSION_FUNCTION_VALIDATE(args->GetString(kType, &type_name));
views::Event::EventType type = GetTypeFromString(type_name);
if (type == views::Event::ET_UNKNOWN) {
error_ = kUnknownEventTypeError;
return false;
}
std::string identifier;
EXTENSION_FUNCTION_VALIDATE(args->GetString(kKeyIdentifier, &identifier));
base::KeyboardCode code = base::KeyCodeFromKeyIdentifier(identifier);
if (code == base::VKEY_UNKNOWN) {
error_ = kUnknownOrUnsupportedKeyIdentiferError;
return false;
}
int flags = 0;
bool alt = false;
if (args->GetBoolean(kAlt, &alt))
flags |= alt ? WebKit::WebInputEvent::AltKey : 0;
bool ctrl = false;
if (args->GetBoolean(kCtrl, &ctrl))
flags |= ctrl ? WebKit::WebInputEvent::ControlKey : 0;
bool meta = false;
if (args->GetBoolean(kMeta, &meta))
flags |= meta ? WebKit::WebInputEvent::MetaKey : 0;
bool shift = false;
if (args->GetBoolean(kShift, &shift))
flags |= shift ? WebKit::WebInputEvent::ShiftKey : 0;
views::RootView* root_view = GetRootView();
if (!root_view) {
error_ = kNoValidRecipientError;
return false;
}
views::KeyEvent event(type, code, flags, 0, 0);
if (!root_view->ProcessKeyEvent(event)) {
error_ = kKeyEventUnprocessedError;
return false;
}
return true;
}
// Copyright (c) 2010 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_INPUT_API_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_INPUT_API_H_
#pragma once
#include "chrome/browser/extensions/extension_function.h"
namespace views {
class RootView;
} // namespace views
// Base class for input APIs.
class InputFunction : public AsyncExtensionFunction {
public:
virtual void Run();
virtual bool RunImpl() = 0;
};
// Note that this experimental API is currently only available for
// TOOLKIT_VIEWS (see chrome/chrome_browser.gypi).
//
// We may eventually support other platforms by adding the necessary
// synthetic event distribution code to this Function.
class SendKeyboardEventInputFunction : public InputFunction {
public:
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.input.sendKeyboardEvent");
private:
views::RootView* GetRootView();
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INPUT_API_H_
// Copyright (c) 2010 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 "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Input) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
ASSERT_TRUE(RunExtensionTest("input")) << message_;
}
...@@ -1366,6 +1366,8 @@ ...@@ -1366,6 +1366,8 @@
'browser/extensions/extension_infobar_module_constants.h', 'browser/extensions/extension_infobar_module_constants.h',
'browser/extensions/extension_infobar_delegate.cc', 'browser/extensions/extension_infobar_delegate.cc',
'browser/extensions/extension_infobar_delegate.h', 'browser/extensions/extension_infobar_delegate.h',
'browser/extensions/extension_input_api.cc',
'browser/extensions/extension_input_api.h',
'browser/extensions/extension_install_ui.cc', 'browser/extensions/extension_install_ui.cc',
'browser/extensions/extension_install_ui.h', 'browser/extensions/extension_install_ui.h',
'browser/extensions/extension_menu_manager.cc', 'browser/extensions/extension_menu_manager.cc',
...@@ -3669,6 +3671,14 @@ ...@@ -3669,6 +3671,14 @@
['exclude', '^browser/browser_list_gtk.cc'], ['exclude', '^browser/browser_list_gtk.cc'],
], ],
}], }],
# Exclude these toolkit_views specific files again.
# (Required because of the '^browser/extensions/' include above)
['toolkit_views==0', {
'sources/': [
['exclude', '^browser/extensions/extension_input_api.cc'],
['exclude', '^browser/extensions/extension_input_api.h'],
],
}],
# These GTK files haven't been ported to views, while ChromeOS has # These GTK files haven't been ported to views, while ChromeOS has
# its own separate implementation below. So re-include them only on # its own separate implementation below. So re-include them only on
# non-ChromeOS views Linux builds. # non-ChromeOS views Linux builds.
......
...@@ -1714,6 +1714,7 @@ ...@@ -1714,6 +1714,7 @@
'browser/extensions/extension_i18n_apitest.cc', 'browser/extensions/extension_i18n_apitest.cc',
'browser/extensions/extension_incognito_apitest.cc', 'browser/extensions/extension_incognito_apitest.cc',
'browser/extensions/extension_infobar_apitest.cc', 'browser/extensions/extension_infobar_apitest.cc',
'browser/extensions/extension_input_apitest.cc',
'browser/extensions/extension_install_ui_browsertest.cc', 'browser/extensions/extension_install_ui_browsertest.cc',
'browser/extensions/extension_javascript_url_apitest.cc', 'browser/extensions/extension_javascript_url_apitest.cc',
'browser/extensions/extension_management_browsertest.cc', 'browser/extensions/extension_management_browsertest.cc',
...@@ -1789,6 +1790,11 @@ ...@@ -1789,6 +1790,11 @@
'browser/dom_ui/file_browse_browsertest.cc', 'browser/dom_ui/file_browse_browsertest.cc',
], ],
}], }],
['toolkit_views==0', {
'sources!': [
'browser/extensions/extension_input_apitest.cc',
],
}],
['OS!="linux" or toolkit_views==1', { ['OS!="linux" or toolkit_views==1', {
'sources!': [ 'sources!': [
'browser/extensions/browser_action_test_util_gtk.cc', 'browser/extensions/browser_action_test_util_gtk.cc',
......
...@@ -2199,6 +2199,61 @@ ...@@ -2199,6 +2199,61 @@
], ],
"events": [] "events": []
}, },
{
"namespace": "experimental.input",
"nodoc": true,
"types": [],
"functions": [
{
"name": "sendKeyboardEvent",
"type": "function",
"description": "Send a keyboard event to Chrome.",
"parameters": [
{ "type": "object",
"name": "event",
"properties": {
"type": {
"type": "string",
"description": "One of 'keyup' or 'keydown'."
},
"keyIdentifier": {
"type": "string",
"description": "See http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/keyset.html#KeySet-Set"
},
"altKey": {
"type": "boolean",
"optional": true,
"description": "Whether or not the ALT key is pressed."
},
"ctrlKey": {
"type": "boolean",
"optional": true,
"description": "Whether or not the CTRL key is pressed."
},
"metaKey": {
"type": "boolean",
"optional": true,
"description": "Whether or not the META key is pressed."
},
"shiftKey": {
"type": "boolean",
"optional": true,
"description": "Whether or not the SHIFT key is pressed."
}
},
"description": "The keyboard event to be sent."
},
{ "type": "function",
"name": "callback",
"optional": true,
"description": "This function is called when the event processing is completed.",
"parameters": []
}
]
}
],
"events": []
},
{ {
"namespace": "experimental.popup", "namespace": "experimental.popup",
"nodoc": true, "nodoc": true,
......
...@@ -255,6 +255,7 @@ var chrome = chrome || {}; ...@@ -255,6 +255,7 @@ var chrome = chrome || {};
"experimental.clipboard", "experimental.clipboard",
"experimental.extension", "experimental.extension",
"experimental.infobars", "experimental.infobars",
"experimental.input",
"experimental.metrics", "experimental.metrics",
"experimental.omnibox", "experimental.omnibox",
"experimental.popup", "experimental.popup",
......
{
"name": "chrome.experimental.input",
"version": "0.1",
"description": "end-to-end browser test for chrome.experimental.input API",
"background_page": "test.html",
"permissions": ["experimental"]
}
// Copyright (c) 2010 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.
// experimental.input API test for Chrome
// browser_tests --gtest_filter=ExtensionApiTest.Input
chrome.test.runTests([
function sendKeyboardEvent() {
var e = { 'type': 'keydown', 'keyIdentifier': 'A' };
chrome.experimental.input.sendKeyboardEvent(e, function() {
if (chrome.extension.lastError) {
// this is expected for now: no one is handling keys yet
// chrome.test.fail();
}
// when the browser is listening to events, we should check that
// this event was delivered as we expected. For now, just succeed.
chrome.test.succeed();
});
},
function badKeyIdentifier() {
var e = { 'type': 'keydown', 'keyIdentifier': 'BogusId' };
chrome.experimental.input.sendKeyboardEvent(e, function() {
if (!chrome.extension.lastError) {
chrome.test.fail();
}
chrome.test.succeed();
});
},
function badEventType() {
var e = { 'type': 'BAD', 'keyIdentifier': 'A' };
chrome.experimental.input.sendKeyboardEvent(e, function() {
if (!chrome.extension.lastError) {
chrome.test.fail();
}
chrome.test.succeed();
});
},
function unmappedKeyIdentifier() {
var e = { 'type': 'keydown', 'keyIdentifier': 'Again' };
chrome.experimental.input.sendKeyboardEvent(e, function() {
if (!chrome.extension.lastError) {
chrome.test.fail();
}
chrome.test.succeed();
});
},
]);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment