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

Side by Side Diff: chrome/browser/chromeos/input_method/input_method_engine_ibus.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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/input_method/input_method_engine_ibus.h"
6
7 #include <map>
8
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/string_number_conversions.h"
12 #include "base/string_util.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 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "chromeos/dbus/ibus/ibus_client.h"
18 #include "chromeos/dbus/ibus/ibus_component.h"
19 #include "chromeos/dbus/ibus/ibus_engine_factory_service.h"
20 #include "chromeos/dbus/ibus/ibus_engine_service.h"
21 #include "chromeos/dbus/ibus/ibus_lookup_table.h"
22 #include "chromeos/dbus/ibus/ibus_property.h"
23 #include "chromeos/dbus/ibus/ibus_text.h"
24 #include "dbus/object_path.h"
25
26 namespace chromeos {
27 const char* kExtensionImePrefix = "_ext_ime_";
28 const char* kErrorNotActive = "IME is not active";
29 const char* kErrorWrongContext = "Context is not active";
30 const char* kCandidateNotFound = "Candidate not found";
31 const char* kEngineBusPrefix = "org.freedesktop.IBus.";
32 const char* kObjectPathPrefix = "/org/freedesktop/IBus/Engine/";
33
34 namespace {
35 const uint32 kIBusAltKeyMask = 1 << 3;
36 const uint32 kIBusCtrlKeyMask = 1 << 2;
37 const uint32 kIBusShiftKeyMask = 1 << 0;
38 const uint32 kIBusKeyReleaseMask = 1 << 30;
39 }
40
41 InputMethodEngineIBus::InputMethodEngineIBus()
42 : focused_(false),
43 active_(false),
44 context_id_(0),
45 next_context_id_(1),
46 current_object_path_(0),
47 aux_text_(new ibus::IBusText()),
48 aux_text_visible_(false),
49 observer_(NULL),
50 preedit_text_(new ibus::IBusText()),
51 preedit_cursor_(0),
52 component_(new ibus::IBusComponent()),
53 table_(new ibus::IBusLookupTable()),
54 table_visible_(false),
55 weak_ptr_factory_(this) {
56 }
57
58 void InputMethodEngineIBus::Initialize(
59 InputMethodEngine::Observer* observer,
60 const char* engine_name,
61 const char* extension_id,
62 const char* engine_id,
63 const char* description,
64 const char* language,
65 const std::vector<std::string>& layouts,
66 std::string* error) {
67 DCHECK(observer) << "Observer must not be null.";
68
69 observer_ = observer;
70 engine_id_ = engine_id;
71 ibus_id_ = kExtensionImePrefix;
72 ibus_id_ += extension_id;
73 ibus_id_ += engine_id;
74
75 input_method::InputMethodManager* manager =
76 input_method::InputMethodManager::GetInstance();
77 std::string layout;
78 if (!layouts.empty()) {
79 layout = JoinString(layouts, ',');
80 } else {
81 input_method::InputMethodManager* manager =
82 input_method::InputMethodManager::GetInstance();
83 const std::string fallback_id =
84 manager->GetInputMethodUtil()->GetHardwareInputMethodId();
85 const input_method::InputMethodDescriptor* fallback_desc =
86 manager->GetInputMethodUtil()->GetInputMethodDescriptorFromId(
87 fallback_id);
88 layout = fallback_desc->keyboard_layout();
89 }
90
91 component_.reset(new ibus::IBusComponent());
92 component_->set_name(std::string(kEngineBusPrefix) + std::string(engine_id));
93 component_->set_description(description);
94 component_->set_author(engine_name);
95
96 chromeos::ibus::IBusComponent::EngineDescription engine_desc;
97 engine_desc.engine_id = ibus_id_;
98 engine_desc.display_name = description;
99 engine_desc.description = description;
100 engine_desc.language_code = language;
101 engine_desc.author = ibus_id_;
102 engine_desc.layout = layout.c_str();
103
104 component_->mutable_engine_description()->push_back(engine_desc);
105 manager->AddInputMethodExtension(ibus_id_, engine_name, layouts, language,
106 this);
107 // If connection is avaiable, register component. If there are no connection
108 // to ibus-daemon, OnConnected callback will register component instead.
109 if (IsConnected())
110 RegisterComponent();
111 }
112
113 InputMethodEngineIBus::~InputMethodEngineIBus() {
114 }
115
116 bool InputMethodEngineIBus::SetComposition(
117 int context_id,
118 const char* text,
119 int selection_start,
120 int selection_end,
121 int cursor,
122 const std::vector<SegmentInfo>& segments,
123 std::string* error) {
124 if (!active_) {
125 *error = kErrorNotActive;
126 return false;
127 }
128 if (context_id != context_id_ || context_id_ == -1) {
129 *error = kErrorWrongContext;
130 return false;
131 }
132
133 preedit_cursor_ = cursor;
134 preedit_text_.reset(new ibus::IBusText());
135 preedit_text_->set_text(text);
136
137 // TODO: Add support for displaying selected text in the composition string.
138 for (std::vector<SegmentInfo>::const_iterator segment = segments.begin();
139 segment != segments.end(); ++segment) {
140 ibus::IBusText::UnderlineAttribute underline;
141
142 switch (segment->style) {
143 case SEGMENT_STYLE_UNDERLINE:
144 underline.type = ibus::IBusText::IBUS_TEXT_UNDERLINE_SINGLE;
145 break;
146 case SEGMENT_STYLE_DOUBLE_UNDERLINE:
147 underline.type = ibus::IBusText::IBUS_TEXT_UNDERLINE_DOUBLE;
148 break;
149 default:
150 continue;
151 }
152
153 underline.start_index = segment->start;
154 underline.end_index = segment->end;
155 preedit_text_->mutable_underline_attributes()->push_back(underline);
156 }
157
158 // TODO(nona): Makes focus out mode configuable, if necessary.
159 GetCurrentService()->UpdatePreedit(
160 *preedit_text_.get(),
161 preedit_cursor_,
162 true,
163 chromeos::IBusEngineService::IBUS_ENGINE_PREEEDIT_FOCUS_OUT_MODE_COMMIT);
164 return true;
165 }
166
167 bool InputMethodEngineIBus::ClearComposition(int context_id,
168 std::string* error) {
169 if (!active_) {
170 *error = kErrorNotActive;
171 return false;
172 }
173 if (context_id != context_id_ || context_id_ == -1) {
174 *error = kErrorWrongContext;
175 return false;
176 }
177
178 preedit_cursor_ = 0;
179 preedit_text_.reset(new ibus::IBusText());
180 GetCurrentService()->UpdatePreedit(
181 *preedit_text_.get(),
182 0,
183 true,
184 chromeos::IBusEngineService::IBUS_ENGINE_PREEEDIT_FOCUS_OUT_MODE_COMMIT);
185 return true;
186 }
187
188 bool InputMethodEngineIBus::CommitText(int context_id, const char* text,
189 std::string* error) {
190 if (!active_) {
191 // TODO: Commit the text anyways.
192 *error = kErrorNotActive;
193 return false;
194 }
195 if (context_id != context_id_ || context_id_ == -1) {
196 *error = kErrorWrongContext;
197 return false;
198 }
199
200 GetCurrentService()->CommitText(text);
201 return true;
202 }
203
204 bool InputMethodEngineIBus::SetCandidateWindowVisible(bool visible,
205 std::string* error) {
206 if (!active_) {
207 *error = kErrorNotActive;
208 return false;
209 }
210
211 table_visible_ = visible;
212 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_);
213 return true;
214 }
215
216 void InputMethodEngineIBus::SetCandidateWindowCursorVisible(bool visible) {
217 if (!active_)
218 return;
219 table_->set_is_cursor_visible(visible);
220 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_);
221 }
222
223 void InputMethodEngineIBus::SetCandidateWindowVertical(bool vertical) {
224 if (!active_)
225 return;
226 table_->set_orientation(
227 vertical ? ibus::IBusLookupTable::IBUS_LOOKUP_TABLE_ORIENTATION_VERTICAL :
228 ibus::IBusLookupTable::IBUS_LOOKUP_TABLE_ORIENTATION_HORIZONTAL);
229 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_);
230 }
231
232 void InputMethodEngineIBus::SetCandidateWindowPageSize(int size) {
233 if (!active_)
234 return;
235 table_->set_page_size(size);
236 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_);
237 }
238
239 void InputMethodEngineIBus::SetCandidateWindowAuxText(const char* text) {
240 if (!active_)
241 return;
242 aux_text_->set_text(text);
243 GetCurrentService()->UpdateAuxiliaryText(*aux_text_.get(), aux_text_visible_);
244 }
245
246 void InputMethodEngineIBus::SetCandidateWindowAuxTextVisible(bool visible) {
247 if (!active_)
248 return;
249 aux_text_visible_ = visible;
250 GetCurrentService()->UpdateAuxiliaryText(*aux_text_.get(), aux_text_visible_);
251 }
252
253 bool InputMethodEngineIBus::SetCandidates(
254 int context_id,
255 const std::vector<Candidate>& candidates,
256 std::string* error) {
257 if (!active_) {
258 *error = kErrorNotActive;
259 return false;
260 }
261 if (context_id != context_id_ || context_id_ == -1) {
262 *error = kErrorWrongContext;
263 return false;
264 }
265
266 // TODO: Nested candidates
267 candidate_ids_.clear();
268 candidate_indexes_.clear();
269 table_->mutable_candidates()->clear();
270 for (std::vector<Candidate>::const_iterator ix = candidates.begin();
271 ix != candidates.end(); ++ix) {
272 ibus::IBusLookupTable::Entry entry;
273 // TODO(nona): support annotation(crbug.com/140186).
274 entry.value = ix->value + " " + ix->annotation;
275 entry.label = ix->label;
276
277 // Store a mapping from the user defined ID to the candidate index.
278 candidate_indexes_[ix->id] = candidate_ids_.size();
279 candidate_ids_.push_back(ix->id);
280
281 table_->mutable_candidates()->push_back(entry);
282 }
283 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_);
284 return true;
285 }
286
287 bool InputMethodEngineIBus::SetCursorPosition(int context_id, int candidate_id,
288 std::string* error) {
289 if (!active_) {
290 *error = kErrorNotActive;
291 return false;
292 }
293 if (context_id != context_id_ || context_id_ == -1) {
294 *error = kErrorWrongContext;
295 return false;
296 }
297
298 std::map<int, int>::const_iterator position =
299 candidate_indexes_.find(candidate_id);
300 if (position == candidate_indexes_.end()) {
301 *error = kCandidateNotFound;
302 return false;
303 }
304
305 table_->set_cursor_position(position->second);
306 GetCurrentService()->UpdateLookupTable(*table_.get(), table_visible_);
307 return true;
308 }
309
310 bool InputMethodEngineIBus::SetMenuItems(const std::vector<MenuItem>& items) {
311 if (!active_)
312 return false;
313
314 ibus::IBusPropertyList properties;
315 for (std::vector<MenuItem>::const_iterator item = items.begin();
316 item != items.end(); ++item) {
317 ibus::IBusProperty* property = new ibus::IBusProperty();
318 if (!MenuItemToProperty(*item, property)) {
319 delete property;
320 DVLOG(1) << "Bad menu item";
321 return false;
322 }
323 properties.push_back(property);
324 }
325 GetCurrentService()->RegisterProperties(properties);
326 return true;
327 }
328
329 bool InputMethodEngineIBus::UpdateMenuItems(
330 const std::vector<MenuItem>& items) {
331 if (!active_)
332 return false;
333
334 ibus::IBusPropertyList properties;
335 for (std::vector<MenuItem>::const_iterator item = items.begin();
336 item != items.end(); ++item) {
337 ibus::IBusProperty* property = new ibus::IBusProperty();
338 if (!MenuItemToProperty(*item, property)) {
339 delete property;
340 DVLOG(1) << "Bad menu item";
341 return false;
342 }
343 properties.push_back(property);
344 }
345 GetCurrentService()->RegisterProperties(properties);
346 return true;
347 }
348
349 bool InputMethodEngineIBus::IsActive() const {
350 return active_;
351 }
352
353 void InputMethodEngineIBus::KeyEventDone(input_method::KeyEventHandle* key_data,
354 bool handled) {
355 KeyEventDoneCallback* callback =
356 reinterpret_cast<KeyEventDoneCallback*>(key_data);
357 callback->Run(handled);
358 delete callback;
359 }
360
361 void InputMethodEngineIBus::FocusIn() {
362 focused_ = true;
363 if (!active_)
364 return;
365 context_id_ = next_context_id_;
366 ++next_context_id_;
367
368 InputContext context;
369 context.id = context_id_;
370 // TODO: Other types
371 context.type = "text";
372
373 observer_->OnFocus(context);
374 }
375
376 void InputMethodEngineIBus::FocusOut() {
377 focused_ = false;
378 if (!active_)
379 return;
380 int context_id = context_id_;
381 context_id_ = -1;
382 observer_->OnBlur(context_id);
383 }
384
385 void InputMethodEngineIBus::Enable() {
386 active_ = true;
387 observer_->OnActivate(engine_id_);
388 FocusIn();
389 }
390
391 void InputMethodEngineIBus::Disable() {
392 active_ = false;
393 observer_->OnDeactivated(engine_id_);
394 }
395
396 void InputMethodEngineIBus::PropertyActivate(
397 const std::string& property_name,
398 IBusPropertyState property_state) {
399 observer_->OnMenuItemActivated(engine_id_, property_name);
400 }
401
402 void InputMethodEngineIBus::PropertyShow(
403 const std::string& property_name) {
404 }
405
406 void InputMethodEngineIBus::PropertyHide(
407 const std::string& property_name) {
408 }
409
410 void InputMethodEngineIBus::SetCapability(
411 IBusCapability capability) {
412 }
413
414 void InputMethodEngineIBus::Reset() {
415 }
416
417 void InputMethodEngineIBus::ProcessKeyEvent(
418 uint32 keysym,
419 uint32 keycode,
420 uint32 state,
421 const KeyEventDoneCallback& callback) {
422
423 KeyEventDoneCallback *handler = new KeyEventDoneCallback();
424 *handler = callback;
425
426 KeyboardEvent event;
427 event.type = !(state & kIBusKeyReleaseMask) ? "keydown" : "keyup";
428 event.key = input_method::GetIBusKey(keysym);
429 event.alt_key = state & kIBusAltKeyMask;
430 event.ctrl_key = state & kIBusCtrlKeyMask;
431 event.shift_key = state & kIBusShiftKeyMask;
432 observer_->OnKeyEvent(
433 engine_id_,
434 event,
435 reinterpret_cast<input_method::KeyEventHandle*>(handler));
436 }
437
438 void InputMethodEngineIBus::CandidateClicked(
439 uint32 index,
440 IBusMouseButton button,
441 uint32 state) {
442 if (index > candidate_ids_.size()) {
443 return;
444 }
445
446 MouseButtonEvent pressed_button;
447 switch (button) {
448 case IBusEngineHandlerInterface::IBUS_MOUSE_BUTTON_LEFT:
449 pressed_button = MOUSE_BUTTON_LEFT;
450 break;
451 case IBusEngineHandlerInterface::IBUS_MOUSE_BUTTON_MIDDLE:
452 pressed_button = MOUSE_BUTTON_MIDDLE;
453 break;
454 case IBusEngineHandlerInterface::IBUS_MOUSE_BUTTON_RIGHT:
455 pressed_button = MOUSE_BUTTON_RIGHT;
456 break;
457 default:
458 DVLOG(1) << "Unknown button: " << button;
459 pressed_button = MOUSE_BUTTON_LEFT;
460 break;
461 }
462
463 observer_->OnCandidateClicked(
464 engine_id_, candidate_ids_.at(index), pressed_button);
465 }
466
467 void InputMethodEngineIBus::SetSurroundingText(
468 const std::string& text,
469 uint32 cursor_pos,
470 uint32 anchor_pos) {
471 }
472
473 IBusEngineService* InputMethodEngineIBus::GetCurrentService() {
474 return DBusThreadManager::Get()->GetIBusEngineService(object_path_);
475 }
476
477 bool InputMethodEngineIBus::MenuItemToProperty(
478 const MenuItem& item,
479 ibus::IBusProperty* property) {
480 property->set_key(item.id);
481
482 if (item.modified & MENU_ITEM_MODIFIED_LABEL) {
483 property->set_label(item.label);
484 }
485 if (item.modified & MENU_ITEM_MODIFIED_VISIBLE) {
486 property->set_visible(item.visible);
487 }
488 if (item.modified & MENU_ITEM_MODIFIED_CHECKED) {
489 property->set_checked(item.checked);
490 }
491 if (item.modified & MENU_ITEM_MODIFIED_ENABLED) {
492 // TODO(nona): implement sensitive entry(crbug.com/140192).
493 }
494 if (item.modified & MENU_ITEM_MODIFIED_STYLE) {
495 ibus::IBusProperty::IBusPropertyType type =
496 ibus::IBusProperty::IBUS_PROPERTY_TYPE_NORMAL;
497 if (!item.children.empty()) {
498 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_MENU;
499 } else {
500 switch (item.style) {
501 case MENU_ITEM_STYLE_NONE:
502 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_NORMAL;
503 break;
504 case MENU_ITEM_STYLE_CHECK:
505 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_TOGGLE;
506 break;
507 case MENU_ITEM_STYLE_RADIO:
508 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_RADIO;
509 break;
510 case MENU_ITEM_STYLE_SEPARATOR:
511 type = ibus::IBusProperty::IBUS_PROPERTY_TYPE_SEPARATOR;
512 break;
513 }
514 }
515 property->set_type(type);
516 }
517
518 for (std::vector<MenuItem>::const_iterator child = item.children.begin();
519 child != item.children.end(); ++child) {
520 ibus::IBusProperty* new_property = new ibus::IBusProperty();
521 if (!MenuItemToProperty(*child, new_property)) {
522 delete new_property;
523 DVLOG(1) << "Bad menu item child";
524 return false;
525 }
526 property->mutable_sub_properties()->push_back(new_property);
527 }
528
529 return true;
530 }
531
532 void InputMethodEngineIBus::OnConnected() {
533 RegisterComponent();
534 }
535
536 void InputMethodEngineIBus::OnDisconnected() {
537 }
538
539 bool InputMethodEngineIBus::IsConnected() {
540 return DBusThreadManager::Get()->GetIBusClient() != NULL;
541 }
542
543 void InputMethodEngineIBus::RegisterComponent() {
544 chromeos::IBusClient* client =
545 chromeos::DBusThreadManager::Get()->GetIBusClient();
546 client->RegisterComponent(
547 *component_.get(),
548 base::Bind(&InputMethodEngineIBus::OnComponentRegistered,
549 weak_ptr_factory_.GetWeakPtr()),
550 base::Bind(&InputMethodEngineIBus::OnComponentRegistrationFailed,
551 weak_ptr_factory_.GetWeakPtr()));
552 }
553
554 void InputMethodEngineIBus::OnComponentRegistered() {
555 DBusThreadManager::Get()->GetIBusEngineFactoryService()->
556 SetCreateEngineHandler(ibus_id_,
557 base::Bind(
558 &InputMethodEngineIBus::CreateEngineHandler,
559 weak_ptr_factory_.GetWeakPtr()));
560 }
561
562 void InputMethodEngineIBus::OnComponentRegistrationFailed() {
563 DVLOG(1) << "Failed to register input method components.";
564 // TODO(nona): Implement error handling.
565 }
566
567 void InputMethodEngineIBus::CreateEngineHandler(
568 const IBusEngineFactoryService::CreateEngineResponseSender& sender) {
569 DBusThreadManager::Get()->RemoveIBusEngineService(object_path_);
570
571 current_object_path_++;
572 object_path_ = dbus::ObjectPath(kObjectPathPrefix +
573 base::IntToString(current_object_path_));
574 GetCurrentService()->Initialize(this);
575 sender.Run(object_path_);
576 }
577
578 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698