diff options
author | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-08 05:18:06 +0000 |
---|---|---|
committer | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-08 05:18:06 +0000 |
commit | cd0b04c94c9d2dd922bcdd63b9325dfdacef3b85 (patch) | |
tree | 86cd0e0bad4e5a3ecbdf44da6cbc2836c154950c | |
parent | b103b5975f6ac1b1b491510b8246091f160d9013 (diff) | |
download | chromium_src-cd0b04c94c9d2dd922bcdd63b9325dfdacef3b85.zip chromium_src-cd0b04c94c9d2dd922bcdd63b9325dfdacef3b85.tar.gz chromium_src-cd0b04c94c9d2dd922bcdd63b9325dfdacef3b85.tar.bz2 |
Make OnKeyEvent asynchronous to match the design.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/7721006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100107 0039d316-1c4b-4281-b951-d872f2087c98
9 files changed, 205 insertions, 19 deletions
diff --git a/chrome/browser/chromeos/input_method/ibus_engine_controller.cc b/chrome/browser/chromeos/input_method/ibus_engine_controller.cc index fa38801..7654bfd 100644 --- a/chrome/browser/chromeos/input_method/ibus_engine_controller.cc +++ b/chrome/browser/chromeos/input_method/ibus_engine_controller.cc @@ -32,7 +32,7 @@ namespace input_method { (G_TYPE_CHECK_CLASS_TYPE((klass), IBUS_TYPE_CHROMEOS_ENGINE)) #define IBUS_CHROMEOS_ENGINE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), IBUS_TYPE_CHROMEOS_ENGINE, \ - IBusChromeOSEngine)) + IBusChromeOSEngineClass)) class IBusEngineControllerImpl; struct IBusChromeOSEngine { @@ -332,6 +332,15 @@ class IBusEngineControllerImpl : public IBusEngineController { } } + virtual void KeyEventDone(KeyEventHandle* key_data, bool handled) { + GDBusMethodInvocation* invocation = + reinterpret_cast<GDBusMethodInvocation*>(key_data); + + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(b)", handled)); + } + + static void InitEngineClass(IBusChromeOSEngineClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS(klass); @@ -340,7 +349,9 @@ class IBusEngineControllerImpl : public IBusEngineController { object_class->constructor = EngineConstructor; ibus_object_class->destroy = (IBusObjectDestroyFunc) OnDestroy; - engine_class->process_key_event = OnProcessKeyEvent; + IBUS_SERVICE_CLASS(klass)->service_method_call = OnServiceMethodCall; + + engine_class->process_key_event = NULL; engine_class->reset = OnReset; engine_class->enable = OnEnable; engine_class->disable = OnDisable; @@ -439,17 +450,51 @@ class IBusEngineControllerImpl : public IBusEngineController { return true; } - static gboolean OnProcessKeyEvent(IBusEngine* ibus_engine, guint keyval, - guint keycode, guint modifiers) { + static void OnServiceMethodCall(IBusService* service, + GDBusConnection* connection, + const gchar* sender, + const gchar* object_path, + const gchar* interface_name, + const gchar* method_name, + GVariant* parameters, + GDBusMethodInvocation* invocation) { + if (g_strcmp0(method_name, "ProcessKeyEvent") == 0) { + // Override the default ProcessKeyEvent handler so that we can send the + // response asynchronously. + IBusEngine *engine = IBUS_ENGINE(service); + + guint keyval; + guint keycode; + guint state; + g_variant_get(parameters, "(uuu)", &keyval, &keycode, &state); + + OnProcessKeyEvent(engine, keyval, keycode, state, invocation); + } else { + IBUS_SERVICE_CLASS( + ibus_chromeos_engine_parent_class)->service_method_call( + service, + connection, + sender, + object_path, + interface_name, + method_name, + parameters, + invocation); + } + } + + static void OnProcessKeyEvent(IBusEngine* ibus_engine, guint keyval, + guint keycode, guint modifiers, + GDBusMethodInvocation* key_data) { VLOG(1) << "OnProcessKeyEvent"; - // TODO: Use async version. IBusChromeOSEngine* engine = IBUS_CHROMEOS_ENGINE(ibus_engine); - engine->connection->observer_->OnKeyEvent(!(modifiers & IBUS_RELEASE_MASK), - keyval, keycode, - modifiers & IBUS_MOD1_MASK, - modifiers & IBUS_CONTROL_MASK, - modifiers & IBUS_SHIFT_MASK); - return true; + engine->connection->observer_->OnKeyEvent( + !(modifiers & IBUS_RELEASE_MASK), + keyval, keycode, + modifiers & IBUS_MOD1_MASK, + modifiers & IBUS_CONTROL_MASK, + modifiers & IBUS_SHIFT_MASK, + reinterpret_cast<KeyEventHandle*>(key_data)); } static void OnReset(IBusEngine* ibus_engine) { diff --git a/chrome/browser/chromeos/input_method/ibus_engine_controller.h b/chrome/browser/chromeos/input_method/ibus_engine_controller.h index a5763dc..b7f741b 100644 --- a/chrome/browser/chromeos/input_method/ibus_engine_controller.h +++ b/chrome/browser/chromeos/input_method/ibus_engine_controller.h @@ -14,6 +14,8 @@ namespace chromeos { namespace input_method { +struct KeyEventHandle; + // IBusEngineController is used to encapsulate an ibus engine. class IBusEngineController { public: @@ -22,7 +24,8 @@ class IBusEngineController { // Called when a key is pressed or released. virtual void OnKeyEvent(bool key_press, unsigned int keyval, unsigned int keycode, bool alt_key, - bool ctrl_key, bool shift_key) = 0; + bool ctrl_key, bool shift_key, + KeyEventHandle* key_data) = 0; // Called when the engine should reset its internal state. virtual void OnReset() = 0; @@ -114,6 +117,9 @@ class IBusEngineController { // Set the posistion of the cursor in the candidate window. virtual void SetCursorPosition(unsigned int position) = 0; + + // Inform the engine that a key event has been processed. + virtual void KeyEventDone(KeyEventHandle* key_data, bool handled) = 0; }; } // namespace input_method diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc index f758409..e4b55be 100644 --- a/chrome/browser/chromeos/input_method/input_method_engine.cc +++ b/chrome/browser/chromeos/input_method/input_method_engine.cc @@ -90,6 +90,8 @@ class InputMethodEngineImpl virtual bool IsActive() const { return active_; } + virtual void KeyEventDone(input_method::KeyEventHandle* key_data, + bool handled); virtual void OnReset(); virtual void OnEnable(); @@ -97,8 +99,9 @@ class InputMethodEngineImpl virtual void OnFocusIn(); virtual void OnFocusOut(); virtual void OnKeyEvent(bool key_press, unsigned int keyval, - unsigned int keycode, bool alt_key, - bool ctrl_key, bool shift_key); + unsigned int keycode, bool alt_key, bool ctrl_key, + bool shift_key, + input_method::KeyEventHandle* key_data); virtual void OnPropertyActivate(const char* name, unsigned int state); virtual void OnCandidateClicked(unsigned int index, unsigned int button, unsigned int state); @@ -359,6 +362,11 @@ void InputMethodEngineImpl::UpdateMenuItems( // TODO(zork): Implement this function } +void InputMethodEngineImpl::KeyEventDone(input_method::KeyEventHandle* key_data, + bool handled) { + connection_->KeyEventDone(key_data, handled); +} + void InputMethodEngineImpl::OnReset() { // Ignored } @@ -393,7 +401,8 @@ void InputMethodEngineImpl::OnFocusOut() { void InputMethodEngineImpl::OnKeyEvent(bool key_press, unsigned int keyval, unsigned int keycode, bool alt_key, - bool ctrl_key, bool shift_key) { + bool ctrl_key, bool shift_key, + input_method::KeyEventHandle* key_data) { KeyboardEvent event; event.type = key_press ? "keydown" : "keyup"; event.key = input_method::GetIBusKey(keyval); @@ -401,7 +410,7 @@ void InputMethodEngineImpl::OnKeyEvent(bool key_press, unsigned int keyval, event.alt_key = alt_key; event.ctrl_key = ctrl_key; event.shift_key = shift_key; - observer_->OnKeyEvent(engine_id_, event); + observer_->OnKeyEvent(engine_id_, event, key_data); } void InputMethodEngineImpl::OnPropertyActivate(const char* name, diff --git a/chrome/browser/chromeos/input_method/input_method_engine.h b/chrome/browser/chromeos/input_method/input_method_engine.h index de9c871..3cf82dd 100644 --- a/chrome/browser/chromeos/input_method/input_method_engine.h +++ b/chrome/browser/chromeos/input_method/input_method_engine.h @@ -11,6 +11,10 @@ namespace chromeos { +namespace input_method { +struct KeyEventHandle; +} // namespace input_method + extern const char* kExtensionImePrefix; // InputMethodEngine is used to translate from the Chrome IME API to the native @@ -87,7 +91,8 @@ class InputMethodEngine { // Called when the user pressed a key with a text field focused. virtual void OnKeyEvent(const std::string& engine_id, - const KeyboardEvent& event) = 0; + const KeyboardEvent& event, + input_method::KeyEventHandle* key_data) = 0; // Called when the user clicks on an item in the candidate list. virtual void OnCandidateClicked(const std::string& engine_id, @@ -172,6 +177,10 @@ class InputMethodEngine { // Returns true if this IME is active, false if not. virtual bool IsActive() const = 0; + // Inform the engine that a key event has been processed. + virtual void KeyEventDone(input_method::KeyEventHandle* key_data, + bool handled) = 0; + // Create an IME engine. static InputMethodEngine* CreateEngine( InputMethodEngine::Observer* observer, diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 79d6fa3..8e871ee 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -315,6 +315,8 @@ void FactoryRegistry::ResetFunctions() { RegisterFunction<SetCursorPositionFunction>(); RegisterFunction<SetMenuItemsFunction>(); RegisterFunction<UpdateMenuItemsFunction>(); + + RegisterFunction<InputEventHandled>(); #if defined(TOUCH_UI) RegisterFunction<CandidateClickedInputUiFunction>(); RegisterFunction<CursorUpInputUiFunction>(); diff --git a/chrome/browser/extensions/extension_input_ime_api.cc b/chrome/browser/extensions/extension_input_ime_api.cc index 662b5c2..13e59b5 100644 --- a/chrome/browser/extensions/extension_input_ime_api.cc +++ b/chrome/browser/extensions/extension_input_ime_api.cc @@ -5,6 +5,7 @@ #include "chrome/browser/extensions/extension_input_ime_api.h" #include "base/json/json_writer.h" +#include "base/string_number_conversions.h" #include "base/values.h" #include "chrome/browser/chromeos/input_method/input_method_engine.h" #include "chrome/browser/extensions/extension_event_router.h" @@ -115,12 +116,18 @@ class ImeObserver : public chromeos::InputMethodEngine::Observer { } virtual void OnKeyEvent(const std::string& engine_id, - const InputMethodEngine::KeyboardEvent& event) { + const InputMethodEngine::KeyboardEvent& event, + chromeos::input_method::KeyEventHandle* key_data) { if (profile_ == NULL || extension_id_.empty()) return; + std::string request_id = + ExtensionInputImeEventRouter::GetInstance()->AddRequest(engine_id, + key_data); + DictionaryValue* dict = new DictionaryValue(); dict->SetString("type", event.type); + dict->SetString("requestId", request_id); dict->SetString("key", event.key); dict->SetString("keyCode", event.key_code); dict->SetBoolean("altKey", event.alt_key); @@ -200,7 +207,8 @@ ExtensionInputImeEventRouter::GetInstance() { return Singleton<ExtensionInputImeEventRouter>::get(); } -ExtensionInputImeEventRouter::ExtensionInputImeEventRouter() { +ExtensionInputImeEventRouter::ExtensionInputImeEventRouter() + : next_request_id_(1) { } ExtensionInputImeEventRouter::~ExtensionInputImeEventRouter() { @@ -296,6 +304,40 @@ chromeos::InputMethodEngine* ExtensionInputImeEventRouter::GetActiveEngine( return NULL; } +void ExtensionInputImeEventRouter::OnEventHandled( + const std::string& extension_id, + const std::string& request_id, + bool handled) { + RequestMap::iterator request = request_map_.find(request_id); + if (request == request_map_.end()) { + LOG(ERROR) << "Request ID not found: " << request_id; + return; + } + + std::string engine_id = request->second.first; + chromeos::input_method::KeyEventHandle* key_data = request->second.second; + request_map_.erase(request); + + chromeos::InputMethodEngine* engine = GetEngine(extension_id, engine_id); + if (!engine) { + LOG(ERROR) << "Engine does not exist: " << engine_id; + return; + } + + engine->KeyEventDone(key_data, handled); +} + +std::string ExtensionInputImeEventRouter::AddRequest( + const std::string& engine_id, + chromeos::input_method::KeyEventHandle* key_data) { + std::string request_id = base::IntToString(next_request_id_); + ++next_request_id_; + + request_map_[request_id] = std::make_pair(engine_id, key_data); + + return request_id; +} + bool SetCompositionFunction::RunImpl() { chromeos::InputMethodEngine* engine = ExtensionInputImeEventRouter::GetInstance()-> @@ -631,4 +673,17 @@ bool UpdateMenuItemsFunction::RunImpl() { // TODO return true; } + +bool InputEventHandled::RunImpl() { + std::string request_id_str; + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &request_id_str)); + + bool handled = false; + EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &handled)); + + ExtensionInputImeEventRouter::GetInstance()->OnEventHandled( + extension_id(), request_id_str, handled); + + return true; +} #endif diff --git a/chrome/browser/extensions/extension_input_ime_api.h b/chrome/browser/extensions/extension_input_ime_api.h index 7a714d2..b1ebeaced 100644 --- a/chrome/browser/extensions/extension_input_ime_api.h +++ b/chrome/browser/extensions/extension_input_ime_api.h @@ -37,8 +37,18 @@ class ExtensionInputImeEventRouter { chromeos::InputMethodEngine* GetActiveEngine(const std::string& extension_id); + // Called when a key event was handled. + void OnEventHandled(const std::string& extension_id, + const std::string& request_id, + bool handled); + + std::string AddRequest(const std::string& engine_id, + chromeos::input_method::KeyEventHandle* key_data); + private: friend struct DefaultSingletonTraits<ExtensionInputImeEventRouter>; + typedef std::map<std::string, std::pair<std::string, + chromeos::input_method::KeyEventHandle*> > RequestMap; ExtensionInputImeEventRouter(); ~ExtensionInputImeEventRouter(); @@ -48,6 +58,9 @@ class ExtensionInputImeEventRouter { std::map<std::string, std::map<std::string, chromeos::ImeObserver*> > observers_; + unsigned int next_request_id_; + RequestMap request_map_; + DISALLOW_COPY_AND_ASSIGN(ExtensionInputImeEventRouter); }; @@ -111,4 +124,10 @@ class UpdateMenuItemsFunction : public AsyncExtensionFunction { "experimental.input.updateMenuItems"); }; +class InputEventHandled : public AsyncExtensionFunction { + public: + virtual bool RunImpl(); + DECLARE_EXTENSION_FUNCTION_NAME("experimental.input.eventHandled"); +}; + #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INPUT_IME_API_H_ diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index 3c9d5ad..dbc5e60 100644 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -2823,6 +2823,7 @@ "description": "See http://www.w3.org/TR/DOM-Level-3-Events/#events-KeyboardEvent", "properties": { "type": {"type": "string", "description": "One of keyup or keydown.", "enum": ["keyup", "keydown"]}, + "requestId": {"type": "string", "description": "The ID of the request."}, "key": {"type": "string", "description": "Value of the key being pressed"}, "keyCode": {"type": "string", "description": "Value of the key being press, unmodified by control keys."}, "altKey": {"type": "boolean", "optional": true, "description": "Whether or not the ALT key is pressed."}, @@ -3325,6 +3326,16 @@ "minimum": 0 } ] + }, + { + "name": "eventHandled", + "nodoc": true, + "type": "function", + "description": "Used internally to send a response for onKeyEvent.", + "parameters": [ + {"type": "string", "name": "requestId"}, + {"type": "boolean", "name": "response"} + ] } ], "events": [ diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index c0c93ee..4dd5461 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -415,6 +415,35 @@ var chrome = chrome || {}; customBindings['ContentSetting'] = ContentSetting; } + function setupInputEvents() { + chrome.experimental.input.onKeyEvent.dispatch = + function(engineID, keyData) { + var args = Array.prototype.slice.call(arguments); + if (this.validate_) { + var validationErrors = this.validate_(args); + if (validationErrors) { + chrome.experimental.input.eventHandled(requestId, false); + return validationErrors; + } + } + if (this.listeners_.length > 1) { + console.error("Too many listeners for 'onKeyEvent': " + e.stack); + chrome.experimental.input.eventHandled(requestId, false); + return; + } + for (var i = 0; i < this.listeners_.length; i++) { + try { + var requestId = keyData.requestId; + var result = this.listeners_[i].apply(null, args); + chrome.experimental.input.eventHandled(requestId, result); + } catch (e) { + console.error("Error in event handler for 'onKeyEvent': " + e.stack); + chrome.experimental.input.eventHandled(requestId, false); + } + } + }; + } + // Page action events send (pageActionId, {tabId, tabUrl}). function setupPageActionEvents(extensionId) { var pageActions = GetCurrentPageActions(extensionId); @@ -1021,6 +1050,7 @@ var chrome = chrome || {}; setupPageActionEvents(extensionId); setupToolstripEvents(GetRenderViewId()); setupHiddenContextMenuEvent(extensionId); + setupInputEvents(); setupOmniboxEvents(); setupTtsEvents(); }); |