summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/base.gyp1
-rw-r--r--base/base.gypi2
-rw-r--r--base/keyboard_code_conversion.cc296
-rw-r--r--base/keyboard_code_conversion.h22
-rw-r--r--base/keyboard_code_conversion_unittest.cc43
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc9
-rw-r--r--chrome/browser/extensions/extension_input_api.cc120
-rw-r--r--chrome/browser/extensions/extension_input_api.h36
-rw-r--r--chrome/browser/extensions/extension_input_apitest.cc14
-rw-r--r--chrome/chrome_browser.gypi10
-rw-r--r--chrome/chrome_tests.gypi6
-rw-r--r--chrome/common/extensions/api/extension_api.json55
-rw-r--r--chrome/renderer/resources/renderer_extension_bindings.js1
-rw-r--r--chrome/test/data/extensions/api_test/input/manifest.json7
-rw-r--r--chrome/test/data/extensions/api_test/input/test.html1
-rw-r--r--chrome/test/data/extensions/api_test/input/test.js51
16 files changed, 674 insertions, 0 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 85d71ca..a1d34aa 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -95,6 +95,7 @@
'json/json_reader_unittest.cc',
'json/json_writer_unittest.cc',
'json/string_escape_unittest.cc',
+ 'keyboard_code_conversion_unittest.cc',
'lazy_instance_unittest.cc',
'leak_tracker_unittest.cc',
'linked_list_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index 383f645..1d4fc21 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -432,6 +432,8 @@
'hmac_win.cc',
'image_util.cc',
'image_util.h',
+ 'keyboard_code_conversion.cc',
+ 'keyboard_code_conversion.h',
'keyboard_code_conversion_gtk.cc',
'keyboard_code_conversion_gtk.h',
'keyboard_code_conversion_mac.mm',
diff --git a/base/keyboard_code_conversion.cc b/base/keyboard_code_conversion.cc
new file mode 100644
index 0000000..31f3c14
--- /dev/null
+++ b/base/keyboard_code_conversion.cc
@@ -0,0 +1,296 @@
+// 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 <string.h>
+
+#include "base/keyboard_codes.h"
+
+namespace base {
+
+namespace {
+
+typedef struct KeyIdentifier {
+ const char* key_name;
+ const char character;
+ const char* unicode_codepoint;
+ const KeyboardCode key_code;
+} KeyIdentifier;
+
+// Taken from Section 6.3.3 here:
+// http://www.w3.org/TR/DOM-Level-3-Events/#keyset-keyidentifiers
+// TODO(bryeung): keycodes could be wrong: I took the keydown code only
+static const KeyIdentifier kKeyIdentifiers[] = {
+ { "Accept", '\0', "", VKEY_ACCEPT },
+ { "Add", '\0', "", VKEY_ADD },
+ { "Again", '\0', "", VKEY_UNKNOWN },
+ { "AllCandidates", '\0', "", VKEY_UNKNOWN },
+ { "Alphanumeric", '\0', "", VKEY_UNKNOWN },
+ { "Alt", '\0', "", VKEY_MENU },
+ { "AltGraph", '\0', "", VKEY_UNKNOWN },
+ { "Apps", '\0', "", VKEY_APPS },
+ { "Attn", '\0', "", VKEY_ATTN },
+ { "BrowserBack", '\0', "", VKEY_BROWSER_BACK },
+ { "BrowserFavorites", '\0', "", VKEY_BROWSER_FAVORITES },
+ { "BrowserForward", '\0', "", VKEY_BROWSER_FAVORITES },
+ { "BrowserHome", '\0', "", VKEY_BROWSER_HOME },
+ { "BrowserRefresh", '\0', "", VKEY_BROWSER_REFRESH },
+ { "BrowserSearch", '\0', "", VKEY_BROWSER_SEARCH },
+ { "BrowserStop", '\0', "", VKEY_BROWSER_STOP },
+ { "CapsLock", '\0', "", VKEY_CAPITAL },
+ { "Clear", '\0', "", VKEY_OEM_CLEAR },
+ { "CodeInput", '\0', "", VKEY_UNKNOWN },
+ { "Compose", '\0', "", VKEY_UNKNOWN },
+ { "Control", '\0', "", VKEY_CONTROL },
+ { "Crsel", '\0', "", VKEY_CRSEL },
+ { "Convert", '\0', "", VKEY_CONVERT },
+ { "Copy", '\0', "", VKEY_UNKNOWN },
+ { "Cut", '\0', "", VKEY_UNKNOWN },
+ { "Decimal", '\0', "", VKEY_DECIMAL },
+ { "Divide", '\0', "", VKEY_DIVIDE },
+ { "Down", '\0', "", VKEY_DOWN },
+ { "DownLeft", '\0', "", VKEY_UNKNOWN },
+ { "DownRight", '\0', "", VKEY_UNKNOWN },
+ { "End", '\0', "", VKEY_END },
+ { "Enter", '\0', "", VKEY_RETURN },
+ { "EraseEof", '\0', "", VKEY_EREOF },
+ { "Execute", '\0', "", VKEY_EXECUTE },
+ { "Exsel", '\0', "", VKEY_EXSEL },
+ { "Fn", '\0', "", VKEY_UNKNOWN },
+ { "F1", '\0', "", VKEY_F1 },
+ { "F2", '\0', "", VKEY_F2 },
+ { "F3", '\0', "", VKEY_F3 },
+ { "F4", '\0', "", VKEY_F4 },
+ { "F5", '\0', "", VKEY_F5 },
+ { "F6", '\0', "", VKEY_F6 },
+ { "F7", '\0', "", VKEY_F7 },
+ { "F8", '\0', "", VKEY_F8 },
+ { "F9", '\0', "", VKEY_F9 },
+ { "F10", '\0', "", VKEY_F10 },
+ { "F11", '\0', "", VKEY_F11 },
+ { "F12", '\0', "", VKEY_F12 },
+ { "F13", '\0', "", VKEY_F13 },
+ { "F14", '\0', "", VKEY_F14 },
+ { "F15", '\0', "", VKEY_F15 },
+ { "F16", '\0', "", VKEY_F16 },
+ { "F17", '\0', "", VKEY_F17 },
+ { "F18", '\0', "", VKEY_F18 },
+ { "F19", '\0', "", VKEY_F19 },
+ { "F20", '\0', "", VKEY_F20 },
+ { "F21", '\0', "", VKEY_F21 },
+ { "F22", '\0', "", VKEY_F22 },
+ { "F23", '\0', "", VKEY_F23 },
+ { "F24", '\0', "", VKEY_F24 },
+ { "FinalMode", '\0', "", VKEY_FINAL },
+ { "Find", '\0', "", VKEY_UNKNOWN },
+ { "FullWidth", '\0', "", VKEY_UNKNOWN },
+ { "HalfWidth", '\0', "", VKEY_UNKNOWN },
+ { "HangulMode", '\0', "", VKEY_HANGUL },
+ { "HanjaMode", '\0', "", VKEY_HANJA },
+ { "Help", '\0', "", VKEY_HELP },
+ { "Hiragana", '\0', "", VKEY_UNKNOWN },
+ { "Home", '\0', "", VKEY_HOME },
+ { "Insert", '\0', "", VKEY_INSERT },
+ { "JapaneseHiragana", '\0', "", VKEY_UNKNOWN },
+ { "JapaneseKatakana", '\0', "", VKEY_UNKNOWN },
+ { "JapaneseRomaji", '\0', "", VKEY_UNKNOWN },
+ { "JunjaMode", '\0', "", VKEY_JUNJA },
+ { "KanaMode", '\0', "", VKEY_KANA },
+ { "KanjiMode", '\0', "", VKEY_KANJI },
+ { "Katakana", '\0', "", VKEY_UNKNOWN },
+ { "LaunchApplication1", '\0', "", VKEY_MEDIA_LAUNCH_APP1 },
+ { "LaunchApplication2", '\0', "", VKEY_MEDIA_LAUNCH_APP2 },
+ { "LaunchMail", '\0', "", VKEY_MEDIA_LAUNCH_MAIL },
+ { "Left", '\0', "", VKEY_LEFT },
+ { "Menu", '\0', "", VKEY_MENU },
+ { "Meta", '\0', "", VKEY_UNKNOWN },
+ { "MediaNextTrack", '\0', "", VKEY_MEDIA_NEXT_TRACK },
+ { "MediaPlayPause", '\0', "", VKEY_MEDIA_PLAY_PAUSE },
+ { "MediaPreviousTrack", '\0', "", VKEY_MEDIA_PREV_TRACK },
+ { "MediaStop", '\0', "", VKEY_MEDIA_STOP },
+ { "ModeChange", '\0', "", VKEY_MODECHANGE },
+ { "Multiply", '\0', "", VKEY_MULTIPLY },
+ { "NextCandidate", '\0', "", VKEY_UNKNOWN },
+ { "Nonconvert", '\0', "", VKEY_NONCONVERT },
+ { "NumLock", '\0', "", VKEY_NUMLOCK },
+ { "PageDown", '\0', "", VKEY_NEXT },
+ { "PageUp", '\0', "", VKEY_PRIOR },
+ { "Paste", '\0', "", VKEY_UNKNOWN },
+ { "Pause", '\0', "", VKEY_PAUSE },
+ { "Play", '\0', "", VKEY_PLAY },
+ { "PreviousCandidate", '\0', "", VKEY_UNKNOWN },
+ { "PrintScreen", '\0', "", VKEY_SNAPSHOT },
+ { "Process", '\0', "", VKEY_PROCESSKEY },
+ { "Props", '\0', "", VKEY_UNKNOWN },
+ { "Right", '\0', "", VKEY_RIGHT },
+ { "RomanCharacters", '\0', "", VKEY_UNKNOWN },
+ { "Scroll", '\0', "", VKEY_SCROLL },
+ { "Select", '\0', "", VKEY_SELECT },
+ { "SelectMedia", '\0', "", VKEY_MEDIA_LAUNCH_MEDIA_SELECT },
+ { "Separator", '\0', "", VKEY_SEPARATOR },
+ { "Shift", '\0', "", VKEY_SHIFT },
+ { "Soft1", '\0', "", VKEY_UNKNOWN },
+ { "Soft2", '\0', "", VKEY_UNKNOWN },
+ { "Soft3", '\0', "", VKEY_UNKNOWN },
+ { "Soft4", '\0', "", VKEY_UNKNOWN },
+ { "Stop", '\0', "", VKEY_UNKNOWN },
+ { "Subtract", '\0', "", VKEY_SUBTRACT },
+ { "Up", '\0', "", VKEY_UP },
+ { "UpLeft", '\0', "", VKEY_UNKNOWN },
+ { "UpRight", '\0', "", VKEY_UNKNOWN },
+ { "Undo", '\0', "", VKEY_UNKNOWN },
+ { "VolumeDown", '\0', "", VKEY_VOLUME_DOWN },
+ { "VolumeMute", '\0', "", VKEY_VOLUME_MUTE },
+ { "VolumeUp", '\0', "", VKEY_VOLUME_UP },
+ { "Win", '\0', "", VKEY_LWIN },
+ { "Zoom", '\0', "", VKEY_ZOOM },
+ { "Backspace", '\0', "U+0008", VKEY_BACK },
+ { "Tab", '\0', "U+0009", VKEY_TAB },
+ { "Cancel", '\0', "U+0018", VKEY_UNKNOWN },
+ { "Esc", '\0', "U+001B", VKEY_ESCAPE },
+ { "Spacebar", ' ', "U+0020", VKEY_SPACE },
+ { "Exclamation", '!', "U+0021", VKEY_1 },
+ { "DoubleQuote", '\"', "U+0022", VKEY_OEM_7 },
+ { "Hash", '\0', "U+0023", VKEY_3 },
+ { "Dollar", '$', "U+0024", VKEY_4 },
+ { "Ampersand", '&', "U+0026", VKEY_5 },
+ { "Apostrophe", '\'', "U+0027", VKEY_OEM_7 },
+ { "LeftParen", '(', "U+0028", VKEY_9 },
+ { "RightParen", ')', "U+0029", VKEY_0 },
+ { "Asterisk", '*', "U+002A", VKEY_8 },
+ { "Plus", '+', "U+002B", VKEY_OEM_PLUS },
+ { "Percent", '+', "U+0025", VKEY_5 },
+ { "Comma", ',', "U+002C", VKEY_OEM_COMMA },
+ { "HyphenMinus", '-', "U+002D", VKEY_OEM_MINUS },
+ { "Period", '.', "U+002E", VKEY_OEM_PERIOD },
+ { "Solidus", '/', "U+002F", VKEY_OEM_2 },
+ { "", '0', "U+0030", VKEY_0 },
+ { "", '1', "U+0031", VKEY_1 },
+ { "", '2', "U+0032", VKEY_2 },
+ { "", '3', "U+0033", VKEY_3 },
+ { "", '4', "U+0034", VKEY_4 },
+ { "", '5', "U+0035", VKEY_5 },
+ { "", '6', "U+0036", VKEY_6 },
+ { "", '7', "U+0037", VKEY_7 },
+ { "", '8', "U+0038", VKEY_8 },
+ { "", '9', "U+0039", VKEY_9 },
+ { "Colon", ':', "U+003A", VKEY_OEM_1 },
+ { "Semicolon", ';', "U+003B", VKEY_OEM_1 },
+ { "LessThan", '<', "U+003C", VKEY_OEM_COMMA },
+ { "Equals", '=', "U+003D", VKEY_OEM_PLUS },
+ { "GreaterThan", '>', "U+003E", VKEY_OEM_PERIOD },
+ { "QuestionMark", '?', "U+003F", VKEY_OEM_2 },
+ { "At", '@', "U+0040", VKEY_2 },
+ { "", 'A', "U+0041", VKEY_A },
+ { "", 'B', "U+0042", VKEY_B },
+ { "", 'C', "U+0043", VKEY_C },
+ { "", 'D', "U+0044", VKEY_D },
+ { "", 'E', "U+0045", VKEY_E },
+ { "", 'F', "U+0046", VKEY_F },
+ { "", 'G', "U+0047", VKEY_G },
+ { "", 'H', "U+0048", VKEY_H },
+ { "", 'I', "U+0049", VKEY_I },
+ { "", 'J', "U+004A", VKEY_J },
+ { "", 'K', "U+004B", VKEY_K },
+ { "", 'L', "U+004C", VKEY_L },
+ { "", 'M', "U+004D", VKEY_M },
+ { "", 'N', "U+004E", VKEY_N },
+ { "", 'O', "U+004F", VKEY_O },
+ { "", 'P', "U+0050", VKEY_P },
+ { "", 'Q', "U+0051", VKEY_Q },
+ { "", 'R', "U+0052", VKEY_R },
+ { "", 'S', "U+0053", VKEY_S },
+ { "", 'T', "U+0054", VKEY_T },
+ { "", 'U', "U+0055", VKEY_U },
+ { "", 'V', "U+0056", VKEY_V },
+ { "", 'W', "U+0057", VKEY_W },
+ { "", 'X', "U+0058", VKEY_X },
+ { "", 'Y', "U+0059", VKEY_Y },
+ { "", 'Z', "U+005A", VKEY_Z },
+ { "", 'a', "U+0061", VKEY_A },
+ { "", 'b', "U+0062", VKEY_B },
+ { "", 'c', "U+0063", VKEY_C },
+ { "", 'd', "U+0064", VKEY_D },
+ { "", 'e', "U+0065", VKEY_E },
+ { "", 'f', "U+0066", VKEY_F },
+ { "", 'g', "U+0067", VKEY_G },
+ { "", 'h', "U+0068", VKEY_H },
+ { "", 'i', "U+0069", VKEY_I },
+ { "", 'j', "U+006A", VKEY_J },
+ { "", 'k', "U+006B", VKEY_K },
+ { "", 'l', "U+006C", VKEY_L },
+ { "", 'm', "U+006D", VKEY_M },
+ { "", 'n', "U+006E", VKEY_N },
+ { "", 'o', "U+006F", VKEY_O },
+ { "", 'p', "U+0070", VKEY_P },
+ { "", 'q', "U+0071", VKEY_Q },
+ { "", 'r', "U+0072", VKEY_R },
+ { "", 's', "U+0073", VKEY_S },
+ { "", 't', "U+0074", VKEY_T },
+ { "", 'u', "U+0075", VKEY_U },
+ { "", 'v', "U+0076", VKEY_V },
+ { "", 'w', "U+0077", VKEY_W },
+ { "", 'x', "U+0078", VKEY_X },
+ { "", 'y', "U+0079", VKEY_Y },
+ { "", 'z', "U+007A", VKEY_Z },
+ { "LeftSquareBracket", '[', "U+005B", VKEY_OEM_4 },
+ { "Backslash", '\\', "U+005C", VKEY_OEM_5 },
+ { "RightSquareBracket", ']', "U+005D", VKEY_OEM_6 },
+ { "Circumflex", '^', "U+005E", VKEY_OEM_6 },
+ { "Underscore", '_', "U+005F", VKEY_OEM_MINUS },
+ { "Grave", '`', "U+0060", VKEY_OEM_3 },
+ { "LeftCurlyBracket", '{', "U+007B", VKEY_OEM_4 },
+ { "Pipe", '|', "U+007C", VKEY_OEM_5 },
+ { "RightCurlyBracket", '}', "U+007D", VKEY_OEM_6 },
+ { "Del", '\0', "U+007F", VKEY_DELETE },
+ { "InvertedExclamation", '\0', "U+00A1", VKEY_UNKNOWN },
+ { "DeadGrave", '\0', "U+0300", VKEY_UNKNOWN },
+ { "DeadEacute", '\0', "U+0301", VKEY_UNKNOWN },
+ { "DeadCircumflex", '\0', "U+0302", VKEY_UNKNOWN },
+ { "DeadTilde", '\0', "U+0303", VKEY_UNKNOWN },
+ { "DeadMacron", '\0', "U+0304", VKEY_UNKNOWN },
+ { "DeadBreve", '\0', "U+0306", VKEY_UNKNOWN },
+ { "DeadAboveDot", '\0', "U+0307", VKEY_UNKNOWN },
+ { "DeadUmlaut", '\0', "U+0308", VKEY_UNKNOWN },
+ { "DeadAboveRing", '\0', "U+030A", VKEY_UNKNOWN },
+ { "DeadDoubleacute", '\0', "U+030B", VKEY_UNKNOWN },
+ { "DeadCaron", '\0', "U+030C", VKEY_UNKNOWN },
+ { "DeadCedilla", '\0', "U+0327", VKEY_UNKNOWN },
+ { "DeadOgonek", '\0', "U+0328", VKEY_UNKNOWN },
+ { "DeadIota", '\0', "U+0345", VKEY_UNKNOWN },
+ { "Euro", '\0', "U+20AC", VKEY_UNKNOWN },
+ { "DeadVoicedSound", '\0', "U+3099", VKEY_UNKNOWN },
+ { "DeadSemivoicedSound", '\0', "U+309A", VKEY_UNKNOWN }
+};
+
+static const int kNumKeyIdentifiers =
+ sizeof(kKeyIdentifiers)/sizeof(KeyIdentifier);
+
+static const KeyIdentifier* GetKeyIdentifierData(const std::string& id) {
+ for (int i = 0; i < kNumKeyIdentifiers; ++i) {
+ const KeyIdentifier& key = kKeyIdentifiers[i];
+ if ((key.key_name[0] != '\0' && strcmp(id.c_str(), key.key_name) == 0) ||
+ (id.length() == 1 && id[0] == key.character) ||
+ (key.unicode_codepoint[0] != '\0' &&
+ strcmp(id.c_str(), key.unicode_codepoint) == 0)) {
+ return &key;
+ }
+ }
+
+ return NULL;
+}
+
+} // namespace
+
+
+KeyboardCode KeyCodeFromKeyIdentifier(const std::string& key_identifier) {
+ const KeyIdentifier* id = GetKeyIdentifierData(key_identifier);
+ if (!id) {
+ return VKEY_UNKNOWN;
+ }
+ return id->key_code;
+}
+
+} // namespace base
diff --git a/base/keyboard_code_conversion.h b/base/keyboard_code_conversion.h
new file mode 100644
index 0000000..1324d52
--- /dev/null
+++ b/base/keyboard_code_conversion.h
@@ -0,0 +1,22 @@
+// 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_
diff --git a/base/keyboard_code_conversion_unittest.cc b/base/keyboard_code_conversion_unittest.cc
new file mode 100644
index 0000000..91e151b
--- /dev/null
+++ b/base/keyboard_code_conversion_unittest.cc
@@ -0,0 +1,43 @@
+// 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
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index a2b16ee..4eb02c0 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -30,6 +30,9 @@
#include "chrome/browser/extensions/extension_idle_api.h"
#include "chrome/browser/extensions/extension_i18n_api.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_metrics_module.h"
#include "chrome/browser/extensions/extension_omnibox_api.h"
@@ -54,6 +57,7 @@
#include "chrome/common/result_codes.h"
#include "chrome/common/url_constants.h"
+
// FactoryRegistry -------------------------------------------------------------
namespace {
@@ -261,6 +265,11 @@ void FactoryRegistry::ResetFunctions() {
RegisterFunction<SetIconSidebarFunction>();
RegisterFunction<SetTitleSidebarFunction>();
RegisterFunction<ShowSidebarFunction>();
+
+#if defined(TOOLKIT_VIEWS)
+ // Input.
+ RegisterFunction<SendKeyboardEventInputFunction>();
+#endif
}
void FactoryRegistry::GetAllNames(std::vector<std::string>* names) {
diff --git a/chrome/browser/extensions/extension_input_api.cc b/chrome/browser/extensions/extension_input_api.cc
new file mode 100644
index 0000000..40c4bc0
--- /dev/null
+++ b/chrome/browser/extensions/extension_input_api.cc
@@ -0,0 +1,120 @@
+// 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;
+}
diff --git a/chrome/browser/extensions/extension_input_api.h b/chrome/browser/extensions/extension_input_api.h
new file mode 100644
index 0000000..3000211
--- /dev/null
+++ b/chrome/browser/extensions/extension_input_api.h
@@ -0,0 +1,36 @@
+// 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_
diff --git a/chrome/browser/extensions/extension_input_apitest.cc b/chrome/browser/extensions/extension_input_apitest.cc
new file mode 100644
index 0000000..009329d
--- /dev/null
+++ b/chrome/browser/extensions/extension_input_apitest.cc
@@ -0,0 +1,14 @@
+// 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_;
+}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 55ab8a1..ace895c 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1366,6 +1366,8 @@
'browser/extensions/extension_infobar_module_constants.h',
'browser/extensions/extension_infobar_delegate.cc',
'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.h',
'browser/extensions/extension_menu_manager.cc',
@@ -3669,6 +3671,14 @@
['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
# its own separate implementation below. So re-include them only on
# non-ChromeOS views Linux builds.
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 0dbcf63..1f60543 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1714,6 +1714,7 @@
'browser/extensions/extension_i18n_apitest.cc',
'browser/extensions/extension_incognito_apitest.cc',
'browser/extensions/extension_infobar_apitest.cc',
+ 'browser/extensions/extension_input_apitest.cc',
'browser/extensions/extension_install_ui_browsertest.cc',
'browser/extensions/extension_javascript_url_apitest.cc',
'browser/extensions/extension_management_browsertest.cc',
@@ -1789,6 +1790,11 @@
'browser/dom_ui/file_browse_browsertest.cc',
],
}],
+ ['toolkit_views==0', {
+ 'sources!': [
+ 'browser/extensions/extension_input_apitest.cc',
+ ],
+ }],
['OS!="linux" or toolkit_views==1', {
'sources!': [
'browser/extensions/browser_action_test_util_gtk.cc',
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index 63cc5d1..6dcdf8e 100644
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -2200,6 +2200,61 @@
"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",
"nodoc": true,
"types": [],
diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js
index 22f7f48..31f980b 100644
--- a/chrome/renderer/resources/renderer_extension_bindings.js
+++ b/chrome/renderer/resources/renderer_extension_bindings.js
@@ -255,6 +255,7 @@ var chrome = chrome || {};
"experimental.clipboard",
"experimental.extension",
"experimental.infobars",
+ "experimental.input",
"experimental.metrics",
"experimental.omnibox",
"experimental.popup",
diff --git a/chrome/test/data/extensions/api_test/input/manifest.json b/chrome/test/data/extensions/api_test/input/manifest.json
new file mode 100644
index 0000000..7e00c04
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/input/manifest.json
@@ -0,0 +1,7 @@
+{
+ "name": "chrome.experimental.input",
+ "version": "0.1",
+ "description": "end-to-end browser test for chrome.experimental.input API",
+ "background_page": "test.html",
+ "permissions": ["experimental"]
+}
diff --git a/chrome/test/data/extensions/api_test/input/test.html b/chrome/test/data/extensions/api_test/input/test.html
new file mode 100644
index 0000000..46f4d74
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/input/test.html
@@ -0,0 +1 @@
+<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/input/test.js b/chrome/test/data/extensions/api_test/input/test.js
new file mode 100644
index 0000000..2506400
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/input/test.js
@@ -0,0 +1,51 @@
+// 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();
+ });
+ },
+]);