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" | |
|
Shu Chen
2014/08/04 15:59:31
Nona, I guess the original design was to avoid dep
Seigo Nonaka
2014/08/04 23:29:47
Probably, it is historical reasons. It used to be
Shu Chen
2014/08/05 01:23:09
Done.
| |
| 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 } | 107 } |
| 115 | 108 |
| 116 virtual ~ImeObserver() {} | 109 virtual ~ImeObserver() {} |
| 117 | 110 |
| 118 virtual void OnActivate(const std::string& engine_id) OVERRIDE { | 111 virtual void OnActivate(const std::string& engine_id) OVERRIDE { |
| 119 if (profile_ == NULL || extension_id_.empty()) | 112 if (extension_id_.empty()) |
| 120 return; | 113 return; |
| 121 | 114 |
| 122 scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(engine_id)); | 115 scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(engine_id)); |
| 123 | 116 |
| 124 DispatchEventToExtension(profile_, extension_id_, | 117 DispatchEventToExtension(extension_id_, |
| 125 input_ime::OnActivate::kEventName, args.Pass()); | 118 input_ime::OnActivate::kEventName, args.Pass()); |
| 126 } | 119 } |
| 127 | 120 |
| 128 virtual void OnDeactivated(const std::string& engine_id) OVERRIDE { | 121 virtual void OnDeactivated(const std::string& engine_id) OVERRIDE { |
| 129 if (profile_ == NULL || extension_id_.empty()) | 122 if (extension_id_.empty()) |
| 130 return; | 123 return; |
| 131 | 124 |
| 132 scoped_ptr<base::ListValue> args( | 125 scoped_ptr<base::ListValue> args( |
| 133 input_ime::OnDeactivated::Create(engine_id)); | 126 input_ime::OnDeactivated::Create(engine_id)); |
| 134 | 127 |
| 135 DispatchEventToExtension(profile_, extension_id_, | 128 DispatchEventToExtension(extension_id_, |
| 136 input_ime::OnDeactivated::kEventName, args.Pass()); | 129 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(extension_id_, |
| 169 input_ime::OnFocus::kEventName, args.Pass()); | 162 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(extension_id_, |
| 179 input_ime::OnBlur::kEventName, args.Pass()); | 172 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& engine_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 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 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(engine_id, key_data_value)); |
| 236 | 228 |
| 237 DispatchEventToExtension(profile_, extension_id_, | 229 DispatchEventToExtension(extension_id_, |
| 238 input_ime::OnKeyEvent::kEventName, args.Pass()); | 230 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& engine_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( |
| 267 input_ime::OnCandidateClicked::Create(engine_id, | 259 input_ime::OnCandidateClicked::Create(engine_id, |
| 268 candidate_id, | 260 candidate_id, |
| 269 button_enum)); | 261 button_enum)); |
| 270 | 262 |
| 271 DispatchEventToExtension(profile_, | 263 DispatchEventToExtension(extension_id_, |
| 272 extension_id_, | |
| 273 input_ime::OnCandidateClicked::kEventName, | 264 input_ime::OnCandidateClicked::kEventName, |
| 274 args.Pass()); | 265 args.Pass()); |
| 275 } | 266 } |
| 276 | 267 |
| 277 virtual void OnMenuItemActivated(const std::string& engine_id, | 268 virtual void OnMenuItemActivated(const std::string& engine_id, |
| 278 const std::string& menu_id) OVERRIDE { | 269 const std::string& menu_id) OVERRIDE { |
| 279 if (profile_ == NULL || extension_id_.empty()) | 270 if (extension_id_.empty()) |
| 280 return; | 271 return; |
| 281 | 272 |
| 282 scoped_ptr<base::ListValue> args( | 273 scoped_ptr<base::ListValue> args( |
| 283 input_ime::OnMenuItemActivated::Create(engine_id, menu_id)); | 274 input_ime::OnMenuItemActivated::Create(engine_id, menu_id)); |
| 284 | 275 |
| 285 DispatchEventToExtension(profile_, | 276 DispatchEventToExtension(extension_id_, |
| 286 extension_id_, | |
| 287 input_ime::OnMenuItemActivated::kEventName, | 277 input_ime::OnMenuItemActivated::kEventName, |
| 288 args.Pass()); | 278 args.Pass()); |
| 289 } | 279 } |
| 290 | 280 |
| 291 virtual void OnSurroundingTextChanged(const std::string& engine_id, | 281 virtual void OnSurroundingTextChanged(const std::string& engine_id, |
| 292 const std::string& text, | 282 const std::string& text, |
| 293 int cursor_pos, | 283 int cursor_pos, |
| 294 int anchor_pos) OVERRIDE { | 284 int anchor_pos) OVERRIDE { |
| 295 if (profile_ == NULL || extension_id_.empty()) | 285 if (extension_id_.empty()) |
| 296 return; | 286 return; |
| 297 | 287 |
| 298 input_ime::OnSurroundingTextChanged::SurroundingInfo info; | 288 input_ime::OnSurroundingTextChanged::SurroundingInfo info; |
| 299 info.text = text; | 289 info.text = text; |
| 300 info.focus = cursor_pos; | 290 info.focus = cursor_pos; |
| 301 info.anchor = anchor_pos; | 291 info.anchor = anchor_pos; |
| 302 scoped_ptr<base::ListValue> args( | 292 scoped_ptr<base::ListValue> args( |
| 303 input_ime::OnSurroundingTextChanged::Create(engine_id, info)); | 293 input_ime::OnSurroundingTextChanged::Create(engine_id, info)); |
| 304 | 294 |
| 305 DispatchEventToExtension(profile_, | 295 DispatchEventToExtension(extension_id_, |
| 306 extension_id_, | |
| 307 input_ime::OnSurroundingTextChanged::kEventName, | 296 input_ime::OnSurroundingTextChanged::kEventName, |
| 308 args.Pass()); | 297 args.Pass()); |
| 309 } | 298 } |
| 310 | 299 |
| 311 virtual void OnReset(const std::string& engine_id) OVERRIDE { | 300 virtual void OnReset(const std::string& engine_id) OVERRIDE { |
| 312 if (profile_ == NULL || extension_id_.empty()) | 301 if (extension_id_.empty()) |
| 313 return; | 302 return; |
| 314 | 303 |
| 315 scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(engine_id)); | 304 scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(engine_id)); |
| 316 | 305 |
| 317 DispatchEventToExtension(profile_, | 306 DispatchEventToExtension(extension_id_, |
| 318 extension_id_, | |
| 319 input_ime::OnReset::kEventName, | 307 input_ime::OnReset::kEventName, |
| 320 args.Pass()); | 308 args.Pass()); |
| 321 } | 309 } |
| 322 | 310 |
| 323 private: | 311 private: |
| 324 // Returns true if the extension is ready to accept key event, otherwise | 312 // Returns true if the extension is ready to accept key event, otherwise |
| 325 // returns false. | 313 // returns false. |
| 326 bool ShouldForwardKeyEvent() const { | 314 bool ShouldForwardKeyEvent() const { |
| 327 // Need to check the background page first since the | 315 // Need to check the background page first since the |
| 328 // ExtensionHasEventListner returns true if the extension does not have a | 316 // ExtensionHasEventListner returns true if the extension does not have a |
| 329 // background page. See crbug.com/394682. | 317 // background page. See crbug.com/394682. |
| 330 return has_background_ && extensions::EventRouter::Get(profile_) | 318 return extensions::EventRouter::Get(ProfileManager::GetActiveUserProfile()) |
| 331 ->ExtensionHasEventListener(extension_id_, | 319 ->ExtensionHasEventListener(extension_id_, |
| 332 input_ime::OnKeyEvent::kEventName); | 320 input_ime::OnKeyEvent::kEventName); |
| 333 } | 321 } |
| 334 | 322 |
| 335 Profile* profile_; | |
| 336 std::string extension_id_; | 323 std::string extension_id_; |
| 337 bool has_background_; | |
| 338 | 324 |
| 339 DISALLOW_COPY_AND_ASSIGN(ImeObserver); | 325 DISALLOW_COPY_AND_ASSIGN(ImeObserver); |
| 340 }; | 326 }; |
| 341 | 327 |
| 342 } // namespace chromeos | 328 } // namespace chromeos |
| 343 | 329 |
| 344 namespace extensions { | 330 namespace extensions { |
| 345 | 331 |
| 346 InputImeEventRouter* | 332 InputImeEventRouter* |
| 347 InputImeEventRouter::GetInstance() { | 333 InputImeEventRouter::GetInstance() { |
| 348 return Singleton<InputImeEventRouter>::get(); | 334 return Singleton<InputImeEventRouter>::get(); |
| 349 } | 335 } |
| 350 | 336 |
| 351 bool InputImeEventRouter::RegisterIme( | 337 bool InputImeEventRouter::RegisterImeExtension( |
| 352 const std::string& extension_id, | 338 const std::string& extension_id, |
| 353 const extensions::InputComponentInfo& component) { | 339 const std::vector<extensions::InputComponentInfo>& input_components) { |
| 354 #if defined(USE_X11) | 340 #if defined(USE_X11) |
| 355 VLOG(1) << "RegisterIme: " << extension_id << " id: " << component.id; | 341 VLOG(1) << "RegisterImeExtension: " << extension_id; |
| 356 | 342 |
| 357 Profile* profile = ProfileManager::GetActiveUserProfile(); | 343 if (engine_map_[extension_id]) |
| 358 // Avoid potential mem leaks due to duplicated component IDs. | 344 return false; |
| 359 if (!profile_engine_map_[profile][extension_id][component.id]) { | |
| 360 std::vector<std::string> layouts; | |
| 361 layouts.assign(component.layouts.begin(), component.layouts.end()); | |
| 362 | 345 |
| 363 std::vector<std::string> languages; | 346 chromeos::input_method::InputMethodManager* manager = |
| 364 languages.assign(component.languages.begin(), component.languages.end()); | 347 chromeos::input_method::InputMethodManager::Get(); |
| 348 chromeos::ComponentExtensionIMEManager* comp_ext_ime_manager = | |
| 349 manager->GetComponentExtensionIMEManager(); | |
| 365 | 350 |
| 366 // Ideally Observer should be per (extension_id + Profile), and multiple | 351 chromeos::input_method::InputMethodDescriptors descriptors; |
| 367 // InputMethodEngine can share one Observer. But it would become tricky | 352 // Only creates descriptors for 3rd party IME extension, because the |
| 368 // to maintain an internal map for observers which does nearly nothing | 353 // descriptors for component IME extensions are managed by InputMethodUtil. |
| 369 // but just make sure they can properly deleted. | 354 if (!comp_ext_ime_manager->IsWhitelistedExtension(extension_id)) { |
| 370 // Making Obesrver per InputMethodEngine can make things cleaner. | 355 for (std::vector<extensions::InputComponentInfo>::const_iterator it = |
| 371 scoped_ptr<chromeos::InputMethodEngineInterface::Observer> observer( | 356 input_components.begin(); it != input_components.end(); ++it) { |
| 372 new chromeos::ImeObserver(profile, extension_id)); | 357 const extensions::InputComponentInfo& component = *it; |
| 373 chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine(); | 358 DCHECK(component.type == extensions::INPUT_COMPONENT_TYPE_IME); |
| 374 engine->Initialize(observer.Pass(), | 359 |
| 375 component.name.c_str(), | 360 std::vector<std::string> layouts; |
| 376 extension_id.c_str(), | 361 layouts.assign(component.layouts.begin(), component.layouts.end()); |
| 377 component.id.c_str(), | 362 std::vector<std::string> languages; |
| 378 languages, | 363 languages.assign(component.languages.begin(), component.languages.end()); |
| 379 layouts, | 364 |
| 380 component.options_page_url, | 365 std::string input_method_id = |
| 381 component.input_view_url); | 366 chromeos::extension_ime_util::GetInputMethodID( |
| 382 profile_engine_map_[profile][extension_id][component.id] = engine; | 367 extension_id, component.id); |
| 368 descriptors.push_back(chromeos::input_method::InputMethodDescriptor( | |
| 369 input_method_id, | |
| 370 component.name, | |
| 371 std::string(), // TODO(uekawa): Set short name. | |
| 372 layouts, | |
| 373 languages, | |
| 374 false, // 3rd party IMEs are always not for login. | |
| 375 component.options_page_url, | |
| 376 component.input_view_url)); | |
| 377 } | |
| 383 } | 378 } |
| 384 | 379 |
| 380 scoped_ptr<chromeos::InputMethodEngineInterface::Observer> observer( | |
| 381 new chromeos::ImeObserver(extension_id)); | |
| 382 chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine(); | |
| 383 engine->Initialize(observer.Pass(), extension_id.c_str()); | |
| 384 engine_map_[extension_id] = engine; | |
| 385 manager->AddInputMethodExtension(extension_id, descriptors, engine); | |
| 386 | |
| 385 return true; | 387 return true; |
| 386 #else | 388 #else |
| 387 // TODO(spang): IME support under ozone. | 389 // TODO(spang): IME support under ozone. |
| 388 NOTIMPLEMENTED(); | 390 NOTIMPLEMENTED(); |
| 389 return false; | 391 return false; |
| 390 #endif | 392 #endif |
| 391 } | 393 } |
| 392 | 394 |
| 393 void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) { | 395 void InputImeEventRouter::UnregisterAllImes(const std::string& extension_id) { |
| 394 Profile* profile = ProfileManager::GetActiveUserProfile(); | 396 if (engine_map_.find(extension_id) != engine_map_.end()) { |
| 395 ProfileEngineMap::iterator extension_map = | 397 chromeos::input_method::InputMethodManager::Get() |
| 396 profile_engine_map_.find(profile); | 398 ->RemoveInputMethodExtension(extension_id); |
| 397 if (extension_map == profile_engine_map_.end()) | 399 delete engine_map_[extension_id]; |
| 398 return; | 400 engine_map_.erase(extension_id); |
| 399 ExtensionMap::iterator engine_map = extension_map->second.find(extension_id); | 401 } |
| 400 if (engine_map == extension_map->second.end()) | |
| 401 return; | |
| 402 STLDeleteContainerPairSecondPointers(engine_map->second.begin(), | |
| 403 engine_map->second.end()); | |
| 404 extension_map->second.erase(extension_id); | |
| 405 profile_engine_map_.erase(profile); | |
| 406 } | 402 } |
| 407 | 403 |
| 408 InputMethodEngineInterface* InputImeEventRouter::GetEngine( | 404 InputMethodEngineInterface* InputImeEventRouter::GetEngine( |
| 409 const std::string& extension_id, const std::string& engine_id) { | 405 const std::string& extension_id, const std::string& engine_id) { |
| 410 // IME can only work on active user profile. | 406 if (engine_map_.find(extension_id) != engine_map_.end()) { |
|
Seigo Nonaka
2014/08/04 23:29:48
nit: it is totally up to you but I prefer
if (eng
Shu Chen
2014/08/05 01:23:09
Done.
| |
| 411 Profile* profile = ProfileManager::GetActiveUserProfile(); | 407 if (engine_map_[extension_id]->GetActiveEngineId() == engine_id) |
| 412 | 408 return engine_map_[extension_id]; |
| 413 ProfileEngineMap::const_iterator extension_map = | 409 } |
| 414 profile_engine_map_.find(profile); | 410 return NULL; |
| 415 if (extension_map == profile_engine_map_.end()) | |
| 416 return NULL; | |
| 417 ExtensionMap::const_iterator engine_map = | |
| 418 extension_map->second.find(extension_id); | |
| 419 if (engine_map == extension_map->second.end()) | |
| 420 return NULL; | |
| 421 EngineMap::const_iterator engine = engine_map->second.find(engine_id); | |
| 422 if (engine == engine_map->second.end()) | |
| 423 return NULL; | |
| 424 return engine->second; | |
| 425 } | 411 } |
| 426 | 412 |
| 427 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine( | 413 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine( |
| 428 const std::string& extension_id) { | 414 const std::string& extension_id) { |
| 429 // IME can only work on active user profile. | 415 if (engine_map_.find(extension_id) != engine_map_.end()) { |
|
Seigo Nonaka
2014/08/04 23:29:47
same as above.
Shu Chen
2014/08/05 01:23:09
Done.
| |
| 430 Profile* profile = ProfileManager::GetActiveUserProfile(); | 416 if (engine_map_[extension_id]->IsActive()) |
| 431 | 417 return engine_map_[extension_id]; |
| 432 ProfileEngineMap::const_iterator extension_map = | |
| 433 profile_engine_map_.find(profile); | |
| 434 if (extension_map == profile_engine_map_.end()) | |
| 435 return NULL; | |
| 436 ExtensionMap::const_iterator engine_map = | |
| 437 extension_map->second.find(extension_id); | |
| 438 if (engine_map == extension_map->second.end()) | |
| 439 return NULL; | |
| 440 | |
| 441 for (EngineMap::const_iterator i = engine_map->second.begin(); | |
| 442 i != engine_map->second.end(); | |
| 443 ++i) { | |
| 444 if (i->second->IsActive()) | |
| 445 return i->second; | |
| 446 } | 418 } |
| 447 return NULL; | 419 return NULL; |
| 448 } | 420 } |
| 449 | 421 |
| 450 void InputImeEventRouter::OnKeyEventHandled( | 422 void InputImeEventRouter::OnKeyEventHandled( |
| 451 const std::string& extension_id, | 423 const std::string& extension_id, |
| 452 const std::string& request_id, | 424 const std::string& request_id, |
| 453 bool handled) { | 425 bool handled) { |
| 454 RequestMap::iterator request = request_map_.find(request_id); | 426 RequestMap::iterator request = request_map_.find(request_id); |
| 455 if (request == request_map_.end()) { | 427 if (request == request_map_.end()) { |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 820 InputImeEventRouter::GetInstance()->OnKeyEventHandled( | 792 InputImeEventRouter::GetInstance()->OnKeyEventHandled( |
| 821 extension_id(), params->request_id, params->response); | 793 extension_id(), params->request_id, params->response); |
| 822 return true; | 794 return true; |
| 823 } | 795 } |
| 824 | 796 |
| 825 InputImeAPI::InputImeAPI(content::BrowserContext* context) | 797 InputImeAPI::InputImeAPI(content::BrowserContext* context) |
| 826 : browser_context_(context), extension_registry_observer_(this) { | 798 : browser_context_(context), extension_registry_observer_(this) { |
| 827 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); | 799 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); |
| 828 | 800 |
| 829 EventRouter* event_router = EventRouter::Get(browser_context_); | 801 EventRouter* event_router = EventRouter::Get(browser_context_); |
| 830 event_router->RegisterObserver(this, input_ime::OnActivate::kEventName); | |
| 831 event_router->RegisterObserver(this, input_ime::OnFocus::kEventName); | 802 event_router->RegisterObserver(this, input_ime::OnFocus::kEventName); |
| 832 } | 803 } |
| 833 | 804 |
| 834 InputImeAPI::~InputImeAPI() { | 805 InputImeAPI::~InputImeAPI() { |
| 835 EventRouter::Get(browser_context_)->UnregisterObserver(this); | 806 EventRouter::Get(browser_context_)->UnregisterObserver(this); |
| 836 } | 807 } |
| 837 | 808 |
| 838 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> > | 809 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> > |
| 839 g_factory = LAZY_INSTANCE_INITIALIZER; | 810 g_factory = LAZY_INSTANCE_INITIALIZER; |
| 840 | 811 |
| 841 // static | 812 // static |
| 842 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() { | 813 BrowserContextKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() { |
| 843 return g_factory.Pointer(); | 814 return g_factory.Pointer(); |
| 844 } | 815 } |
| 845 | 816 |
| 846 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context, | 817 void InputImeAPI::OnExtensionLoaded(content::BrowserContext* browser_context, |
| 847 const Extension* extension) { | 818 const Extension* extension) { |
| 848 const std::vector<InputComponentInfo>* input_components = | 819 const std::vector<InputComponentInfo>* input_components = |
| 849 extensions::InputComponents::GetInputComponents(extension); | 820 extensions::InputComponents::GetInputComponents(extension); |
| 850 if (!input_components) | 821 if (input_components) |
| 851 return; | 822 input_ime_event_router()->RegisterImeExtension( |
| 852 for (std::vector<extensions::InputComponentInfo>::const_iterator component = | 823 extension->id(), *input_components); |
| 853 input_components->begin(); | |
| 854 component != input_components->end(); | |
| 855 ++component) { | |
| 856 if (component->type == extensions::INPUT_COMPONENT_TYPE_IME) { | |
| 857 // Don't pass profile_ to register ime, instead always use | |
| 858 // GetActiveUserProfile. It is because: | |
| 859 // The original profile for login screen is called signin profile. | |
| 860 // And the active profile is the incognito profile based on signin | |
| 861 // profile. 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 input_ime_event_router()->RegisterIme(extension->id(), *component); | |
| 865 } | |
| 866 } | |
| 867 } | 824 } |
| 868 | 825 |
| 869 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context, | 826 void InputImeAPI::OnExtensionUnloaded(content::BrowserContext* browser_context, |
| 870 const Extension* extension, | 827 const Extension* extension, |
| 871 UnloadedExtensionInfo::Reason reason) { | 828 UnloadedExtensionInfo::Reason reason) { |
| 872 const std::vector<InputComponentInfo>* input_components = | 829 const std::vector<InputComponentInfo>* input_components = |
| 873 extensions::InputComponents::GetInputComponents(extension); | 830 extensions::InputComponents::GetInputComponents(extension); |
| 874 if (!input_components) | 831 if (!input_components) |
| 875 return; | 832 return; |
| 876 if (input_components->size() > 0) | 833 if (input_components->size() > 0) |
| 877 input_ime_event_router()->UnregisterAllImes(extension->id()); | 834 input_ime_event_router()->UnregisterAllImes(extension->id()); |
| 878 } | 835 } |
| 879 | 836 |
| 880 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) { | 837 void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) { |
| 881 InputMethodEngineInterface* engine = | 838 InputMethodEngineInterface* engine = |
| 882 input_ime_event_router()->GetActiveEngine(details.extension_id); | 839 input_ime_event_router()->GetActiveEngine(details.extension_id); |
| 840 // Notifies the IME extension for IME ready with onActivate/onFocus events. | |
| 883 if (engine) | 841 if (engine) |
| 884 engine->NotifyImeReady(); | 842 engine->Enable(engine->GetActiveEngineId()); |
| 885 } | 843 } |
| 886 | 844 |
| 887 InputImeEventRouter* InputImeAPI::input_ime_event_router() { | 845 InputImeEventRouter* InputImeAPI::input_ime_event_router() { |
| 888 return InputImeEventRouter::GetInstance(); | 846 return InputImeEventRouter::GetInstance(); |
| 889 } | 847 } |
| 890 | 848 |
| 891 } // namespace extensions | 849 } // namespace extensions |
| OLD | NEW |