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.
5 #include "chromeos/dbus/ibus/ibus_input_context_client.h"
9 #include "base/callback.h"
10 #include "chromeos/dbus/ibus/ibus_constants.h"
11 #include "chromeos/dbus/ibus/ibus_engine_service.h"
12 #include "chromeos/dbus/ibus/ibus_panel_service.h"
13 #include "chromeos/dbus/ibus/ibus_text.h"
14 #include "chromeos/ime/ibus_bridge.h"
16 #include "dbus/message.h"
17 #include "dbus/object_path.h"
18 #include "dbus/object_proxy.h"
22 using chromeos::IBusText
;
26 // The IBusInputContextClient implementation.
27 class IBusInputContextClientImpl
: public IBusInputContextClient
{
29 IBusInputContextClientImpl()
32 weak_ptr_factory_(this) {
35 virtual ~IBusInputContextClientImpl() {}
38 // IBusInputContextClient override.
39 virtual void Initialize(dbus::Bus
* bus
,
40 const dbus::ObjectPath
& object_path
) OVERRIDE
{
42 LOG(ERROR
) << "IBusInputContextClient is already initialized.";
45 proxy_
= bus
->GetObjectProxy(ibus::kServiceName
, object_path
);
50 // IBusInputContextClient override.
51 virtual void SetInputContextHandler(
52 IBusInputContextHandlerInterface
* handler
) OVERRIDE
{
56 // IBusInputContextClient override.
57 virtual void SetSetCursorLocationHandler(
58 const SetCursorLocationHandler
& set_cursor_location_handler
) OVERRIDE
{
59 DCHECK(!set_cursor_location_handler
.is_null());
60 set_cursor_location_handler_
= set_cursor_location_handler
;
63 // IBusInputContextClient override.
64 virtual void UnsetSetCursorLocationHandler() OVERRIDE
{
65 set_cursor_location_handler_
.Reset();
68 // IBusInputContextClient override.
69 virtual void ResetObjectProxy() OVERRIDE
{
70 // Do not delete proxy here, proxy object is managed by dbus::Bus object.
74 // IBusInputContextClient override.
75 virtual bool IsObjectProxyReady() const OVERRIDE
{
76 return proxy_
!= NULL
;
79 // IBusInputContextClient override.
80 virtual void SetCapabilities(uint32 capabilities
) OVERRIDE
{
81 dbus::MethodCall
method_call(ibus::input_context::kServiceInterface
,
82 ibus::input_context::kSetCapabilitiesMethod
);
83 dbus::MessageWriter
writer(&method_call
);
84 writer
.AppendUint32(capabilities
);
85 CallNoResponseMethod(&method_call
,
86 ibus::input_context::kSetCapabilitiesMethod
);
89 // IBusInputContextClient override.
90 virtual void FocusIn() OVERRIDE
{
91 dbus::MethodCall
method_call(ibus::input_context::kServiceInterface
,
92 ibus::input_context::kFocusInMethod
);
93 CallNoResponseMethod(&method_call
, ibus::input_context::kFocusInMethod
);
96 // IBusInputContextClient override.
97 virtual void FocusOut() OVERRIDE
{
98 dbus::MethodCall
method_call(ibus::input_context::kServiceInterface
,
99 ibus::input_context::kFocusOutMethod
);
100 CallNoResponseMethod(&method_call
, ibus::input_context::kFocusOutMethod
);
103 // IBusInputContextClient override.
104 virtual void Reset() OVERRIDE
{
105 dbus::MethodCall
method_call(ibus::input_context::kServiceInterface
,
106 ibus::input_context::kResetMethod
);
107 CallNoResponseMethod(&method_call
, ibus::input_context::kResetMethod
);
110 // IBusInputContextClient override.
111 virtual void SetCursorLocation(const ibus::Rect
& cursor_location
,
112 const ibus::Rect
& composition_head
) OVERRIDE
{
113 if (!set_cursor_location_handler_
.is_null())
114 set_cursor_location_handler_
.Run(cursor_location
, composition_head
);
117 // IBusInputContextClient override.
118 virtual void ProcessKeyEvent(
122 const ProcessKeyEventCallback
& callback
,
123 const ErrorCallback
& error_callback
) OVERRIDE
{
124 dbus::MethodCall
method_call(ibus::input_context::kServiceInterface
,
125 ibus::input_context::kProcessKeyEventMethod
);
126 dbus::MessageWriter
writer(&method_call
);
127 writer
.AppendUint32(keyval
);
128 writer
.AppendUint32(keycode
);
129 writer
.AppendUint32(state
);
130 proxy_
->CallMethodWithErrorCallback(
132 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
133 base::Bind(&IBusInputContextClientImpl::OnProcessKeyEvent
,
136 base::Bind(&IBusInputContextClientImpl::OnProecessKeyEventFail
,
140 // IBusInputContextClient override.
141 virtual void SetSurroundingText(const std::string
& text
,
143 uint32 end_index
) OVERRIDE
{
144 dbus::MethodCall
method_call(
145 ibus::input_context::kServiceInterface
,
146 ibus::input_context::kSetSurroundingTextMethod
);
147 dbus::MessageWriter
writer(&method_call
);
148 AppendStringAsIBusText(text
, &writer
);
149 writer
.AppendUint32(start_index
);
150 writer
.AppendUint32(end_index
);
151 CallNoResponseMethod(&method_call
,
152 ibus::input_context::kSetSurroundingTextMethod
);
155 // IBusInputContextClient override.
156 virtual void PropertyActivate(const std::string
& key
,
157 ibus::IBusPropertyState state
) OVERRIDE
{
158 dbus::MethodCall
method_call(ibus::input_context::kServiceInterface
,
159 ibus::input_context::kPropertyActivateMethod
);
160 dbus::MessageWriter
writer(&method_call
);
161 writer
.AppendString(key
);
162 if (state
== ibus::IBUS_PROPERTY_STATE_CHECKED
) {
163 writer
.AppendUint32(ibus::IBUS_PROPERTY_STATE_CHECKED
);
165 writer
.AppendUint32(ibus::IBUS_PROPERTY_STATE_UNCHECKED
);
167 CallNoResponseMethod(&method_call
,
168 ibus::input_context::kPropertyActivateMethod
);
171 // IBusInputContextClient override.
172 virtual bool IsXKBLayout() OVERRIDE
{
173 return is_xkb_layout_
;
176 // IBusInputContextClient override.
177 virtual void SetIsXKBLayout(bool is_xkb_layout
) OVERRIDE
{
178 is_xkb_layout_
= is_xkb_layout
;
182 void CallNoResponseMethod(dbus::MethodCall
* method_call
,
183 const std::string
& method_name
) {
184 proxy_
->CallMethodWithErrorCallback(
186 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
187 base::Bind(&IBusInputContextClientImpl::DefaultCallback
,
189 base::Bind(&IBusInputContextClientImpl::DefaultErrorCallback
,
193 // Handles no response method call reply.
194 static void DefaultCallback(const std::string
& method_name
,
195 dbus::Response
* response
) {
197 LOG(ERROR
) << "Failed to call method: " << method_name
;
202 // Handles error response of default method call.
203 static void DefaultErrorCallback(const std::string
& method_name
,
204 dbus::ErrorResponse
* response
) {
205 LOG(ERROR
) << "Failed to call method: " << method_name
;
208 // Handles ProcessKeyEvent method call reply.
209 static void OnProcessKeyEvent(const ProcessKeyEventCallback
& callback
,
210 const ErrorCallback
& error_callback
,
211 dbus::Response
* response
) {
213 LOG(ERROR
) << "Cannot get input context: " << response
->ToString();
214 error_callback
.Run();
217 dbus::MessageReader
reader(response
);
218 bool is_keyevent_used
;
219 if (!reader
.PopBool(&is_keyevent_used
)) {
220 // The IBus message structure may be changed.
221 LOG(ERROR
) << "Invalid response: " << response
->ToString();
222 error_callback
.Run();
225 DCHECK(!callback
.is_null());
226 callback
.Run(is_keyevent_used
);
229 // Handles error response of ProcessKeyEvent method call.
230 static void OnProecessKeyEventFail(const ErrorCallback
& error_callback
,
231 dbus::ErrorResponse
* response
) {
232 error_callback
.Run();
235 // Handles CommitText signal.
236 void OnCommitText(dbus::Signal
* signal
) {
239 dbus::MessageReader
reader(signal
);
241 if (!PopIBusText(&reader
, &ibus_text
)) {
242 // The IBus message structure may be changed.
243 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
246 handler_
->CommitText(ibus_text
);
249 // Handles ForwardKeyEvetn signal.
250 void OnForwardKeyEvent(dbus::Signal
* signal
) {
253 dbus::MessageReader
reader(signal
);
257 if (!reader
.PopUint32(&keyval
) ||
258 !reader
.PopUint32(&keycode
) ||
259 !reader
.PopUint32(&state
)) {
260 // The IBus message structure may be changed.
261 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
264 handler_
->ForwardKeyEvent(keyval
, keycode
, state
);
267 // Handles UpdatePreeditText signal.
268 void OnUpdatePreeditText(dbus::Signal
* signal
) {
271 dbus::MessageReader
reader(signal
);
273 uint32 cursor_pos
= 0;
275 if (!PopIBusText(&reader
, &ibus_text
) ||
276 !reader
.PopUint32(&cursor_pos
) ||
277 !reader
.PopBool(&visible
)) {
278 // The IBus message structure may be changed.
279 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
282 handler_
->UpdatePreeditText(ibus_text
, cursor_pos
, visible
);
285 // Handles ShowPreeditText signal.
286 void OnShowPreeditText(dbus::Signal
* signal
) {
288 handler_
->ShowPreeditText();
291 // Handles HidePreeditText signal.
292 void OnHidePreeditText(dbus::Signal
* signal
) {
294 handler_
->HidePreeditText();
297 // Connects signals to signal handlers.
298 void ConnectSignals() {
299 proxy_
->ConnectToSignal(
300 ibus::input_context::kServiceInterface
,
301 ibus::input_context::kCommitTextSignal
,
302 base::Bind(&IBusInputContextClientImpl::OnCommitText
,
303 weak_ptr_factory_
.GetWeakPtr()),
304 base::Bind(&IBusInputContextClientImpl::OnSignalConnected
,
305 weak_ptr_factory_
.GetWeakPtr()));
307 proxy_
->ConnectToSignal(
308 ibus::input_context::kServiceInterface
,
309 ibus::input_context::kForwardKeyEventSignal
,
310 base::Bind(&IBusInputContextClientImpl::OnForwardKeyEvent
,
311 weak_ptr_factory_
.GetWeakPtr()),
312 base::Bind(&IBusInputContextClientImpl::OnSignalConnected
,
313 weak_ptr_factory_
.GetWeakPtr()));
315 proxy_
->ConnectToSignal(
316 ibus::input_context::kServiceInterface
,
317 ibus::input_context::kUpdatePreeditTextSignal
,
318 base::Bind(&IBusInputContextClientImpl::OnUpdatePreeditText
,
319 weak_ptr_factory_
.GetWeakPtr()),
320 base::Bind(&IBusInputContextClientImpl::OnSignalConnected
,
321 weak_ptr_factory_
.GetWeakPtr()));
323 proxy_
->ConnectToSignal(
324 ibus::input_context::kServiceInterface
,
325 ibus::input_context::kShowPreeditTextSignal
,
326 base::Bind(&IBusInputContextClientImpl::OnShowPreeditText
,
327 weak_ptr_factory_
.GetWeakPtr()),
328 base::Bind(&IBusInputContextClientImpl::OnSignalConnected
,
329 weak_ptr_factory_
.GetWeakPtr()));
331 proxy_
->ConnectToSignal(
332 ibus::input_context::kServiceInterface
,
333 ibus::input_context::kHidePreeditTextSignal
,
334 base::Bind(&IBusInputContextClientImpl::OnHidePreeditText
,
335 weak_ptr_factory_
.GetWeakPtr()),
336 base::Bind(&IBusInputContextClientImpl::OnSignalConnected
,
337 weak_ptr_factory_
.GetWeakPtr()));
340 // Handles the result of signal connection setup.
341 void OnSignalConnected(const std::string
& interface
,
342 const std::string
& signal
,
344 LOG_IF(ERROR
, !succeeded
) << "Connect to " << interface
<< " "
345 << signal
<< " failed.";
348 dbus::ObjectProxy
* proxy_
;
350 // The pointer for input context handler. This can be NULL.
351 IBusInputContextHandlerInterface
* handler_
;
353 SetCursorLocationHandler set_cursor_location_handler_
;
355 // True if the current input method is xkb layout.
358 base::WeakPtrFactory
<IBusInputContextClientImpl
> weak_ptr_factory_
;
360 DISALLOW_COPY_AND_ASSIGN(IBusInputContextClientImpl
);
363 // An implementation of IBusInputContextClient without ibus-daemon interaction.
364 // Currently this class is used only on linux desktop.
365 // TODO(nona): Use this on ChromeOS device once crbug.com/171351 is fixed.
366 class IBusInputContextClientDaemonlessImpl
: public IBusInputContextClient
{
368 IBusInputContextClientDaemonlessImpl()
369 : is_xkb_layout_(true),
372 virtual ~IBusInputContextClientDaemonlessImpl() {}
374 // IBusInputContextClient override.
375 virtual void Initialize(dbus::Bus
* bus
,
376 const dbus::ObjectPath
& object_path
) OVERRIDE
{
380 virtual void SetInputContextHandler(
381 IBusInputContextHandlerInterface
* handler
) OVERRIDE
{
382 IBusBridge::Get()->SetInputContextHandler(handler
);
385 virtual void SetSetCursorLocationHandler(
386 const SetCursorLocationHandler
& set_cursor_location_handler
) OVERRIDE
{
389 virtual void UnsetSetCursorLocationHandler() OVERRIDE
{
392 virtual void ResetObjectProxy() OVERRIDE
{
393 initialized_
= false;
396 virtual bool IsObjectProxyReady() const OVERRIDE
{
400 virtual void SetCapabilities(uint32 capability
) OVERRIDE
{
401 IBusEngineHandlerInterface
* engine
= IBusBridge::Get()->GetEngineHandler();
403 engine
->SetCapability(
404 static_cast<IBusEngineHandlerInterface::IBusCapability
>(capability
));
407 virtual void FocusIn() OVERRIDE
{
408 IBusEngineHandlerInterface
* engine
= IBusBridge::Get()->GetEngineHandler();
413 virtual void FocusOut() OVERRIDE
{
414 IBusEngineHandlerInterface
* engine
= IBusBridge::Get()->GetEngineHandler();
419 virtual void Reset() OVERRIDE
{
420 IBusEngineHandlerInterface
* engine
= IBusBridge::Get()->GetEngineHandler();
425 virtual void SetCursorLocation(const ibus::Rect
& cursor_location
,
426 const ibus::Rect
& composition_head
) OVERRIDE
{
427 IBusPanelCandidateWindowHandlerInterface
* candidate_window
=
428 IBusBridge::Get()->GetCandidateWindowHandler();
430 if (candidate_window
)
431 candidate_window
->SetCursorLocation(cursor_location
, composition_head
);
434 virtual void ProcessKeyEvent(
438 const ProcessKeyEventCallback
& callback
,
439 const ErrorCallback
& error_callback
) OVERRIDE
{
440 IBusEngineHandlerInterface
* engine
= IBusBridge::Get()->GetEngineHandler();
442 engine
->ProcessKeyEvent(keyval
, keycode
, state
, callback
);
445 virtual void SetSurroundingText(const std::string
& text
,
447 uint32 end_index
) OVERRIDE
{
448 // TODO(nona): Implement this.
451 virtual void PropertyActivate(const std::string
& key
,
452 ibus::IBusPropertyState state
) OVERRIDE
{
453 IBusEngineHandlerInterface
* engine
= IBusBridge::Get()->GetEngineHandler();
455 engine
->PropertyActivate(key
,
456 static_cast<ibus::IBusPropertyState
>(state
));
459 virtual bool IsXKBLayout() OVERRIDE
{
460 return is_xkb_layout_
;
463 virtual void SetIsXKBLayout(bool is_xkb_layout
) OVERRIDE
{
464 is_xkb_layout_
= is_xkb_layout
;
468 // True if the current input method is xkb layout.
472 DISALLOW_COPY_AND_ASSIGN(IBusInputContextClientDaemonlessImpl
);
477 ///////////////////////////////////////////////////////////////////////////////
478 // IBusInputContextClient
480 IBusInputContextClient::IBusInputContextClient() {}
482 IBusInputContextClient::~IBusInputContextClient() {}
485 IBusInputContextClient
* IBusInputContextClient::Create(
486 DBusClientImplementationType type
) {
487 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
) {
488 return new IBusInputContextClientImpl();
490 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
491 return new IBusInputContextClientDaemonlessImpl();
493 } // namespace chromeos