diff options
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/base.gypi | 2 | ||||
-rw-r--r-- | base/keyboard_code_conversion.cc | 296 | ||||
-rw-r--r-- | base/keyboard_code_conversion.h | 22 | ||||
-rw-r--r-- | base/keyboard_code_conversion_unittest.cc | 43 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_dispatcher.cc | 9 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_input_api.cc | 120 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_input_api.h | 36 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_input_apitest.cc | 14 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 10 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 6 | ||||
-rw-r--r-- | chrome/common/extensions/api/extension_api.json | 55 | ||||
-rw-r--r-- | chrome/renderer/resources/renderer_extension_bindings.js | 1 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/input/manifest.json | 7 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/input/test.html | 1 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/input/test.js | 51 |
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(); + }); + }, +]); |