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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h" 6 7 #include "base/strings/string_number_conversions.h" 8 #include "base/values.h" 9 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/chromeos/input_method/input_method_engine.h" 11 #include "chrome/browser/extensions/extension_function_registry.h" 12 #include "chrome/browser/extensions/extension_system.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/common/extensions/api/input_ime.h" 15 #include "chrome/common/extensions/api/input_ime/input_components_handler.h" 16 #include "content/public/browser/notification_details.h" 17 #include "content/public/browser/notification_source.h" 18 #include "extensions/browser/event_router.h" 19 20 namespace input_ime = extensions::api::input_ime; 21 namespace KeyEventHandled = extensions::api::input_ime::KeyEventHandled; 22 namespace DeleteSurroundingText = 23 extensions::api::input_ime::DeleteSurroundingText; 24 namespace UpdateMenuItems = extensions::api::input_ime::UpdateMenuItems; 25 namespace SendKeyEvents = extensions::api::input_ime::SendKeyEvents; 26 namespace SetMenuItems = extensions::api::input_ime::SetMenuItems; 27 namespace SetCursorPosition = extensions::api::input_ime::SetCursorPosition; 28 namespace SetCandidates = extensions::api::input_ime::SetCandidates; 29 namespace SetCandidateWindowProperties = 30 extensions::api::input_ime::SetCandidateWindowProperties; 31 namespace CommitText = extensions::api::input_ime::CommitText; 32 namespace ClearComposition = extensions::api::input_ime::ClearComposition; 33 namespace SetComposition = extensions::api::input_ime::SetComposition; 34 using chromeos::InputMethodEngineInterface; 35 36 namespace { 37 38 const char kErrorEngineNotAvailable[] = "Engine is not available"; 39 const char kErrorSetMenuItemsFail[] = "Could not create menu Items"; 40 const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items"; 41 42 void SetMenuItemToMenu(const input_ime::MenuItem& input, 43 InputMethodEngineInterface::MenuItem* out) { 44 out->modified = 0; 45 out->id = input.id; 46 if (input.label) { 47 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_LABEL; 48 out->label = *input.label; 49 } 50 51 if (input.style != input_ime::MenuItem::STYLE_NONE) { 52 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_STYLE; 53 out->style = static_cast<InputMethodEngineInterface::MenuItemStyle>( 54 input.style); 55 } 56 57 if (input.visible) 58 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_VISIBLE; 59 out->visible = input.visible ? *input.visible : true; 60 61 if (input.checked) 62 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_CHECKED; 63 out->checked = input.checked ? *input.checked : false; 64 65 if (input.enabled) 66 out->modified |= InputMethodEngineInterface::MENU_ITEM_MODIFIED_ENABLED; 67 out->enabled = input.enabled ? *input.enabled : true; 68 } 69 70 static void DispatchEventToExtension(Profile* profile, 71 const std::string& extension_id, 72 const std::string& event_name, 73 scoped_ptr<base::ListValue> args) { 74 scoped_ptr<extensions::Event> event(new extensions::Event( 75 event_name, args.Pass())); 76 event->restrict_to_browser_context = profile; 77 extensions::ExtensionSystem::Get(profile)->event_router()-> 78 DispatchEventToExtension(extension_id, event.Pass()); 79 } 80 81 } // namespace 82 83 namespace chromeos { 84 class ImeObserver : public InputMethodEngineInterface::Observer { 85 public: 86 ImeObserver(Profile* profile, const std::string& extension_id, 87 const std::string& engine_id) : 88 profile_(profile), 89 extension_id_(extension_id), 90 engine_id_(engine_id) { 91 } 92 93 virtual ~ImeObserver() {} 94 95 virtual void OnActivate(const std::string& engine_id) OVERRIDE { 96 if (profile_ == NULL || extension_id_.empty()) 97 return; 98 99 scoped_ptr<base::ListValue> args(input_ime::OnActivate::Create(engine_id)); 100 101 DispatchEventToExtension(profile_, extension_id_, 102 input_ime::OnActivate::kEventName, args.Pass()); 103 } 104 105 virtual void OnDeactivated(const std::string& engine_id) OVERRIDE { 106 if (profile_ == NULL || extension_id_.empty()) 107 return; 108 109 scoped_ptr<base::ListValue> args( 110 input_ime::OnDeactivated::Create(engine_id)); 111 112 DispatchEventToExtension(profile_, extension_id_, 113 input_ime::OnDeactivated::kEventName, args.Pass()); 114 } 115 116 virtual void OnFocus( 117 const InputMethodEngineInterface::InputContext& context) OVERRIDE { 118 if (profile_ == NULL || extension_id_.empty()) 119 return; 120 121 input_ime::InputContext context_value; 122 context_value.context_id = context.id; 123 context_value.type = input_ime::InputContext::ParseType(context.type); 124 125 scoped_ptr<base::ListValue> args(input_ime::OnFocus::Create(context_value)); 126 127 DispatchEventToExtension(profile_, extension_id_, 128 input_ime::OnFocus::kEventName, args.Pass()); 129 } 130 131 virtual void OnBlur(int context_id) OVERRIDE { 132 if (profile_ == NULL || extension_id_.empty()) 133 return; 134 135 scoped_ptr<base::ListValue> args(input_ime::OnBlur::Create(context_id)); 136 137 DispatchEventToExtension(profile_, extension_id_, 138 input_ime::OnBlur::kEventName, args.Pass()); 139 } 140 141 virtual void OnInputContextUpdate( 142 const InputMethodEngineInterface::InputContext& context) OVERRIDE { 143 if (profile_ == NULL || extension_id_.empty()) 144 return; 145 146 input_ime::InputContext context_value; 147 context_value.context_id = context.id; 148 context_value.type = input_ime::InputContext::ParseType(context.type); 149 150 scoped_ptr<base::ListValue> args( 151 input_ime::OnInputContextUpdate::Create(context_value)); 152 153 DispatchEventToExtension(profile_, 154 extension_id_, 155 input_ime::OnInputContextUpdate::kEventName, 156 args.Pass()); 157 } 158 159 virtual void OnKeyEvent( 160 const std::string& engine_id, 161 const InputMethodEngineInterface::KeyboardEvent& event, 162 chromeos::input_method::KeyEventHandle* key_data) OVERRIDE { 163 if (profile_ == NULL || extension_id_.empty()) 164 return; 165 166 std::string request_id = 167 extensions::InputImeEventRouter::GetInstance()->AddRequest(engine_id, 168 key_data); 169 170 input_ime::KeyboardEvent key_data_value; 171 key_data_value.type = input_ime::KeyboardEvent::ParseType(event.type); 172 key_data_value.request_id = request_id; 173 key_data_value.key = event.key; 174 key_data_value.code = event.code; 175 key_data_value.alt_key.reset(new bool(event.alt_key)); 176 key_data_value.ctrl_key.reset(new bool(event.ctrl_key)); 177 key_data_value.shift_key.reset(new bool(event.shift_key)); 178 key_data_value.caps_lock.reset(new bool(event.caps_lock)); 179 180 scoped_ptr<base::ListValue> args( 181 input_ime::OnKeyEvent::Create(engine_id, key_data_value)); 182 183 DispatchEventToExtension(profile_, extension_id_, 184 input_ime::OnKeyEvent::kEventName, args.Pass()); 185 } 186 187 virtual void OnCandidateClicked( 188 const std::string& engine_id, 189 int candidate_id, 190 InputMethodEngineInterface::MouseButtonEvent button) OVERRIDE { 191 if (profile_ == NULL || extension_id_.empty()) 192 return; 193 194 input_ime::OnCandidateClicked::Button button_enum = 195 input_ime::OnCandidateClicked::BUTTON_NONE; 196 switch (button) { 197 case InputMethodEngineInterface::MOUSE_BUTTON_MIDDLE: 198 button_enum = input_ime::OnCandidateClicked::BUTTON_MIDDLE; 199 break; 200 201 case InputMethodEngineInterface::MOUSE_BUTTON_RIGHT: 202 button_enum = input_ime::OnCandidateClicked::BUTTON_RIGHT; 203 break; 204 205 case InputMethodEngineInterface::MOUSE_BUTTON_LEFT: 206 // Default to left. 207 default: 208 button_enum = input_ime::OnCandidateClicked::BUTTON_LEFT; 209 break; 210 } 211 212 scoped_ptr<base::ListValue> args( 213 input_ime::OnCandidateClicked::Create(engine_id, 214 candidate_id, 215 button_enum)); 216 217 DispatchEventToExtension(profile_, 218 extension_id_, 219 input_ime::OnCandidateClicked::kEventName, 220 args.Pass()); 221 } 222 223 virtual void OnMenuItemActivated(const std::string& engine_id, 224 const std::string& menu_id) OVERRIDE { 225 if (profile_ == NULL || extension_id_.empty()) 226 return; 227 228 scoped_ptr<base::ListValue> args( 229 input_ime::OnMenuItemActivated::Create(engine_id, menu_id)); 230 231 DispatchEventToExtension(profile_, 232 extension_id_, 233 input_ime::OnMenuItemActivated::kEventName, 234 args.Pass()); 235 } 236 237 virtual void OnSurroundingTextChanged(const std::string& engine_id, 238 const std::string& text, 239 int cursor_pos, 240 int anchor_pos) OVERRIDE { 241 if (profile_ == NULL || extension_id_.empty()) 242 return; 243 244 input_ime::OnSurroundingTextChanged::SurroundingInfo info; 245 info.text = text; 246 info.focus = cursor_pos; 247 info.anchor = anchor_pos; 248 scoped_ptr<base::ListValue> args( 249 input_ime::OnSurroundingTextChanged::Create(engine_id, info)); 250 251 DispatchEventToExtension(profile_, 252 extension_id_, 253 input_ime::OnSurroundingTextChanged::kEventName, 254 args.Pass()); 255 } 256 257 virtual void OnReset(const std::string& engine_id) OVERRIDE { 258 if (profile_ == NULL || extension_id_.empty()) 259 return; 260 261 scoped_ptr<base::ListValue> args(input_ime::OnReset::Create(engine_id)); 262 263 DispatchEventToExtension(profile_, 264 extension_id_, 265 input_ime::OnReset::kEventName, 266 args.Pass()); 267 } 268 269 private: 270 Profile* profile_; 271 std::string extension_id_; 272 std::string engine_id_; 273 274 DISALLOW_COPY_AND_ASSIGN(ImeObserver); 275 }; 276 277 } // namespace chromeos 278 279 namespace extensions { 280 281 InputImeEventRouter* 282 InputImeEventRouter::GetInstance() { 283 return Singleton<InputImeEventRouter>::get(); 284 } 285 286 #if defined(OS_CHROMEOS) 287 bool InputImeEventRouter::RegisterIme( 288 Profile* profile, 289 const std::string& extension_id, 290 const extensions::InputComponentInfo& component) { 291 VLOG(1) << "RegisterIme: " << extension_id << " id: " << component.id; 292 293 std::map<std::string, InputMethodEngineInterface*>& engine_map = 294 engines_[extension_id]; 295 296 std::map<std::string, InputMethodEngineInterface*>::iterator engine_ix = 297 engine_map.find(component.id); 298 if (engine_ix != engine_map.end()) 299 return false; 300 301 chromeos::ImeObserver* observer = new chromeos::ImeObserver(profile, 302 extension_id, 303 component.id); 304 std::vector<std::string> layouts; 305 layouts.assign(component.layouts.begin(), component.layouts.end()); 306 307 std::vector<std::string> languages; 308 languages.assign(component.languages.begin(), component.languages.end()); 309 310 chromeos::InputMethodEngine* engine = new chromeos::InputMethodEngine(); 311 engine->Initialize(observer, component.name.c_str(), extension_id.c_str(), 312 component.id.c_str(), languages, layouts, 313 component.options_page_url, component.input_view_url); 314 engine_map[component.id] = engine; 315 316 std::map<std::string, chromeos::ImeObserver*>& observer_list = 317 observers_[extension_id]; 318 319 observer_list[component.id] = observer; 320 321 return true; 322 } 323 324 void InputImeEventRouter::UnregisterAllImes( 325 Profile* profile, const std::string& extension_id) { 326 std::map<std::string, 327 std::map<std::string, 328 InputMethodEngineInterface*> >::iterator engine_map = 329 engines_.find(extension_id); 330 if (engine_map != engines_.end()) { 331 STLDeleteContainerPairSecondPointers(engine_map->second.begin(), 332 engine_map->second.end()); 333 engines_.erase(engine_map); 334 } 335 336 std::map<std::string, 337 std::map<std::string, 338 chromeos::ImeObserver*> >::iterator observer_list = 339 observers_.find(extension_id); 340 if (observer_list != observers_.end()) { 341 STLDeleteContainerPairSecondPointers(observer_list->second.begin(), 342 observer_list->second.end()); 343 observers_.erase(observer_list); 344 } 345 } 346 #endif 347 348 InputMethodEngineInterface* InputImeEventRouter::GetEngine( 349 const std::string& extension_id, const std::string& engine_id) { 350 std::map<std::string, 351 std::map<std::string, InputMethodEngineInterface*> >::const_iterator 352 engine_list = engines_.find(extension_id); 353 if (engine_list != engines_.end()) { 354 std::map<std::string, InputMethodEngineInterface*>::const_iterator 355 engine_ix = engine_list->second.find(engine_id); 356 if (engine_ix != engine_list->second.end()) 357 return engine_ix->second; 358 } 359 return NULL; 360 } 361 362 InputMethodEngineInterface* InputImeEventRouter::GetActiveEngine( 363 const std::string& extension_id) { 364 std::map<std::string, 365 std::map<std::string, InputMethodEngineInterface*> >::const_iterator 366 engine_list = engines_.find(extension_id); 367 if (engine_list != engines_.end()) { 368 std::map<std::string, InputMethodEngineInterface*>::const_iterator 369 engine_ix; 370 for (engine_ix = engine_list->second.begin(); 371 engine_ix != engine_list->second.end(); 372 ++engine_ix) { 373 if (engine_ix->second->IsActive()) 374 return engine_ix->second; 375 } 376 } 377 return NULL; 378 } 379 380 void InputImeEventRouter::OnKeyEventHandled( 381 const std::string& extension_id, 382 const std::string& request_id, 383 bool handled) { 384 RequestMap::iterator request = request_map_.find(request_id); 385 if (request == request_map_.end()) { 386 LOG(ERROR) << "Request ID not found: " << request_id; 387 return; 388 } 389 390 std::string engine_id = request->second.first; 391 chromeos::input_method::KeyEventHandle* key_data = request->second.second; 392 request_map_.erase(request); 393 394 InputMethodEngineInterface* engine = GetEngine(extension_id, engine_id); 395 if (!engine) { 396 LOG(ERROR) << "Engine does not exist: " << engine_id; 397 return; 398 } 399 400 engine->KeyEventDone(key_data, handled); 401 } 402 403 std::string InputImeEventRouter::AddRequest( 404 const std::string& engine_id, 405 chromeos::input_method::KeyEventHandle* key_data) { 406 std::string request_id = base::IntToString(next_request_id_); 407 ++next_request_id_; 408 409 request_map_[request_id] = std::make_pair(engine_id, key_data); 410 411 return request_id; 412 } 413 414 InputImeEventRouter::InputImeEventRouter() 415 : next_request_id_(1) { 416 } 417 418 InputImeEventRouter::~InputImeEventRouter() {} 419 420 bool InputImeSetCompositionFunction::RunImpl() { 421 InputMethodEngineInterface* engine = 422 InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id()); 423 if (!engine) { 424 SetResult(new base::FundamentalValue(false)); 425 return true; 426 } 427 428 scoped_ptr<SetComposition::Params> parent_params( 429 SetComposition::Params::Create(*args_)); 430 const SetComposition::Params::Parameters& params = parent_params->parameters; 431 std::vector<InputMethodEngineInterface::SegmentInfo> segments; 432 if (params.segments) { 433 const std::vector<linked_ptr< 434 SetComposition::Params::Parameters::SegmentsType> >& 435 segments_args = *params.segments; 436 for (size_t i = 0; i < segments_args.size(); ++i) { 437 EXTENSION_FUNCTION_VALIDATE( 438 segments_args[i]->style != 439 SetComposition::Params::Parameters::SegmentsType::STYLE_NONE); 440 segments.push_back(InputMethodEngineInterface::SegmentInfo()); 441 segments.back().start = segments_args[i]->start; 442 segments.back().end = segments_args[i]->end; 443 if (segments_args[i]->style == 444 SetComposition::Params::Parameters::SegmentsType::STYLE_UNDERLINE) { 445 segments.back().style = 446 InputMethodEngineInterface::SEGMENT_STYLE_UNDERLINE; 447 } else { 448 segments.back().style = 449 InputMethodEngineInterface::SEGMENT_STYLE_DOUBLE_UNDERLINE; 450 } 451 } 452 } 453 454 int selection_start = 455 params.selection_start ? *params.selection_start : params.cursor; 456 int selection_end = 457 params.selection_end ? *params.selection_end : params.cursor; 458 459 SetResult(new base::FundamentalValue( 460 engine->SetComposition(params.context_id, params.text.c_str(), 461 selection_start, selection_end, params.cursor, 462 segments, &error_))); 463 return true; 464 } 465 466 bool InputImeClearCompositionFunction::RunImpl() { 467 InputMethodEngineInterface* engine = 468 InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id()); 469 if (!engine) { 470 SetResult(new base::FundamentalValue(false)); 471 return true; 472 } 473 474 scoped_ptr<ClearComposition::Params> parent_params( 475 ClearComposition::Params::Create(*args_)); 476 const ClearComposition::Params::Parameters& params = 477 parent_params->parameters; 478 479 SetResult(new base::FundamentalValue( 480 engine->ClearComposition(params.context_id, &error_))); 481 return true; 482 } 483 484 bool InputImeCommitTextFunction::RunImpl() { 485 // TODO(zork): Support committing when not active. 486 InputMethodEngineInterface* engine = 487 InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id()); 488 if (!engine) { 489 SetResult(new base::FundamentalValue(false)); 490 return true; 491 } 492 493 scoped_ptr<CommitText::Params> parent_params( 494 CommitText::Params::Create(*args_)); 495 const CommitText::Params::Parameters& params = 496 parent_params->parameters; 497 498 SetResult(new base::FundamentalValue( 499 engine->CommitText(params.context_id, params.text.c_str(), &error_))); 500 return true; 501 } 502 503 bool InputImeSendKeyEventsFunction::RunImpl() { 504 // TODO(komatsu): Implement here. 505 return true; 506 } 507 508 bool InputImeSetCandidateWindowPropertiesFunction::RunImpl() { 509 scoped_ptr<SetCandidateWindowProperties::Params> parent_params( 510 SetCandidateWindowProperties::Params::Create(*args_)); 511 const SetCandidateWindowProperties::Params::Parameters& 512 params = parent_params->parameters; 513 514 InputMethodEngineInterface* engine = 515 InputImeEventRouter::GetInstance()->GetEngine(extension_id(), 516 params.engine_id); 517 518 if (!engine) { 519 SetResult(new base::FundamentalValue(false)); 520 return true; 521 } 522 523 const SetCandidateWindowProperties::Params::Parameters::Properties& 524 properties = params.properties; 525 526 if (properties.visible && 527 !engine->SetCandidateWindowVisible(*properties.visible, &error_)) { 528 SetResult(new base::FundamentalValue(false)); 529 return true; 530 } 531 532 InputMethodEngineInterface::CandidateWindowProperty properties_out = 533 engine->GetCandidateWindowProperty(); 534 bool modified = false; 535 536 if (properties.cursor_visible) { 537 properties_out.is_cursor_visible = *properties.cursor_visible; 538 modified = true; 539 } 540 541 if (properties.vertical) { 542 properties_out.is_vertical = *properties.vertical; 543 modified = true; 544 } 545 546 if (properties.page_size) { 547 properties_out.page_size = *properties.page_size; 548 modified = true; 549 } 550 551 if (properties.window_position == 552 SetCandidateWindowProperties::Params::Parameters::Properties:: 553 WINDOW_POSITION_COMPOSITION) { 554 properties_out.show_window_at_composition = true; 555 modified = true; 556 } else if (properties.window_position == 557 SetCandidateWindowProperties::Params::Parameters::Properties:: 558 WINDOW_POSITION_CURSOR) { 559 properties_out.show_window_at_composition = false; 560 modified = true; 561 } 562 563 if (modified) { 564 engine->SetCandidateWindowProperty(properties_out); 565 } 566 567 if (properties.auxiliary_text) 568 engine->SetCandidateWindowAuxText(properties.auxiliary_text->c_str()); 569 570 if (properties.auxiliary_text_visible) { 571 engine->SetCandidateWindowAuxTextVisible( 572 *properties.auxiliary_text_visible); 573 } 574 575 SetResult(new base::FundamentalValue(true)); 576 577 return true; 578 } 579 580 #if defined(OS_CHROMEOS) 581 bool InputImeSetCandidatesFunction::RunImpl() { 582 InputMethodEngineInterface* engine = 583 InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id()); 584 if (!engine) { 585 SetResult(new base::FundamentalValue(false)); 586 return true; 587 } 588 589 scoped_ptr<SetCandidates::Params> parent_params( 590 SetCandidates::Params::Create(*args_)); 591 const SetCandidates::Params::Parameters& params = 592 parent_params->parameters; 593 594 std::vector<InputMethodEngineInterface::Candidate> candidates_out; 595 const std::vector<linked_ptr< 596 SetCandidates::Params::Parameters::CandidatesType> >& candidates_in = 597 params.candidates; 598 for (size_t i = 0; i < candidates_in.size(); ++i) { 599 candidates_out.push_back(InputMethodEngineInterface::Candidate()); 600 candidates_out.back().value = candidates_in[i]->candidate; 601 candidates_out.back().id = candidates_in[i]->id; 602 if (candidates_in[i]->label) 603 candidates_out.back().label = *candidates_in[i]->label; 604 if (candidates_in[i]->annotation) 605 candidates_out.back().annotation = *candidates_in[i]->annotation; 606 if (candidates_in[i]->usage) { 607 candidates_out.back().usage.title = candidates_in[i]->usage->title; 608 candidates_out.back().usage.body = candidates_in[i]->usage->body; 609 } 610 } 611 612 SetResult(new base::FundamentalValue( 613 engine->SetCandidates(params.context_id, candidates_out, &error_))); 614 return true; 615 } 616 617 bool InputImeSetCursorPositionFunction::RunImpl() { 618 InputMethodEngineInterface* engine = 619 InputImeEventRouter::GetInstance()->GetActiveEngine(extension_id()); 620 if (!engine) { 621 SetResult(new base::FundamentalValue(false)); 622 return true; 623 } 624 625 scoped_ptr<SetCursorPosition::Params> parent_params( 626 SetCursorPosition::Params::Create(*args_)); 627 const SetCursorPosition::Params::Parameters& params = 628 parent_params->parameters; 629 630 SetResult(new base::FundamentalValue( 631 engine->SetCursorPosition(params.context_id, params.candidate_id, 632 &error_))); 633 return true; 634 } 635 636 bool InputImeSetMenuItemsFunction::RunImpl() { 637 scoped_ptr<SetMenuItems::Params> parent_params( 638 SetMenuItems::Params::Create(*args_)); 639 const SetMenuItems::Params::Parameters& params = 640 parent_params->parameters; 641 642 InputMethodEngineInterface* engine = 643 InputImeEventRouter::GetInstance()->GetEngine(extension_id(), 644 params.engine_id); 645 if (!engine) { 646 error_ = kErrorEngineNotAvailable; 647 return false; 648 } 649 650 const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items; 651 std::vector<InputMethodEngineInterface::MenuItem> items_out; 652 653 for (size_t i = 0; i < items.size(); ++i) { 654 items_out.push_back(InputMethodEngineInterface::MenuItem()); 655 SetMenuItemToMenu(*items[i], &items_out.back()); 656 } 657 658 if (!engine->SetMenuItems(items_out)) 659 error_ = kErrorSetMenuItemsFail; 660 return true; 661 } 662 663 bool InputImeUpdateMenuItemsFunction::RunImpl() { 664 scoped_ptr<UpdateMenuItems::Params> parent_params( 665 UpdateMenuItems::Params::Create(*args_)); 666 const UpdateMenuItems::Params::Parameters& params = 667 parent_params->parameters; 668 669 InputMethodEngineInterface* engine = 670 InputImeEventRouter::GetInstance()->GetEngine(extension_id(), 671 params.engine_id); 672 if (!engine) { 673 error_ = kErrorEngineNotAvailable; 674 return false; 675 } 676 677 const std::vector<linked_ptr<input_ime::MenuItem> >& items = params.items; 678 std::vector<InputMethodEngineInterface::MenuItem> items_out; 679 680 for (size_t i = 0; i < items.size(); ++i) { 681 items_out.push_back(InputMethodEngineInterface::MenuItem()); 682 SetMenuItemToMenu(*items[i], &items_out.back()); 683 } 684 685 if (!engine->UpdateMenuItems(items_out)) 686 error_ = kErrorUpdateMenuItemsFail; 687 return true; 688 } 689 690 bool InputImeDeleteSurroundingTextFunction::RunImpl() { 691 scoped_ptr<DeleteSurroundingText::Params> parent_params( 692 DeleteSurroundingText::Params::Create(*args_)); 693 const DeleteSurroundingText::Params::Parameters& params = 694 parent_params->parameters; 695 696 InputMethodEngineInterface* engine = 697 InputImeEventRouter::GetInstance()->GetEngine(extension_id(), 698 params.engine_id); 699 if (!engine) { 700 error_ = kErrorEngineNotAvailable; 701 return false; 702 } 703 704 engine->DeleteSurroundingText(params.context_id, params.offset, params.length, 705 &error_); 706 return true; 707 } 708 709 bool InputImeKeyEventHandledFunction::RunImpl() { 710 scoped_ptr<KeyEventHandled::Params> params( 711 KeyEventHandled::Params::Create(*args_)); 712 InputImeEventRouter::GetInstance()->OnKeyEventHandled( 713 extension_id(), params->request_id, params->response); 714 return true; 715 } 716 #endif 717 718 InputImeAPI::InputImeAPI(Profile* profile) 719 : profile_(profile) { 720 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 721 content::Source<Profile>(profile)); 722 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 723 content::Source<Profile>(profile)); 724 } 725 726 InputImeAPI::~InputImeAPI() { 727 } 728 729 static base::LazyInstance<ProfileKeyedAPIFactory<InputImeAPI> > 730 g_factory = LAZY_INSTANCE_INITIALIZER; 731 732 // static 733 ProfileKeyedAPIFactory<InputImeAPI>* InputImeAPI::GetFactoryInstance() { 734 return &g_factory.Get(); 735 } 736 737 void InputImeAPI::Observe(int type, 738 const content::NotificationSource& source, 739 const content::NotificationDetails& details) { 740 if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { 741 const Extension* extension = 742 content::Details<const Extension>(details).ptr(); 743 const std::vector<InputComponentInfo>* input_components = 744 extensions::InputComponents::GetInputComponents(extension); 745 if (!input_components) 746 return; 747 for (std::vector<extensions::InputComponentInfo>::const_iterator component = 748 input_components->begin(); component != input_components->end(); 749 ++component) { 750 if (component->type == extensions::INPUT_COMPONENT_TYPE_IME) { 751 input_ime_event_router()->RegisterIme( 752 profile_, extension->id(), *component); 753 } 754 } 755 } else if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { 756 const Extension* extension = 757 content::Details<const UnloadedExtensionInfo>(details)->extension; 758 const std::vector<InputComponentInfo>* input_components = 759 extensions::InputComponents::GetInputComponents(extension); 760 if (!input_components) 761 return; 762 if (input_components->size() > 0) 763 input_ime_event_router()->UnregisterAllImes(profile_, extension->id()); 764 } 765 } 766 767 InputImeEventRouter* InputImeAPI::input_ime_event_router() { 768 return InputImeEventRouter::GetInstance(); 769 } 770 771 } // namespace extensions 772