Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: chrome/browser/chromeos/input_method/input_method_engine.cc

Issue 10834108: Replace InputMethodEngineIBus. (Closed) Base URL: http://git.chromium.org/chromium/src.git@input_method_engine_ibus
Patch Set: Address comments Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/input_method/ibus_keymap.cc ('k') | chrome/browser/chromeos/input_method/input_method_engine_ibus.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698