diff options
24 files changed, 205 insertions, 123 deletions
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc index 0c35000..71281f5 100644 --- a/chrome/browser/chromeos/input_method/input_method_engine.cc +++ b/chrome/browser/chromeos/input_method/input_method_engine.cc @@ -73,50 +73,6 @@ InputMethodEngine::InputMethodEngine() InputMethodEngine::~InputMethodEngine() {} -bool InputMethodEngine::SendKeyEvents( - int context_id, - const std::vector<KeyboardEvent>& events) { - if (!IsActive()) { - return false; - } - // context_id == 0, means sending key events to non-input field. - // context_id_ == -1, means the focus is not in an input field. - if (context_id != 0 && (context_id != context_id_ || context_id_ == -1)) { - return false; - } - - ui::EventProcessor* dispatcher = - ash::Shell::GetPrimaryRootWindow()->GetHost()->event_processor(); - - for (size_t i = 0; i < events.size(); ++i) { - const KeyboardEvent& event = events[i]; - const ui::EventType type = - (event.type == "keyup") ? ui::ET_KEY_RELEASED : ui::ET_KEY_PRESSED; - ui::KeyboardCode key_code = static_cast<ui::KeyboardCode>(event.key_code); - if (key_code == ui::VKEY_UNKNOWN) - key_code = ui::DomKeycodeToKeyboardCode(event.code); - - int flags = ui::EF_NONE; - flags |= event.alt_key ? ui::EF_ALT_DOWN : ui::EF_NONE; - flags |= event.ctrl_key ? ui::EF_CONTROL_DOWN : ui::EF_NONE; - flags |= event.shift_key ? ui::EF_SHIFT_DOWN : ui::EF_NONE; - flags |= event.caps_lock ? ui::EF_CAPS_LOCK_ON : ui::EF_NONE; - - ui::KeyEvent ui_event( - type, key_code, - ui::KeycodeConverter::CodeStringToDomCode(event.code), flags, - ui::KeycodeConverter::KeyStringToDomKey(event.key), - ui::EventTimeForNow()); - base::AutoReset<const ui::KeyEvent*> reset_sent_key(&sent_key_event_, - &ui_event); - ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&ui_event); - if (details.dispatcher_destroyed) - break; - } - - return true; -} - const InputMethodEngine::CandidateWindowProperty& InputMethodEngine::GetCandidateWindowProperty() const { return candidate_window_property_; @@ -368,4 +324,16 @@ void InputMethodEngine::CommitTextToInputContext(int context_id, } } +bool InputMethodEngine::SendKeyEvent(ui::KeyEvent* event, + const std::string& code) { + DCHECK(event); + if (event->key_code() == ui::VKEY_UNKNOWN) + event->set_key_code(ui::DomKeycodeToKeyboardCode(code)); + + ui::EventProcessor* dispatcher = + ash::Shell::GetPrimaryRootWindow()->GetHost()->event_processor(); + ui::EventDispatchDetails details = dispatcher->OnEventFromSource(event); + return !details.dispatcher_destroyed; +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/input_method/input_method_engine.h b/chrome/browser/chromeos/input_method/input_method_engine.h index 578950c..ed82dc0 100644 --- a/chrome/browser/chromeos/input_method/input_method_engine.h +++ b/chrome/browser/chromeos/input_method/input_method_engine.h @@ -89,8 +89,6 @@ class InputMethodEngine : public ::input_method::InputMethodEngineBase { ~InputMethodEngine() override; // IMEEngineHandlerInterface overrides. - bool SendKeyEvents(int context_id, - const std::vector<KeyboardEvent>& events) override; bool SetCandidateWindowVisible(bool visible, std::string* error) override; bool SetCursorPosition(int context_id, int candidate_id, @@ -139,6 +137,7 @@ class InputMethodEngine : public ::input_method::InputMethodEngineBase { bool is_visible) override; void CommitTextToInputContext(int context_id, const std::string& text) override; + bool SendKeyEvent(ui::KeyEvent* event, const std::string& code) override; // The current candidate window. scoped_ptr<ui::CandidateWindow> candidate_window_; diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc index 31dc260..d2980016 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc +++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc @@ -12,9 +12,14 @@ namespace input_ime = extensions::api::input_ime; namespace KeyEventHandled = extensions::api::input_ime::KeyEventHandled; namespace SetComposition = extensions::api::input_ime::SetComposition; namespace CommitText = extensions::api::input_ime::CommitText; +namespace SendKeyEvents = extensions::api::input_ime::SendKeyEvents; using ui::IMEEngineHandlerInterface; using input_method::InputMethodEngineBase; +namespace { +const char kErrorEngineNotAvailable[] = "Engine is not available"; +const char kErrorSetKeyEventsFail[] = "Could not send key events"; +} namespace ui { ImeObserver::ImeObserver(const std::string& extension_id, Profile* profile) @@ -329,6 +334,39 @@ ExtensionFunction::ResponseAction InputImeCommitTextFunction::Run() { return RespondNow(ArgumentList(std::move(output))); } +ExtensionFunction::ResponseAction InputImeSendKeyEventsFunction::Run() { + InputImeEventRouter* event_router = + GetInputImeEventRouter(Profile::FromBrowserContext(browser_context())); + InputMethodEngineBase* engine = + event_router ? event_router->GetActiveEngine(extension_id()) : nullptr; + if (!engine) + return RespondNow(Error(kErrorEngineNotAvailable)); + + scoped_ptr<SendKeyEvents::Params> parent_params( + SendKeyEvents::Params::Create(*args_)); + EXTENSION_FUNCTION_VALIDATE(parent_params); + const SendKeyEvents::Params::Parameters& params = parent_params->parameters; + const std::vector<linked_ptr<input_ime::KeyboardEvent>>& key_data = + params.key_data; + std::vector<InputMethodEngineBase::KeyboardEvent> key_data_out; + + for (const auto& key_event : key_data) { + InputMethodEngineBase::KeyboardEvent event; + event.type = input_ime::ToString(key_event->type); + event.key = key_event->key; + event.code = key_event->code; + event.key_code = key_event->key_code.get() ? *(key_event->key_code) : 0; + event.alt_key = key_event->alt_key ? *(key_event->alt_key) : false; + event.ctrl_key = key_event->ctrl_key ? *(key_event->ctrl_key) : false; + event.shift_key = key_event->shift_key ? *(key_event->shift_key) : false; + event.caps_lock = key_event->caps_lock ? *(key_event->caps_lock) : false; + key_data_out.push_back(event); + } + if (!engine->SendKeyEvents(params.context_id, key_data_out)) + return RespondNow(Error(kErrorSetKeyEventsFail)); + return RespondNow(NoArguments()); +} + InputImeAPI::InputImeAPI(content::BrowserContext* context) : browser_context_(context), extension_registry_observer_(this) { extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.h b/chrome/browser/extensions/api/input_ime/input_ime_api.h index d16275d..26a56fb 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api.h +++ b/chrome/browser/extensions/api/input_ime/input_ime_api.h @@ -151,6 +151,17 @@ class InputImeCommitTextFunction : public UIThreadExtensionFunction { ResponseAction Run() override; }; +class InputImeSendKeyEventsFunction : public UIThreadExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("input.ime.sendKeyEvents", INPUT_IME_SENDKEYEVENTS) + + protected: + ~InputImeSendKeyEventsFunction() override {} + + // UIThreadExtensionFunction: + ResponseAction Run() override; +}; + class InputImeAPI : public BrowserContextKeyedAPI, public ExtensionRegistryObserver, public EventRouter::Observer { diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc index eabbb1d..e2fdc7d 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc +++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc @@ -28,7 +28,6 @@ namespace input_ime = extensions::api::input_ime; namespace DeleteSurroundingText = extensions::api::input_ime::DeleteSurroundingText; namespace UpdateMenuItems = extensions::api::input_ime::UpdateMenuItems; -namespace SendKeyEvents = extensions::api::input_ime::SendKeyEvents; namespace HideInputView = extensions::api::input_ime::HideInputView; namespace SetMenuItems = extensions::api::input_ime::SetMenuItems; namespace SetCursorPosition = extensions::api::input_ime::SetCursorPosition; @@ -378,43 +377,6 @@ bool InputImeHideInputViewFunction::RunAsync() { return true; } -bool InputImeSendKeyEventsFunction::RunAsync() { - scoped_ptr<SendKeyEvents::Params> parent_params( - SendKeyEvents::Params::Create(*args_)); - const SendKeyEvents::Params::Parameters& params = - parent_params->parameters; - InputMethodEngine* engine = GetActiveEngine( - Profile::FromBrowserContext(browser_context()), extension_id()); - if (!engine) { - error_ = kErrorEngineNotAvailable; - return false; - } - - const std::vector<linked_ptr<input_ime::KeyboardEvent> >& key_data = - params.key_data; - std::vector<InputMethodEngineBase::KeyboardEvent> key_data_out; - - for (size_t i = 0; i < key_data.size(); ++i) { - InputMethodEngineBase::KeyboardEvent event; - event.type = input_ime::ToString(key_data[i]->type); - event.key = key_data[i]->key; - event.code = key_data[i]->code; - event.key_code = key_data[i]->key_code.get() ? *(key_data[i]->key_code) : 0; - if (key_data[i]->alt_key) - event.alt_key = *(key_data[i]->alt_key); - if (key_data[i]->ctrl_key) - event.ctrl_key = *(key_data[i]->ctrl_key); - if (key_data[i]->shift_key) - event.shift_key = *(key_data[i]->shift_key); - if (key_data[i]->caps_lock) - event.caps_lock = *(key_data[i]->caps_lock); - key_data_out.push_back(event); - } - - engine->SendKeyEvents(params.context_id, key_data_out); - return true; -} - bool InputImeSetCandidateWindowPropertiesFunction::RunSync() { scoped_ptr<SetCandidateWindowProperties::Params> parent_params( SetCandidateWindowProperties::Params::Create(*args_)); diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h index 4dc0b17..4516d68 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h +++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h @@ -103,18 +103,6 @@ class InputImeDeleteSurroundingTextFunction : public SyncExtensionFunction { bool RunSync() override; }; -class InputImeSendKeyEventsFunction : public AsyncExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("input.ime.sendKeyEvents", - INPUT_IME_SENDKEYEVENTS) - - protected: - ~InputImeSendKeyEventsFunction() override {} - - // ExtensionFunction: - bool RunAsync() override; -}; - class InputImeHideInputViewFunction : public AsyncExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("input.ime.hideInputView", diff --git a/chrome/browser/ui/input_method/input_method_engine.cc b/chrome/browser/ui/input_method/input_method_engine.cc index a8c6214..644ad0a 100644 --- a/chrome/browser/ui/input_method/input_method_engine.cc +++ b/chrome/browser/ui/input_method/input_method_engine.cc @@ -8,6 +8,7 @@ #include "ui/base/ime/composition_text.h" #include "ui/base/ime/ime_bridge.h" #include "ui/base/ime/ime_input_context_handler_interface.h" +#include "ui/events/keycodes/keyboard_code_conversion.h" namespace { @@ -30,13 +31,6 @@ InputMethodEngine::~InputMethodEngine() { CloseImeWindows(); } -bool InputMethodEngine::SendKeyEvents( - int context_id, - const std::vector<KeyboardEvent>& events) { - // TODO(azurewei) Implement SendKeyEvents funciton - return false; -} - bool InputMethodEngine::IsActive() const { return true; } @@ -189,4 +183,19 @@ ui::ImeWindow* InputMethodEngine::FindWindowById(int window_id) const { return nullptr; } +bool InputMethodEngine::SendKeyEvent(ui::KeyEvent* event, + const std::string& code) { + DCHECK(event); + if (event->key_code() == ui::VKEY_UNKNOWN) + event->set_key_code(ui::DomCodeToUsLayoutKeyboardCode(event->code())); + + ui::IMEInputContextHandlerInterface* input_context = + ui::IMEBridge::Get()->GetInputContextHandler(); + if (!input_context) + return false; + input_context->SendKeyEvent(event); + + return true; +} + } // namespace input_method diff --git a/chrome/browser/ui/input_method/input_method_engine.h b/chrome/browser/ui/input_method/input_method_engine.h index 9710ced..adf1921 100644 --- a/chrome/browser/ui/input_method/input_method_engine.h +++ b/chrome/browser/ui/input_method/input_method_engine.h @@ -26,8 +26,6 @@ class InputMethodEngine : public InputMethodEngineBase, ~InputMethodEngine() override; // ui::IMEEngineHandlerInterface: - bool SendKeyEvents(int context_id, - const std::vector<KeyboardEvent>& events) override; bool IsActive() const override; std::string GetExtensionId() const override; @@ -54,6 +52,7 @@ class InputMethodEngine : public InputMethodEngineBase, bool is_visible) override; void CommitTextToInputContext(int context_id, const std::string& text) override; + bool SendKeyEvent(ui::KeyEvent* ui_event, const std::string& code) override; // ui::ImeWindowObserver: void OnWindowDestroyed(ui::ImeWindow* ime_window) override; diff --git a/chrome/browser/ui/input_method/input_method_engine_base.cc b/chrome/browser/ui/input_method/input_method_engine_base.cc index 6764d7d..3257e73 100644 --- a/chrome/browser/ui/input_method/input_method_engine_base.cc +++ b/chrome/browser/ui/input_method/input_method_engine_base.cc @@ -27,6 +27,7 @@ #include "ui/events/event_processor.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/dom/dom_code.h" +#include "ui/events/keycodes/dom/keycode_converter.h" #include "ui/keyboard/keyboard_controller.h" #include "ui/keyboard/keyboard_util.h" @@ -419,4 +420,37 @@ std::string InputMethodEngineBase::AddRequest( return request_id; } +bool InputMethodEngineBase::SendKeyEvents( + int context_id, + const std::vector<KeyboardEvent>& events) { + // context_id == 0, means sending key events to non-input field. + // context_id_ == -1, means the focus is not in an input field. + if (!IsActive() || + (context_id != 0 && (context_id != context_id_ || context_id_ == -1))) + return false; + + for (size_t i = 0; i < events.size(); ++i) { + const KeyboardEvent& event = events[i]; + const ui::EventType type = + (event.type == "keyup") ? ui::ET_KEY_RELEASED : ui::ET_KEY_PRESSED; + ui::KeyboardCode key_code = static_cast<ui::KeyboardCode>(event.key_code); + + int flags = ui::EF_NONE; + flags |= event.alt_key ? ui::EF_ALT_DOWN : ui::EF_NONE; + flags |= event.ctrl_key ? ui::EF_CONTROL_DOWN : ui::EF_NONE; + flags |= event.shift_key ? ui::EF_SHIFT_DOWN : ui::EF_NONE; + flags |= event.caps_lock ? ui::EF_CAPS_LOCK_ON : ui::EF_NONE; + + ui::KeyEvent ui_event( + type, key_code, ui::KeycodeConverter::CodeStringToDomCode(event.code), + flags, ui::KeycodeConverter::KeyStringToDomKey(event.key), + ui::EventTimeForNow()); + base::AutoReset<const ui::KeyEvent*> reset_sent_key(&sent_key_event_, + &ui_event); + if (!SendKeyEvent(&ui_event, event.code)) + return false; + } + return true; +} + } // namespace input_method diff --git a/chrome/browser/ui/input_method/input_method_engine_base.h b/chrome/browser/ui/input_method/input_method_engine_base.h index 1ca4a16..bdd2f40 100644 --- a/chrome/browser/ui/input_method/input_method_engine_base.h +++ b/chrome/browser/ui/input_method/input_method_engine_base.h @@ -154,8 +154,7 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface { bool IsInterestedInKeyEvent() const override; // Send the sequence of key events. - virtual bool SendKeyEvents(int context_id, - const std::vector<KeyboardEvent>& events) = 0; + bool SendKeyEvents(int context_id, const std::vector<KeyboardEvent>& events); // Set the current composition and associated properties. bool SetComposition(int context_id, @@ -186,6 +185,9 @@ class InputMethodEngineBase : virtual public ui::IMEEngineHandlerInterface { // Notifies InputContextHanlder to commit |text|. virtual void CommitTextToInputContext(int context_id, const std::string& text) = 0; + // Sends the key event to the window tree host. + virtual bool SendKeyEvent(ui::KeyEvent* ui_event, + const std::string& code) = 0; ui::TextInputType current_input_type_; diff --git a/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc b/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc index 31de3d9..e1341b9 100644 --- a/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc +++ b/chrome/browser/ui/views/ime/input_ime_apitest_nonchromeos.cc @@ -38,6 +38,10 @@ IN_PROC_BROWSER_TEST_F(InputImeApiTest, CreateWindowTest) { ASSERT_TRUE(RunExtensionTest("input_ime_nonchromeos")) << message_; + // Test the input.ime.sendKeyEvents API. + ASSERT_EQ(client->insert_char_count(), 1); + ASSERT_EQ(client->last_insert_char(), L'a'); + input_method->DetachTextInputClient(client.get()); } diff --git a/chrome/common/extensions/api/input_ime.json b/chrome/common/extensions/api/input_ime.json index 0f981fc..4656903 100644 --- a/chrome/common/extensions/api/input_ime.json +++ b/chrome/common/extensions/api/input_ime.json @@ -269,7 +269,7 @@ "name": "sendKeyEvents", "type": "function", "description": "Sends the key events. This function is expected to be used by virtual keyboards. When key(s) on a virtual keyboard is pressed by a user, this function is used to propagate that event to the system.", - "platforms": ["chromeos"], + "platforms": ["chromeos", "win", "linux"], "parameters": [ { "name": "parameters", @@ -744,7 +744,7 @@ { "name": "onKeyEvent", "type": "function", - "description": "This event is sent if this extension owns the active IME.", + "description": "Fired when a key event is sent from the operating system. The event will be sent to the extension if this extension owns the active IME.", "platforms": ["chromeos", "win", "linux"], "options": { "supportsFilters": false, diff --git a/chrome/test/data/extensions/api_test/input_ime_nonchromeos/background.js b/chrome/test/data/extensions/api_test/input_ime_nonchromeos/background.js index e3ba1d6..d007bc6 100644 --- a/chrome/test/data/extensions/api_test/input_ime_nonchromeos/background.js +++ b/chrome/test/data/extensions/api_test/input_ime_nonchromeos/background.js @@ -52,5 +52,23 @@ chrome.test.runTests([ win.addEventListener('unload', function() {}); chrome.test.succeed(); }); + }, + + function testSendKeyEvents() { + chrome.input.ime.sendKeyEvents({ + 'contextID': 1, + 'keyData': [{ + 'type': 'keydown', + 'requestId': '0', + 'key': 'a', + 'code': 'KeyA' + }, { + 'type': 'keyup', + 'requestId': '1', + 'key': 'a', + 'code': 'KeyA' + }] + }); + chrome.test.succeed(); } ]); diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index 718de9d..e2a30a8 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn @@ -675,7 +675,10 @@ source_set("test_support") { "ime/dummy_text_input_client.h", ] - deps += [ "//ui/base/ime" ] + deps += [ + "//ui/base/ime", + "//ui/events", + ] } if (!use_aura) { diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc index e4decfd..35cda00 100644 --- a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc +++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc @@ -46,4 +46,6 @@ void MockIMEInputContextHandler::Reset() { last_commit_text_.clear(); } +void MockIMEInputContextHandler::SendKeyEvent(ui::KeyEvent* event) {} + } // namespace chromeos diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.h b/ui/base/ime/chromeos/mock_ime_input_context_handler.h index 78dec902..751dad9 100644 --- a/ui/base/ime/chromeos/mock_ime_input_context_handler.h +++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.h @@ -35,6 +35,7 @@ class UI_BASE_IME_EXPORT MockIMEInputContextHandler uint32_t cursor_pos, bool visible) override; void DeleteSurroundingText(int32_t offset, uint32_t length) override; + void SendKeyEvent(ui::KeyEvent* event) override; int commit_text_call_count() const { return commit_text_call_count_; } diff --git a/ui/base/ime/dummy_text_input_client.cc b/ui/base/ime/dummy_text_input_client.cc index 478b489..ac9b973 100644 --- a/ui/base/ime/dummy_text_input_client.cc +++ b/ui/base/ime/dummy_text_input_client.cc @@ -3,15 +3,16 @@ // found in the LICENSE file. #include "ui/base/ime/dummy_text_input_client.h" +#include "ui/events/event.h" #include "ui/gfx/geometry/rect.h" namespace ui { DummyTextInputClient::DummyTextInputClient() - : text_input_type_(TEXT_INPUT_TYPE_NONE) {} + : text_input_type_(TEXT_INPUT_TYPE_NONE), insert_char_count_(0) {} DummyTextInputClient::DummyTextInputClient(TextInputType text_input_type) - : text_input_type_(text_input_type) {} + : text_input_type_(text_input_type), insert_char_count_(0) {} DummyTextInputClient::~DummyTextInputClient() { } @@ -29,7 +30,10 @@ void DummyTextInputClient::ClearCompositionText() { void DummyTextInputClient::InsertText(const base::string16& text) { } -void DummyTextInputClient::InsertChar(const KeyEvent& event) {} +void DummyTextInputClient::InsertChar(const KeyEvent& event) { + ++insert_char_count_; + last_insert_char_ = event.GetCharacter(); +} TextInputType DummyTextInputClient::GetTextInputType() const { return text_input_type_; diff --git a/ui/base/ime/dummy_text_input_client.h b/ui/base/ime/dummy_text_input_client.h index 3c51782..a177993 100644 --- a/ui/base/ime/dummy_text_input_client.h +++ b/ui/base/ime/dummy_text_input_client.h @@ -49,9 +49,16 @@ class DummyTextInputClient : public TextInputClient { bool IsEditCommandEnabled(int command_id) override; void SetEditCommandForNextKeyEvent(int command_id) override; + int insert_char_count() const { return insert_char_count_; } + base::char16 last_insert_char() const { return last_insert_char_; } + TextInputType text_input_type_; DISALLOW_COPY_AND_ASSIGN(DummyTextInputClient); + + private: + int insert_char_count_; + base::char16 last_insert_char_; }; } // namespace ui diff --git a/ui/base/ime/ime_input_context_handler_interface.h b/ui/base/ime/ime_input_context_handler_interface.h index 5a8f6ae..b8fbb2b 100644 --- a/ui/base/ime/ime_input_context_handler_interface.h +++ b/ui/base/ime/ime_input_context_handler_interface.h @@ -10,6 +10,7 @@ #include <string> #include "ui/base/ime/composition_text.h" #include "ui/base/ime/ui_base_ime_export.h" +#include "ui/events/event.h" namespace ui { @@ -25,6 +26,9 @@ class UI_BASE_IME_EXPORT IMEInputContextHandlerInterface { // Called when the engine request deleting surrounding string. virtual void DeleteSurroundingText(int32_t offset, uint32_t length) = 0; + + // Called when the engine sends a key event. + virtual void SendKeyEvent(KeyEvent* event) = 0; }; } // namespace ui diff --git a/ui/base/ime/input_method_auralinux.cc b/ui/base/ime/input_method_auralinux.cc index c5c0d5e..08ec50b 100644 --- a/ui/base/ime/input_method_auralinux.cc +++ b/ui/base/ime/input_method_auralinux.cc @@ -65,6 +65,20 @@ void InputMethodAuraLinux::DispatchKeyEvent(ui::KeyEvent* event) { return; } + if (!event->HasNativeEvent() && sending_key_event_) { + // Faked key events that are sent from input.ime.sendKeyEvents. + ui::EventDispatchDetails details = DispatchKeyEventPostIME(event); + if (details.dispatcher_destroyed || details.target_destroyed || + event->stopped_propagation()) { + return; + } + if ((event->is_char() || event->GetDomKey().IsCharacter()) && + event->type() == ui::ET_KEY_PRESSED) { + GetTextInputClient()->InsertChar(*event); + } + return; + } + suppress_next_result_ = false; composition_changed_ = false; result_text_.clear(); diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc index e4af2e8..d66cb94 100644 --- a/ui/base/ime/input_method_base.cc +++ b/ui/base/ime/input_method_base.cc @@ -17,7 +17,9 @@ namespace ui { InputMethodBase::InputMethodBase() - : delegate_(nullptr), text_input_client_(nullptr) {} + : sending_key_event_(false), + delegate_(nullptr), + text_input_client_(nullptr) {} InputMethodBase::~InputMethodBase() { FOR_EACH_OBSERVER(InputMethodObserver, @@ -195,4 +197,10 @@ void InputMethodBase::UpdateCompositionText(const CompositionText& composition_, void InputMethodBase::DeleteSurroundingText(int32_t offset, uint32_t length) {} +void InputMethodBase::SendKeyEvent(KeyEvent* event) { + sending_key_event_ = true; + DispatchKeyEvent(event); + sending_key_event_ = false; +} + } // namespace ui diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h index a0ac432..3a44e37 100644 --- a/ui/base/ime/input_method_base.h +++ b/ui/base/ime/input_method_base.h @@ -69,6 +69,7 @@ class UI_BASE_IME_EXPORT InputMethodBase uint32_t cursor_pos, bool visible) override; void DeleteSurroundingText(int32_t offset, uint32_t length) override; + void SendKeyEvent(KeyEvent* event) override; // Sends a fake key event for IME composing without physical key events. // Returns true if the faked key event is stopped propagation. @@ -102,6 +103,10 @@ class UI_BASE_IME_EXPORT InputMethodBase // Gets the bounds of the composition text or cursor in |client|. std::vector<gfx::Rect> GetCompositionBounds(const TextInputClient* client); + // Indicates whether the IME extension is currently sending a fake key event. + // This is used in SendKeyEvent. + bool sending_key_event_; + private: void SetFocusedTextInputClientInternal(TextInputClient* client); diff --git a/ui/base/ime/input_method_win.cc b/ui/base/ime/input_method_win.cc index 0bc9052..9b04a8d 100644 --- a/ui/base/ime/input_method_win.cc +++ b/ui/base/ime/input_method_win.cc @@ -623,15 +623,16 @@ bool InputMethodWin::IsWindowFocused(const TextInputClient* client) const { } void InputMethodWin::DispatchFabricatedKeyEvent(ui::KeyEvent* event) { - if (event->is_char()) { - if (GetTextInputClient()) { - ui::KeyEvent ch_event(*event); - ch_event.set_character(static_cast<base::char16>(event->key_code())); - GetTextInputClient()->InsertChar(ch_event); - return; - } + // The key event if from calling input.ime.sendKeyEvent or test. + ui::EventDispatchDetails details = DispatchKeyEventPostIME(event); + if (details.dispatcher_destroyed || details.target_destroyed || + event->stopped_propagation()) { + return; } - ignore_result(DispatchKeyEventPostIME(event)); + + if ((event->is_char() || event->GetDomKey().IsCharacter()) && + event->type() == ui::ET_KEY_PRESSED && GetTextInputClient()) + GetTextInputClient()->InsertChar(*event); } void InputMethodWin::ConfirmCompositionText() { diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp index ae6f6e57..853e95e 100644 --- a/ui/base/ui_base.gyp +++ b/ui/base/ui_base.gyp @@ -726,7 +726,8 @@ ], 'conditions': [ ['OS!="ios"', { - 'dependecies': [ + 'dependencies': [ + '../events/events.gyp:events', 'ime/ui_base_ime.gyp:ui_base_ime', ], 'sources': [ |