Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h" | 5 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h" |
| 6 | 6 |
| 7 #include "base/strings/string_number_conversions.h" | 7 #include "base/strings/string_number_conversions.h" |
| 8 #include "base/values.h" | 8 #include "base/values.h" |
| 9 #include "chrome/browser/chromeos/login/lock/screen_locker.h" | 9 #include "chrome/browser/chromeos/login/lock/screen_locker.h" |
| 10 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h" | 10 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h" |
| 11 #include "chrome/browser/chromeos/login/users/user_manager.h" | 11 #include "chrome/browser/chromeos/login/users/user_manager.h" |
| 12 #include "chrome/browser/chromeos/profiles/profile_helper.h" | 12 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
| 14 #include "chrome/browser/profiles/profile_manager.h" | 14 #include "chrome/browser/profiles/profile_manager.h" |
| 15 #include "chrome/common/extensions/api/input_ime.h" | 15 #include "chrome/common/extensions/api/input_ime.h" |
| 16 #include "chrome/common/extensions/api/input_ime/input_components_handler.h" | 16 #include "chrome/common/extensions/api/input_ime/input_components_handler.h" |
| 17 #include "chromeos/ime/component_extension_ime_manager.h" | |
| 18 #include "chromeos/ime/extension_ime_util.h" | |
| 19 #include "chromeos/ime/input_method_manager.h" | |
| 17 #include "extensions/browser/event_router.h" | 20 #include "extensions/browser/event_router.h" |
| 18 #include "extensions/browser/extension_function_registry.h" | 21 #include "extensions/browser/extension_function_registry.h" |
| 19 #include "extensions/browser/extension_registry.h" | 22 #include "extensions/browser/extension_registry.h" |
| 20 #include "extensions/browser/extension_system.h" | 23 #include "extensions/browser/extension_system.h" |
| 21 #include "extensions/common/manifest_handlers/background_info.h" | 24 #include "extensions/common/manifest_handlers/background_info.h" |
| 22 | 25 |
| 23 #if defined(USE_X11) | 26 #if defined(USE_X11) |
| 24 #include "chrome/browser/chromeos/input_method/input_method_engine.h" | 27 #include "chrome/browser/chromeos/input_method/input_method_engine.h" |
| 25 #endif | 28 #endif |
| 26 | 29 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 | 71 |
| 69 if (input.checked) | 72 if (input.checked) |
| 70 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_CHECKED; | 73 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_CHECKED; |
| 71 out->checked = input.checked ? *input.checked : false; | 74 out->checked = input.checked ? *input.checked : false; |
| 72 | 75 |
| 73 if (input.enabled) | 76 if (input.enabled) |
| 74 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_ENABLED; | 77 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_ENABLED; |
| 75 out->enabled = input.enabled ? *input.enabled : true; | 78 out->enabled = input.enabled ? *input.enabled : true; |
| 76 } | 79 } |
| 77 | 80 |
| 78 static void DispatchEventToExtension(Profile* profile, | 81 static void DispatchEventToExtension(const std::string& extension_id, |
| 79 const std::string& extension_id, | |
| 80 const std::string& event_name, | 82 const std::string& event_name, |
| 81 scoped_ptr<base::ListValue> args) { | 83 scoped_ptr<base::ListValue> args) { |
| 84 Profile* profile = ProfileManager::GetActiveUserProfile(); | |
| 82 scoped_ptr<extensions::Event> event(new extensions::Event( | 85 scoped_ptr<extensions::Event> event(new extensions::Event( |
| 83 event_name, args.Pass())); | 86 event_name, args.Pass())); |
| 84 event->restrict_to_browser_context = profile; | 87 event->restrict_to_browser_context = profile; |
| 85 extensions::EventRouter::Get(profile) | 88 extensions::EventRouter::Get(profile) |
| 86 ->DispatchEventToExtension(extension_id, event.Pass()); | 89 ->DispatchEventToExtension(extension_id, event.Pass()); |
| 87 } | 90 } |
| 88 | 91 |
| 89 void CallbackKeyEventHandle(chromeos::input_method::KeyEventHandle* key_data, | 92 void CallbackKeyEventHandle(chromeos::input_method::KeyEventHandle* key_data, |
| 90 bool handled) { | 93 bool handled) { |
| 91 base::Callback<void(bool consumed)>* callback = | 94 base::Callback<void(bool consumed)>* callback = |
| 92 reinterpret_cast<base::Callback<void(bool consumed)>*>(key_data); | 95 reinterpret_cast<base::Callback<void(bool consumed)>*>(key_data); |
| 93 callback->Run(handled); | 96 callback->Run(handled); |
| 94 delete callback; | 97 delete callback; |
| 95 } | 98 } |
| 96 | 99 |
| 97 } // namespace | 100 } // namespace |
| 98 | 101 |
| 99 namespace chromeos { | 102 namespace chromeos { |
| 100 class ImeObserver : public InputMethodEngineInterface::Observer { | 103 class ImeObserver : public InputMethodEngineInterface::Observer { |
| 101 public: | 104 public: |
| 102 ImeObserver(Profile* profile, const std::string& extension_id) | 105 explicit ImeObserver(const std::string& extension_id) |
| 103 : profile_(profile), extension_id_(extension_id), has_background_(false) { | 106 : extension_id_(extension_id) {} |
| 104 extensions::ExtensionSystem* extension_system = | |
| 105 extensions::ExtensionSystem::Get(profile_); | |
| 106 ExtensionService* extension_service = extension_system->extension_service(); | |
| 107 const extensions::Extension* extension = | |
| 108 extension_service->GetExtensionById(extension_id, false); | |
| 109 DCHECK(extension); | |
| 110 extensions::BackgroundInfo* info = static_cast<extensions::BackgroundInfo*>( | |
| 111 extension->GetManifestData("background")); | |
| 112 if (info) | |
| 113 has_background_ = info->has_background_page(); | |
| 114 } | |
| 115 | 107 |
| 116 virtual ~ImeObserver() {} | 108 virtual ~ImeObserver() {} |
| 117 | 109 |
| 118 virtual void OnActivate(const std::string& engine_id) OVERRIDE { | 110 virtual void OnActivate(const std::string& component_id) OVERRIDE { |
| 119 if (profile_ == NULL || extension_id_.empty()) | 111 if (extension_id_.empty()) |
| 120 return; | |
| 121 | |
| 122 scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(engine_id)); | |
| 123 | |
| 124 DispatchEventToExtension(profile_, extension_id_, | |
| 125 input_ime::OnActivate::kEventName, args.Pass()); | |
| 126 } | |
| 127 | |
| 128 virtual void OnDeactivated(const std::string& engine_id) OVERRIDE { | |
| 129 if (profile_ == NULL || extension_id_.empty()) | |
| 130 return; | 112 return; |
| 131 | 113 |
| 132 scoped_ptr<base::ListValue> args( | 114 scoped_ptr<base::ListValue> args( |
| 133 input_ime::OnDeactivated::Create(engine_id)); | 115 input_ime::OnActivate::Create(component_id)); |
| 134 | 116 |
| 135 DispatchEventToExtension(profile_, extension_id_, | 117 DispatchEventToExtension( |
| 136 input_ime::OnDeactivated::kEventName, args.Pass()); | 118 extension_id_, input_ime::OnActivate::kEventName, args.Pass()); |
| 119 } | |
| 120 | |
| 121 virtual void OnDeactivated(const std::string& component_id) OVERRIDE { | |
| 122 if (extension_id_.empty()) | |
| 123 return; | |
| 124 | |
| 125 scoped_ptr<base::ListValue> args( | |
| 126 input_ime::OnDeactivated::Create(component_id)); | |
| 127 | |
| 128 DispatchEventToExtension( | |
| 129 extension_id_, input_ime::OnDeactivated::kEventName, args.Pass()); | |
| 137 } | 130 } |
| 138 | 131 |
| 139 virtual void OnFocus( | 132 virtual void OnFocus( |
| 140 const InputMethodEngineInterface::InputContext& context) OVERRIDE { | 133 const InputMethodEngineInterface::InputContext& context) OVERRIDE { |
| 141 if (profile_ == NULL || extension_id_.empty()) | 134 if (extension_id_.empty()) |
| 142 return; | 135 return; |
| 143 | 136 |
| 144 input_ime::InputContext context_value; | 137 input_ime::InputContext context_value; |
| 145 context_value.context_id = context.id; | 138 context_value.context_id = context.id; |
| 146 context_value.type = input_ime::InputContext::ParseType(context.type); | 139 context_value.type = input_ime::InputContext::ParseType(context.type); |
| 147 | 140 |
| 148 scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value)); | 141 scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value)); |
| 149 | 142 |
| 150 // The component IME extensions need to know the current screen type (e.g. | 143 // The component IME extensions need to know the current screen type (e.g. |
| 151 // lock screen, login screen, etc.) so that its on-screen keyboard page | 144 // lock screen, login screen, etc.) so that its on-screen keyboard page |
| 152 // won't open new windows/pages. See crbug.com/395621. | 145 // won't open new windows/pages. See crbug.com/395621. |
| 153 base::DictionaryValue* val = NULL; | 146 base::DictionaryValue* val = NULL; |
| 154 if (args->GetDictionary(0, &val)) { | 147 if (args->GetDictionary(0, &val)) { |
| 155 std::string screen_type; | 148 std::string screen_type; |
| 156 if (!UserManager::Get()->IsUserLoggedIn()) { | 149 if (!UserManager::Get()->IsUserLoggedIn()) { |
| 157 screen_type = "login"; | 150 screen_type = "login"; |
| 158 } else if (chromeos::ScreenLocker::default_screen_locker() && | 151 } else if (chromeos::ScreenLocker::default_screen_locker() && |
| 159 chromeos::ScreenLocker::default_screen_locker()->locked()) { | 152 chromeos::ScreenLocker::default_screen_locker()->locked()) { |
| 160 screen_type = "lock"; | 153 screen_type = "lock"; |
| 161 } else if (UserAddingScreen::Get()->IsRunning()) { | 154 } else if (UserAddingScreen::Get()->IsRunning()) { |
| 162 screen_type = "secondary-login"; | 155 screen_type = "secondary-login"; |
| 163 } | 156 } |
| 164 if (!screen_type.empty()) | 157 if (!screen_type.empty()) |
| 165 val->SetStringWithoutPathExpansion("screen", screen_type); | 158 val->SetStringWithoutPathExpansion("screen", screen_type); |
| 166 } | 159 } |
| 167 | 160 |
| 168 DispatchEventToExtension(profile_, extension_id_, | 161 DispatchEventToExtension( |
| 169 input_ime::OnFocus::kEventName, args.Pass()); | 162 extension_id_, input_ime::OnFocus::kEventName, args.Pass()); |
| 170 } | 163 } |
| 171 | 164 |
| 172 virtual void OnBlur(int context_id) OVERRIDE { | 165 virtual void OnBlur(int context_id) OVERRIDE { |
| 173 if (profile_ == NULL || extension_id_.empty()) | 166 if (extension_id_.empty()) |
| 174 return; | 167 return; |
| 175 | 168 |
| 176 scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id)); | 169 scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id)); |
| 177 | 170 |
| 178 DispatchEventToExtension(profile_, extension_id_, | 171 DispatchEventToExtension( |
| 179 input_ime::OnBlur::kEventName, args.Pass()); | 172 extension_id_, input_ime::OnBlur::kEventName, args.Pass()); |
| 180 } | 173 } |
| 181 | 174 |
| 182 virtual void OnInputContextUpdate( | 175 virtual void OnInputContextUpdate( |
| 183 const InputMethodEngineInterface::InputContext& context) OVERRIDE { | 176 const InputMethodEngineInterface::InputContext& context) OVERRIDE { |
| 184 if (profile_ == NULL || extension_id_.empty()) | 177 if (extension_id_.empty()) |
| 185 return; | 178 return; |
| 186 | 179 |
| 187 input_ime::InputContext context_value; | 180 input_ime::InputContext context_value; |
| 188 context_value.context_id = context.id; | 181 context_value.context_id = context.id; |
| 189 context_value.type = input_ime::InputContext::ParseType(context.type); | 182 context_value.type = input_ime::InputContext::ParseType(context.type); |
| 190 | 183 |
| 191 scoped_ptr<base::ListValue> args( | 184 scoped_ptr<base::ListValue> args( |
| 192 input_ime::OnInputContextUpdate::Create(context_value)); | 185 input_ime::OnInputContextUpdate::Create(context_value)); |
| 193 | 186 |
| 194 DispatchEventToExtension(profile_, | 187 DispatchEventToExtension(extension_id_, |
| 195 extension_id_, | |
| 196 input_ime::OnInputContextUpdate::kEventName, | 188 input_ime::OnInputContextUpdate::kEventName, |
| 197 args.Pass()); | 189 args.Pass()); |
| 198 } | 190 } |
| 199 | 191 |
| 200 virtual void OnKeyEvent( | 192 virtual void OnKeyEvent( |
| 201 const std::string& engine_id, | 193 const std::string& component_id, |
| 202 const InputMethodEngineInterface::KeyboardEvent& event, | 194 const InputMethodEngineInterface::KeyboardEvent& event, |
| 203 chromeos::input_method::KeyEventHandle* key_data) OVERRIDE { | 195 chromeos::input_method::KeyEventHandle* key_data) OVERRIDE { |
| 204 if (profile_ == NULL || extension_id_.empty()) | 196 if (extension_id_.empty()) |
| 205 return; | 197 return; |
| 206 | 198 |
| 207 // If there is no listener for the event, no need to dispatch the event to | 199 // If there is no listener for the event, no need to dispatch the event to |
| 208 // extension. Instead, releases the key event for default system behavior. | 200 // extension. Instead, releases the key event for default system behavior. |
| 209 if (!ShouldForwardKeyEvent()) { | 201 if (!ShouldForwardKeyEvent()) { |
| 210 // Continue processing the key event so that the physical keyboard can | 202 // Continue processing the key event so that the physical keyboard can |
| 211 // still work. | 203 // still work. |
| 212 CallbackKeyEventHandle(key_data, false); | 204 CallbackKeyEventHandle(key_data, false); |
| 213 return; | 205 return; |
| 214 } | 206 } |
| 215 | 207 |
| 216 extensions::InputImeEventRouter* ime_event_router = | 208 extensions::InputImeEventRouter* ime_event_router = |
| 217 extensions::InputImeEventRouter::GetInstance(); | 209 extensions::InputImeEventRouter::GetInstance(); |
| 218 | 210 |
| 219 const std::string request_id = | 211 const std::string request_id = |
| 220 ime_event_router->AddRequest(engine_id, key_data); | 212 ime_event_router->AddRequest(component_id, key_data); |
| 221 | 213 |
| 222 input_ime::KeyboardEvent key_data_value; | 214 input_ime::KeyboardEvent key_data_value; |
| 223 key_data_value.type = input_ime::KeyboardEvent::ParseType(event.type); | 215 key_data_value.type = input_ime::KeyboardEvent::ParseType(event.type); |
| 224 key_data_value.request_id = request_id; | 216 key_data_value.request_id = request_id; |
| 225 if (!event.extension_id.empty()) | 217 if (!event.extension_id.empty()) |
| 226 key_data_value.extension_id.reset(new std::string(event.extension_id)); | 218 key_data_value.extension_id.reset(new std::string(event.extension_id)); |
| 227 key_data_value.key = event.key; | 219 key_data_value.key = event.key; |
| 228 key_data_value.code = event.code; | 220 key_data_value.code = event.code; |
| 229 key_data_value.alt_key.reset(new bool(event.alt_key)); | 221 key_data_value.alt_key.reset(new bool(event.alt_key)); |
| 230 key_data_value.ctrl_key.reset(new bool(event.ctrl_key)); | 222 key_data_value.ctrl_key.reset(new bool(event.ctrl_key)); |
| 231 key_data_value.shift_key.reset(new bool(event.shift_key)); | 223 key_data_value.shift_key.reset(new bool(event.shift_key)); |
| 232 key_data_value.caps_lock.reset(new bool(event.caps_lock)); | 224 key_data_value.caps_lock.reset(new bool(event.caps_lock)); |
| 233 | 225 |
| 234 scoped_ptr<base::ListValue> args( | 226 scoped_ptr<base::ListValue> args( |
| 235 input_ime::OnKeyEvent::Create(engine_id, key_data_value)); | 227 input_ime::OnKeyEvent::Create(component_id, key_data_value)); |
| 236 | 228 |
| 237 DispatchEventToExtension(profile_, extension_id_, | 229 DispatchEventToExtension( |
| 238 input_ime::OnKeyEvent::kEventName, args.Pass()); | 230 extension_id_, input_ime::OnKeyEvent::kEventName, args.Pass()); |
| 239 } | 231 } |
| 240 | 232 |
| 241 virtual void OnCandidateClicked( | 233 virtual void OnCandidateClicked( |
| 242 const std::string& engine_id, | 234 const std::string& component_id, |
| 243 int candidate_id, | 235 int candidate_id, |
| 244 InputMethodEngineInterface::MouseButtonEvent button) OVERRIDE { | 236 InputMethodEngineInterface::MouseButtonEvent button) OVERRIDE { |
| 245 if (profile_ == NULL || extension_id_.empty()) | 237 if (extension_id_.empty()) |
| 246 return; | 238 return; |
| 247 | 239 |
| 248 input_ime::OnCandidateClicked::Button button_enum = | 240 input_ime::OnCandidateClicked::Button button_enum = |
| 249 input_ime::OnCandidateClicked::BUTTON_NONE; | 241 input_ime::OnCandidateClicked::BUTTON_NONE; |
| 250 switch (button) { | 242 switch (button) { |
| 251 case InputMethodEngineInterface::MOUSE_BUTTON_MIDDLE: | 243 case InputMethodEngineInterface::MOUSE_BUTTON_MIDDLE: |
| 252 button_enum = input_ime::OnCandidateClicked::BUTTON_MIDDLE; | 244 button_enum = input_ime::OnCandidateClicked::BUTTON_MIDDLE; |
| 253 break; | 245 break; |
| 254 | 246 |
| 255 case InputMethodEngineInterface::MOUSE_BUTTON_RIGHT: | 247 case InputMethodEngineInterface::MOUSE_BUTTON_RIGHT: |
| 256 button_enum = input_ime::OnCandidateClicked::BUTTON_RIGHT; | 248 button_enum = input_ime::OnCandidateClicked::BUTTON_RIGHT; |
| 257 break; | 249 break; |
| 258 | 250 |
| 259 case InputMethodEngineInterface::MOUSE_BUTTON_LEFT: | 251 case InputMethodEngineInterface::MOUSE_BUTTON_LEFT: |
| 260 // Default to left. | 252 // Default to left. |
| 261 default: | 253 default: |
| 262 button_enum = input_ime::OnCandidateClicked::BUTTON_LEFT; | 254 button_enum = input_ime::OnCandidateClicked::BUTTON_LEFT; |
| 263 break; | 255 break; |
| 264 } | 256 } |
| 265 | 257 |
| 266 scoped_ptr<base::ListValue> args( | 258 scoped_ptr<base::ListValue> args(input_ime::OnCandidateClicked::Create( |
| 267 input_ime::OnCandidateClicked::Create(engine_id, | 259 component_id, candidate_id, button_enum)); |
| 268 candidate_id, | |
| 269 button_enum)); | |
| 270 | 260 |
| 271 DispatchEventToExtension(profile_, | 261 DispatchEventToExtension( |
| 272 extension_id_, | 262 extension_id_, input_ime::OnCandidateClicked::kEventName, args.Pass()); |
| 273 input_ime::OnCandidateClicked::kEventName, | |
| 274 args.Pass()); | |
| 275 } | 263 } |
| 276 | 264 |
| 277 virtual void OnMenuItemActivated(const std::string& engine_id, | 265 virtual void OnMenuItemActivated(const std::string& component_id, |
| 278 const std::string& menu_id) OVERRIDE { | 266 const std::string& menu_id) OVERRIDE { |
| 279 if (profile_ == NULL || extension_id_.empty()) | 267 if (extension_id_.empty()) |
| 280 return; | 268 return; |
| 281 | 269 |
| 282 scoped_ptr<base::ListValue> args( | 270 scoped_ptr<base::ListValue> args( |
| 283 input_ime::OnMenuItemActivated::Create(engine_id, menu_id)); | 271 input_ime::OnMenuItemActivated::Create(component_id, menu_id)); |
| 284 | 272 |
| 285 DispatchEventToExtension(profile_, | 273 DispatchEventToExtension( |
| 286 extension_id_, | 274 extension_id_, input_ime::OnMenuItemActivated::kEventName, args.Pass()); |
| 287 input_ime::OnMenuItemActivated::kEventName, | |
| 288 args.Pass()); | |
| 289 } | 275 } |
| 290 | 276 |
| 291 virtual void OnSurroundingTextChanged(const std::string& engine_id, | 277 virtual void OnSurroundingTextChanged(const std::string& component_id, |
| 292 const std::string& text, | 278 const std::string& text, |
| 293 int cursor_pos, | 279 int cursor_pos, |
| 294 int anchor_pos) OVERRIDE { | 280 int anchor_pos) OVERRIDE { |
| 295 if (profile_ == NULL || extension_id_.empty()) | 281 if (extension_id_.empty()) |
| 296 return; | 282 return; |
| 297 | 283 |
| 298 input_ime::OnSurroundingTextChanged::SurroundingInfo info; | 284 input_ime::OnSurroundingTextChanged::SurroundingInfo info; |
| 299 info.text = text; | 285 info.text = text; |
| 300 info.focus = cursor_pos; | 286 info.focus = cursor_pos; |
| 301 info.anchor = anchor_pos; | 287 info.anchor = anchor_pos; |
| 302 scoped_ptr<base::ListValue> args( | 288 scoped_ptr<base::ListValue> args( |
| 303 input_ime::OnSurroundingTextChanged::Create(engine_id, info)); | 289 input_ime::OnSurroundingTextChanged::Create(component_id, info)); |
| 304 | 290 |
| 305 DispatchEventToExtension(profile_, | 291 DispatchEventToExtension(extension_id_, |
| 306 extension_id_, | |
| 307 input_ime::OnSurroundingTextChanged::kEventName, | 292 input_ime::OnSurroundingTextChanged::kEventName, |
| 308 args.Pass()); | 293 args.Pass()); |
| 309 } | 294 } |
| 310 | 295 |
| 311 virtual void OnReset(const std::string& engine_id) OVERRIDE { | 296 virtual void OnReset(const std::string& component_id) OVERRIDE { |
| 312 if (profile_ == NULL || extension_id_.empty()) | 297 if (extension_id_.empty()) |
| 313 return; | 298 return; |
| 314 | 299 |
| 315 scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(engine_id)); | 300 scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(component_id)); |
| 316 | 301 |
| 317 DispatchEventToExtension(profile_, | 302 DispatchEventToExtension( |
| 318 extension_id_, | 303 extension_id_, input_ime::OnReset::kEventName, args.Pass()); |
| 319 input_ime::OnReset::kEventName, | |
| 320 args.Pass()); | |
| 321 } | 304 } |
| 322 | 305 |
| 323 private: | 306 private: |
| 324 // Returns true if the extension is ready to accept key event, otherwise | 307 // Returns true if the extension is ready to accept key event, otherwise |
| 325 // returns false. | 308 // returns false. |
| 326 bool ShouldForwardKeyEvent() const { | 309 bool ShouldForwardKeyEvent() const { |
| 327 // Need to check the background page first since the | 310 // Only forward key events to extension if there are non-lazy listeners |
| 328 // ExtensionHasEventListner returns true if the extension does not have a | 311 // for onKeyEvent. Because if something wrong with the lazy background |
| 329 // background page. See crbug.com/394682. | 312 // page which doesn't register listener for onKeyEvent, it will not handle |
| 330 return has_background_ && extensions::EventRouter::Get(profile_) | 313 // the key events, and therefore, all key events will be eaten. |
| 331 ->ExtensionHasEventListener(extension_id_, | 314 // This is for error-tolerance, and it means that onKeyEvent will never wake |
| 332 input_ime::OnKeyEvent::kEventName); | 315 // up lazy background page. |
| 316 const extensions::EventListenerMap::ListenerList& listener_list = | |
| 317 extensions::EventRouter::Get(ProfileManager::GetActiveUserProfile()) | |
| 318 ->listeners().GetEventListenersByName( | |
| 319 input_ime::OnKeyEvent::kEventName); | |
| 320 for (extensions::EventListenerMap::ListenerList::const_iterator it = | |
| 321 listener_list.begin(); | |
| 322 it != listener_list.end(); it++) { | |
|
Yuki
2014/08/06 04:42:24
s/it++/++it/ for iterators.
it++ may be slower tha
Shu Chen
2014/08/06 05:45:03
Done.
| |
| 323 if ((*it)->extension_id() == extension_id_ && !(*it)->IsLazy()) | |
| 324 return true; | |
| 325 } | |
| 326 return false; | |
| 333 } | 327 } |
| 334 | 328 |
| 335 Profile* profile_; | |
| 336 std::string extension_id_; | 329 std::string extension_id_; |
| 337 bool has_background_; | |
| 338 | 330 |
| 339 DISALLOW_COPY_AND_ASSIGN(ImeObserver); | 331 DISALLOW_COPY_AND_ASSIGN(ImeObserver); |
| 340 }; | 332 }; |
| 341 | 333 |
| 342 } // namespace chromeos | 334 } // namespace chromeos |
| 343 | 335 |
| 344 namespace extensions { | 336 namespace extensions { |
| 345 | 337 |
| 346 InputImeEventRouter* | 338 InputImeEventRouter* |
| 347 InputImeEventRouter::GetInstance() { | 339 InputImeEventRouter::GetInstance() { |
| 348 return Singleton<InputImeEventRouter>::get(); | 340 return Singleton<InputImeEventRouter>::get(); |
| 349 } | 341 } |
| 350 | 342 |
| 351 bool InputImeEventRouter::RegisterIme( | 343 bool InputImeEventRouter::RegisterImeExtension( |
| 352 Profile* profile, | |
| 353 const std::string& extension_id, | 344 const std::string& extension_id, |
| 354 const extensions::InputComponentInfo& component) { | 345 const std::vector<extensions::InputComponentInfo>& input_components) { |
| 355 #if defined(USE_X11) | 346 #if defined(USE_X11) |
| 356 VLOG(1) << "RegisterIme: " << extension_id << " id: " << component.id; | 347 VLOG(1) << "RegisterImeExtension: " << extension_id; |
| 357 | 348 |
| 358 // Avoid potential mem leaks due to duplicated component IDs. | 349 if (engine_map_[extension_id]) |
| 359 if (!profile_engine_map_[profile][extension_id][component.id]) { | 350 return false; |
| 360 std::vector<std::string> layouts; | |
| 361 layouts.assign(component.layouts.begin(), component.layouts.end()); | |
| 362 | 351 |
| 363 std::vector<std::string> languages; | 352 chromeos::input_method::InputMethodManager* manager = |
| 364 languages.assign(component.languages.begin(), component.languages.end()); | 353 chromeos::input_method::InputMethodManager::Get(); |
| 354 chromeos::ComponentExtensionIMEManager* comp_ext_ime_manager = | |
| 355 manager->GetComponentExtensionIMEManager(); | |
| 365 | 356 |
| 366 // Ideally Observer should be per (extension_id + Profile), and multiple | 357 chromeos::input_method::InputMethodDescriptors descriptors; |
| 367 // InputMethodEngine can share one Observer. But it would become tricky | 358 // Only creates descriptors for 3rd party IME extension, because the |
| 368 // to maintain an internal map for observers which does nearly nothing | 359 // descriptors for component IME extensions are managed by InputMethodUtil. |
| 369 // but just make sure they can properly deleted. | 360 if (!comp_ext_ime_manager->IsWhitelistedExtension(extension_id)) { |
| 370 // Making Obesrver per InputMethodEngine can make things cleaner. | 361 for (std::vector<extensions::InputComponentInfo>::const_iterator it = |
| 371 scoped_ptr<chromeos::InputMethodEngineInterface::Observer> observer( | 362 input_components.begin(); |
| 372 new chromeos::ImeObserver(profile, extension_id)); | 363 it != input_components.end(); |
| 373 chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine(); | 364 ++it) { |
| 374 engine->Initialize(profile, | 365 const extensions::InputComponentInfo& component = *it; |
| 375 observer.Pass(), | 366 DCHECK(component.type == extensions::INPUT_COMPONENT_TYPE_IME); |
| 376 component.name.c_str(), | 367 |
| 377 extension_id.c_str(), | 368 std::vector<std::string> layouts; |
| 378 component.id.c_str(), | 369 layouts.assign(component.layouts.begin(), component.layouts.end()); |
| 379 languages, | 370 std::vector<std::string> languages; |
| 380 layouts, | 371 languages.assign(component.languages.begin(), component.languages.end()); |
| 381 component.options_page_url, | 372 |
| 382 component.input_view_url); | 373 const std::string& input_method_id = |
| 383 profile_engine_map_[profile][extension_id][component.id] = engine; | 374 chromeos::extension_ime_util::GetInputMethodID(extension_id, |
| 375 component.id); | |
| 376 descriptors.push_back(chromeos::input_method::InputMethodDescriptor( | |
| 377 input_method_id, | |
| 378 component.name, | |
| 379 std::string(), // TODO(uekawa): Set short name. | |
| 380 layouts, | |
| 381 languages, | |
| 382 false, // 3rd party IMEs are always not for login. | |
| 383 component.options_page_url, | |
| 384 component.input_view_url)); | |
| 385 } | |
| 384 } | 386 } |
| 385 | 387 |
| 388 scoped_ptr<chromeos::InputMethodEngineInterface::Observer> observer( | |
| 389 new chromeos::ImeObserver(extension_id)); | |
| 390 chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine(); | |
| 391 engine->Initialize(observer.Pass(), extension_id.c_str()); | |
| 392 engine_map_[extension_id] = engine; | |
| 393 manager->AddInputMethodExtension(extension_id, descriptors, engine); | |
| 394 | |
| 386 return true; | 395 return true; |
| 387 #else | 396 #else |
| 388 // TODO(spang): IME support under ozone. | 397 // TODO(spang): IME support under ozone. |
| 389 NOTIMPLEMENTED(); | 398 NOTIMPLEMENTED(); |
| 390 return false; | 399 return false; |
| 391 #endif | 400 #endif |
| 392 } | 401 } |
| 393 | 402 |
| 394 void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) { | 403 void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) { |
| 395 Profile* profile = ProfileManager::GetActiveUserProfile(); | 404 std::map<std::string, InputMethodEngineInterface*>::iterator it = |
| 396 ProfileEngineMap::iterator extension_map = | 405 engine_map_.find(extension_id); |
| 397 profile_engine_map_.find(profile); | 406 if (it != engine_map_.end()) { |
| 398 if (extension_map == profile_engine_map_.end()) | 407 chromeos::input_method::InputMethodManager::Get() |
| 399 return; | 408 ->RemoveInputMethodExtension(extension_id); |
| 400 ExtensionMap::iterator engine_map = extension_map->second.find(extension_id); | 409 delete it->second; |
| 401 if (engine_map == extension_map->second.end()) | 410 engine_map_.erase(it); |
| 402 return; | 411 } |
| 403 STLDeleteContainerPairSecondPointers(engine_map->second.begin(), | |
| 404 engine_map->second.end()); | |
| 405 extension_map->second.erase(extension_id); | |
| 406 profile_engine_map_.erase(profile); | |
| 407 } | 412 } |
| 408 | 413 |
| 409 InputMethodEngineInterface* InputImeEventRouter::GetEngine( | 414 InputMethodEngineInterface* InputImeEventRouter::GetEngine( |
| 410 const std::string& extension_id, const std::string& engine_id) { | 415 const std::string& extension_id, |
| 411 // IME can only work on active user profile. | 416 const std::string& component_id) { |
| 412 Profile* profile = ProfileManager::GetActiveUserProfile(); | 417 std::map<std::string, InputMethodEngineInterface*>::iterator it = |
| 413 | 418 engine_map_.find(extension_id); |
| 414 ProfileEngineMap::const_iterator extension_map = | 419 if (it != engine_map_.end() && |
| 415 profile_engine_map_.find(profile); | 420 it->second->GetActiveComponentId() == component_id) |
| 416 if (extension_map == profile_engine_map_.end()) | 421 return it->second; |
| 417 return NULL; | 422 return NULL; |
| 418 ExtensionMap::const_iterator engine_map = | |
| 419 extension_map->second.find(extension_id); | |
| 420 if (engine_map == extension_map->second.end()) | |
| 421 return NULL; | |
| 422 EngineMap::const_iterator engine = engine_map->second.find(engine_id); | |
| 423 if (engine == engine_map->second.end()) | |
| 424 return NULL; | |
| 425 return engine->second; | |
| 426 } | 423 } |
| 427 | 424 |
| 428 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine( | 425 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine( |
| 429 const std::string& extension_id) { | 426 const std::string& extension_id) { |
| 430 // IME can only work on active user profile. | 427 std::map<std::string, InputMethodEngineInterface*>::iterator it = |
| 431 Profile* profile = ProfileManager::GetActiveUserProfile(); | 428 engine_map_.find(extension_id); |
| 432 | 429 if (it != engine_map_.end() && it->second->IsActive()) |
| 433 ProfileEngineMap::const_iterator extension_map = | 430 return it->second; |
| 434 profile_engine_map_.find(profile); | |
| 435 if (extension_map == profile_engine_map_.end()) | |
| 436 return NULL; | |
| 437 ExtensionMap::const_iterator engine_map = | |
| 438 extension_map->second.find(extension_id); | |
| 439 if (engine_map == extension_map->second.end()) | |
| 440 return NULL; | |
| 441 | |
| 442 for (EngineMap::const_iterator i = engine_map->second.begin(); | |
| 443 i != engine_map->second.end(); | |
| 444 ++i) { | |
| 445 if (i->second->IsActive()) | |
| 446 return i->second; | |
| 447 } | |
| 448 return NULL; | 431 return NULL; |
| 449 } | 432 } |
| 450 | 433 |
| 451 void InputImeEventRouter::OnKeyEventHandled( | 434 void InputImeEventRouter::OnKeyEventHandled( |
| 452 const std::string& extension_id, | 435 const std::string& extension_id, |
| 453 const std::string& request_id, | 436 const std::string& request_id, |
| 454 bool handled) { | 437 bool handled) { |
| 455 RequestMap::iterator request = request_map_.find(request_id); | 438 RequestMap::iterator request = request_map_.find(request_id); |
| 456 if (request == request_map_.end()) { | 439 if (request == request_map_.end()) { |
| 457 LOG(ERROR) << "Request ID not found: " << request_id; | 440 LOG(ERROR) << "Request ID not found: " << request_id; |
| 458 return; | 441 return; |
| 459 } | 442 } |
| 460 | 443 |
| 461 std::string engine_id = request->second.first; | 444 std::string component_id = request->second.first; |
| 462 chromeos::input_method::KeyEventHandle* key_data = request->second.second; | 445 chromeos::input_method::KeyEventHandle* key_data = request->second.second; |
| 463 request_map_.erase(request); | 446 request_map_.erase(request); |
| 464 | 447 |
| 465 CallbackKeyEventHandle(key_data, handled); | 448 CallbackKeyEventHandle(key_data, handled); |
| 466 } | 449 } |
| 467 | 450 |
| 468 std::string InputImeEventRouter::AddRequest( | 451 std::string InputImeEventRouter::AddRequest( |
| 469 const std::string& engine_id, | 452 const std::string& component_id, |
| 470 chromeos::input_method::KeyEventHandle* key_data) { | 453 chromeos::input_method::KeyEventHandle* key_data) { |
| 471 std::string request_id = base::IntToString(next_request_id_); | 454 std::string request_id = base::IntToString(next_request_id_); |
| 472 ++next_request_id_; | 455 ++next_request_id_; |
| 473 | 456 |
| 474 request_map_[request_id] = std::make_pair(engine_id, key_data); | 457 request_map_[request_id] = std::make_pair(component_id, key_data); |
| 475 | 458 |
| 476 return request_id; | 459 return request_id; |
| 477 } | 460 } |
| 478 | 461 |
| 479 InputImeEventRouter::InputImeEventRouter() | 462 InputImeEventRouter::InputImeEventRouter() |
| 480 : next_request_id_(1) { | 463 : next_request_id_(1) { |
| 481 } | 464 } |
| 482 | 465 |
| 483 InputImeEventRouter::~InputImeEventRouter() {} | 466 InputImeEventRouter::~InputImeEventRouter() {} |
| 484 | 467 |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 821 InputImeEventRouter::GetInstance()->OnKeyEventHandled( | 804 InputImeEventRouter::GetInstance()->OnKeyEventHandled( |
| 822 extension_id(), params->request_id, params->response); | 805 extension_id(), params->request_id, params->response); |
| 823 return true; | 806 return true; |
| 824 } | 807 } |
| 825 | 808 |
| 826 InputImeAPI::InputImeAPI(content::BrowserContext* context) | 809 InputImeAPI::InputImeAPI(content::BrowserContext* context) |
| 827 : browser_context_(context), extension_registry_observer_(this) { | 810 : browser_context_(context), extension_registry_observer_(this) { |
| 828 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | 811 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); |
| 829 | 812 |
| 830 EventRouter* event_router = EventRouter::Get(browser_context_); | 813 EventRouter* event_router = EventRouter::Get(browser_context_); |
| 831 event_router->RegisterObserver(this, input_ime::OnActivate::kEventName); | |
| 832 event_router->RegisterObserver(this, input_ime::OnFocus::kEventName); | 814 event_router->RegisterObserver(this, input_ime::OnFocus::kEventName); |
| 833 } | 815 } |
| 834 | 816 |
| 835 InputImeAPI::~InputImeAPI() { | 817 InputImeAPI::~InputImeAPI() { |
| 836 EventRouter::Get(browser_context_)->UnregisterObserver(this); | 818 EventRouter::Get(browser_context_)->UnregisterObserver(this); |
| 837 } | 819 } |
| 838 | 820 |
| 839 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> > | 821 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> > |
| 840 g_factory = LAZY_INSTANCE_INITIALIZER; | 822 g_factory = LAZY_INSTANCE_INITIALIZER; |
| 841 | 823 |
| 842 // static | 824 // static |
| 843 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() { | 825 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() { |
| 844 return g_factory.Pointer(); | 826 return g_factory.Pointer(); |
| 845 } | 827 } |
| 846 | 828 |
| 847 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context, | 829 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context, |
| 848 const Extension* extension) { | 830 const Extension* extension) { |
| 849 const std::vector<InputComponentInfo>* input_components = | 831 const std::vector<InputComponentInfo>* input_components = |
| 850 extensions::InputComponents::GetInputComponents(extension); | 832 extensions::InputComponents::GetInputComponents(extension); |
| 851 if (!input_components) | 833 if (input_components) |
| 852 return; | 834 input_ime_event_router()->RegisterImeExtension(extension->id(), |
| 853 for (std::vector<extensions::InputComponentInfo>::const_iterator component = | 835 *input_components); |
| 854 input_components->begin(); | |
| 855 component != input_components->end(); | |
| 856 ++component) { | |
| 857 if (component->type == extensions::INPUT_COMPONENT_TYPE_IME) { | |
| 858 // If |browser_context| looks like signin profile, use the real signin | |
| 859 // profile. This is because IME extensions for signin profile are run | |
| 860 // in Off-The-Record profile, based on given static defaults. | |
| 861 // So if |profile_| is signin profile, we need to make sure | |
| 862 // the router/observer runs under its incognito profile, because the | |
| 863 // component extensions were installed under its incognito profile. | |
| 864 Profile* profile = Profile::FromBrowserContext(browser_context); | |
| 865 if (chromeos::ProfileHelper::IsSigninProfile(profile)) | |
| 866 profile = chromeos::ProfileHelper::GetSigninProfile(); | |
| 867 input_ime_event_router()->RegisterIme( | |
| 868 profile, extension->id(), *component); | |
| 869 } | |
| 870 } | |
| 871 } | 836 } |
| 872 | 837 |
| 873 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context, | 838 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context, |
| 874 const Extension* extension, | 839 const Extension* extension, |
| 875 UnloadedExtensionInfo::Reason reason) { | 840 UnloadedExtensionInfo::Reason reason) { |
| 876 const std::vector<InputComponentInfo>* input_components = | 841 const std::vector<InputComponentInfo>* input_components = |
| 877 extensions::InputComponents::GetInputComponents(extension); | 842 extensions::InputComponents::GetInputComponents(extension); |
| 878 if (!input_components) | 843 if (!input_components) |
| 879 return; | 844 return; |
| 880 if (input_components->size() > 0) | 845 if (input_components->size() > 0) |
| 881 input_ime_event_router()->UnregisterAllImes(extension->id()); | 846 input_ime_event_router()->UnregisterAllImes(extension->id()); |
| 882 } | 847 } |
| 883 | 848 |
| 884 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) { | 849 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) { |
| 885 InputMethodEngineInterface* engine = | 850 InputMethodEngineInterface* engine = |
| 886 input_ime_event_router()->GetActiveEngine(details.extension_id); | 851 input_ime_event_router()->GetActiveEngine(details.extension_id); |
| 852 // Notifies the IME extension for IME ready with onActivate/onFocus events. | |
| 887 if (engine) | 853 if (engine) |
| 888 engine->NotifyImeReady(); | 854 engine->Enable(engine->GetActiveComponentId()); |
| 889 } | 855 } |
| 890 | 856 |
| 891 InputImeEventRouter* InputImeAPI::input_ime_event_router() { | 857 InputImeEventRouter* InputImeAPI::input_ime_event_router() { |
| 892 return InputImeEventRouter::GetInstance(); | 858 return InputImeEventRouter::GetInstance(); |
| 893 } | 859 } |
| 894 | 860 |
| 895 } // namespace extensions | 861 } // namespace extensions |
| OLD | NEW |