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 |