diff options
author | yusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-27 02:18:57 +0000 |
---|---|---|
committer | yusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-27 02:18:57 +0000 |
commit | 000216bf8f9e65726df376d6cec16ab87f725fe0 (patch) | |
tree | fc410cc775afd396dab5541c5000085044fac025 | |
parent | 54edcea75724b0cf2d883768c247ac448f2b408e (diff) | |
download | chromium_src-000216bf8f9e65726df376d6cec16ab87f725fe0.zip chromium_src-000216bf8f9e65726df376d6cec16ab87f725fe0.tar.gz chromium_src-000216bf8f9e65726df376d6cec16ab87f725fe0.tar.bz2 |
Add Unicode character support to chrome.input.sendKeyboardEvent.
Currently, the API can fabricate a key event which is supported by src/ui/base/keycodes/keyboard_codes_posix.h. This means the API only supports ASCII characters (<= 0x7f).
However, since some i18n virtual keyboards need to call the API to generate a key event which is not supported by the header, it'd be better to relax the limitation. For example, French virtual keyboard might call the API with U+00E1 (LATIN SMALL LETTER A WITH ACUTE), Russian one might do it with U+0410 (CYRILLIC CAPITAL LETTER A).
BUG=chromium-os:18048
TEST=run browser_tests
Review URL: http://codereview.chromium.org/7473025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@94236 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/extensions/extension_input_api.cc | 33 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/input/test.js | 67 | ||||
-rw-r--r-- | views/events/event.cc | 4 | ||||
-rw-r--r-- | views/events/event.h | 12 | ||||
-rw-r--r-- | views/events/event_gtk.cc | 4 | ||||
-rw-r--r-- | views/events/event_unittest.cc | 13 | ||||
-rw-r--r-- | views/events/event_win.cc | 8 | ||||
-rw-r--r-- | views/events/event_x.cc | 10 |
8 files changed, 143 insertions, 8 deletions
diff --git a/chrome/browser/extensions/extension_input_api.cc b/chrome/browser/extensions/extension_input_api.cc index 503bea3..7916a5f 100644 --- a/chrome/browser/extensions/extension_input_api.cc +++ b/chrome/browser/extensions/extension_input_api.cc @@ -6,6 +6,7 @@ #include <string> +#include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/extensions/key_identifier_conversion_views.h" @@ -58,6 +59,20 @@ ui::EventType GetTypeFromString(const std::string& type) { return ui::ET_UNKNOWN; } +// Converts a hex string "U+NNNN" to uint16. Returns 0 on error. +uint16 UnicodeIdentifierStringToInt(const std::string& key_identifier) { + int character = 0; + if ((key_identifier.length() == 6) && + (key_identifier.substr(0, 2) == "U+") && + (key_identifier.substr(2).find_first_not_of("0123456789abcdefABCDEF") == + std::string::npos)) { + const bool result = + base::HexStringToInt(key_identifier.substr(2), &character); + DCHECK(result) << key_identifier; + } + return character; +} + } // namespace void InputFunction::Run() { @@ -109,13 +124,20 @@ bool SendKeyboardEventInputFunction::RunImpl() { const views::KeyEvent& prototype_event = KeyEventFromKeyIdentifier(identifier); + uint16 character = 0; if (prototype_event.key_code() == ui::VKEY_UNKNOWN) { - error_ = kUnknownOrUnsupportedKeyIdentiferError; - return false; + // Check if |identifier| is "U+NNNN" format. + character = UnicodeIdentifierStringToInt(identifier); + if (!character) { + error_ = kUnknownOrUnsupportedKeyIdentiferError; + return false; + } } bool flag = false; - int flags = prototype_event.flags(); + int flags = 0; + if (prototype_event.key_code() != ui::VKEY_UNKNOWN) + flags = prototype_event.flags(); flags |= (args->GetBoolean(kAlt, &flag) && flag) ? ui::EF_ALT_DOWN : 0; flags |= (args->GetBoolean(kCtrl, &flag) && flag) ? ui::EF_CONTROL_DOWN : 0; flags |= (args->GetBoolean(kShift, &flag) && flag) ? ui::EF_SHIFT_DOWN : 0; @@ -132,6 +154,11 @@ bool SendKeyboardEventInputFunction::RunImpl() { } views::KeyEvent event(type, prototype_event.key_code(), flags); + if (character) { + event.set_character(character); + event.set_unmodified_character(character); + } + views::InputMethod* ime = widget->GetInputMethod(); if (ime) { ime->DispatchKeyEvent(event); diff --git a/chrome/test/data/extensions/api_test/input/test.js b/chrome/test/data/extensions/api_test/input/test.js index 2506400..e1ef0f9 100644 --- a/chrome/test/data/extensions/api_test/input/test.js +++ b/chrome/test/data/extensions/api_test/input/test.js @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -48,4 +48,69 @@ chrome.test.runTests([ chrome.test.succeed(); }); }, + + function sendKeyboardEventUnicode1() { + // U+00E1: LATIN SMALL LATTER A WITH ACUTE. + var e = { 'type': 'keydown', 'keyIdentifier': 'U+00E1' }; + chrome.experimental.input.sendKeyboardEvent(e, function() { + if (chrome.extension.lastError) { + // this is expected for now. See sendKeyboardEvent(). + // chrome.test.fail(); + } + chrome.test.succeed(); + }); + }, + + function sendKeyboardEventUnicode2() { + // U+043A: CYRILLIC SMALL LETTER KA + var e = { 'type': 'keydown', + 'keyIdentifier': 'U+043a' }; // lower case is also ok. + chrome.experimental.input.sendKeyboardEvent(e, function() { + if (chrome.extension.lastError) { + // this is expected for now. See sendKeyboardEvent(). + // chrome.test.fail(); + } + chrome.test.succeed(); + }); + }, + + function sendKeyboardEventBadUnicode1() { + var e = { 'type': 'keydown', 'keyIdentifier': 'U+' }; + chrome.experimental.input.sendKeyboardEvent(e, function() { + if (!chrome.extension.lastError) { + chrome.test.fail(); + } + chrome.test.succeed(); + }); + }, + + function sendKeyboardEventBadUnicode2() { + var e = { 'type': 'keydown', 'keyIdentifier': 'U+1' }; + chrome.experimental.input.sendKeyboardEvent(e, function() { + if (!chrome.extension.lastError) { + chrome.test.fail(); + } + chrome.test.succeed(); + }); + }, + + function sendKeyboardEventBadUnicode3() { + var e = { 'type': 'keydown', 'keyIdentifier': 'U+111g' }; + chrome.experimental.input.sendKeyboardEvent(e, function() { + if (!chrome.extension.lastError) { + chrome.test.fail(); + } + chrome.test.succeed(); + }); + }, + + function sendKeyboardEventBadUnicode4() { + var e = { 'type': 'keydown', 'keyIdentifier': 'U+11111' }; + chrome.experimental.input.sendKeyboardEvent(e, function() { + if (!chrome.extension.lastError) { + chrome.test.fail(); + } + chrome.test.succeed(); + }); + }, ]); diff --git a/views/events/event.cc b/views/events/event.cc index 102243a..a8db132 100644 --- a/views/events/event.cc +++ b/views/events/event.cc @@ -66,7 +66,9 @@ LocatedEvent::LocatedEvent(const LocatedEvent& model, View* root) KeyEvent::KeyEvent(ui::EventType type, ui::KeyboardCode key_code, int event_flags) : Event(type, event_flags), - key_code_(key_code) { + key_code_(key_code), + character_(0), + unmodified_character_(0) { } // KeyEvent, private: --------------------------------------------------------- diff --git a/views/events/event.h b/views/events/event.h index 03eec99..7c42537 100644 --- a/views/events/event.h +++ b/views/events/event.h @@ -316,6 +316,15 @@ class KeyEvent : public Event { ui::KeyboardCode key_code() const { return key_code_; } + // These setters allow an I18N virtual keyboard to fabricate a keyboard event + // which does not have a corresponding ui::KeyboardCode (example: U+00E1 Latin + // small letter A with acute, U+0410 Cyrillic capital letter A.) + // GetCharacter() and GetUnmodifiedCharacter() return the character. + void set_character(uint16 character) { character_ = character; } + void set_unmodified_character(uint16 unmodified_character) { + unmodified_character_ = unmodified_character; + } + // Gets the character generated by this key event. It only supports Unicode // BMP characters. uint16 GetCharacter() const; @@ -351,6 +360,9 @@ class KeyEvent : public Event { ui::KeyboardCode key_code_; + uint16 character_; + uint16 unmodified_character_; + DISALLOW_COPY_AND_ASSIGN(KeyEvent); }; diff --git a/views/events/event_gtk.cc b/views/events/event_gtk.cc index e5018df..13c8a8d 100644 --- a/views/events/event_gtk.cc +++ b/views/events/event_gtk.cc @@ -169,7 +169,9 @@ KeyEvent::KeyEvent(NativeEvent native_event) : Event(native_event, EventTypeFromNative(native_event), GetFlagsFromGdkEvent(native_event)), key_code_(ui::KeyboardCodeFromGdkEventKey( - GetGdkEventKeyFromNative(native_event))) { + GetGdkEventKeyFromNative(native_event))), + character_(0), + unmodified_character_(0) { } //////////////////////////////////////////////////////////////////////////////// diff --git a/views/events/event_unittest.cc b/views/events/event_unittest.cc index 8afb48e..4694b59 100644 --- a/views/events/event_unittest.cc +++ b/views/events/event_unittest.cc @@ -103,4 +103,17 @@ TEST_F(EventTest, KeyEvent) { } } +TEST_F(EventTest, KeyEventDirectUnicode) { + KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_UNKNOWN, ui::EF_SHIFT_DOWN); + key.set_character(0x1234U); + key.set_unmodified_character(0x4321U); + EXPECT_EQ(0x1234U, key.GetCharacter()); + EXPECT_EQ(0x4321U, key.GetUnmodifiedCharacter()); + KeyEvent key2(ui::ET_KEY_RELEASED, ui::VKEY_UNKNOWN, ui::EF_CONTROL_DOWN); + key2.set_character(0x4321U); + key2.set_unmodified_character(0x1234U); + EXPECT_EQ(0x4321U, key2.GetCharacter()); + EXPECT_EQ(0x1234U, key2.GetUnmodifiedCharacter()); +} + } // namespace views diff --git a/views/events/event_win.cc b/views/events/event_win.cc index 683a4be..609e190 100644 --- a/views/events/event_win.cc +++ b/views/events/event_win.cc @@ -233,7 +233,9 @@ KeyEvent::KeyEvent(NativeEvent native_event) : Event(native_event, EventTypeFromNative(native_event), GetKeyStateFlags()), - key_code_(ui::KeyboardCodeForWindowsKeyCode(native_event.wParam)) { + key_code_(ui::KeyboardCodeForWindowsKeyCode(native_event.wParam)), + character_(0), + unmodified_character_(0) { } KeyEvent::KeyEvent(NativeEvent2 native_event_2, FromNativeEvent2 from_native) @@ -244,11 +246,15 @@ KeyEvent::KeyEvent(NativeEvent2 native_event_2, FromNativeEvent2 from_native) } uint16 KeyEvent::GetCharacter() const { + if (character_) + return character_; return (native_event().message == WM_CHAR) ? key_code_ : GetCharacterFromKeyCode(key_code_, flags()); } uint16 KeyEvent::GetUnmodifiedCharacter() const { + if (unmodified_character_) + return unmodified_character_; // Looks like there is no way to get unmodified character on Windows. return (native_event().message == WM_CHAR) ? key_code_ : GetCharacterFromKeyCode(key_code_, flags() & ui::EF_SHIFT_DOWN); diff --git a/views/events/event_x.cc b/views/events/event_x.cc index dc88121..1f54303 100644 --- a/views/events/event_x.cc +++ b/views/events/event_x.cc @@ -295,10 +295,15 @@ KeyEvent::KeyEvent(NativeEvent2 native_event_2, FromNativeEvent2 from_native) EventTypeFromNative(native_event_2), GetEventFlagsFromXState(native_event_2->xkey.state), from_native), - key_code_(ui::KeyboardCodeFromXKeyEvent(native_event_2)) { + key_code_(ui::KeyboardCodeFromXKeyEvent(native_event_2)), + character_(0), + unmodified_character_(0) { } uint16 KeyEvent::GetCharacter() const { + if (character_) + return character_; + if (!native_event_2()) { // This event may have been created from a Gdk event. if (IsControlDown() || !native_event()) @@ -317,6 +322,9 @@ uint16 KeyEvent::GetCharacter() const { } uint16 KeyEvent::GetUnmodifiedCharacter() const { + if (unmodified_character_) + return unmodified_character_; + if (!native_event_2()) { // This event may have been created from a Gdk event. if (!native_event()) |