| OLD | NEW |
| (Empty) |
| 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/extension_input_ime_api.h" | |
| 6 | |
| 7 #include "base/json/json_writer.h" | |
| 8 #include "base/stl_util.h" | |
| 9 #include "base/string_number_conversions.h" | |
| 10 #include "base/values.h" | |
| 11 #include "chrome/browser/chromeos/input_method/input_method_engine.h" | |
| 12 #include "chrome/browser/extensions/event_router.h" | |
| 13 #include "chrome/browser/extensions/extension_input_module_constants.h" | |
| 14 #include "chrome/browser/profiles/profile.h" | |
| 15 | |
| 16 namespace keys = extension_input_module_constants; | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 const char kStyleNone[] = "none"; | |
| 21 const char kStyleCheck[] = "check"; | |
| 22 const char kStyleRadio[] = "radio"; | |
| 23 const char kStyleSeparator[] = "separator"; | |
| 24 | |
| 25 const char kErrorEngineNotAvailable[] = "Engine is not available"; | |
| 26 const char kErrorBadCandidateList[] = "Invalid candidate list provided"; | |
| 27 const char kErrorSetMenuItemsFail[] = "Could not create menu Items"; | |
| 28 const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items"; | |
| 29 | |
| 30 bool ReadMenuItems( | |
| 31 ListValue* menu_items, | |
| 32 std::vector<chromeos::InputMethodEngine::MenuItem>* output) { | |
| 33 for (size_t i = 0; i < menu_items->GetSize(); ++i) { | |
| 34 DictionaryValue* item_dict; | |
| 35 if (!menu_items->GetDictionary(i, &item_dict)) { | |
| 36 return false; | |
| 37 } | |
| 38 | |
| 39 std::string id; | |
| 40 std::string label; | |
| 41 chromeos::InputMethodEngine::MenuItemStyle style = | |
| 42 chromeos::InputMethodEngine::MENU_ITEM_STYLE_NONE; | |
| 43 bool visible = true; | |
| 44 bool enabled = true; | |
| 45 bool checked = false; | |
| 46 std::string icon; | |
| 47 chromeos::InputMethodEngine::KeyboardEvent shortcut_key; | |
| 48 | |
| 49 unsigned int modified = 0; | |
| 50 | |
| 51 if (!item_dict->GetString(keys::kIdKey, &id)) { | |
| 52 return false; | |
| 53 } | |
| 54 | |
| 55 if (item_dict->HasKey(keys::kLabelKey)) { | |
| 56 if (!item_dict->GetString(keys::kLabelKey, &label)) { | |
| 57 return false; | |
| 58 } | |
| 59 modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_LABEL; | |
| 60 } | |
| 61 if (item_dict->HasKey(keys::kStyleKey)) { | |
| 62 std::string style_string; | |
| 63 if (!item_dict->GetString(keys::kStyleKey, &style_string)) { | |
| 64 return false; | |
| 65 } | |
| 66 | |
| 67 if (style_string == kStyleNone) { | |
| 68 style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_NONE; | |
| 69 } else if (style_string == kStyleCheck) { | |
| 70 style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_CHECK; | |
| 71 } else if (style_string == kStyleRadio) { | |
| 72 style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_RADIO; | |
| 73 } else if (style_string == kStyleSeparator) { | |
| 74 style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_SEPARATOR; | |
| 75 } else { | |
| 76 return false; | |
| 77 } | |
| 78 modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_STYLE; | |
| 79 } | |
| 80 | |
| 81 if (item_dict->HasKey(keys::kVisibleKey)) { | |
| 82 if (!item_dict->GetBoolean(keys::kVisibleKey, &visible)) { | |
| 83 return false; | |
| 84 } | |
| 85 modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_VISIBLE; | |
| 86 } | |
| 87 | |
| 88 if (item_dict->HasKey(keys::kCheckedKey)) { | |
| 89 if (!item_dict->GetBoolean(keys::kCheckedKey, &checked)) { | |
| 90 return false; | |
| 91 } | |
| 92 modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_CHECKED; | |
| 93 } | |
| 94 | |
| 95 if (item_dict->HasKey(keys::kEnabledKey)) { | |
| 96 if (!item_dict->GetBoolean(keys::kEnabledKey, &enabled)) { | |
| 97 return false; | |
| 98 } | |
| 99 modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_ENABLED; | |
| 100 } | |
| 101 | |
| 102 output->push_back(chromeos::InputMethodEngine::MenuItem()); | |
| 103 output->back().id = id; | |
| 104 output->back().label = label; | |
| 105 output->back().style = style; | |
| 106 output->back().visible = visible; | |
| 107 output->back().enabled = enabled; | |
| 108 output->back().checked = checked; | |
| 109 | |
| 110 output->back().modified = modified; | |
| 111 | |
| 112 if (item_dict->HasKey(keys::kItemsKey)) { | |
| 113 ListValue* sub_list; | |
| 114 if (!item_dict->GetList(keys::kItemsKey, &sub_list)) { | |
| 115 return false; | |
| 116 } | |
| 117 | |
| 118 if (!ReadMenuItems(sub_list, &(output->back().children))) { | |
| 119 return false; | |
| 120 } | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 return true; | |
| 125 } | |
| 126 | |
| 127 } // namespace | |
| 128 | |
| 129 namespace events { | |
| 130 | |
| 131 const char kOnActivate[] = "input.ime.onActivate"; | |
| 132 const char kOnDeactivated[] = "input.ime.onDeactivated"; | |
| 133 const char kOnFocus[] = "input.ime.onFocus"; | |
| 134 const char kOnBlur[] = "input.ime.onBlur"; | |
| 135 const char kOnInputContextUpdate[] = "input.ime.onInputContextUpdate"; | |
| 136 const char kOnKeyEvent[] = "input.ime.onKeyEvent"; | |
| 137 const char kOnCandidateClicked[] = "input.ime.onCandidateClicked"; | |
| 138 const char kOnMenuItemActivated[] = "input.ime.onMenuItemActivated"; | |
| 139 | |
| 140 } // namespace events | |
| 141 | |
| 142 namespace chromeos { | |
| 143 class ImeObserver : public chromeos::InputMethodEngine::Observer { | |
| 144 public: | |
| 145 ImeObserver(Profile* profile, const std::string& extension_id, | |
| 146 const std::string& engine_id) : | |
| 147 profile_(profile), | |
| 148 extension_id_(extension_id), | |
| 149 engine_id_(engine_id) { | |
| 150 } | |
| 151 | |
| 152 virtual ~ImeObserver() {} | |
| 153 | |
| 154 virtual void OnActivate(const std::string& engine_id) { | |
| 155 if (profile_ == NULL || extension_id_.empty()) | |
| 156 return; | |
| 157 | |
| 158 ListValue args; | |
| 159 args.Append(Value::CreateStringValue(engine_id)); | |
| 160 | |
| 161 std::string json_args; | |
| 162 base::JSONWriter::Write(&args, &json_args); | |
| 163 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 164 extension_id_, events::kOnActivate, json_args, profile_, GURL()); | |
| 165 } | |
| 166 | |
| 167 virtual void OnDeactivated(const std::string& engine_id) { | |
| 168 if (profile_ == NULL || extension_id_.empty()) | |
| 169 return; | |
| 170 | |
| 171 ListValue args; | |
| 172 args.Append(Value::CreateStringValue(engine_id)); | |
| 173 | |
| 174 std::string json_args; | |
| 175 base::JSONWriter::Write(&args, &json_args); | |
| 176 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 177 extension_id_, events::kOnDeactivated, json_args, profile_, GURL()); | |
| 178 } | |
| 179 | |
| 180 virtual void OnFocus(const InputMethodEngine::InputContext& context) { | |
| 181 if (profile_ == NULL || extension_id_.empty()) | |
| 182 return; | |
| 183 | |
| 184 DictionaryValue* dict = new DictionaryValue(); | |
| 185 dict->SetInteger("contextID", context.id); | |
| 186 dict->SetString("type", context.type); | |
| 187 | |
| 188 ListValue args; | |
| 189 args.Append(dict); | |
| 190 | |
| 191 std::string json_args; | |
| 192 base::JSONWriter::Write(&args, &json_args); | |
| 193 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 194 extension_id_, events::kOnFocus, json_args, profile_, GURL()); | |
| 195 } | |
| 196 | |
| 197 virtual void OnBlur(int context_id) { | |
| 198 if (profile_ == NULL || extension_id_.empty()) | |
| 199 return; | |
| 200 | |
| 201 ListValue args; | |
| 202 args.Append(Value::CreateIntegerValue(context_id)); | |
| 203 | |
| 204 std::string json_args; | |
| 205 base::JSONWriter::Write(&args, &json_args); | |
| 206 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 207 extension_id_, events::kOnBlur, json_args, profile_, GURL()); | |
| 208 } | |
| 209 | |
| 210 virtual void OnInputContextUpdate( | |
| 211 const InputMethodEngine::InputContext& context) { | |
| 212 if (profile_ == NULL || extension_id_.empty()) | |
| 213 return; | |
| 214 | |
| 215 DictionaryValue* dict = new DictionaryValue(); | |
| 216 dict->SetInteger("contextID", context.id); | |
| 217 dict->SetString("type", context.type); | |
| 218 | |
| 219 ListValue args; | |
| 220 args.Append(dict); | |
| 221 | |
| 222 std::string json_args; | |
| 223 base::JSONWriter::Write(&args, &json_args); | |
| 224 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 225 extension_id_, events::kOnInputContextUpdate, json_args, profile_, | |
| 226 GURL()); | |
| 227 } | |
| 228 | |
| 229 virtual void OnKeyEvent(const std::string& engine_id, | |
| 230 const InputMethodEngine::KeyboardEvent& event, | |
| 231 chromeos::input_method::KeyEventHandle* key_data) { | |
| 232 if (profile_ == NULL || extension_id_.empty()) | |
| 233 return; | |
| 234 | |
| 235 std::string request_id = | |
| 236 ExtensionInputImeEventRouter::GetInstance()->AddRequest(engine_id, | |
| 237 key_data); | |
| 238 | |
| 239 DictionaryValue* dict = new DictionaryValue(); | |
| 240 dict->SetString("type", event.type); | |
| 241 dict->SetString("requestId", request_id); | |
| 242 dict->SetString("key", event.key); | |
| 243 dict->SetBoolean("altKey", event.alt_key); | |
| 244 dict->SetBoolean("ctrlKey", event.ctrl_key); | |
| 245 dict->SetBoolean("shiftKey", event.shift_key); | |
| 246 | |
| 247 ListValue args; | |
| 248 args.Append(Value::CreateStringValue(engine_id)); | |
| 249 args.Append(dict); | |
| 250 | |
| 251 std::string json_args; | |
| 252 base::JSONWriter::Write(&args, &json_args); | |
| 253 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 254 extension_id_, events::kOnKeyEvent, json_args, profile_, GURL()); | |
| 255 } | |
| 256 | |
| 257 virtual void OnCandidateClicked( | |
| 258 const std::string& engine_id, | |
| 259 int candidate_id, | |
| 260 chromeos::InputMethodEngine::MouseButtonEvent button) { | |
| 261 if (profile_ == NULL || extension_id_.empty()) | |
| 262 return; | |
| 263 | |
| 264 ListValue args; | |
| 265 args.Append(Value::CreateStringValue(engine_id)); | |
| 266 args.Append(Value::CreateIntegerValue(candidate_id)); | |
| 267 switch (button) { | |
| 268 case chromeos::InputMethodEngine::MOUSE_BUTTON_MIDDLE: | |
| 269 args.Append(Value::CreateStringValue("middle")); | |
| 270 break; | |
| 271 | |
| 272 case chromeos::InputMethodEngine::MOUSE_BUTTON_RIGHT: | |
| 273 args.Append(Value::CreateStringValue("right")); | |
| 274 break; | |
| 275 | |
| 276 case chromeos::InputMethodEngine::MOUSE_BUTTON_LEFT: | |
| 277 // Default to left. | |
| 278 default: | |
| 279 args.Append(Value::CreateStringValue("left")); | |
| 280 break; | |
| 281 } | |
| 282 | |
| 283 std::string json_args; | |
| 284 base::JSONWriter::Write(&args, &json_args); | |
| 285 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 286 extension_id_, events::kOnCandidateClicked, json_args, profile_, | |
| 287 GURL()); | |
| 288 } | |
| 289 | |
| 290 virtual void OnMenuItemActivated(const std::string& engine_id, | |
| 291 const std::string& menu_id) { | |
| 292 if (profile_ == NULL || extension_id_.empty()) | |
| 293 return; | |
| 294 | |
| 295 ListValue args; | |
| 296 args.Append(Value::CreateStringValue(engine_id)); | |
| 297 args.Append(Value::CreateStringValue(menu_id)); | |
| 298 | |
| 299 std::string json_args; | |
| 300 base::JSONWriter::Write(&args, &json_args); | |
| 301 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 302 extension_id_, events::kOnMenuItemActivated, json_args, profile_, | |
| 303 GURL()); | |
| 304 } | |
| 305 | |
| 306 private: | |
| 307 Profile* profile_; | |
| 308 std::string extension_id_; | |
| 309 std::string engine_id_; | |
| 310 | |
| 311 DISALLOW_COPY_AND_ASSIGN(ImeObserver); | |
| 312 }; | |
| 313 | |
| 314 } // namespace chromeos | |
| 315 | |
| 316 ExtensionInputImeEventRouter* | |
| 317 ExtensionInputImeEventRouter::GetInstance() { | |
| 318 return Singleton<ExtensionInputImeEventRouter>::get(); | |
| 319 } | |
| 320 | |
| 321 void ExtensionInputImeEventRouter::Init() {} | |
| 322 | |
| 323 #if defined(OS_CHROMEOS) | |
| 324 bool ExtensionInputImeEventRouter::RegisterIme( | |
| 325 Profile* profile, | |
| 326 const std::string& extension_id, | |
| 327 const extensions::Extension::InputComponentInfo& component) { | |
| 328 VLOG(1) << "RegisterIme: " << extension_id << " id: " << component.id; | |
| 329 | |
| 330 std::map<std::string, chromeos::InputMethodEngine*>& engine_map = | |
| 331 engines_[extension_id]; | |
| 332 | |
| 333 std::map<std::string, chromeos::InputMethodEngine*>::iterator engine_ix = | |
| 334 engine_map.find(component.id); | |
| 335 if (engine_ix != engine_map.end()) { | |
| 336 return false; | |
| 337 } | |
| 338 | |
| 339 std::string error; | |
| 340 chromeos::ImeObserver* observer = new chromeos::ImeObserver(profile, | |
| 341 extension_id, | |
| 342 component.id); | |
| 343 std::vector<std::string> layouts; | |
| 344 layouts.assign(component.layouts.begin(), component.layouts.end()); | |
| 345 | |
| 346 chromeos::InputMethodEngine* engine = | |
| 347 chromeos::InputMethodEngine::CreateEngine( | |
| 348 observer, component.name.c_str(), extension_id.c_str(), | |
| 349 component.id.c_str(), component.description.c_str(), | |
| 350 component.language.c_str(), layouts, &error); | |
| 351 if (!engine) { | |
| 352 delete observer; | |
| 353 LOG(ERROR) << "RegisterIme: " << error; | |
| 354 return false; | |
| 355 } | |
| 356 | |
| 357 engine_map[component.id] = engine; | |
| 358 | |
| 359 std::map<std::string, chromeos::ImeObserver*>& observer_list = | |
| 360 observers_[extension_id]; | |
| 361 | |
| 362 observer_list[component.id] = observer; | |
| 363 | |
| 364 return true; | |
| 365 } | |
| 366 | |
| 367 void ExtensionInputImeEventRouter::UnregisterAllImes( | |
| 368 Profile* profile, const std::string& extension_id) { | |
| 369 std::map<std::string, | |
| 370 std::map<std::string, | |
| 371 chromeos::InputMethodEngine*> >::iterator engine_map = | |
| 372 engines_.find(extension_id); | |
| 373 if (engine_map != engines_.end()) { | |
| 374 STLDeleteContainerPairSecondPointers(engine_map->second.begin(), | |
| 375 engine_map->second.end()); | |
| 376 engines_.erase(engine_map); | |
| 377 } | |
| 378 | |
| 379 std::map<std::string, | |
| 380 std::map<std::string, | |
| 381 chromeos::ImeObserver*> >::iterator observer_list = | |
| 382 observers_.find(extension_id); | |
| 383 if (observer_list != observers_.end()) { | |
| 384 STLDeleteContainerPairSecondPointers(observer_list->second.begin(), | |
| 385 observer_list->second.end()); | |
| 386 observers_.erase(observer_list); | |
| 387 } | |
| 388 } | |
| 389 #endif | |
| 390 | |
| 391 chromeos::InputMethodEngine* ExtensionInputImeEventRouter::GetEngine( | |
| 392 const std::string& extension_id, const std::string& engine_id) { | |
| 393 std::map<std::string, | |
| 394 std::map<std::string, chromeos::InputMethodEngine*> >::const_iterator | |
| 395 engine_list = engines_.find(extension_id); | |
| 396 if (engine_list != engines_.end()) { | |
| 397 std::map<std::string, chromeos::InputMethodEngine*>::const_iterator | |
| 398 engine_ix = engine_list->second.find(engine_id); | |
| 399 if (engine_ix != engine_list->second.end()) { | |
| 400 return engine_ix->second; | |
| 401 } | |
| 402 } | |
| 403 return NULL; | |
| 404 } | |
| 405 | |
| 406 chromeos::InputMethodEngine* ExtensionInputImeEventRouter::GetActiveEngine( | |
| 407 const std::string& extension_id) { | |
| 408 std::map<std::string, | |
| 409 std::map<std::string, chromeos::InputMethodEngine*> >::const_iterator | |
| 410 engine_list = engines_.find(extension_id); | |
| 411 if (engine_list != engines_.end()) { | |
| 412 std::map<std::string, chromeos::InputMethodEngine*>::const_iterator | |
| 413 engine_ix; | |
| 414 for (engine_ix = engine_list->second.begin(); | |
| 415 engine_ix != engine_list->second.end(); | |
| 416 ++engine_ix) { | |
| 417 if (engine_ix->second->IsActive()) { | |
| 418 return engine_ix->second; | |
| 419 } | |
| 420 } | |
| 421 } | |
| 422 return NULL; | |
| 423 } | |
| 424 | |
| 425 void ExtensionInputImeEventRouter::OnEventHandled( | |
| 426 const std::string& extension_id, | |
| 427 const std::string& request_id, | |
| 428 bool handled) { | |
| 429 RequestMap::iterator request = request_map_.find(request_id); | |
| 430 if (request == request_map_.end()) { | |
| 431 LOG(ERROR) << "Request ID not found: " << request_id; | |
| 432 return; | |
| 433 } | |
| 434 | |
| 435 std::string engine_id = request->second.first; | |
| 436 chromeos::input_method::KeyEventHandle* key_data = request->second.second; | |
| 437 request_map_.erase(request); | |
| 438 | |
| 439 chromeos::InputMethodEngine* engine = GetEngine(extension_id, engine_id); | |
| 440 if (!engine) { | |
| 441 LOG(ERROR) << "Engine does not exist: " << engine_id; | |
| 442 return; | |
| 443 } | |
| 444 | |
| 445 engine->KeyEventDone(key_data, handled); | |
| 446 } | |
| 447 | |
| 448 std::string ExtensionInputImeEventRouter::AddRequest( | |
| 449 const std::string& engine_id, | |
| 450 chromeos::input_method::KeyEventHandle* key_data) { | |
| 451 std::string request_id = base::IntToString(next_request_id_); | |
| 452 ++next_request_id_; | |
| 453 | |
| 454 request_map_[request_id] = std::make_pair(engine_id, key_data); | |
| 455 | |
| 456 return request_id; | |
| 457 } | |
| 458 | |
| 459 ExtensionInputImeEventRouter::ExtensionInputImeEventRouter() | |
| 460 : next_request_id_(1) { | |
| 461 } | |
| 462 | |
| 463 ExtensionInputImeEventRouter::~ExtensionInputImeEventRouter() {} | |
| 464 | |
| 465 bool SetCompositionFunction::RunImpl() { | |
| 466 chromeos::InputMethodEngine* engine = | |
| 467 ExtensionInputImeEventRouter::GetInstance()-> | |
| 468 GetActiveEngine(extension_id()); | |
| 469 if (!engine) { | |
| 470 SetResult(Value::CreateBooleanValue(false)); | |
| 471 return true; | |
| 472 } | |
| 473 | |
| 474 DictionaryValue* args; | |
| 475 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 476 int context_id; | |
| 477 std::string text; | |
| 478 int selection_start; | |
| 479 int selection_end; | |
| 480 int cursor; | |
| 481 std::vector<chromeos::InputMethodEngine::SegmentInfo> segments; | |
| 482 | |
| 483 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kContextIdKey, | |
| 484 &context_id)); | |
| 485 EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kTextKey, &text)); | |
| 486 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kCursorKey, &cursor)); | |
| 487 if (args->HasKey(keys::kSelectionStartKey)) { | |
| 488 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kSelectionStartKey, | |
| 489 &selection_start)); | |
| 490 } else { | |
| 491 selection_start = cursor; | |
| 492 } | |
| 493 if (args->HasKey(keys::kSelectionEndKey)) { | |
| 494 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kSelectionEndKey, | |
| 495 &selection_end)); | |
| 496 } else { | |
| 497 selection_end = cursor; | |
| 498 } | |
| 499 | |
| 500 if (args->HasKey(keys::kSegmentsKey)) { | |
| 501 ListValue* segment_list = NULL; | |
| 502 EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kSegmentsKey, | |
| 503 &segment_list)); | |
| 504 | |
| 505 for (size_t i = 0; i < segment_list->GetSize(); ++i) { | |
| 506 DictionaryValue* segment = NULL; | |
| 507 if (!segment_list->GetDictionary(i, &segment)) | |
| 508 continue; | |
| 509 | |
| 510 int start; | |
| 511 int end; | |
| 512 std::string style; | |
| 513 | |
| 514 EXTENSION_FUNCTION_VALIDATE(segment->GetInteger(keys::kStartKey, | |
| 515 &start)); | |
| 516 EXTENSION_FUNCTION_VALIDATE(segment->GetInteger(keys::kEndKey, &end)); | |
| 517 EXTENSION_FUNCTION_VALIDATE(segment->GetString(keys::kStyleKey, &style)); | |
| 518 | |
| 519 segments.push_back(chromeos::InputMethodEngine::SegmentInfo()); | |
| 520 segments.back().start = start; | |
| 521 segments.back().end = end; | |
| 522 if (style == keys::kStyleUnderline) { | |
| 523 segments.back().style = | |
| 524 chromeos::InputMethodEngine::SEGMENT_STYLE_UNDERLINE; | |
| 525 } else if (style == keys::kStyleDoubleUnderline) { | |
| 526 segments.back().style = | |
| 527 chromeos::InputMethodEngine::SEGMENT_STYLE_DOUBLE_UNDERLINE; | |
| 528 } | |
| 529 } | |
| 530 } | |
| 531 | |
| 532 if (engine->SetComposition(context_id, text.c_str(), selection_start, | |
| 533 selection_end, cursor, segments, &error_)) { | |
| 534 SetResult(Value::CreateBooleanValue(true)); | |
| 535 } else { | |
| 536 SetResult(Value::CreateBooleanValue(false)); | |
| 537 } | |
| 538 return true; | |
| 539 } | |
| 540 | |
| 541 bool ClearCompositionFunction::RunImpl() { | |
| 542 chromeos::InputMethodEngine* engine = | |
| 543 ExtensionInputImeEventRouter::GetInstance()-> | |
| 544 GetActiveEngine(extension_id()); | |
| 545 if (!engine) { | |
| 546 SetResult(Value::CreateBooleanValue(false)); | |
| 547 return true; | |
| 548 } | |
| 549 | |
| 550 DictionaryValue* args; | |
| 551 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 552 int context_id; | |
| 553 | |
| 554 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kContextIdKey, | |
| 555 &context_id)); | |
| 556 | |
| 557 if (engine->ClearComposition(context_id, &error_)) { | |
| 558 SetResult(Value::CreateBooleanValue(true)); | |
| 559 } else { | |
| 560 SetResult(Value::CreateBooleanValue(false)); | |
| 561 } | |
| 562 return true; | |
| 563 } | |
| 564 | |
| 565 bool CommitTextFunction::RunImpl() { | |
| 566 // TODO(zork): Support committing when not active. | |
| 567 chromeos::InputMethodEngine* engine = | |
| 568 ExtensionInputImeEventRouter::GetInstance()-> | |
| 569 GetActiveEngine(extension_id()); | |
| 570 if (!engine) { | |
| 571 SetResult(Value::CreateBooleanValue(false)); | |
| 572 return true; | |
| 573 } | |
| 574 | |
| 575 DictionaryValue* args; | |
| 576 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 577 int context_id; | |
| 578 std::string text; | |
| 579 | |
| 580 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kContextIdKey, | |
| 581 &context_id)); | |
| 582 EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kTextKey, &text)); | |
| 583 | |
| 584 if (engine->CommitText(context_id, text.c_str(), &error_)) { | |
| 585 SetResult(Value::CreateBooleanValue(true)); | |
| 586 } else { | |
| 587 SetResult(Value::CreateBooleanValue(false)); | |
| 588 } | |
| 589 return true; | |
| 590 } | |
| 591 | |
| 592 bool SetCandidateWindowPropertiesFunction::RunImpl() { | |
| 593 DictionaryValue* args; | |
| 594 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 595 | |
| 596 std::string engine_id; | |
| 597 EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kEngineIdKey, &engine_id)); | |
| 598 | |
| 599 chromeos::InputMethodEngine* engine = | |
| 600 ExtensionInputImeEventRouter::GetInstance()->GetEngine(extension_id(), | |
| 601 engine_id); | |
| 602 if (!engine) { | |
| 603 SetResult(Value::CreateBooleanValue(false)); | |
| 604 return true; | |
| 605 } | |
| 606 | |
| 607 DictionaryValue* properties; | |
| 608 EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(keys::kPropertiesKey, | |
| 609 &properties)); | |
| 610 | |
| 611 if (properties->HasKey(keys::kVisibleKey)) { | |
| 612 bool visible; | |
| 613 EXTENSION_FUNCTION_VALIDATE(properties->GetBoolean(keys::kVisibleKey, | |
| 614 &visible)); | |
| 615 if (!engine->SetCandidateWindowVisible(visible, &error_)) { | |
| 616 SetResult(Value::CreateBooleanValue(false)); | |
| 617 return true; | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 if (properties->HasKey(keys::kCursorVisibleKey)) { | |
| 622 bool visible; | |
| 623 EXTENSION_FUNCTION_VALIDATE(properties->GetBoolean(keys::kCursorVisibleKey, | |
| 624 &visible)); | |
| 625 engine->SetCandidateWindowCursorVisible(visible); | |
| 626 } | |
| 627 | |
| 628 if (properties->HasKey(keys::kVerticalKey)) { | |
| 629 bool vertical; | |
| 630 EXTENSION_FUNCTION_VALIDATE(properties->GetBoolean(keys::kVerticalKey, | |
| 631 &vertical)); | |
| 632 engine->SetCandidateWindowVertical(vertical); | |
| 633 } | |
| 634 | |
| 635 if (properties->HasKey(keys::kPageSizeKey)) { | |
| 636 int page_size; | |
| 637 EXTENSION_FUNCTION_VALIDATE(properties->GetInteger(keys::kPageSizeKey, | |
| 638 &page_size)); | |
| 639 engine->SetCandidateWindowPageSize(page_size); | |
| 640 } | |
| 641 | |
| 642 if (properties->HasKey(keys::kAuxiliaryTextKey)) { | |
| 643 std::string aux_text; | |
| 644 EXTENSION_FUNCTION_VALIDATE(properties->GetString(keys::kAuxiliaryTextKey, | |
| 645 &aux_text)); | |
| 646 engine->SetCandidateWindowAuxText(aux_text.c_str()); | |
| 647 } | |
| 648 | |
| 649 if (properties->HasKey(keys::kAuxiliaryTextVisibleKey)) { | |
| 650 bool visible; | |
| 651 EXTENSION_FUNCTION_VALIDATE(properties->GetBoolean( | |
| 652 keys::kAuxiliaryTextVisibleKey, | |
| 653 &visible)); | |
| 654 engine->SetCandidateWindowAuxTextVisible(visible); | |
| 655 } | |
| 656 | |
| 657 SetResult(Value::CreateBooleanValue(true)); | |
| 658 | |
| 659 return true; | |
| 660 } | |
| 661 | |
| 662 #if defined(OS_CHROMEOS) | |
| 663 bool SetCandidatesFunction::ReadCandidates( | |
| 664 ListValue* candidates, | |
| 665 std::vector<chromeos::InputMethodEngine::Candidate>* output) { | |
| 666 for (size_t i = 0; i < candidates->GetSize(); ++i) { | |
| 667 DictionaryValue* candidate_dict; | |
| 668 EXTENSION_FUNCTION_VALIDATE(candidates->GetDictionary(i, &candidate_dict)); | |
| 669 | |
| 670 std::string candidate; | |
| 671 int id; | |
| 672 std::string label; | |
| 673 std::string annotation; | |
| 674 | |
| 675 EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetString(keys::kCandidateKey, | |
| 676 &candidate)); | |
| 677 EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetInteger(keys::kIdKey, &id)); | |
| 678 | |
| 679 if (candidate_dict->HasKey(keys::kLabelKey)) { | |
| 680 EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetString(keys::kLabelKey, | |
| 681 &label)); | |
| 682 } | |
| 683 if (candidate_dict->HasKey(keys::kAnnotationKey)) { | |
| 684 EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetString( | |
| 685 keys::kAnnotationKey, | |
| 686 &annotation)); | |
| 687 } | |
| 688 | |
| 689 output->push_back(chromeos::InputMethodEngine::Candidate()); | |
| 690 output->back().value = candidate; | |
| 691 output->back().id = id; | |
| 692 output->back().label = label; | |
| 693 output->back().annotation = annotation; | |
| 694 | |
| 695 if (candidate_dict->HasKey(keys::kCandidatesKey)) { | |
| 696 ListValue* sub_list; | |
| 697 EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetList(keys::kCandidatesKey, | |
| 698 &sub_list)); | |
| 699 if (!ReadCandidates(sub_list, &(output->back().candidates))) { | |
| 700 error_ = kErrorBadCandidateList; | |
| 701 return false; | |
| 702 } | |
| 703 } | |
| 704 } | |
| 705 | |
| 706 return true; | |
| 707 } | |
| 708 | |
| 709 bool SetCandidatesFunction::RunImpl() { | |
| 710 chromeos::InputMethodEngine* engine = | |
| 711 ExtensionInputImeEventRouter::GetInstance()-> | |
| 712 GetActiveEngine(extension_id()); | |
| 713 if (!engine) { | |
| 714 SetResult(Value::CreateBooleanValue(false)); | |
| 715 return true; | |
| 716 } | |
| 717 | |
| 718 DictionaryValue* args; | |
| 719 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 720 | |
| 721 int context_id; | |
| 722 std::vector<chromeos::InputMethodEngine::Candidate> candidates; | |
| 723 | |
| 724 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kContextIdKey, | |
| 725 &context_id)); | |
| 726 | |
| 727 ListValue* candidate_list; | |
| 728 EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kCandidatesKey, | |
| 729 &candidate_list)); | |
| 730 if (!ReadCandidates(candidate_list, &candidates)) { | |
| 731 error_ = kErrorBadCandidateList; | |
| 732 return false; | |
| 733 } | |
| 734 | |
| 735 std::string error; | |
| 736 if (engine->SetCandidates(context_id, candidates, &error_)) { | |
| 737 SetResult(Value::CreateBooleanValue(true)); | |
| 738 } else { | |
| 739 SetResult(Value::CreateBooleanValue(false)); | |
| 740 } | |
| 741 return true; | |
| 742 } | |
| 743 | |
| 744 bool SetCursorPositionFunction::RunImpl() { | |
| 745 chromeos::InputMethodEngine* engine = | |
| 746 ExtensionInputImeEventRouter::GetInstance()-> | |
| 747 GetActiveEngine(extension_id()); | |
| 748 if (!engine) { | |
| 749 SetResult(Value::CreateBooleanValue(false)); | |
| 750 return true; | |
| 751 } | |
| 752 | |
| 753 DictionaryValue* args; | |
| 754 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 755 int context_id; | |
| 756 int candidate_id; | |
| 757 | |
| 758 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kContextIdKey, | |
| 759 &context_id)); | |
| 760 EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kCandidateIdKey, | |
| 761 &candidate_id)); | |
| 762 | |
| 763 if (engine->SetCursorPosition(context_id, candidate_id, &error_)) { | |
| 764 SetResult(Value::CreateBooleanValue(true)); | |
| 765 } else { | |
| 766 SetResult(Value::CreateBooleanValue(false)); | |
| 767 } | |
| 768 return true; | |
| 769 } | |
| 770 | |
| 771 bool SetMenuItemsFunction::RunImpl() { | |
| 772 DictionaryValue* args; | |
| 773 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 774 | |
| 775 std::string engine_id; | |
| 776 EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kEngineIdKey, &engine_id)); | |
| 777 | |
| 778 chromeos::InputMethodEngine* engine = | |
| 779 ExtensionInputImeEventRouter::GetInstance()->GetEngine(extension_id(), | |
| 780 engine_id); | |
| 781 if (!engine) { | |
| 782 error_ = kErrorEngineNotAvailable; | |
| 783 return false; | |
| 784 } | |
| 785 | |
| 786 ListValue* items; | |
| 787 EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kItemsKey, &items)); | |
| 788 | |
| 789 std::vector<chromeos::InputMethodEngine::MenuItem> menu_items; | |
| 790 EXTENSION_FUNCTION_VALIDATE(ReadMenuItems(items, &menu_items)); | |
| 791 | |
| 792 if (!engine->SetMenuItems(menu_items)) { | |
| 793 error_ = kErrorSetMenuItemsFail; | |
| 794 } | |
| 795 return true; | |
| 796 } | |
| 797 | |
| 798 bool UpdateMenuItemsFunction::RunImpl() { | |
| 799 DictionaryValue* args; | |
| 800 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); | |
| 801 | |
| 802 std::string engine_id; | |
| 803 EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kEngineIdKey, &engine_id)); | |
| 804 | |
| 805 chromeos::InputMethodEngine* engine = | |
| 806 ExtensionInputImeEventRouter::GetInstance()->GetEngine(extension_id(), | |
| 807 engine_id); | |
| 808 if (!engine) { | |
| 809 error_ = kErrorEngineNotAvailable; | |
| 810 return false; | |
| 811 } | |
| 812 | |
| 813 ListValue* items; | |
| 814 EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kItemsKey, &items)); | |
| 815 | |
| 816 std::vector<chromeos::InputMethodEngine::MenuItem> menu_items; | |
| 817 EXTENSION_FUNCTION_VALIDATE(ReadMenuItems(items, &menu_items)); | |
| 818 | |
| 819 if (!engine->UpdateMenuItems(menu_items)) { | |
| 820 error_ = kErrorUpdateMenuItemsFail; | |
| 821 } | |
| 822 return true; | |
| 823 } | |
| 824 | |
| 825 bool InputEventHandled::RunImpl() { | |
| 826 std::string request_id_str; | |
| 827 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &request_id_str)); | |
| 828 | |
| 829 bool handled = false; | |
| 830 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &handled)); | |
| 831 | |
| 832 ExtensionInputImeEventRouter::GetInstance()->OnEventHandled( | |
| 833 extension_id(), request_id_str, handled); | |
| 834 | |
| 835 return true; | |
| 836 } | |
| 837 #endif | |
| OLD | NEW |