Chromium Code Reviews| 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 "ui/base/ime/input_method_ibus.h" | 5 #include "ui/base/ime/input_method_ibus.h" |
| 6 | 6 |
| 7 #include <X11/X.h> | 7 #include <X11/X.h> |
| 8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
| 9 #include <X11/Xutil.h> | 9 #include <X11/Xutil.h> |
| 10 #undef FocusIn | 10 #undef FocusIn |
| 11 #undef FocusOut | 11 #undef FocusOut |
| 12 | 12 |
| 13 #include <algorithm> | 13 #include <algorithm> |
| 14 #include <cstring> | 14 #include <cstring> |
| 15 #include <set> | 15 #include <set> |
| 16 #include <vector> | 16 #include <vector> |
| 17 | 17 |
| 18 #include "base/basictypes.h" | 18 #include "base/basictypes.h" |
| 19 #include "base/bind.h" | 19 #include "base/bind.h" |
| 20 #include "base/i18n/char_iterator.h" | 20 #include "base/i18n/char_iterator.h" |
| 21 #include "base/logging.h" | 21 #include "base/logging.h" |
| 22 #include "base/string_util.h" | 22 #include "base/string_util.h" |
| 23 #include "base/third_party/icu/icu_utf.h" | 23 #include "base/third_party/icu/icu_utf.h" |
| 24 #include "base/utf_string_conversions.h" | 24 #include "base/utf_string_conversions.h" |
| 25 #include "chromeos/dbus/dbus_thread_manager.h" | 25 #include "chromeos/dbus/dbus_thread_manager.h" |
| 26 #include "chromeos/dbus/ibus/ibus_client.h" | |
| 26 #include "chromeos/dbus/ibus/ibus_input_context_client.h" | 27 #include "chromeos/dbus/ibus/ibus_input_context_client.h" |
| 27 #include "chromeos/dbus/ibus/ibus_text.h" | 28 #include "chromeos/dbus/ibus/ibus_text.h" |
| 28 #include "ui/base/events.h" | 29 #include "ui/base/events.h" |
| 29 #include "ui/base/ime/ibus_client_impl.h" | 30 #include "ui/base/ime/ibus_client.h" |
| 30 #include "ui/base/ime/text_input_client.h" | 31 #include "ui/base/ime/text_input_client.h" |
| 31 #include "ui/base/keycodes/keyboard_code_conversion.h" | 32 #include "ui/base/keycodes/keyboard_code_conversion.h" |
| 32 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | 33 #include "ui/base/keycodes/keyboard_code_conversion_x.h" |
| 33 #include "ui/base/keycodes/keyboard_codes.h" | 34 #include "ui/base/keycodes/keyboard_codes.h" |
| 34 #include "ui/gfx/rect.h" | 35 #include "ui/gfx/rect.h" |
| 35 | 36 |
| 36 namespace { | 37 namespace { |
| 37 | 38 |
| 38 const int kIBusReleaseMask = 1 << 30; | 39 const int kIBusReleaseMask = 1 << 30; |
| 40 const char kClientName[] = "chrome"; | |
| 41 | |
| 42 // Following capability mask is introduced from | |
| 43 // http://ibus.googlecode.com/svn/docs/ibus-1.4/ibus-ibustypes.html#IBusCapabili te | |
| 44 const uint32 kIBusCapabilityPreeditText = 1U; | |
| 45 const uint32 kIBusCapabilityFocus = 8U; | |
| 39 | 46 |
| 40 XKeyEvent* GetKeyEvent(XEvent* event) { | 47 XKeyEvent* GetKeyEvent(XEvent* event) { |
| 41 DCHECK(event && (event->type == KeyPress || event->type == KeyRelease)); | 48 DCHECK(event && (event->type == KeyPress || event->type == KeyRelease)); |
| 42 return &event->xkey; | 49 return &event->xkey; |
| 43 } | 50 } |
| 44 | 51 |
| 45 // Converts X (and ibus) flags to event flags. | 52 // Converts X (and ibus) flags to event flags. |
| 46 int EventFlagsFromXFlags(unsigned int flags) { | 53 int EventFlagsFromXFlags(unsigned int flags) { |
| 47 return (flags & LockMask ? ui::EF_CAPS_LOCK_DOWN : 0) | | 54 return (flags & LockMask ? ui::EF_CAPS_LOCK_DOWN : 0) | |
| 48 (flags & ControlMask ? ui::EF_CONTROL_DOWN : 0) | | 55 (flags & ControlMask ? ui::EF_CONTROL_DOWN : 0) | |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 70 // translate Shift and CapsLock states. | 77 // translate Shift and CapsLock states. |
| 71 KeySym keysym = NoSymbol; | 78 KeySym keysym = NoSymbol; |
| 72 ::XLookupString(x_key, NULL, 0, &keysym, NULL); | 79 ::XLookupString(x_key, NULL, 0, &keysym, NULL); |
| 73 *ibus_keyval = keysym; | 80 *ibus_keyval = keysym; |
| 74 *ibus_keycode = x_key->keycode; | 81 *ibus_keycode = x_key->keycode; |
| 75 *ibus_state = IBusStateFromXFlags(x_key->state); | 82 *ibus_state = IBusStateFromXFlags(x_key->state); |
| 76 if (native_event->type == KeyRelease) | 83 if (native_event->type == KeyRelease) |
| 77 *ibus_state |= kIBusReleaseMask; | 84 *ibus_state |= kIBusReleaseMask; |
| 78 } | 85 } |
| 79 | 86 |
| 87 chromeos::IBusInputContextClient* GetInputContextClient() { | |
| 88 chromeos::IBusInputContextClient* client = | |
| 89 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); | |
| 90 DCHECK(client->IsConnected()); | |
| 91 return client; | |
| 92 } | |
| 93 | |
| 80 } // namespace | 94 } // namespace |
| 81 | 95 |
| 82 namespace ui { | 96 namespace ui { |
| 83 | 97 |
| 84 // InputMethodIBus::PendingKeyEventImpl implementation ------------------------ | 98 // A class to hold all data related to a key event being processed by the input |
| 85 class InputMethodIBus::PendingKeyEventImpl | 99 // method but still has no result back yet. |
| 86 : public internal::IBusClient::PendingKeyEvent { | 100 class InputMethodIBus::PendingKeyEvent { |
| 87 public: | 101 public: |
| 88 PendingKeyEventImpl(InputMethodIBus* input_method, | 102 PendingKeyEvent(InputMethodIBus* input_method, |
| 89 const base::NativeEvent& native_event, | 103 const base::NativeEvent& native_event, |
| 90 uint32 ibus_keyval); | 104 uint32 ibus_keyval); |
| 91 virtual ~PendingKeyEventImpl(); | 105 virtual ~PendingKeyEvent(); |
| 92 | 106 |
| 93 // internal::IBusClient::PendingKeyEvent overrides: | 107 // Process this pending key event after we receive its result from the input |
| 94 virtual void ProcessPostIME(bool handled) OVERRIDE; | 108 // method. It just call through InputMethodIBus::ProcessKeyEventPostIME(). |
| 109 void ProcessPostIME(bool handled); | |
| 95 | 110 |
| 96 // Abandon this pending key event. Its result will just be discarded. | 111 // Abandon this pending key event. Its result will just be discarded. |
| 97 void Abandon() { input_method_ = NULL; } | 112 void Abandon() { input_method_ = NULL; } |
| 98 | 113 |
| 99 InputMethodIBus* input_method() const { return input_method_; } | 114 InputMethodIBus* input_method() const { return input_method_; } |
| 100 | 115 |
| 101 private: | 116 private: |
| 102 InputMethodIBus* input_method_; | 117 InputMethodIBus* input_method_; |
| 103 | 118 |
| 104 // TODO(yusukes): To support a fabricated key event (which is typically from | 119 // TODO(yusukes): To support a fabricated key event (which is typically from |
| 105 // a virtual keyboard), we might have to copy event type, event flags, key | 120 // a virtual keyboard), we might have to copy event type, event flags, key |
| 106 // code, 'character_', and 'unmodified_character_'. See views::InputMethodIBus | 121 // code, 'character_', and 'unmodified_character_'. See views::InputMethodIBus |
| 107 // for details. | 122 // for details. |
| 108 | 123 |
| 109 // corresponding XEvent data of a key event. It's a plain struct so we can do | 124 // corresponding XEvent data of a key event. It's a plain struct so we can do |
| 110 // bitwise copy. | 125 // bitwise copy. |
| 111 XKeyEvent x_event_; | 126 XKeyEvent x_event_; |
| 112 | 127 |
| 113 const uint32 ibus_keyval_; | 128 const uint32 ibus_keyval_; |
| 114 | 129 |
| 115 DISALLOW_COPY_AND_ASSIGN(PendingKeyEventImpl); | 130 DISALLOW_COPY_AND_ASSIGN(PendingKeyEvent); |
| 116 }; | 131 }; |
| 117 | 132 |
| 118 InputMethodIBus::PendingKeyEventImpl::PendingKeyEventImpl( | 133 InputMethodIBus::PendingKeyEvent::PendingKeyEvent( |
| 119 InputMethodIBus* input_method, | 134 InputMethodIBus* input_method, |
| 120 const base::NativeEvent& native_event, | 135 const base::NativeEvent& native_event, |
| 121 uint32 ibus_keyval) | 136 uint32 ibus_keyval) |
| 122 : input_method_(input_method), | 137 : input_method_(input_method), |
| 123 ibus_keyval_(ibus_keyval) { | 138 ibus_keyval_(ibus_keyval) { |
| 124 DCHECK(input_method_); | 139 DCHECK(input_method_); |
| 125 | 140 |
| 126 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). | 141 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| 127 DCHECK(native_event); | 142 DCHECK(native_event); |
| 128 x_event_ = *GetKeyEvent(native_event); | 143 x_event_ = *GetKeyEvent(native_event); |
| 129 } | 144 } |
| 130 | 145 |
| 131 InputMethodIBus::PendingKeyEventImpl::~PendingKeyEventImpl() { | 146 InputMethodIBus::PendingKeyEvent::~PendingKeyEvent() { |
| 132 if (input_method_) | 147 if (input_method_) |
| 133 input_method_->FinishPendingKeyEvent(this); | 148 input_method_->FinishPendingKeyEvent(this); |
| 134 } | 149 } |
| 135 | 150 |
| 136 void InputMethodIBus::PendingKeyEventImpl::ProcessPostIME(bool handled) { | 151 void InputMethodIBus::PendingKeyEvent::ProcessPostIME(bool handled) { |
| 137 if (!input_method_) | 152 if (!input_method_) |
| 138 return; | 153 return; |
| 139 | 154 |
| 140 if (x_event_.type == KeyPress || x_event_.type == KeyRelease) { | 155 if (x_event_.type == KeyPress || x_event_.type == KeyRelease) { |
| 141 input_method_->ProcessKeyEventPostIME(reinterpret_cast<XEvent*>(&x_event_), | 156 input_method_->ProcessKeyEventPostIME(reinterpret_cast<XEvent*>(&x_event_), |
| 142 ibus_keyval_, | 157 ibus_keyval_, |
| 143 handled); | 158 handled); |
| 144 return; | 159 return; |
| 145 } | 160 } |
| 146 | 161 |
| 147 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). | 162 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| 148 // See views::InputMethodIBus for details. Never forget to set 'character_' | 163 // See views::InputMethodIBus for details. Never forget to set 'character_' |
| 149 // and 'unmodified_character_' to support i18n VKs like a French VK! | 164 // and 'unmodified_character_' to support i18n VKs like a French VK! |
| 150 } | 165 } |
| 151 | 166 |
| 152 // InputMethodIBus::PendingCreateICRequestImpl implementation ----------------- | 167 // A class to hold information of a pending request for creating an ibus input |
| 153 class InputMethodIBus::PendingCreateICRequestImpl | 168 // context. |
| 154 : public internal::IBusClient::PendingCreateICRequest { | 169 class InputMethodIBus::PendingCreateICRequest { |
| 155 public: | 170 public: |
| 156 PendingCreateICRequestImpl(InputMethodIBus* input_method, | 171 PendingCreateICRequest(InputMethodIBus* input_method, |
| 157 internal::IBusClient* ibus_client, | 172 PendingCreateICRequest** request_ptr); |
| 158 PendingCreateICRequestImpl** request_ptr); | 173 virtual ~PendingCreateICRequest(); |
| 159 virtual ~PendingCreateICRequestImpl(); | |
| 160 | 174 |
| 161 // internal::IBusClient::PendingCreateICRequest overrides: | 175 // Set up signal handlers, or destroy object proxy if the input context is |
| 162 virtual void InitOrAbandonInputContext() OVERRIDE; | 176 // already abandoned. |
| 163 virtual void OnCreateInputContextFailed() OVERRIDE; | 177 void InitOrAbandonInputContext(); |
| 178 | |
| 179 // Called if the create input context method call is failed. | |
| 180 void OnCreateInputContextFailed(); | |
| 164 | 181 |
| 165 // Abandon this pending key event. Its result will just be discarded. | 182 // Abandon this pending key event. Its result will just be discarded. |
| 166 void Abandon() { | 183 void Abandon() { |
| 167 input_method_ = NULL; | 184 input_method_ = NULL; |
| 168 request_ptr_ = NULL; | 185 request_ptr_ = NULL; |
| 169 // Do not reset |ibus_client_| here. | 186 // Do not reset |ibus_client_| here. |
| 170 } | 187 } |
| 171 | 188 |
| 172 private: | 189 private: |
| 173 InputMethodIBus* input_method_; | 190 InputMethodIBus* input_method_; |
| 174 internal::IBusClient* ibus_client_; | 191 PendingCreateICRequest** request_ptr_; |
| 175 PendingCreateICRequestImpl** request_ptr_; | |
| 176 | 192 |
| 177 DISALLOW_COPY_AND_ASSIGN(PendingCreateICRequestImpl); | 193 DISALLOW_COPY_AND_ASSIGN(PendingCreateICRequest); |
| 178 }; | 194 }; |
| 179 | 195 |
| 180 InputMethodIBus::PendingCreateICRequestImpl::PendingCreateICRequestImpl( | 196 InputMethodIBus::PendingCreateICRequest::PendingCreateICRequest( |
| 181 InputMethodIBus* input_method, | 197 InputMethodIBus* input_method, |
| 182 internal::IBusClient* ibus_client, | 198 PendingCreateICRequest** request_ptr) |
| 183 PendingCreateICRequestImpl** request_ptr) | |
| 184 : input_method_(input_method), | 199 : input_method_(input_method), |
| 185 ibus_client_(ibus_client), | |
| 186 request_ptr_(request_ptr) { | 200 request_ptr_(request_ptr) { |
| 187 } | 201 } |
| 188 | 202 |
| 189 InputMethodIBus::PendingCreateICRequestImpl::~PendingCreateICRequestImpl() { | 203 InputMethodIBus::PendingCreateICRequest::~PendingCreateICRequest() { |
| 190 if (request_ptr_) { | 204 if (request_ptr_) { |
| 191 DCHECK_EQ(*request_ptr_, this); | 205 DCHECK_EQ(*request_ptr_, this); |
| 192 *request_ptr_ = NULL; | 206 *request_ptr_ = NULL; |
| 193 } | 207 } |
| 194 } | 208 } |
| 195 | 209 |
| 196 void InputMethodIBus::PendingCreateICRequestImpl::OnCreateInputContextFailed() { | 210 void InputMethodIBus::PendingCreateICRequest::OnCreateInputContextFailed() { |
| 197 // TODO(nona): If the connection between Chrome and ibus-daemon terminates | 211 // TODO(nona): If the connection between Chrome and ibus-daemon terminates |
| 198 // for some reason, the create ic request will fail. We might want to call | 212 // for some reason, the create ic request will fail. We might want to call |
| 199 // ibus_client_->CreateContext() again after some delay. | 213 // ibus_client_->CreateContext() again after some delay. |
| 200 } | 214 } |
| 201 | 215 |
| 202 void InputMethodIBus::PendingCreateICRequestImpl::InitOrAbandonInputContext() { | 216 void InputMethodIBus::PendingCreateICRequest::InitOrAbandonInputContext() { |
| 203 if (input_method_) { | 217 if (input_method_) { |
| 204 DCHECK(ibus_client_->IsContextReady()); | 218 DCHECK(input_method_->IsContextReady()); |
| 205 input_method_->SetUpSignalHandlers(); | 219 input_method_->SetUpSignalHandlers(); |
| 206 } else { | 220 } else { |
| 207 ibus_client_->DestroyProxy(); | 221 GetInputContextClient()->ResetObjectProxy(); |
| 208 DCHECK(!ibus_client_->IsContextReady()); | |
| 209 } | 222 } |
| 210 } | 223 } |
| 211 | 224 |
| 212 // InputMethodIBus implementation ----------------------------------------- | 225 // InputMethodIBus implementation ----------------------------------------- |
| 213 InputMethodIBus::InputMethodIBus( | 226 InputMethodIBus::InputMethodIBus( |
| 214 internal::InputMethodDelegate* delegate) | 227 internal::InputMethodDelegate* delegate) |
| 215 : | 228 : ibus_client_(new internal::IBusClient()), |
|
Yusuke Sato
2012/06/25 13:41:33
omit () for style consistency
Seigo Nonaka
2012/06/28 03:43:03
Done.
| |
| 216 ibus_client_(new internal::IBusClientImpl), | |
| 217 pending_create_ic_request_(NULL), | 229 pending_create_ic_request_(NULL), |
| 218 context_focused_(false), | 230 context_focused_(false), |
| 219 composing_text_(false), | 231 composing_text_(false), |
| 220 composition_changed_(false), | 232 composition_changed_(false), |
| 221 suppress_next_result_(false), | 233 suppress_next_result_(false), |
| 222 weak_ptr_factory_(this) { | 234 weak_ptr_factory_(this) { |
| 223 SetDelegate(delegate); | 235 SetDelegate(delegate); |
| 224 } | 236 } |
| 225 | 237 |
| 226 InputMethodIBus::~InputMethodIBus() { | 238 InputMethodIBus::~InputMethodIBus() { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 247 InputMethodBase::OnBlur(); | 259 InputMethodBase::OnBlur(); |
| 248 UpdateContextFocusState(); | 260 UpdateContextFocusState(); |
| 249 } | 261 } |
| 250 | 262 |
| 251 void InputMethodIBus::Init(bool focused) { | 263 void InputMethodIBus::Init(bool focused) { |
| 252 // Initializes the connection to ibus daemon. It may happen asynchronously, | 264 // Initializes the connection to ibus daemon. It may happen asynchronously, |
| 253 // and as soon as the connection is established, the |context_| will be | 265 // and as soon as the connection is established, the |context_| will be |
| 254 // created automatically. | 266 // created automatically. |
| 255 | 267 |
| 256 // Create the input context if the connection is already established. | 268 // Create the input context if the connection is already established. |
| 257 if (ibus_client_->IsConnected()) | 269 if (IsConnected()) |
| 258 CreateContext(); | 270 CreateContext(); |
| 259 | 271 |
| 260 InputMethodBase::Init(focused); | 272 InputMethodBase::Init(focused); |
| 261 } | 273 } |
| 262 | 274 |
| 263 // static | 275 // static |
| 264 void InputMethodIBus::ProcessKeyEventDone( | 276 void InputMethodIBus::ProcessKeyEventDone( |
| 265 PendingKeyEventImpl* pending_key_event, bool is_handled) { | 277 PendingKeyEvent* pending_key_event, bool is_handled) { |
| 266 DCHECK(pending_key_event); | 278 DCHECK(pending_key_event); |
| 267 pending_key_event->ProcessPostIME(is_handled); | 279 pending_key_event->ProcessPostIME(is_handled); |
| 268 delete pending_key_event; | 280 delete pending_key_event; |
| 269 } | 281 } |
| 270 | 282 |
| 271 void InputMethodIBus::DispatchKeyEvent(const base::NativeEvent& native_event) { | 283 void InputMethodIBus::DispatchKeyEvent(const base::NativeEvent& native_event) { |
| 272 DCHECK(native_event && (native_event->type == KeyPress || | 284 DCHECK(native_event && (native_event->type == KeyPress || |
| 273 native_event->type == KeyRelease)); | 285 native_event->type == KeyRelease)); |
| 274 DCHECK(system_toplevel_window_focused()); | 286 DCHECK(system_toplevel_window_focused()); |
| 275 | 287 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 288 GetTextInputType() == TEXT_INPUT_TYPE_PASSWORD || | 300 GetTextInputType() == TEXT_INPUT_TYPE_PASSWORD || |
| 289 ibus_client_->GetInputMethodType() == | 301 ibus_client_->GetInputMethodType() == |
| 290 internal::IBusClient::INPUT_METHOD_XKB_LAYOUT) { | 302 internal::IBusClient::INPUT_METHOD_XKB_LAYOUT) { |
| 291 if (native_event->type == KeyPress) | 303 if (native_event->type == KeyPress) |
| 292 ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); | 304 ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); |
| 293 else | 305 else |
| 294 DispatchKeyEventPostIME(native_event); | 306 DispatchKeyEventPostIME(native_event); |
| 295 return; | 307 return; |
| 296 } | 308 } |
| 297 | 309 |
| 298 PendingKeyEventImpl* pending_key = | 310 PendingKeyEvent* pending_key = |
| 299 new PendingKeyEventImpl(this, native_event, ibus_keyval); | 311 new PendingKeyEvent(this, native_event, ibus_keyval); |
| 300 pending_key_events_.insert(pending_key); | 312 pending_key_events_.insert(pending_key); |
| 301 | 313 |
| 302 ibus_client_->SendKeyEvent(ibus_keyval, | 314 GetInputContextClient()->ProcessKeyEvent( |
| 303 ibus_keycode, | 315 ibus_keyval, |
| 304 ibus_state, | 316 ibus_keycode, |
| 305 base::Bind(&InputMethodIBus::ProcessKeyEventDone, | 317 ibus_state, base::Bind(&InputMethodIBus::ProcessKeyEventDone, |
| 306 base::Unretained(pending_key))); | 318 base::Unretained(pending_key))); |
| 307 | 319 |
| 308 // We don't want to suppress the result generated by this key event, but it | 320 // We don't want to suppress the result generated by this key event, but it |
| 309 // may cause problem. See comment in ResetContext() method. | 321 // may cause problem. See comment in ResetContext() method. |
| 310 suppress_next_result_ = false; | 322 suppress_next_result_ = false; |
| 311 } | 323 } |
| 312 | 324 |
| 313 void InputMethodIBus::OnTextInputTypeChanged(const TextInputClient* client) { | 325 void InputMethodIBus::OnTextInputTypeChanged(const TextInputClient* client) { |
| 314 if (ibus_client_->IsContextReady() && IsTextInputClientFocused(client)) { | 326 if (IsContextReady() && IsTextInputClientFocused(client)) { |
| 315 ResetContext(); | 327 ResetContext(); |
| 316 UpdateContextFocusState(); | 328 UpdateContextFocusState(); |
| 317 } | 329 } |
| 318 InputMethodBase::OnTextInputTypeChanged(client); | 330 InputMethodBase::OnTextInputTypeChanged(client); |
| 319 } | 331 } |
| 320 | 332 |
| 321 void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) { | 333 void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) { |
| 322 if (!context_focused_ || !IsTextInputClientFocused(client)) | 334 if (!context_focused_ || !IsTextInputClientFocused(client)) |
| 323 return; | 335 return; |
| 324 | 336 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 367 // focus and after it acquires focus again are the same. | 379 // focus and after it acquires focus again are the same. |
| 368 OnTextInputTypeChanged(focused); | 380 OnTextInputTypeChanged(focused); |
| 369 | 381 |
| 370 UpdateContextFocusState(); | 382 UpdateContextFocusState(); |
| 371 // Force to update caret bounds, in case the client thinks that the caret | 383 // Force to update caret bounds, in case the client thinks that the caret |
| 372 // bounds has not changed. | 384 // bounds has not changed. |
| 373 OnCaretBoundsChanged(focused); | 385 OnCaretBoundsChanged(focused); |
| 374 } | 386 } |
| 375 | 387 |
| 376 void InputMethodIBus::CreateContext() { | 388 void InputMethodIBus::CreateContext() { |
| 377 DCHECK(ibus_client_->IsConnected()); | 389 DCHECK(IsConnected()); |
| 378 DCHECK(!pending_create_ic_request_); | 390 DCHECK(!pending_create_ic_request_); |
| 379 | 391 |
| 392 pending_create_ic_request_ = new PendingCreateICRequest( | |
| 393 this, &pending_create_ic_request_); | |
| 394 | |
| 380 // Creates the input context asynchronously. | 395 // Creates the input context asynchronously. |
| 381 pending_create_ic_request_ = new PendingCreateICRequestImpl( | 396 chromeos::DBusThreadManager::Get()->GetIBusClient()->CreateInputContext( |
| 382 this, ibus_client_.get(), &pending_create_ic_request_); | 397 kClientName, |
| 383 ibus_client_->CreateContext(pending_create_ic_request_); | 398 base::Bind(&InputMethodIBus::CreateInputContextDone, |
| 399 weak_ptr_factory_.GetWeakPtr(), | |
| 400 base::Unretained(pending_create_ic_request_)), | |
| 401 base::Bind(&InputMethodIBus::CreateInputContextFail, | |
| 402 weak_ptr_factory_.GetWeakPtr(), | |
| 403 base::Unretained(pending_create_ic_request_))); | |
| 384 } | 404 } |
| 385 | 405 |
| 386 void InputMethodIBus::SetUpSignalHandlers() { | 406 void InputMethodIBus::SetUpSignalHandlers() { |
| 387 DCHECK(ibus_client_->IsContextReady()); | 407 DCHECK(IsContextReady()); |
| 388 | 408 |
| 389 // connect input context signals | 409 // connect input context signals |
| 390 chromeos::IBusInputContextClient* input_context_client = | 410 chromeos::IBusInputContextClient* input_context_client = |
| 391 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); | 411 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); |
| 392 input_context_client->SetCommitTextHandler( | 412 input_context_client->SetCommitTextHandler( |
| 393 base::Bind(&InputMethodIBus::OnCommitText, | 413 base::Bind(&InputMethodIBus::OnCommitText, |
| 394 weak_ptr_factory_.GetWeakPtr())); | 414 weak_ptr_factory_.GetWeakPtr())); |
| 395 | 415 |
| 396 input_context_client->SetForwardKeyEventHandler( | 416 input_context_client->SetForwardKeyEventHandler( |
| 397 base::Bind(&InputMethodIBus::OnForwardKeyEvent, | 417 base::Bind(&InputMethodIBus::OnForwardKeyEvent, |
| 398 weak_ptr_factory_.GetWeakPtr())); | 418 weak_ptr_factory_.GetWeakPtr())); |
| 399 | 419 |
| 400 input_context_client->SetUpdatePreeditTextHandler( | 420 input_context_client->SetUpdatePreeditTextHandler( |
| 401 base::Bind(&InputMethodIBus::OnUpdatePreeditText, | 421 base::Bind(&InputMethodIBus::OnUpdatePreeditText, |
| 402 weak_ptr_factory_.GetWeakPtr())); | 422 weak_ptr_factory_.GetWeakPtr())); |
| 403 | 423 |
| 404 input_context_client->SetShowPreeditTextHandler( | 424 input_context_client->SetShowPreeditTextHandler( |
| 405 base::Bind(&InputMethodIBus::OnShowPreeditText, | 425 base::Bind(&InputMethodIBus::OnShowPreeditText, |
| 406 weak_ptr_factory_.GetWeakPtr())); | 426 weak_ptr_factory_.GetWeakPtr())); |
| 407 | 427 |
| 408 input_context_client->SetHidePreeditTextHandler( | 428 input_context_client->SetHidePreeditTextHandler( |
| 409 base::Bind(&InputMethodIBus::OnHidePreeditText, | 429 base::Bind(&InputMethodIBus::OnHidePreeditText, |
| 410 weak_ptr_factory_.GetWeakPtr())); | 430 weak_ptr_factory_.GetWeakPtr())); |
| 411 | 431 |
| 412 ibus_client_->SetCapabilities(internal::IBusClient::INLINE_COMPOSITION); | 432 GetInputContextClient()->SetCapabilities( |
| 433 kIBusCapabilityPreeditText | kIBusCapabilityFocus); | |
| 413 | 434 |
| 414 UpdateContextFocusState(); | 435 UpdateContextFocusState(); |
| 415 // Since ibus-daemon is launched in an on-demand basis on Chrome OS, RWHVA (or | 436 // Since ibus-daemon is launched in an on-demand basis on Chrome OS, RWHVA (or |
| 416 // equivalents) might call OnCaretBoundsChanged() before the daemon starts. To | 437 // equivalents) might call OnCaretBoundsChanged() before the daemon starts. To |
| 417 // save the case, call OnCaretBoundsChanged() here. | 438 // save the case, call OnCaretBoundsChanged() here. |
| 418 OnCaretBoundsChanged(GetTextInputClient()); | 439 OnCaretBoundsChanged(GetTextInputClient()); |
| 419 OnInputMethodChanged(); | 440 OnInputMethodChanged(); |
| 420 } | 441 } |
| 421 | 442 |
| 422 void InputMethodIBus::DestroyContext() { | 443 void InputMethodIBus::DestroyContext() { |
| 423 if (pending_create_ic_request_) { | 444 if (pending_create_ic_request_) { |
| 424 DCHECK(!ibus_client_->IsContextReady()); | 445 DCHECK(!IsContextReady()); |
| 425 // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). | 446 // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). |
| 426 pending_create_ic_request_->Abandon(); | 447 pending_create_ic_request_->Abandon(); |
| 427 pending_create_ic_request_ = NULL; | 448 pending_create_ic_request_ = NULL; |
| 428 } else if (chromeos::DBusThreadManager::Get()->GetIBusInputContextClient() | 449 } else if (chromeos::DBusThreadManager::Get()->GetIBusInputContextClient() |
| 429 ->IsConnected()) { | 450 ->IsConnected()) { |
| 430 // We can't use IsContextReady here because we want to destroy input context | 451 // We can't use IsContextReady here because we want to destroy input context |
| 431 // due to connection lost here and IsContextReady contains connection check. | 452 // due to connection lost here and IsContextReady contains connection check. |
| 432 ResetInputContext(); | 453 ResetInputContext(); |
| 433 DCHECK(!ibus_client_->IsContextReady()); | 454 DCHECK(!IsContextReady()); |
| 434 } | 455 } |
| 435 } | 456 } |
| 436 | 457 |
| 437 void InputMethodIBus::ConfirmCompositionText() { | 458 void InputMethodIBus::ConfirmCompositionText() { |
| 438 TextInputClient* client = GetTextInputClient(); | 459 TextInputClient* client = GetTextInputClient(); |
| 439 if (client && client->HasCompositionText()) | 460 if (client && client->HasCompositionText()) |
| 440 client->ConfirmCompositionText(); | 461 client->ConfirmCompositionText(); |
| 441 | 462 |
| 442 ResetContext(); | 463 ResetContext(); |
| 443 } | 464 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 465 | 486 |
| 466 // We need to abandon all pending key events, but as above comment says, there | 487 // We need to abandon all pending key events, but as above comment says, there |
| 467 // is no reliable way to abandon all results generated by these abandoned key | 488 // is no reliable way to abandon all results generated by these abandoned key |
| 468 // events. | 489 // events. |
| 469 AbandonAllPendingKeyEvents(); | 490 AbandonAllPendingKeyEvents(); |
| 470 | 491 |
| 471 // This function runs asynchronously. | 492 // This function runs asynchronously. |
| 472 // Note: some input method engines may not support reset method, such as | 493 // Note: some input method engines may not support reset method, such as |
| 473 // ibus-anthy. But as we control all input method engines by ourselves, we can | 494 // ibus-anthy. But as we control all input method engines by ourselves, we can |
| 474 // make sure that all of the engines we are using support it correctly. | 495 // make sure that all of the engines we are using support it correctly. |
| 475 ibus_client_->Reset(); | 496 GetInputContextClient()->Reset(); |
| 476 | 497 |
| 477 character_composer_.Reset(); | 498 character_composer_.Reset(); |
| 478 } | 499 } |
| 479 | 500 |
| 480 void InputMethodIBus::UpdateContextFocusState() { | 501 void InputMethodIBus::UpdateContextFocusState() { |
| 481 if (!ibus_client_->IsContextReady()) { | 502 if (!IsContextReady()) { |
| 482 context_focused_ = false; | 503 context_focused_ = false; |
| 483 return; | 504 return; |
| 484 } | 505 } |
| 485 | 506 |
| 486 const bool old_context_focused = context_focused_; | 507 const bool old_context_focused = context_focused_; |
| 487 // Use switch here in case we are going to add more text input types. | 508 // Use switch here in case we are going to add more text input types. |
| 488 switch (GetTextInputType()) { | 509 switch (GetTextInputType()) { |
| 489 case TEXT_INPUT_TYPE_NONE: | 510 case TEXT_INPUT_TYPE_NONE: |
| 490 case TEXT_INPUT_TYPE_PASSWORD: | 511 case TEXT_INPUT_TYPE_PASSWORD: |
| 491 context_focused_ = false; | 512 context_focused_ = false; |
| 492 break; | 513 break; |
| 493 default: | 514 default: |
| 494 context_focused_ = true; | 515 context_focused_ = true; |
| 495 break; | 516 break; |
| 496 } | 517 } |
| 497 | 518 |
| 498 // We only focus in |context_| when the focus is in a normal textfield. | 519 // We only focus in |context_| when the focus is in a normal textfield. |
| 499 // ibus_input_context_focus_{in|out}() run asynchronously. | 520 // ibus_input_context_focus_{in|out}() run asynchronously. |
| 500 if (old_context_focused && !context_focused_) | 521 if (old_context_focused && !context_focused_) |
| 501 ibus_client_->FocusOut(); | 522 GetInputContextClient()->FocusOut(); |
| 502 else if (!old_context_focused && context_focused_) | 523 else if (!old_context_focused && context_focused_) |
| 503 ibus_client_->FocusIn(); | 524 GetInputContextClient()->FocusIn(); |
| 504 | 525 |
| 505 if (context_focused_) { | 526 if (context_focused_) { |
| 506 internal::IBusClient::InlineCompositionCapability capability = | 527 uint32 capability = kIBusCapabilityFocus; |
| 507 CanComposeInline() ? internal::IBusClient::INLINE_COMPOSITION | 528 if (CanComposeInline()) |
| 508 : internal::IBusClient::OFF_THE_SPOT_COMPOSITION; | 529 capability |= kIBusCapabilityPreeditText; |
| 509 ibus_client_->SetCapabilities(capability); | 530 GetInputContextClient()->SetCapabilities(capability); |
| 510 } | 531 } |
| 511 } | 532 } |
| 512 | 533 |
| 513 void InputMethodIBus::ProcessKeyEventPostIME( | 534 void InputMethodIBus::ProcessKeyEventPostIME( |
| 514 const base::NativeEvent& native_event, | 535 const base::NativeEvent& native_event, |
| 515 uint32 ibus_keyval, | 536 uint32 ibus_keyval, |
| 516 bool handled) { | 537 bool handled) { |
| 517 TextInputClient* client = GetTextInputClient(); | 538 TextInputClient* client = GetTextInputClient(); |
| 518 | 539 |
| 519 if (!client) { | 540 if (!client) { |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 692 bool InputMethodIBus::HasInputMethodResult() const { | 713 bool InputMethodIBus::HasInputMethodResult() const { |
| 693 return result_text_.length() || composition_changed_; | 714 return result_text_.length() || composition_changed_; |
| 694 } | 715 } |
| 695 | 716 |
| 696 void InputMethodIBus::SendFakeProcessKeyEvent(bool pressed) const { | 717 void InputMethodIBus::SendFakeProcessKeyEvent(bool pressed) const { |
| 697 DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, | 718 DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, |
| 698 VKEY_PROCESSKEY, | 719 VKEY_PROCESSKEY, |
| 699 0); | 720 0); |
| 700 } | 721 } |
| 701 | 722 |
| 702 void InputMethodIBus::FinishPendingKeyEvent(PendingKeyEventImpl* pending_key) { | 723 void InputMethodIBus::FinishPendingKeyEvent(PendingKeyEvent* pending_key) { |
| 703 DCHECK(pending_key_events_.count(pending_key)); | 724 DCHECK(pending_key_events_.count(pending_key)); |
| 704 | 725 |
| 705 // |pending_key| will be deleted in ProcessKeyEventDone(). | 726 // |pending_key| will be deleted in ProcessKeyEventDone(). |
| 706 pending_key_events_.erase(pending_key); | 727 pending_key_events_.erase(pending_key); |
| 707 } | 728 } |
| 708 | 729 |
| 709 void InputMethodIBus::AbandonAllPendingKeyEvents() { | 730 void InputMethodIBus::AbandonAllPendingKeyEvents() { |
| 710 std::set<PendingKeyEventImpl*>::iterator i; | 731 std::set<PendingKeyEvent*>::iterator i; |
| 711 for (i = pending_key_events_.begin(); i != pending_key_events_.end(); ++i) { | 732 for (i = pending_key_events_.begin(); i != pending_key_events_.end(); ++i) { |
| 712 // The object will be deleted in ProcessKeyEventDone(). | 733 // The object will be deleted in ProcessKeyEventDone(). |
| 713 (*i)->Abandon(); | 734 (*i)->Abandon(); |
| 714 } | 735 } |
| 715 pending_key_events_.clear(); | 736 pending_key_events_.clear(); |
| 716 } | 737 } |
| 717 | 738 |
| 718 void InputMethodIBus::OnCommitText(const chromeos::ibus::IBusText& text) { | 739 void InputMethodIBus::OnCommitText(const chromeos::ibus::IBusText& text) { |
| 719 if (suppress_next_result_ || text.text().empty()) | 740 if (suppress_next_result_ || text.text().empty()) |
| 720 return; | 741 return; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 827 } | 848 } |
| 828 } | 849 } |
| 829 | 850 |
| 830 void InputMethodIBus::ResetInputContext() { | 851 void InputMethodIBus::ResetInputContext() { |
| 831 context_focused_ = false; | 852 context_focused_ = false; |
| 832 | 853 |
| 833 ConfirmCompositionText(); | 854 ConfirmCompositionText(); |
| 834 | 855 |
| 835 // We are dead, so we need to ask the client to stop relying on us. | 856 // We are dead, so we need to ask the client to stop relying on us. |
| 836 OnInputMethodChanged(); | 857 OnInputMethodChanged(); |
| 837 ibus_client_->DestroyProxy(); | 858 GetInputContextClient()->ResetObjectProxy(); |
| 859 } | |
| 860 | |
| 861 void InputMethodIBus::CreateInputContextDone( | |
| 862 PendingCreateICRequest* ic_request, | |
| 863 const dbus::ObjectPath& object_path) { | |
| 864 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient() | |
| 865 ->Initialize(chromeos::DBusThreadManager::Get()->GetIBusBus(), | |
| 866 object_path); | |
| 867 ic_request->InitOrAbandonInputContext(); | |
| 868 delete ic_request; | |
| 869 } | |
| 870 | |
| 871 void InputMethodIBus::CreateInputContextFail( | |
| 872 PendingCreateICRequest* ic_request) { | |
| 873 ic_request->OnCreateInputContextFailed(); | |
| 874 delete ic_request; | |
| 875 } | |
| 876 | |
| 877 bool InputMethodIBus::IsConnected() { | |
| 878 return chromeos::DBusThreadManager::Get()->GetIBusBus() != NULL; | |
| 879 } | |
| 880 | |
| 881 bool InputMethodIBus::IsContextReady() { | |
| 882 return IsConnected() && | |
| 883 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient() | |
| 884 ->IsConnected(); | |
| 838 } | 885 } |
| 839 | 886 |
| 840 void InputMethodIBus::OnConnected() { | 887 void InputMethodIBus::OnConnected() { |
| 841 DCHECK(ibus_client_->IsConnected()); | 888 DCHECK(IsConnected()); |
| 842 // If already input context is initialized, do nothing. | 889 // If already input context is initialized, do nothing. |
| 843 if (ibus_client_->IsContextReady()) | 890 if (IsContextReady()) |
| 844 return; | 891 return; |
| 845 | 892 |
| 846 DestroyContext(); | 893 DestroyContext(); |
| 847 CreateContext(); | 894 CreateContext(); |
| 848 } | 895 } |
| 849 | 896 |
| 850 void InputMethodIBus::OnDisconnected() { | 897 void InputMethodIBus::OnDisconnected() { |
| 851 DestroyContext(); | 898 DestroyContext(); |
| 852 } | 899 } |
| 853 | 900 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 930 } | 977 } |
| 931 | 978 |
| 932 // Use a black thin underline by default. | 979 // Use a black thin underline by default. |
| 933 if (out_composition->underlines.empty()) { | 980 if (out_composition->underlines.empty()) { |
| 934 out_composition->underlines.push_back(CompositionUnderline( | 981 out_composition->underlines.push_back(CompositionUnderline( |
| 935 0, length, SK_ColorBLACK, false /* thick */)); | 982 0, length, SK_ColorBLACK, false /* thick */)); |
| 936 } | 983 } |
| 937 } | 984 } |
| 938 | 985 |
| 939 } // namespace ui | 986 } // namespace ui |
| OLD | NEW |