| 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 return chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); |
| 89 } |
| 90 |
| 80 } // namespace | 91 } // namespace |
| 81 | 92 |
| 82 namespace ui { | 93 namespace ui { |
| 83 | 94 |
| 84 // InputMethodIBus::PendingKeyEventImpl implementation ------------------------ | 95 // A class to hold all data related to a key event being processed by the input |
| 85 class InputMethodIBus::PendingKeyEventImpl | 96 // method but still has no result back yet. |
| 86 : public internal::IBusClient::PendingKeyEvent { | 97 class InputMethodIBus::PendingKeyEvent { |
| 87 public: | 98 public: |
| 88 PendingKeyEventImpl(InputMethodIBus* input_method, | 99 PendingKeyEvent(InputMethodIBus* input_method, |
| 89 const base::NativeEvent& native_event, | 100 const base::NativeEvent& native_event, |
| 90 uint32 ibus_keyval); | 101 uint32 ibus_keyval); |
| 91 virtual ~PendingKeyEventImpl(); | 102 virtual ~PendingKeyEvent(); |
| 92 | 103 |
| 93 // internal::IBusClient::PendingKeyEvent overrides: | 104 // Process this pending key event after we receive its result from the input |
| 94 virtual void ProcessPostIME(bool handled) OVERRIDE; | 105 // method. It just call through InputMethodIBus::ProcessKeyEventPostIME(). |
| 106 void ProcessPostIME(bool handled); |
| 95 | 107 |
| 96 // Abandon this pending key event. Its result will just be discarded. | 108 // Abandon this pending key event. Its result will just be discarded. |
| 97 void Abandon() { input_method_ = NULL; } | 109 void Abandon() { input_method_ = NULL; } |
| 98 | 110 |
| 99 InputMethodIBus* input_method() const { return input_method_; } | 111 InputMethodIBus* input_method() const { return input_method_; } |
| 100 | 112 |
| 101 private: | 113 private: |
| 102 InputMethodIBus* input_method_; | 114 InputMethodIBus* input_method_; |
| 103 | 115 |
| 104 // TODO(yusukes): To support a fabricated key event (which is typically from | 116 // 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 | 117 // a virtual keyboard), we might have to copy event type, event flags, key |
| 106 // code, 'character_', and 'unmodified_character_'. See views::InputMethodIBus | 118 // code, 'character_', and 'unmodified_character_'. See views::InputMethodIBus |
| 107 // for details. | 119 // for details. |
| 108 | 120 |
| 109 // corresponding XEvent data of a key event. It's a plain struct so we can do | 121 // corresponding XEvent data of a key event. It's a plain struct so we can do |
| 110 // bitwise copy. | 122 // bitwise copy. |
| 111 XKeyEvent x_event_; | 123 XKeyEvent x_event_; |
| 112 | 124 |
| 113 const uint32 ibus_keyval_; | 125 const uint32 ibus_keyval_; |
| 114 | 126 |
| 115 DISALLOW_COPY_AND_ASSIGN(PendingKeyEventImpl); | 127 DISALLOW_COPY_AND_ASSIGN(PendingKeyEvent); |
| 116 }; | 128 }; |
| 117 | 129 |
| 118 InputMethodIBus::PendingKeyEventImpl::PendingKeyEventImpl( | 130 InputMethodIBus::PendingKeyEvent::PendingKeyEvent( |
| 119 InputMethodIBus* input_method, | 131 InputMethodIBus* input_method, |
| 120 const base::NativeEvent& native_event, | 132 const base::NativeEvent& native_event, |
| 121 uint32 ibus_keyval) | 133 uint32 ibus_keyval) |
| 122 : input_method_(input_method), | 134 : input_method_(input_method), |
| 123 ibus_keyval_(ibus_keyval) { | 135 ibus_keyval_(ibus_keyval) { |
| 124 DCHECK(input_method_); | 136 DCHECK(input_method_); |
| 125 | 137 |
| 126 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). | 138 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| 127 DCHECK(native_event); | 139 DCHECK(native_event); |
| 128 x_event_ = *GetKeyEvent(native_event); | 140 x_event_ = *GetKeyEvent(native_event); |
| 129 } | 141 } |
| 130 | 142 |
| 131 InputMethodIBus::PendingKeyEventImpl::~PendingKeyEventImpl() { | 143 InputMethodIBus::PendingKeyEvent::~PendingKeyEvent() { |
| 132 if (input_method_) | 144 if (input_method_) |
| 133 input_method_->FinishPendingKeyEvent(this); | 145 input_method_->FinishPendingKeyEvent(this); |
| 134 } | 146 } |
| 135 | 147 |
| 136 void InputMethodIBus::PendingKeyEventImpl::ProcessPostIME(bool handled) { | 148 void InputMethodIBus::PendingKeyEvent::ProcessPostIME(bool handled) { |
| 137 if (!input_method_) | 149 if (!input_method_) |
| 138 return; | 150 return; |
| 139 | 151 |
| 140 if (x_event_.type == KeyPress || x_event_.type == KeyRelease) { | 152 if (x_event_.type == KeyPress || x_event_.type == KeyRelease) { |
| 141 input_method_->ProcessKeyEventPostIME(reinterpret_cast<XEvent*>(&x_event_), | 153 input_method_->ProcessKeyEventPostIME(reinterpret_cast<XEvent*>(&x_event_), |
| 142 ibus_keyval_, | 154 ibus_keyval_, |
| 143 handled); | 155 handled); |
| 144 return; | 156 return; |
| 145 } | 157 } |
| 146 | 158 |
| 147 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). | 159 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| 148 // See views::InputMethodIBus for details. Never forget to set 'character_' | 160 // See views::InputMethodIBus for details. Never forget to set 'character_' |
| 149 // and 'unmodified_character_' to support i18n VKs like a French VK! | 161 // and 'unmodified_character_' to support i18n VKs like a French VK! |
| 150 } | 162 } |
| 151 | 163 |
| 152 // InputMethodIBus::PendingCreateICRequestImpl implementation ----------------- | 164 // A class to hold information of a pending request for creating an ibus input |
| 153 class InputMethodIBus::PendingCreateICRequestImpl | 165 // context. |
| 154 : public internal::IBusClient::PendingCreateICRequest { | 166 class InputMethodIBus::PendingCreateICRequest { |
| 155 public: | 167 public: |
| 156 PendingCreateICRequestImpl(InputMethodIBus* input_method, | 168 PendingCreateICRequest(InputMethodIBus* input_method, |
| 157 internal::IBusClient* ibus_client, | 169 PendingCreateICRequest** request_ptr); |
| 158 PendingCreateICRequestImpl** request_ptr); | 170 virtual ~PendingCreateICRequest(); |
| 159 virtual ~PendingCreateICRequestImpl(); | |
| 160 | 171 |
| 161 // internal::IBusClient::PendingCreateICRequest overrides: | 172 // Set up signal handlers, or destroy object proxy if the input context is |
| 162 virtual void InitOrAbandonInputContext() OVERRIDE; | 173 // already abandoned. |
| 163 virtual void OnCreateInputContextFailed() OVERRIDE; | 174 void InitOrAbandonInputContext(); |
| 175 |
| 176 // Called if the create input context method call is failed. |
| 177 void OnCreateInputContextFailed(); |
| 164 | 178 |
| 165 // Abandon this pending key event. Its result will just be discarded. | 179 // Abandon this pending key event. Its result will just be discarded. |
| 166 void Abandon() { | 180 void Abandon() { |
| 167 input_method_ = NULL; | 181 input_method_ = NULL; |
| 168 request_ptr_ = NULL; | 182 request_ptr_ = NULL; |
| 169 // Do not reset |ibus_client_| here. | 183 // Do not reset |ibus_client_| here. |
| 170 } | 184 } |
| 171 | 185 |
| 172 private: | 186 private: |
| 173 InputMethodIBus* input_method_; | 187 InputMethodIBus* input_method_; |
| 174 internal::IBusClient* ibus_client_; | 188 PendingCreateICRequest** request_ptr_; |
| 175 PendingCreateICRequestImpl** request_ptr_; | |
| 176 | 189 |
| 177 DISALLOW_COPY_AND_ASSIGN(PendingCreateICRequestImpl); | 190 DISALLOW_COPY_AND_ASSIGN(PendingCreateICRequest); |
| 178 }; | 191 }; |
| 179 | 192 |
| 180 InputMethodIBus::PendingCreateICRequestImpl::PendingCreateICRequestImpl( | 193 InputMethodIBus::PendingCreateICRequest::PendingCreateICRequest( |
| 181 InputMethodIBus* input_method, | 194 InputMethodIBus* input_method, |
| 182 internal::IBusClient* ibus_client, | 195 PendingCreateICRequest** request_ptr) |
| 183 PendingCreateICRequestImpl** request_ptr) | |
| 184 : input_method_(input_method), | 196 : input_method_(input_method), |
| 185 ibus_client_(ibus_client), | |
| 186 request_ptr_(request_ptr) { | 197 request_ptr_(request_ptr) { |
| 187 } | 198 } |
| 188 | 199 |
| 189 InputMethodIBus::PendingCreateICRequestImpl::~PendingCreateICRequestImpl() { | 200 InputMethodIBus::PendingCreateICRequest::~PendingCreateICRequest() { |
| 190 if (request_ptr_) { | 201 if (request_ptr_) { |
| 191 DCHECK_EQ(*request_ptr_, this); | 202 DCHECK_EQ(*request_ptr_, this); |
| 192 *request_ptr_ = NULL; | 203 *request_ptr_ = NULL; |
| 193 } | 204 } |
| 194 } | 205 } |
| 195 | 206 |
| 196 void InputMethodIBus::PendingCreateICRequestImpl::OnCreateInputContextFailed() { | 207 void InputMethodIBus::PendingCreateICRequest::OnCreateInputContextFailed() { |
| 197 // TODO(nona): If the connection between Chrome and ibus-daemon terminates | 208 // 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 | 209 // for some reason, the create ic request will fail. We might want to call |
| 199 // ibus_client_->CreateContext() again after some delay. | 210 // ibus_client_->CreateContext() again after some delay. |
| 200 } | 211 } |
| 201 | 212 |
| 202 void InputMethodIBus::PendingCreateICRequestImpl::InitOrAbandonInputContext() { | 213 void InputMethodIBus::PendingCreateICRequest::InitOrAbandonInputContext() { |
| 203 if (input_method_) { | 214 if (input_method_) { |
| 204 DCHECK(ibus_client_->IsContextReady()); | 215 DCHECK(input_method_->IsContextReady()); |
| 205 input_method_->SetUpSignalHandlers(); | 216 input_method_->SetUpSignalHandlers(); |
| 206 } else { | 217 } else { |
| 207 ibus_client_->DestroyProxy(); | 218 GetInputContextClient()->ResetObjectProxy(); |
| 208 DCHECK(!ibus_client_->IsContextReady()); | |
| 209 } | 219 } |
| 210 } | 220 } |
| 211 | 221 |
| 212 // InputMethodIBus implementation ----------------------------------------- | 222 // InputMethodIBus implementation ----------------------------------------- |
| 213 InputMethodIBus::InputMethodIBus( | 223 InputMethodIBus::InputMethodIBus( |
| 214 internal::InputMethodDelegate* delegate) | 224 internal::InputMethodDelegate* delegate) |
| 215 : | 225 : ibus_client_(new internal::IBusClient), |
| 216 ibus_client_(new internal::IBusClientImpl), | |
| 217 pending_create_ic_request_(NULL), | 226 pending_create_ic_request_(NULL), |
| 218 context_focused_(false), | 227 context_focused_(false), |
| 219 composing_text_(false), | 228 composing_text_(false), |
| 220 composition_changed_(false), | 229 composition_changed_(false), |
| 221 suppress_next_result_(false), | 230 suppress_next_result_(false), |
| 222 weak_ptr_factory_(this) { | 231 weak_ptr_factory_(this) { |
| 223 SetDelegate(delegate); | 232 SetDelegate(delegate); |
| 224 } | 233 } |
| 225 | 234 |
| 226 InputMethodIBus::~InputMethodIBus() { | 235 InputMethodIBus::~InputMethodIBus() { |
| 227 AbandonAllPendingKeyEvents(); | 236 AbandonAllPendingKeyEvents(); |
| 228 if (ibus_client_->IsContextReady()) | 237 if (IsContextReady()) |
| 229 DestroyContext(); | 238 DestroyContext(); |
| 230 } | 239 } |
| 231 | 240 |
| 232 void InputMethodIBus::set_ibus_client( | 241 void InputMethodIBus::set_ibus_client( |
| 233 scoped_ptr<internal::IBusClient> new_client) { | 242 scoped_ptr<internal::IBusClient> new_client) { |
| 234 ibus_client_.swap(new_client); | 243 ibus_client_.swap(new_client); |
| 235 } | 244 } |
| 236 | 245 |
| 237 internal::IBusClient* InputMethodIBus::ibus_client() const { | 246 internal::IBusClient* InputMethodIBus::ibus_client() const { |
| 238 return ibus_client_.get(); | 247 return ibus_client_.get(); |
| 239 } | 248 } |
| 240 | 249 |
| 241 void InputMethodIBus::OnFocus() { | 250 void InputMethodIBus::OnFocus() { |
| 242 InputMethodBase::OnFocus(); | 251 InputMethodBase::OnFocus(); |
| 243 UpdateContextFocusState(); | 252 UpdateContextFocusState(); |
| 244 } | 253 } |
| 245 | 254 |
| 246 void InputMethodIBus::OnBlur() { | 255 void InputMethodIBus::OnBlur() { |
| 247 ConfirmCompositionText(); | 256 ConfirmCompositionText(); |
| 248 InputMethodBase::OnBlur(); | 257 InputMethodBase::OnBlur(); |
| 249 UpdateContextFocusState(); | 258 UpdateContextFocusState(); |
| 250 } | 259 } |
| 251 | 260 |
| 252 void InputMethodIBus::Init(bool focused) { | 261 void InputMethodIBus::Init(bool focused) { |
| 253 // Initializes the connection to ibus daemon. It may happen asynchronously, | 262 // Initializes the connection to ibus daemon. It may happen asynchronously, |
| 254 // and as soon as the connection is established, the |context_| will be | 263 // and as soon as the connection is established, the |context_| will be |
| 255 // created automatically. | 264 // created automatically. |
| 256 | 265 |
| 257 // Create the input context if the connection is already established. | 266 // Create the input context if the connection is already established. |
| 258 if (ibus_client_->IsConnected()) | 267 if (IsConnected()) |
| 259 CreateContext(); | 268 CreateContext(); |
| 260 | 269 |
| 261 InputMethodBase::Init(focused); | 270 InputMethodBase::Init(focused); |
| 262 } | 271 } |
| 263 | 272 |
| 264 // static | 273 // static |
| 265 void InputMethodIBus::ProcessKeyEventDone( | 274 void InputMethodIBus::ProcessKeyEventDone( |
| 266 PendingKeyEventImpl* pending_key_event, bool is_handled) { | 275 PendingKeyEvent* pending_key_event, bool is_handled) { |
| 267 DCHECK(pending_key_event); | 276 DCHECK(pending_key_event); |
| 268 pending_key_event->ProcessPostIME(is_handled); | 277 pending_key_event->ProcessPostIME(is_handled); |
| 269 delete pending_key_event; | 278 delete pending_key_event; |
| 270 } | 279 } |
| 271 | 280 |
| 272 void InputMethodIBus::DispatchKeyEvent(const base::NativeEvent& native_event) { | 281 void InputMethodIBus::DispatchKeyEvent(const base::NativeEvent& native_event) { |
| 273 DCHECK(native_event && (native_event->type == KeyPress || | 282 DCHECK(native_event && (native_event->type == KeyPress || |
| 274 native_event->type == KeyRelease)); | 283 native_event->type == KeyRelease)); |
| 275 DCHECK(system_toplevel_window_focused()); | 284 DCHECK(system_toplevel_window_focused()); |
| 276 | 285 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 289 GetTextInputType() == TEXT_INPUT_TYPE_PASSWORD || | 298 GetTextInputType() == TEXT_INPUT_TYPE_PASSWORD || |
| 290 ibus_client_->GetInputMethodType() == | 299 ibus_client_->GetInputMethodType() == |
| 291 internal::IBusClient::INPUT_METHOD_XKB_LAYOUT) { | 300 internal::IBusClient::INPUT_METHOD_XKB_LAYOUT) { |
| 292 if (native_event->type == KeyPress) | 301 if (native_event->type == KeyPress) |
| 293 ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); | 302 ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); |
| 294 else | 303 else |
| 295 DispatchKeyEventPostIME(native_event); | 304 DispatchKeyEventPostIME(native_event); |
| 296 return; | 305 return; |
| 297 } | 306 } |
| 298 | 307 |
| 299 PendingKeyEventImpl* pending_key = | 308 PendingKeyEvent* pending_key = |
| 300 new PendingKeyEventImpl(this, native_event, ibus_keyval); | 309 new PendingKeyEvent(this, native_event, ibus_keyval); |
| 301 pending_key_events_.insert(pending_key); | 310 pending_key_events_.insert(pending_key); |
| 302 | 311 |
| 303 ibus_client_->SendKeyEvent(ibus_keyval, | 312 GetInputContextClient()->ProcessKeyEvent( |
| 304 ibus_keycode, | 313 ibus_keyval, |
| 305 ibus_state, | 314 ibus_keycode, |
| 306 base::Bind(&InputMethodIBus::ProcessKeyEventDone, | 315 ibus_state, base::Bind(&InputMethodIBus::ProcessKeyEventDone, |
| 307 base::Unretained(pending_key))); | 316 base::Unretained(pending_key))); |
| 308 | 317 |
| 309 // We don't want to suppress the result generated by this key event, but it | 318 // We don't want to suppress the result generated by this key event, but it |
| 310 // may cause problem. See comment in ResetContext() method. | 319 // may cause problem. See comment in ResetContext() method. |
| 311 suppress_next_result_ = false; | 320 suppress_next_result_ = false; |
| 312 } | 321 } |
| 313 | 322 |
| 314 void InputMethodIBus::OnTextInputTypeChanged(const TextInputClient* client) { | 323 void InputMethodIBus::OnTextInputTypeChanged(const TextInputClient* client) { |
| 315 if (ibus_client_->IsContextReady() && IsTextInputClientFocused(client)) { | 324 if (IsContextReady() && IsTextInputClientFocused(client)) { |
| 316 ResetContext(); | 325 ResetContext(); |
| 317 UpdateContextFocusState(); | 326 UpdateContextFocusState(); |
| 318 } | 327 } |
| 319 InputMethodBase::OnTextInputTypeChanged(client); | 328 InputMethodBase::OnTextInputTypeChanged(client); |
| 320 } | 329 } |
| 321 | 330 |
| 322 void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) { | 331 void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) { |
| 323 if (!context_focused_ || !IsTextInputClientFocused(client)) | 332 if (!context_focused_ || !IsTextInputClientFocused(client)) |
| 324 return; | 333 return; |
| 325 | 334 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 // focus and after it acquires focus again are the same. | 377 // focus and after it acquires focus again are the same. |
| 369 OnTextInputTypeChanged(focused); | 378 OnTextInputTypeChanged(focused); |
| 370 | 379 |
| 371 UpdateContextFocusState(); | 380 UpdateContextFocusState(); |
| 372 // Force to update caret bounds, in case the client thinks that the caret | 381 // Force to update caret bounds, in case the client thinks that the caret |
| 373 // bounds has not changed. | 382 // bounds has not changed. |
| 374 OnCaretBoundsChanged(focused); | 383 OnCaretBoundsChanged(focused); |
| 375 } | 384 } |
| 376 | 385 |
| 377 void InputMethodIBus::CreateContext() { | 386 void InputMethodIBus::CreateContext() { |
| 378 DCHECK(ibus_client_->IsConnected()); | 387 DCHECK(IsConnected()); |
| 379 DCHECK(!pending_create_ic_request_); | 388 DCHECK(!pending_create_ic_request_); |
| 380 | 389 |
| 390 pending_create_ic_request_ = new PendingCreateICRequest( |
| 391 this, &pending_create_ic_request_); |
| 392 |
| 381 // Creates the input context asynchronously. | 393 // Creates the input context asynchronously. |
| 382 pending_create_ic_request_ = new PendingCreateICRequestImpl( | 394 chromeos::DBusThreadManager::Get()->GetIBusClient()->CreateInputContext( |
| 383 this, ibus_client_.get(), &pending_create_ic_request_); | 395 kClientName, |
| 384 ibus_client_->CreateContext(pending_create_ic_request_); | 396 base::Bind(&InputMethodIBus::CreateInputContextDone, |
| 397 weak_ptr_factory_.GetWeakPtr(), |
| 398 base::Unretained(pending_create_ic_request_)), |
| 399 base::Bind(&InputMethodIBus::CreateInputContextFail, |
| 400 weak_ptr_factory_.GetWeakPtr(), |
| 401 base::Unretained(pending_create_ic_request_))); |
| 385 } | 402 } |
| 386 | 403 |
| 387 void InputMethodIBus::SetUpSignalHandlers() { | 404 void InputMethodIBus::SetUpSignalHandlers() { |
| 388 DCHECK(ibus_client_->IsContextReady()); | 405 DCHECK(IsContextReady()); |
| 389 | 406 |
| 390 // connect input context signals | 407 // connect input context signals |
| 391 chromeos::IBusInputContextClient* input_context_client = | 408 chromeos::IBusInputContextClient* input_context_client = |
| 392 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); | 409 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); |
| 393 input_context_client->SetCommitTextHandler( | 410 input_context_client->SetCommitTextHandler( |
| 394 base::Bind(&InputMethodIBus::OnCommitText, | 411 base::Bind(&InputMethodIBus::OnCommitText, |
| 395 weak_ptr_factory_.GetWeakPtr())); | 412 weak_ptr_factory_.GetWeakPtr())); |
| 396 | 413 |
| 397 input_context_client->SetForwardKeyEventHandler( | 414 input_context_client->SetForwardKeyEventHandler( |
| 398 base::Bind(&InputMethodIBus::OnForwardKeyEvent, | 415 base::Bind(&InputMethodIBus::OnForwardKeyEvent, |
| 399 weak_ptr_factory_.GetWeakPtr())); | 416 weak_ptr_factory_.GetWeakPtr())); |
| 400 | 417 |
| 401 input_context_client->SetUpdatePreeditTextHandler( | 418 input_context_client->SetUpdatePreeditTextHandler( |
| 402 base::Bind(&InputMethodIBus::OnUpdatePreeditText, | 419 base::Bind(&InputMethodIBus::OnUpdatePreeditText, |
| 403 weak_ptr_factory_.GetWeakPtr())); | 420 weak_ptr_factory_.GetWeakPtr())); |
| 404 | 421 |
| 405 input_context_client->SetShowPreeditTextHandler( | 422 input_context_client->SetShowPreeditTextHandler( |
| 406 base::Bind(&InputMethodIBus::OnShowPreeditText, | 423 base::Bind(&InputMethodIBus::OnShowPreeditText, |
| 407 weak_ptr_factory_.GetWeakPtr())); | 424 weak_ptr_factory_.GetWeakPtr())); |
| 408 | 425 |
| 409 input_context_client->SetHidePreeditTextHandler( | 426 input_context_client->SetHidePreeditTextHandler( |
| 410 base::Bind(&InputMethodIBus::OnHidePreeditText, | 427 base::Bind(&InputMethodIBus::OnHidePreeditText, |
| 411 weak_ptr_factory_.GetWeakPtr())); | 428 weak_ptr_factory_.GetWeakPtr())); |
| 412 | 429 |
| 413 ibus_client_->SetCapabilities(internal::IBusClient::INLINE_COMPOSITION); | 430 GetInputContextClient()->SetCapabilities( |
| 431 kIBusCapabilityPreeditText | kIBusCapabilityFocus); |
| 414 | 432 |
| 415 UpdateContextFocusState(); | 433 UpdateContextFocusState(); |
| 416 // Since ibus-daemon is launched in an on-demand basis on Chrome OS, RWHVA (or | 434 // Since ibus-daemon is launched in an on-demand basis on Chrome OS, RWHVA (or |
| 417 // equivalents) might call OnCaretBoundsChanged() before the daemon starts. To | 435 // equivalents) might call OnCaretBoundsChanged() before the daemon starts. To |
| 418 // save the case, call OnCaretBoundsChanged() here. | 436 // save the case, call OnCaretBoundsChanged() here. |
| 419 OnCaretBoundsChanged(GetTextInputClient()); | 437 OnCaretBoundsChanged(GetTextInputClient()); |
| 420 OnInputMethodChanged(); | 438 OnInputMethodChanged(); |
| 421 } | 439 } |
| 422 | 440 |
| 423 void InputMethodIBus::DestroyContext() { | 441 void InputMethodIBus::DestroyContext() { |
| 424 if (pending_create_ic_request_) { | 442 if (pending_create_ic_request_) { |
| 425 DCHECK(!ibus_client_->IsContextReady()); | 443 DCHECK(!IsContextReady()); |
| 426 // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). | 444 // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). |
| 427 pending_create_ic_request_->Abandon(); | 445 pending_create_ic_request_->Abandon(); |
| 428 pending_create_ic_request_ = NULL; | 446 pending_create_ic_request_ = NULL; |
| 429 return; | 447 return; |
| 430 } | 448 } |
| 431 const chromeos::IBusInputContextClient* input_context = | 449 const chromeos::IBusInputContextClient* input_context = |
| 432 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); | 450 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient(); |
| 433 if (input_context && input_context->IsObjectProxyReady()) { | 451 if (input_context && input_context->IsObjectProxyReady()) { |
| 434 // We can't use IsContextReady here because we want to destroy object proxy | 452 // We can't use IsContextReady here because we want to destroy object proxy |
| 435 // regardless of connection. The IsContextReady contains connection check. | 453 // regardless of connection. The IsContextReady contains connection check. |
| 436 ResetInputContext(); | 454 ResetInputContext(); |
| 437 DCHECK(!ibus_client_->IsContextReady()); | 455 DCHECK(!IsContextReady()); |
| 438 } | 456 } |
| 439 } | 457 } |
| 440 | 458 |
| 441 void InputMethodIBus::ConfirmCompositionText() { | 459 void InputMethodIBus::ConfirmCompositionText() { |
| 442 TextInputClient* client = GetTextInputClient(); | 460 TextInputClient* client = GetTextInputClient(); |
| 443 if (client && client->HasCompositionText()) | 461 if (client && client->HasCompositionText()) |
| 444 client->ConfirmCompositionText(); | 462 client->ConfirmCompositionText(); |
| 445 | 463 |
| 446 ResetContext(); | 464 ResetContext(); |
| 447 } | 465 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 469 | 487 |
| 470 // We need to abandon all pending key events, but as above comment says, there | 488 // We need to abandon all pending key events, but as above comment says, there |
| 471 // is no reliable way to abandon all results generated by these abandoned key | 489 // is no reliable way to abandon all results generated by these abandoned key |
| 472 // events. | 490 // events. |
| 473 AbandonAllPendingKeyEvents(); | 491 AbandonAllPendingKeyEvents(); |
| 474 | 492 |
| 475 // This function runs asynchronously. | 493 // This function runs asynchronously. |
| 476 // Note: some input method engines may not support reset method, such as | 494 // Note: some input method engines may not support reset method, such as |
| 477 // ibus-anthy. But as we control all input method engines by ourselves, we can | 495 // ibus-anthy. But as we control all input method engines by ourselves, we can |
| 478 // make sure that all of the engines we are using support it correctly. | 496 // make sure that all of the engines we are using support it correctly. |
| 479 ibus_client_->Reset(); | 497 GetInputContextClient()->Reset(); |
| 480 | 498 |
| 481 character_composer_.Reset(); | 499 character_composer_.Reset(); |
| 482 } | 500 } |
| 483 | 501 |
| 484 void InputMethodIBus::UpdateContextFocusState() { | 502 void InputMethodIBus::UpdateContextFocusState() { |
| 485 if (!ibus_client_->IsContextReady()) { | 503 if (!IsContextReady()) { |
| 486 context_focused_ = false; | 504 context_focused_ = false; |
| 487 return; | 505 return; |
| 488 } | 506 } |
| 489 | 507 |
| 490 const bool old_context_focused = context_focused_; | 508 const bool old_context_focused = context_focused_; |
| 491 // Use switch here in case we are going to add more text input types. | 509 // Use switch here in case we are going to add more text input types. |
| 492 switch (GetTextInputType()) { | 510 switch (GetTextInputType()) { |
| 493 case TEXT_INPUT_TYPE_NONE: | 511 case TEXT_INPUT_TYPE_NONE: |
| 494 case TEXT_INPUT_TYPE_PASSWORD: | 512 case TEXT_INPUT_TYPE_PASSWORD: |
| 495 context_focused_ = false; | 513 context_focused_ = false; |
| 496 break; | 514 break; |
| 497 default: | 515 default: |
| 498 context_focused_ = true; | 516 context_focused_ = true; |
| 499 break; | 517 break; |
| 500 } | 518 } |
| 501 | 519 |
| 502 // We only focus in |context_| when the focus is in a normal textfield. | 520 // We only focus in |context_| when the focus is in a normal textfield. |
| 503 // ibus_input_context_focus_{in|out}() run asynchronously. | 521 // ibus_input_context_focus_{in|out}() run asynchronously. |
| 504 if (old_context_focused && !context_focused_) | 522 if (old_context_focused && !context_focused_) |
| 505 ibus_client_->FocusOut(); | 523 GetInputContextClient()->FocusOut(); |
| 506 else if (!old_context_focused && context_focused_) | 524 else if (!old_context_focused && context_focused_) |
| 507 ibus_client_->FocusIn(); | 525 GetInputContextClient()->FocusIn(); |
| 508 | 526 |
| 509 if (context_focused_) { | 527 if (context_focused_) { |
| 510 internal::IBusClient::InlineCompositionCapability capability = | 528 uint32 capability = kIBusCapabilityFocus; |
| 511 CanComposeInline() ? internal::IBusClient::INLINE_COMPOSITION | 529 if (CanComposeInline()) |
| 512 : internal::IBusClient::OFF_THE_SPOT_COMPOSITION; | 530 capability |= kIBusCapabilityPreeditText; |
| 513 ibus_client_->SetCapabilities(capability); | 531 GetInputContextClient()->SetCapabilities(capability); |
| 514 } | 532 } |
| 515 } | 533 } |
| 516 | 534 |
| 517 void InputMethodIBus::ProcessKeyEventPostIME( | 535 void InputMethodIBus::ProcessKeyEventPostIME( |
| 518 const base::NativeEvent& native_event, | 536 const base::NativeEvent& native_event, |
| 519 uint32 ibus_keyval, | 537 uint32 ibus_keyval, |
| 520 bool handled) { | 538 bool handled) { |
| 521 TextInputClient* client = GetTextInputClient(); | 539 TextInputClient* client = GetTextInputClient(); |
| 522 | 540 |
| 523 if (!client) { | 541 if (!client) { |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 bool InputMethodIBus::HasInputMethodResult() const { | 718 bool InputMethodIBus::HasInputMethodResult() const { |
| 701 return result_text_.length() || composition_changed_; | 719 return result_text_.length() || composition_changed_; |
| 702 } | 720 } |
| 703 | 721 |
| 704 void InputMethodIBus::SendFakeProcessKeyEvent(bool pressed) const { | 722 void InputMethodIBus::SendFakeProcessKeyEvent(bool pressed) const { |
| 705 DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, | 723 DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, |
| 706 VKEY_PROCESSKEY, | 724 VKEY_PROCESSKEY, |
| 707 0); | 725 0); |
| 708 } | 726 } |
| 709 | 727 |
| 710 void InputMethodIBus::FinishPendingKeyEvent(PendingKeyEventImpl* pending_key) { | 728 void InputMethodIBus::FinishPendingKeyEvent(PendingKeyEvent* pending_key) { |
| 711 DCHECK(pending_key_events_.count(pending_key)); | 729 DCHECK(pending_key_events_.count(pending_key)); |
| 712 | 730 |
| 713 // |pending_key| will be deleted in ProcessKeyEventDone(). | 731 // |pending_key| will be deleted in ProcessKeyEventDone(). |
| 714 pending_key_events_.erase(pending_key); | 732 pending_key_events_.erase(pending_key); |
| 715 } | 733 } |
| 716 | 734 |
| 717 void InputMethodIBus::AbandonAllPendingKeyEvents() { | 735 void InputMethodIBus::AbandonAllPendingKeyEvents() { |
| 718 std::set<PendingKeyEventImpl*>::iterator i; | 736 std::set<PendingKeyEvent*>::iterator i; |
| 719 for (i = pending_key_events_.begin(); i != pending_key_events_.end(); ++i) { | 737 for (i = pending_key_events_.begin(); i != pending_key_events_.end(); ++i) { |
| 720 // The object will be deleted in ProcessKeyEventDone(). | 738 // The object will be deleted in ProcessKeyEventDone(). |
| 721 (*i)->Abandon(); | 739 (*i)->Abandon(); |
| 722 } | 740 } |
| 723 pending_key_events_.clear(); | 741 pending_key_events_.clear(); |
| 724 } | 742 } |
| 725 | 743 |
| 726 void InputMethodIBus::OnCommitText(const chromeos::ibus::IBusText& text) { | 744 void InputMethodIBus::OnCommitText(const chromeos::ibus::IBusText& text) { |
| 727 if (suppress_next_result_ || text.text().empty()) | 745 if (suppress_next_result_ || text.text().empty()) |
| 728 return; | 746 return; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 838 } | 856 } |
| 839 } | 857 } |
| 840 | 858 |
| 841 void InputMethodIBus::ResetInputContext() { | 859 void InputMethodIBus::ResetInputContext() { |
| 842 context_focused_ = false; | 860 context_focused_ = false; |
| 843 | 861 |
| 844 ConfirmCompositionText(); | 862 ConfirmCompositionText(); |
| 845 | 863 |
| 846 // We are dead, so we need to ask the client to stop relying on us. | 864 // We are dead, so we need to ask the client to stop relying on us. |
| 847 OnInputMethodChanged(); | 865 OnInputMethodChanged(); |
| 848 ibus_client_->DestroyProxy(); | 866 GetInputContextClient()->ResetObjectProxy(); |
| 867 } |
| 868 |
| 869 void InputMethodIBus::CreateInputContextDone( |
| 870 PendingCreateICRequest* ic_request, |
| 871 const dbus::ObjectPath& object_path) { |
| 872 chromeos::DBusThreadManager::Get()->GetIBusInputContextClient() |
| 873 ->Initialize(chromeos::DBusThreadManager::Get()->GetIBusBus(), |
| 874 object_path); |
| 875 ic_request->InitOrAbandonInputContext(); |
| 876 delete ic_request; |
| 877 } |
| 878 |
| 879 void InputMethodIBus::CreateInputContextFail( |
| 880 PendingCreateICRequest* ic_request) { |
| 881 ic_request->OnCreateInputContextFailed(); |
| 882 delete ic_request; |
| 883 } |
| 884 |
| 885 bool InputMethodIBus::IsConnected() { |
| 886 return chromeos::DBusThreadManager::Get()->GetIBusBus() != NULL; |
| 887 } |
| 888 |
| 889 bool InputMethodIBus::IsContextReady() { |
| 890 if (!IsConnected()) |
| 891 return false; |
| 892 if (!GetInputContextClient()) |
| 893 return false; |
| 894 return GetInputContextClient()->IsObjectProxyReady(); |
| 849 } | 895 } |
| 850 | 896 |
| 851 void InputMethodIBus::OnConnected() { | 897 void InputMethodIBus::OnConnected() { |
| 852 DCHECK(ibus_client_->IsConnected()); | 898 DCHECK(IsConnected()); |
| 853 // If already input context is initialized, do nothing. | 899 // If already input context is initialized, do nothing. |
| 854 if (ibus_client_->IsContextReady()) | 900 if (IsContextReady()) |
| 855 return; | 901 return; |
| 856 | 902 |
| 857 DestroyContext(); | 903 DestroyContext(); |
| 858 CreateContext(); | 904 CreateContext(); |
| 859 } | 905 } |
| 860 | 906 |
| 861 void InputMethodIBus::OnDisconnected() { | 907 void InputMethodIBus::OnDisconnected() { |
| 862 DestroyContext(); | 908 DestroyContext(); |
| 863 } | 909 } |
| 864 | 910 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 941 } | 987 } |
| 942 | 988 |
| 943 // Use a black thin underline by default. | 989 // Use a black thin underline by default. |
| 944 if (out_composition->underlines.empty()) { | 990 if (out_composition->underlines.empty()) { |
| 945 out_composition->underlines.push_back(CompositionUnderline( | 991 out_composition->underlines.push_back(CompositionUnderline( |
| 946 0, length, SK_ColorBLACK, false /* thick */)); | 992 0, length, SK_ColorBLACK, false /* thick */)); |
| 947 } | 993 } |
| 948 } | 994 } |
| 949 | 995 |
| 950 } // namespace ui | 996 } // namespace ui |
| OLD | NEW |