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