OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/input_method/input_method_engine.h" | 5 #include "chrome/browser/chromeos/input_method/input_method_engine.h" |
6 | 6 |
7 #include <map> | 7 #include "chrome/browser/chromeos/input_method/input_method_engine_ibus.h" |
8 | |
9 #include "base/logging.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/string_util.h" | |
12 #include "chrome/browser/chromeos/input_method/ibus_engine_controller.h" | |
13 #include "chrome/browser/chromeos/input_method/ibus_keymap.h" | |
14 #include "chrome/browser/chromeos/input_method/input_method_manager.h" | |
15 #include "chrome/browser/chromeos/input_method/input_method_util.h" | |
16 | 8 |
17 namespace chromeos { | 9 namespace chromeos { |
18 | 10 |
19 const char* kExtensionImePrefix = "_ext_ime_"; | |
20 const char* kErrorNotActive = "IME is not active"; | |
21 const char* kErrorWrongContext = "Context is not active"; | |
22 const char* kCandidateNotFound = "Candidate not found"; | |
23 | |
24 InputMethodEngine::KeyboardEvent::KeyboardEvent() | 11 InputMethodEngine::KeyboardEvent::KeyboardEvent() |
25 : alt_key(false), | 12 : alt_key(false), |
26 ctrl_key(false), | 13 ctrl_key(false), |
27 shift_key(false) { | 14 shift_key(false) { |
28 } | 15 } |
29 | 16 |
30 InputMethodEngine::KeyboardEvent::~KeyboardEvent() { | 17 InputMethodEngine::KeyboardEvent::~KeyboardEvent() { |
31 } | 18 } |
32 | 19 |
33 InputMethodEngine::MenuItem::MenuItem() { | 20 InputMethodEngine::MenuItem::MenuItem() { |
34 } | 21 } |
35 | 22 |
36 InputMethodEngine::MenuItem::~MenuItem() { | 23 InputMethodEngine::MenuItem::~MenuItem() { |
37 } | 24 } |
38 | 25 |
39 InputMethodEngine::Candidate::Candidate() { | 26 InputMethodEngine::Candidate::Candidate() { |
40 } | 27 } |
41 | 28 |
42 InputMethodEngine::Candidate::~Candidate() { | 29 InputMethodEngine::Candidate::~Candidate() { |
43 } | 30 } |
44 | 31 |
45 InputMethodEngine::Observer::~Observer() { | 32 InputMethodEngine::Observer::~Observer() { |
46 } | 33 } |
47 | 34 |
48 class InputMethodEngineImpl | |
49 : public InputMethodEngine, | |
50 public input_method::IBusEngineController::Observer { | |
51 public: | |
52 InputMethodEngineImpl() | |
53 : observer_(NULL), active_(false), next_context_id_(1), | |
54 context_id_(-1) {} | |
55 | |
56 ~InputMethodEngineImpl() { | |
57 input_method::InputMethodManager* manager = | |
58 input_method::InputMethodManager::GetInstance(); | |
59 manager->RemoveInputMethodExtension(ibus_id_); | |
60 } | |
61 | |
62 bool Init(InputMethodEngine::Observer* observer, | |
63 const char* engine_name, | |
64 const char* extension_id, | |
65 const char* engine_id, | |
66 const char* description, | |
67 const char* language, | |
68 const std::vector<std::string>& layouts, | |
69 std::string* error); | |
70 | |
71 virtual bool SetComposition(int context_id, | |
72 const char* text, int selection_start, | |
73 int selection_end, int cursor, | |
74 const std::vector<SegmentInfo>& segments, | |
75 std::string* error); | |
76 virtual bool ClearComposition(int context_id, | |
77 std::string* error); | |
78 virtual bool CommitText(int context_id, | |
79 const char* text, std::string* error); | |
80 virtual bool SetCandidateWindowVisible(bool visible, std::string* error); | |
81 virtual void SetCandidateWindowCursorVisible(bool visible); | |
82 virtual void SetCandidateWindowVertical(bool vertical); | |
83 virtual void SetCandidateWindowPageSize(int size); | |
84 virtual void SetCandidateWindowAuxText(const char* text); | |
85 virtual void SetCandidateWindowAuxTextVisible(bool visible); | |
86 virtual bool SetCandidates(int context_id, | |
87 const std::vector<Candidate>& candidates, | |
88 std::string* error); | |
89 virtual bool SetCursorPosition(int context_id, int candidate_id, | |
90 std::string* error); | |
91 virtual bool SetMenuItems(const std::vector<MenuItem>& items); | |
92 virtual bool UpdateMenuItems(const std::vector<MenuItem>& items); | |
93 virtual bool IsActive() const { | |
94 return active_; | |
95 } | |
96 virtual void KeyEventDone(input_method::KeyEventHandle* key_data, | |
97 bool handled); | |
98 | |
99 virtual void OnReset(); | |
100 virtual void OnEnable(); | |
101 virtual void OnDisable(); | |
102 virtual void OnFocusIn(); | |
103 virtual void OnFocusOut(); | |
104 virtual void OnKeyEvent(bool key_press, unsigned int keyval, | |
105 unsigned int keycode, bool alt_key, bool ctrl_key, | |
106 bool shift_key, | |
107 input_method::KeyEventHandle* key_data); | |
108 virtual void OnPropertyActivate(const char* name, unsigned int state); | |
109 virtual void OnCandidateClicked(unsigned int index, unsigned int button, | |
110 unsigned int state); | |
111 private: | |
112 bool MenuItemToProperty( | |
113 const MenuItem& item, | |
114 input_method::IBusEngineController::EngineProperty* property); | |
115 | |
116 // Pointer to the object recieving events for this IME. | |
117 InputMethodEngine::Observer* observer_; | |
118 | |
119 // Connection to IBus. | |
120 scoped_ptr<input_method::IBusEngineController> connection_; | |
121 | |
122 // True when this IME is active, false if deactive. | |
123 bool active_; | |
124 | |
125 // Next id that will be assigned to a context. | |
126 int next_context_id_; | |
127 | |
128 // ID that is used for the current input context. False if there is no focus. | |
129 int context_id_; | |
130 | |
131 // User specified id of this IME. | |
132 std::string engine_id_; | |
133 | |
134 // ID used by ibus to reference this IME. | |
135 std::string ibus_id_; | |
136 | |
137 // Mapping of candidate index to candidate id. | |
138 std::vector<int> candidate_ids_; | |
139 | |
140 // Mapping of candidate id to index. | |
141 std::map<int, int> candidate_indexes_; | |
142 }; | |
143 | |
144 bool InputMethodEngineImpl::Init(InputMethodEngine::Observer* observer, | |
145 const char* engine_name, | |
146 const char* extension_id, | |
147 const char* engine_id, | |
148 const char* description, | |
149 const char* language, | |
150 const std::vector<std::string>& layouts, | |
151 std::string* error) { | |
152 ibus_id_ = kExtensionImePrefix; | |
153 ibus_id_ += extension_id; | |
154 ibus_id_ += engine_id; | |
155 | |
156 std::string layout; | |
157 input_method::InputMethodManager* manager = | |
158 input_method::InputMethodManager::GetInstance(); | |
159 | |
160 if (!layouts.empty()) { | |
161 layout = JoinString(layouts, ','); | |
162 } else { | |
163 const std::string fallback_id = | |
164 manager->GetInputMethodUtil()->GetHardwareInputMethodId(); | |
165 const input_method::InputMethodDescriptor* fallback_desc = | |
166 manager->GetInputMethodUtil()->GetInputMethodDescriptorFromId( | |
167 fallback_id); | |
168 layout = fallback_desc->keyboard_layout(); | |
169 } | |
170 | |
171 connection_.reset(input_method::IBusEngineController::Create(this, | |
172 ibus_id_.c_str(), | |
173 engine_name, | |
174 description, | |
175 language, | |
176 layout.c_str())); | |
177 if (!connection_.get()) { | |
178 *error = "ConnectInputMethodExtension() failed."; | |
179 return false; | |
180 } | |
181 | |
182 observer_ = observer; | |
183 engine_id_ = engine_id; | |
184 manager->AddInputMethodExtension(ibus_id_, engine_name, layouts, language); | |
185 return true; | |
186 } | |
187 | |
188 bool InputMethodEngineImpl::SetComposition( | |
189 int context_id, | |
190 const char* text, | |
191 int selection_start, | |
192 int selection_end, | |
193 int cursor, | |
194 const std::vector<SegmentInfo>& segments, | |
195 std::string* error) { | |
196 if (!active_) { | |
197 *error = kErrorNotActive; | |
198 return false; | |
199 } | |
200 if (context_id != context_id_ || context_id_ == -1) { | |
201 *error = kErrorWrongContext; | |
202 return false; | |
203 } | |
204 | |
205 connection_->SetPreeditText(text, cursor); | |
206 // TODO: Add support for displaying selected text in the composition string. | |
207 for (std::vector<SegmentInfo>::const_iterator segment = segments.begin(); | |
208 segment != segments.end(); ++segment) { | |
209 int style; | |
210 switch (segment->style) { | |
211 case SEGMENT_STYLE_UNDERLINE: | |
212 style = input_method::IBusEngineController::UNDERLINE_SINGLE; | |
213 break; | |
214 case SEGMENT_STYLE_DOUBLE_UNDERLINE: | |
215 style = input_method::IBusEngineController::UNDERLINE_DOUBLE; | |
216 break; | |
217 | |
218 default: | |
219 continue; | |
220 } | |
221 | |
222 connection_->SetPreeditUnderline(segment->start, segment->end, style); | |
223 } | |
224 return true; | |
225 } | |
226 | |
227 bool InputMethodEngineImpl::ClearComposition(int context_id, | |
228 std::string* error) { | |
229 if (!active_) { | |
230 *error = kErrorNotActive; | |
231 return false; | |
232 } | |
233 if (context_id != context_id_ || context_id_ == -1) { | |
234 *error = kErrorWrongContext; | |
235 return false; | |
236 } | |
237 | |
238 connection_->SetPreeditText("", 0); | |
239 return true; | |
240 } | |
241 | |
242 bool InputMethodEngineImpl::CommitText(int context_id, | |
243 const char* text, std::string* error) { | |
244 if (context_id != context_id_ || context_id_ == -1) { | |
245 *error = kErrorWrongContext; | |
246 return false; | |
247 } | |
248 if (!active_) { | |
249 // TODO: Commit the text anyways. | |
250 *error = kErrorNotActive; | |
251 return false; | |
252 } | |
253 | |
254 connection_->CommitText(text); | |
255 return true; | |
256 } | |
257 | |
258 bool InputMethodEngineImpl::SetCandidateWindowVisible(bool visible, | |
259 std::string* error) { | |
260 if (!active_) { | |
261 *error = kErrorNotActive; | |
262 return false; | |
263 } | |
264 | |
265 connection_->SetTableVisible(visible); | |
266 return true; | |
267 } | |
268 | |
269 void InputMethodEngineImpl::SetCandidateWindowCursorVisible(bool visible) { | |
270 connection_->SetCursorVisible(visible); | |
271 } | |
272 | |
273 void InputMethodEngineImpl::SetCandidateWindowVertical(bool vertical) { | |
274 connection_->SetOrientationVertical(vertical); | |
275 } | |
276 | |
277 void InputMethodEngineImpl::SetCandidateWindowPageSize(int size) { | |
278 connection_->SetPageSize(size); | |
279 } | |
280 | |
281 void InputMethodEngineImpl::SetCandidateWindowAuxText(const char* text) { | |
282 connection_->SetCandidateAuxText(text); | |
283 } | |
284 | |
285 void InputMethodEngineImpl::SetCandidateWindowAuxTextVisible(bool visible) { | |
286 connection_->SetCandidateAuxTextVisible(visible); | |
287 } | |
288 | |
289 bool InputMethodEngineImpl::SetCandidates( | |
290 int context_id, const std::vector<Candidate>& candidates, | |
291 std::string* error) { | |
292 if (!active_) { | |
293 *error = kErrorNotActive; | |
294 return false; | |
295 } | |
296 if (context_id != context_id_ || context_id_ == -1) { | |
297 *error = kErrorWrongContext; | |
298 return false; | |
299 } | |
300 | |
301 // TODO: Nested candidates | |
302 std::vector<input_method::IBusEngineController::Candidate> ibus_candidates; | |
303 | |
304 candidate_ids_.clear(); | |
305 candidate_indexes_.clear(); | |
306 for (std::vector<Candidate>::const_iterator ix = candidates.begin(); | |
307 ix != candidates.end(); ++ix) { | |
308 ibus_candidates.push_back(input_method::IBusEngineController::Candidate()); | |
309 ibus_candidates.back().value = ix->value; | |
310 ibus_candidates.back().label = ix->label; | |
311 ibus_candidates.back().annotation = ix->annotation; | |
312 | |
313 // Store a mapping from the user defined ID to the candidate index. | |
314 candidate_indexes_[ix->id] = candidate_ids_.size(); | |
315 candidate_ids_.push_back(ix->id); | |
316 } | |
317 connection_->SetCandidates(ibus_candidates); | |
318 return true; | |
319 } | |
320 | |
321 bool InputMethodEngineImpl::SetCursorPosition(int context_id, int candidate_id, | |
322 std::string* error) { | |
323 if (!active_) { | |
324 *error = kErrorNotActive; | |
325 return false; | |
326 } | |
327 if (context_id != context_id_ || context_id_ == -1) { | |
328 *error = kErrorWrongContext; | |
329 return false; | |
330 } | |
331 | |
332 std::map<int, int>::const_iterator position = | |
333 candidate_indexes_.find(candidate_id); | |
334 if (position == candidate_indexes_.end()) { | |
335 *error = kCandidateNotFound; | |
336 return false; | |
337 } | |
338 | |
339 connection_->SetCursorPosition(position->second); | |
340 return true; | |
341 } | |
342 | |
343 bool InputMethodEngineImpl::SetMenuItems(const std::vector<MenuItem>& items) { | |
344 std::vector<input_method::IBusEngineController::EngineProperty*> properties; | |
345 | |
346 for (std::vector<MenuItem>::const_iterator item = items.begin(); | |
347 item != items.end(); ++item) { | |
348 input_method::IBusEngineController::EngineProperty* property = | |
349 new input_method::IBusEngineController::EngineProperty; | |
350 if (!MenuItemToProperty(*item, property)) { | |
351 delete property; | |
352 DVLOG(1) << "Bad menu item"; | |
353 return false; | |
354 } | |
355 properties.push_back(property); | |
356 } | |
357 return connection_->RegisterProperties(properties); | |
358 } | |
359 | |
360 bool InputMethodEngineImpl::MenuItemToProperty( | |
361 const MenuItem& item, | |
362 input_method::IBusEngineController::EngineProperty* property) { | |
363 property->key = item.id; | |
364 property->label = item.label; | |
365 property->visible = item.visible; | |
366 property->sensitive = item.enabled; | |
367 property->checked = item.checked; | |
368 | |
369 if (!item.children.empty()) { | |
370 property->type = input_method::IBusEngineController::PROPERTY_TYPE_MENU; | |
371 } else { | |
372 switch (item.style) { | |
373 case MENU_ITEM_STYLE_NONE: | |
374 property->type = | |
375 input_method::IBusEngineController::PROPERTY_TYPE_NORMAL; | |
376 break; | |
377 case MENU_ITEM_STYLE_CHECK: | |
378 property->type = | |
379 input_method::IBusEngineController::PROPERTY_TYPE_TOGGLE; | |
380 break; | |
381 case MENU_ITEM_STYLE_RADIO: | |
382 property->type = | |
383 input_method::IBusEngineController::PROPERTY_TYPE_RADIO; | |
384 break; | |
385 case MENU_ITEM_STYLE_SEPARATOR: | |
386 property->type = | |
387 input_method::IBusEngineController::PROPERTY_TYPE_SEPARATOR; | |
388 break; | |
389 } | |
390 } | |
391 | |
392 property->modified = 0; | |
393 if (item.modified & MENU_ITEM_MODIFIED_LABEL) { | |
394 property->modified |= | |
395 input_method::IBusEngineController::PROPERTY_MODIFIED_LABEL; | |
396 } | |
397 if (item.modified & MENU_ITEM_MODIFIED_STYLE) { | |
398 property->modified |= | |
399 input_method::IBusEngineController::PROPERTY_MODIFIED_TYPE; | |
400 } | |
401 if (item.modified & MENU_ITEM_MODIFIED_VISIBLE) { | |
402 property->modified |= | |
403 input_method::IBusEngineController::PROPERTY_MODIFIED_VISIBLE; | |
404 } | |
405 if (item.modified & MENU_ITEM_MODIFIED_ENABLED) { | |
406 property->modified |= | |
407 input_method::IBusEngineController::PROPERTY_MODIFIED_SENSITIVE; | |
408 } | |
409 if (item.modified & MENU_ITEM_MODIFIED_CHECKED) { | |
410 property->modified |= | |
411 input_method::IBusEngineController::PROPERTY_MODIFIED_CHECKED; | |
412 } | |
413 | |
414 for (std::vector<MenuItem>::const_iterator child = item.children.begin(); | |
415 child != item.children.end(); ++child) { | |
416 input_method::IBusEngineController::EngineProperty* new_property = | |
417 new input_method::IBusEngineController::EngineProperty; | |
418 if (!MenuItemToProperty(*child, new_property)) { | |
419 delete new_property; | |
420 DVLOG(1) << "Bad menu item child"; | |
421 return false; | |
422 } | |
423 property->children.push_back(new_property); | |
424 } | |
425 | |
426 return true; | |
427 } | |
428 | |
429 bool InputMethodEngineImpl::UpdateMenuItems( | |
430 const std::vector<MenuItem>& items) { | |
431 std::vector<input_method::IBusEngineController::EngineProperty*> properties; | |
432 | |
433 for (std::vector<MenuItem>::const_iterator item = items.begin(); | |
434 item != items.end(); ++item) { | |
435 input_method::IBusEngineController::EngineProperty* new_property = | |
436 new input_method::IBusEngineController::EngineProperty(); | |
437 if (!MenuItemToProperty(*item, new_property)) { | |
438 DVLOG(1) << "Bad menu item"; | |
439 delete new_property; | |
440 return false; | |
441 } | |
442 properties.push_back(new_property); | |
443 } | |
444 return connection_->UpdateProperties(properties); | |
445 } | |
446 | |
447 void InputMethodEngineImpl::KeyEventDone(input_method::KeyEventHandle* key_data, | |
448 bool handled) { | |
449 connection_->KeyEventDone(key_data, handled); | |
450 } | |
451 | |
452 void InputMethodEngineImpl::OnReset() { | |
453 // Ignored | |
454 } | |
455 | |
456 void InputMethodEngineImpl::OnEnable() { | |
457 active_ = true; | |
458 observer_->OnActivate(engine_id_); | |
459 } | |
460 | |
461 void InputMethodEngineImpl::OnDisable() { | |
462 active_ = false; | |
463 observer_->OnDeactivated(engine_id_); | |
464 } | |
465 | |
466 void InputMethodEngineImpl::OnFocusIn() { | |
467 context_id_ = next_context_id_; | |
468 ++next_context_id_; | |
469 | |
470 InputContext context; | |
471 context.id = context_id_; | |
472 // TODO: Other types | |
473 context.type = "text"; | |
474 | |
475 observer_->OnFocus(context); | |
476 } | |
477 | |
478 void InputMethodEngineImpl::OnFocusOut() { | |
479 int context_id = context_id_; | |
480 context_id_ = -1; | |
481 observer_->OnBlur(context_id); | |
482 } | |
483 | |
484 void InputMethodEngineImpl::OnKeyEvent(bool key_press, unsigned int keyval, | |
485 unsigned int keycode, bool alt_key, | |
486 bool ctrl_key, bool shift_key, | |
487 input_method::KeyEventHandle* key_data) { | |
488 KeyboardEvent event; | |
489 event.type = key_press ? "keydown" : "keyup"; | |
490 event.key = input_method::GetIBusKey(keyval); | |
491 event.alt_key = alt_key; | |
492 event.ctrl_key = ctrl_key; | |
493 event.shift_key = shift_key; | |
494 observer_->OnKeyEvent(engine_id_, event, key_data); | |
495 } | |
496 | |
497 void InputMethodEngineImpl::OnPropertyActivate(const char* name, | |
498 unsigned int state) { | |
499 observer_->OnMenuItemActivated(engine_id_, name); | |
500 } | |
501 | |
502 void InputMethodEngineImpl::OnCandidateClicked(unsigned int index, | |
503 unsigned int button, | |
504 unsigned int state) { | |
505 if (index > candidate_ids_.size()) { | |
506 return; | |
507 } | |
508 | |
509 MouseButtonEvent pressed_button; | |
510 if (button & input_method::IBusEngineController::MOUSE_BUTTON_1_MASK) { | |
511 pressed_button = MOUSE_BUTTON_LEFT; | |
512 } else if (button & input_method::IBusEngineController::MOUSE_BUTTON_2_MASK) { | |
513 pressed_button = MOUSE_BUTTON_MIDDLE; | |
514 } else if (button & input_method::IBusEngineController::MOUSE_BUTTON_3_MASK) { | |
515 pressed_button = MOUSE_BUTTON_RIGHT; | |
516 } else { | |
517 DVLOG(1) << "Unknown button: " << button; | |
518 pressed_button = MOUSE_BUTTON_LEFT; | |
519 } | |
520 | |
521 observer_->OnCandidateClicked( | |
522 engine_id_, candidate_ids_.at(index), pressed_button); | |
523 } | |
524 | |
525 class InputMethodEngineStub : public InputMethodEngine { | |
526 public: | |
527 InputMethodEngineStub() : active_(false) {} | |
528 ~InputMethodEngineStub() {} | |
529 | |
530 bool Init(InputMethodEngine::Observer* observer, | |
531 const char* engine_name, | |
532 const char* extension_id, | |
533 const char* engine_id, | |
534 const char* description, | |
535 const char* language, | |
536 const std::vector<std::string>& layouts, | |
537 std::string* error) { | |
538 DVLOG(1) << "Init"; | |
539 return true; | |
540 } | |
541 | |
542 virtual bool SetComposition(int context_id, | |
543 const char* text, int selection_start, | |
544 int selection_end, int cursor, | |
545 const std::vector<SegmentInfo>& segments, | |
546 std::string* error) { | |
547 DVLOG(1) << "SetComposition"; | |
548 return true; | |
549 } | |
550 | |
551 virtual bool ClearComposition(int context_id, std::string* error) { | |
552 DVLOG(1) << "ClearComposition"; | |
553 return true; | |
554 } | |
555 | |
556 virtual bool CommitText(int context_id, | |
557 const char* text, std::string* error) { | |
558 DVLOG(1) << "CommitText"; | |
559 return true; | |
560 } | |
561 | |
562 virtual bool SetCandidateWindowVisible(bool visible, std::string* error) { | |
563 DVLOG(1) << "SetCandidateWindowVisible"; | |
564 return true; | |
565 } | |
566 | |
567 virtual void SetCandidateWindowCursorVisible(bool visible) { | |
568 DVLOG(1) << "SetCandidateWindowCursorVisible"; | |
569 } | |
570 | |
571 virtual void SetCandidateWindowVertical(bool vertical) { | |
572 DVLOG(1) << "SetCandidateWindowVertical"; | |
573 } | |
574 | |
575 virtual void SetCandidateWindowPageSize(int size) { | |
576 DVLOG(1) << "SetCandidateWindowPageSize"; | |
577 } | |
578 | |
579 virtual void SetCandidateWindowAuxText(const char* text) { | |
580 DVLOG(1) << "SetCandidateWindowAuxText"; | |
581 } | |
582 | |
583 virtual void SetCandidateWindowAuxTextVisible(bool visible) { | |
584 DVLOG(1) << "SetCandidateWindowAuxTextVisible"; | |
585 } | |
586 | |
587 virtual bool SetCandidates(int context_id, | |
588 const std::vector<Candidate>& candidates, | |
589 std::string* error) { | |
590 DVLOG(1) << "SetCandidates"; | |
591 return true; | |
592 } | |
593 | |
594 virtual bool SetCursorPosition(int context_id, int candidate_id, | |
595 std::string* error) { | |
596 DVLOG(1) << "SetCursorPosition"; | |
597 return true; | |
598 } | |
599 | |
600 virtual bool SetMenuItems(const std::vector<MenuItem>& items) { | |
601 DVLOG(1) << "SetMenuItems"; | |
602 return true; | |
603 } | |
604 | |
605 virtual bool UpdateMenuItems(const std::vector<MenuItem>& items) { | |
606 DVLOG(1) << "UpdateMenuItems"; | |
607 return true; | |
608 } | |
609 | |
610 virtual bool IsActive() const { | |
611 DVLOG(1) << "IsActive"; | |
612 return active_; | |
613 } | |
614 | |
615 virtual void KeyEventDone(input_method::KeyEventHandle* key_data, | |
616 bool handled) { | |
617 } | |
618 | |
619 private: | |
620 // True when this IME is active, false if deactive. | |
621 bool active_; | |
622 | |
623 // User specified id of this IME. | |
624 std::string engine_id_; | |
625 }; | |
626 | |
627 InputMethodEngine* InputMethodEngine::CreateEngine( | 35 InputMethodEngine* InputMethodEngine::CreateEngine( |
628 InputMethodEngine::Observer* observer, | 36 InputMethodEngine::Observer* observer, |
629 const char* engine_name, | 37 const char* engine_name, |
630 const char* extension_id, | 38 const char* extension_id, |
631 const char* engine_id, | 39 const char* engine_id, |
632 const char* description, | 40 const char* description, |
633 const char* language, | 41 const char* language, |
634 const std::vector<std::string>& layouts, | 42 const std::vector<std::string>& layouts, |
635 std::string* error) { | 43 std::string* error) { |
636 | 44 |
637 #if defined(HAVE_IBUS) | 45 InputMethodEngineIBus* engine = new InputMethodEngineIBus(); |
638 InputMethodEngineImpl* new_engine = new InputMethodEngineImpl(); | 46 engine->Initialize(observer, |
639 #else | 47 engine_name, |
640 InputMethodEngineStub* new_engine = new InputMethodEngineStub(); | 48 extension_id, |
641 #endif | 49 engine_id, |
642 | 50 description, |
643 if (!new_engine->Init(observer, engine_name, extension_id, engine_id, | 51 language, |
644 description, language, layouts, error)) { | 52 layouts, |
645 DVLOG(1) << "Init() failed."; | 53 error); |
646 delete new_engine; | 54 return engine; |
647 new_engine = NULL; | |
648 } | |
649 | |
650 return new_engine; | |
651 } | 55 } |
652 | 56 |
653 } // namespace chromeos | 57 } // namespace chromeos |
OLD | NEW |