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

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

Powered by Google App Engine
This is Rietveld 408576698