Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/views/ime/input_method_ibus.h" | 5 #include "ui/base/ime/input_method_ibus.h" |
| 6 | 6 |
| 7 #include <ibus.h> | 7 #include <ibus.h> |
| 8 #if defined(TOUCH_UI) | 8 |
| 9 #include <X11/X.h> | |
| 9 #include <X11/Xlib.h> | 10 #include <X11/Xlib.h> |
| 10 #include <X11/Xutil.h> | 11 #include <X11/Xutil.h> |
| 11 #endif | |
| 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/command_line.h" | |
|
James Su
2011/11/24 03:57:03
This include is not necessary anymore.
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 18 #include "base/basictypes.h" | 19 #include "base/basictypes.h" |
| 19 #include "base/command_line.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 "ui/base/events.h" | |
| 26 #include "ui/base/ime/text_input_client.h" | |
| 25 #include "ui/base/keycodes/keyboard_codes.h" | 27 #include "ui/base/keycodes/keyboard_codes.h" |
| 26 #include "ui/gfx/point.h" | 28 #include "ui/base/keycodes/keyboard_code_conversion.h" |
| 29 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | |
| 27 #include "ui/gfx/rect.h" | 30 #include "ui/gfx/rect.h" |
| 28 #include "ui/views/events/event.h" | |
| 29 #include "ui/views/widget/widget.h" | |
| 30 | |
| 31 #if defined(USE_AURA) || defined(TOUCH_UI) | |
| 32 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | |
| 33 #elif defined(TOOLKIT_USES_GTK) | |
| 34 #include "ui/base/keycodes/keyboard_code_conversion_gtk.h" | |
| 35 #endif | |
| 36 | 31 |
| 37 namespace { | 32 namespace { |
| 38 | 33 |
| 39 // A global flag to switch the InputMethod implementation to InputMethodIBus | 34 XKeyEvent* GetKeyEvent(XEvent* event) { |
| 40 bool inputmethod_ibus_enabled = false; | 35 DCHECK(event && (event->type == KeyPress || event->type == KeyRelease)); |
| 36 return reinterpret_cast<XKeyEvent*>(event); | |
|
James Su
2011/11/24 03:57:03
return &event->xkey;
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 37 } | |
| 41 | 38 |
| 42 // Converts ibus key state flags to event flags. | 39 // Converts ibus key state flags to event flags. |
| 43 int EventFlagsFromIBusState(guint32 state) { | 40 int EventFlagsFromIBusState(guint32 state) { |
| 44 return (state & IBUS_LOCK_MASK ? ui::EF_CAPS_LOCK_DOWN : 0) | | 41 return (state & IBUS_LOCK_MASK ? ui::EF_CAPS_LOCK_DOWN : 0) | |
| 45 (state & IBUS_CONTROL_MASK ? ui::EF_CONTROL_DOWN : 0) | | 42 (state & IBUS_CONTROL_MASK ? ui::EF_CONTROL_DOWN : 0) | |
| 46 (state & IBUS_SHIFT_MASK ? ui::EF_SHIFT_DOWN : 0) | | 43 (state & IBUS_SHIFT_MASK ? ui::EF_SHIFT_DOWN : 0) | |
| 47 (state & IBUS_MOD1_MASK ? ui::EF_ALT_DOWN : 0) | | 44 (state & IBUS_MOD1_MASK ? ui::EF_ALT_DOWN : 0) | |
| 48 (state & IBUS_BUTTON1_MASK ? ui::EF_LEFT_BUTTON_DOWN : 0) | | 45 (state & IBUS_BUTTON1_MASK ? ui::EF_LEFT_BUTTON_DOWN : 0) | |
| 49 (state & IBUS_BUTTON2_MASK ? ui::EF_MIDDLE_BUTTON_DOWN : 0) | | 46 (state & IBUS_BUTTON2_MASK ? ui::EF_MIDDLE_BUTTON_DOWN : 0) | |
| 50 (state & IBUS_BUTTON3_MASK ? ui::EF_RIGHT_BUTTON_DOWN : 0); | 47 (state & IBUS_BUTTON3_MASK ? ui::EF_RIGHT_BUTTON_DOWN : 0); |
| 51 } | 48 } |
| 52 | 49 |
| 53 // Converts event flags to ibus key state flags. | 50 // Converts X flags to ibus key state flags. |
| 54 guint32 IBusStateFromEventFlags(int flags) { | 51 guint32 IBusStateFromXFlags(unsigned int flags) { |
| 55 return (flags & ui::EF_CAPS_LOCK_DOWN ? IBUS_LOCK_MASK : 0) | | 52 return (flags & LockMask ? IBUS_LOCK_MASK : 0U) | |
| 56 (flags & ui::EF_CONTROL_DOWN ? IBUS_CONTROL_MASK : 0) | | 53 (flags & ControlMask ? IBUS_CONTROL_MASK : 0U) | |
| 57 (flags & ui::EF_SHIFT_DOWN ? IBUS_SHIFT_MASK : 0) | | 54 (flags & ShiftMask ? IBUS_SHIFT_MASK : 0U) | |
| 58 (flags & ui::EF_ALT_DOWN ? IBUS_MOD1_MASK : 0) | | 55 (flags & Mod1Mask ? IBUS_MOD1_MASK : 0U); |
|
James Su
2011/11/24 03:57:03
Add button masks?
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 59 (flags & ui::EF_LEFT_BUTTON_DOWN ? IBUS_BUTTON1_MASK : 0) | | |
| 60 (flags & ui::EF_MIDDLE_BUTTON_DOWN ? IBUS_BUTTON2_MASK : 0) | | |
| 61 (flags & ui::EF_RIGHT_BUTTON_DOWN ? IBUS_BUTTON3_MASK : 0); | |
| 62 } | 56 } |
| 63 | 57 |
| 64 void IBusKeyEventFromViewsKeyEvent(const views::KeyEvent& key, | 58 // Converts X flags to ibus key state flags. |
|
James Su
2011/11/24 03:57:03
This comment is not correct.
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 65 guint32* ibus_keyval, | 59 guint32 EventFlagsFromXFlags(unsigned int flags) { |
| 66 guint32* ibus_keycode, | 60 return EventFlagsFromIBusState(IBusStateFromXFlags(flags)); |
| 67 guint32* ibus_state) { | 61 } |
| 68 #if defined(USE_AURA) | |
| 69 // TODO(yusukes): Handle native_event()? | |
| 70 *ibus_keyval = ui::XKeysymForWindowsKeyCode( | |
| 71 key.key_code(), key.IsShiftDown() ^ key.IsCapsLockDown()); | |
| 72 *ibus_keycode = 0; | |
| 73 #elif defined(TOUCH_UI) | |
| 74 if (key.native_event()) { | |
| 75 XKeyEvent* x_key = reinterpret_cast<XKeyEvent*>(key.native_event()); | |
| 76 // Yes, ibus uses X11 keysym. We cannot use XLookupKeysym(), which doesn't | |
| 77 // translate Shift and CapsLock states. | |
| 78 KeySym keysym = NoSymbol; | |
| 79 ::XLookupString(x_key, NULL, 0, &keysym, NULL); | |
| 80 *ibus_keyval = keysym; | |
| 81 *ibus_keycode = x_key->keycode; | |
| 82 } else { | |
| 83 *ibus_keyval = ui::XKeysymForWindowsKeyCode( | |
| 84 key.key_code(), key.IsShiftDown() ^ key.IsCapsLockDown()); | |
| 85 *ibus_keycode = 0; | |
| 86 } | |
| 87 #elif defined(TOOLKIT_USES_GTK) | |
| 88 if (key.gdk_event()) { | |
| 89 GdkEventKey* gdk_key = reinterpret_cast<GdkEventKey*>(key.gdk_event()); | |
| 90 *ibus_keyval = gdk_key->keyval; | |
| 91 *ibus_keycode = gdk_key->hardware_keycode; | |
| 92 } else { | |
| 93 *ibus_keyval = ui::GdkKeyCodeForWindowsKeyCode( | |
| 94 key.key_code(), key.IsShiftDown() ^ key.IsCapsLockDown()); | |
| 95 *ibus_keycode = 0; | |
| 96 } | |
| 97 #endif | |
| 98 | 62 |
| 99 *ibus_state = IBusStateFromEventFlags(key.flags()); | 63 void IBusKeyEventFromNativeKeyEvent(const base::NativeEvent& native_event, |
| 100 if (key.type() == ui::ET_KEY_RELEASED) | 64 guint32* ibus_keyval, |
| 65 guint32* ibus_keycode, | |
| 66 guint32* ibus_state) { | |
| 67 DCHECK(native_event); // A fabricated event is not supported here. | |
| 68 XKeyEvent* x_key = GetKeyEvent(native_event); | |
| 69 | |
| 70 // Yes, ibus uses X11 keysym. We cannot use XLookupKeysym(), which doesn't | |
| 71 // translate Shift and CapsLock states. | |
| 72 KeySym keysym = NoSymbol; | |
| 73 ::XLookupString(x_key, NULL, 0, &keysym, NULL); | |
| 74 *ibus_keyval = keysym; | |
| 75 *ibus_keycode = x_key->keycode; | |
| 76 *ibus_state = IBusStateFromXFlags(x_key->state); | |
| 77 if (native_event->type == KeyRelease) | |
| 101 *ibus_state |= IBUS_RELEASE_MASK; | 78 *ibus_state |= IBUS_RELEASE_MASK; |
| 102 } | 79 } |
| 103 | 80 |
| 104 void ExtractCompositionTextFromIBusPreedit(IBusText* text, | 81 void ExtractCompositionTextFromIBusPreedit(IBusText* text, |
| 105 guint cursor_position, | 82 guint cursor_position, |
| 106 ui::CompositionText* composition) { | 83 ui::CompositionText* composition) { |
| 107 composition->Clear(); | 84 composition->Clear(); |
| 108 composition->text = UTF8ToUTF16(text->text); | 85 composition->text = UTF8ToUTF16(text->text); |
| 109 | 86 |
| 110 if (composition->text.empty()) | 87 if (composition->text.empty()) |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 } | 144 } |
| 168 } | 145 } |
| 169 | 146 |
| 170 // Use a black thin underline by default. | 147 // Use a black thin underline by default. |
| 171 if (composition->underlines.empty()) { | 148 if (composition->underlines.empty()) { |
| 172 composition->underlines.push_back(ui::CompositionUnderline( | 149 composition->underlines.push_back(ui::CompositionUnderline( |
| 173 0, length, SK_ColorBLACK, false /* thick */)); | 150 0, length, SK_ColorBLACK, false /* thick */)); |
| 174 } | 151 } |
| 175 } | 152 } |
| 176 | 153 |
| 177 // A switch to enable InputMethodIBus | |
| 178 const char kEnableInputMethodIBusSwitch[] = "enable-inputmethod-ibus"; | |
| 179 | |
| 180 } // namespace | 154 } // namespace |
| 181 | 155 |
| 182 namespace views { | 156 namespace ui { |
| 183 | 157 |
| 184 // InputMethodIBus::PendingKeyEvent implementation ---------------------------- | 158 // InputMethodIBus::PendingKeyEvent implementation ------------------------ |
| 185 class InputMethodIBus::PendingKeyEvent { | 159 class InputMethodIBus::PendingKeyEvent { |
| 186 public: | 160 public: |
| 187 PendingKeyEvent(InputMethodIBus* input_method, const KeyEvent& key, | 161 PendingKeyEvent(InputMethodIBus* input_method, |
| 162 const base::NativeEvent& native_event, | |
| 188 guint32 ibus_keyval); | 163 guint32 ibus_keyval); |
| 189 ~PendingKeyEvent(); | 164 ~PendingKeyEvent(); |
| 190 | 165 |
| 191 // Abandon this pending key event. Its result will just be discarded. | 166 // Abandon this pending key event. Its result will just be discarded. |
| 192 void abandon() { input_method_ = NULL; } | 167 void Abandon() { input_method_ = NULL; } |
| 193 | 168 |
| 194 InputMethodIBus* input_method() const { return input_method_; } | 169 InputMethodIBus* input_method() const { return input_method_; } |
| 195 | 170 |
| 196 // Process this pending key event after we receive its result from the input | 171 // Process this pending key event after we receive its result from the input |
| 197 // method. It just call through InputMethodIBus::ProcessKeyEventPostIME(). | 172 // method. It just call through InputMethodIBus::ProcessKeyEventPostIME(). |
| 198 void ProcessPostIME(bool handled); | 173 void ProcessPostIME(bool handled); |
| 199 | 174 |
| 200 private: | 175 private: |
| 201 InputMethodIBus* input_method_; | 176 InputMethodIBus* input_method_; |
| 202 | 177 |
| 203 // Complete information of a views::KeyEvent. Sadly, views::KeyEvent doesn't | 178 // TODO(yusukes): To support a fabricated key event (which is typically from |
| 204 // support copy. | 179 // a virtual keyboard), we might have to copy event type, event flags, key |
| 205 ui::EventType type_; | 180 // code, 'character_', and 'unmodified_character_'. See views::InputMethodIBus |
| 206 int flags_; | 181 // for details. |
| 207 ui::KeyboardCode key_code_; | |
| 208 uint16 character_; | |
| 209 uint16 unmodified_character_; | |
| 210 | 182 |
| 211 guint32 ibus_keyval_; | 183 // corresponding XEvent data of a key event. It's a plain struct so we can do |
| 184 // bitwise copy. | |
| 185 XKeyEvent x_event_; | |
| 212 | 186 |
| 213 #if defined(TOUCH_UI) | 187 const guint32 ibus_keyval_; |
| 214 // corresponding XEvent data of a views::KeyEvent. It's a plain struct so we | |
| 215 // can do bitwise copy. | |
| 216 XKeyEvent x_event_; | |
| 217 #endif | |
| 218 | 188 |
| 219 DISALLOW_COPY_AND_ASSIGN(PendingKeyEvent); | 189 DISALLOW_COPY_AND_ASSIGN(PendingKeyEvent); |
| 220 }; | 190 }; |
| 221 | 191 |
| 222 InputMethodIBus::PendingKeyEvent::PendingKeyEvent(InputMethodIBus* input_method, | 192 InputMethodIBus::PendingKeyEvent::PendingKeyEvent( |
| 223 const KeyEvent& key, | 193 InputMethodIBus* input_method, |
| 224 guint32 ibus_keyval) | 194 const base::NativeEvent& native_event, |
| 195 guint32 ibus_keyval) | |
| 225 : input_method_(input_method), | 196 : input_method_(input_method), |
| 226 type_(key.type()), | |
| 227 flags_(key.flags()), | |
| 228 key_code_(key.key_code()), | |
| 229 character_(key.GetCharacter()), | |
| 230 unmodified_character_(key.GetUnmodifiedCharacter()), | |
| 231 ibus_keyval_(ibus_keyval) { | 197 ibus_keyval_(ibus_keyval) { |
| 232 DCHECK(input_method_); | 198 DCHECK(input_method_); |
| 233 | 199 |
| 234 #if defined(TOUCH_UI) | 200 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| 235 if (key.native_event()) | 201 DCHECK(native_event); |
| 236 x_event_ = *reinterpret_cast<XKeyEvent*>(key.native_event()); | 202 x_event_ = *GetKeyEvent(native_event); |
| 237 else | |
| 238 memset(&x_event_, 0, sizeof(x_event_)); | |
| 239 #endif | |
| 240 } | 203 } |
| 241 | 204 |
| 242 InputMethodIBus::PendingKeyEvent::~PendingKeyEvent() { | 205 InputMethodIBus::PendingKeyEvent::~PendingKeyEvent() { |
| 243 if (input_method_) | 206 if (input_method_) |
| 244 input_method_->FinishPendingKeyEvent(this); | 207 input_method_->FinishPendingKeyEvent(this); |
| 245 } | 208 } |
| 246 | 209 |
| 247 void InputMethodIBus::PendingKeyEvent::ProcessPostIME(bool handled) { | 210 void InputMethodIBus::PendingKeyEvent::ProcessPostIME(bool handled) { |
| 248 if (!input_method_) | 211 if (!input_method_) |
| 249 return; | 212 return; |
| 250 | 213 |
| 251 #if defined(TOUCH_UI) | |
| 252 if (x_event_.type == KeyPress || x_event_.type == KeyRelease) { | 214 if (x_event_.type == KeyPress || x_event_.type == KeyRelease) { |
| 253 KeyEvent key(reinterpret_cast<XEvent*>(&x_event_)); | 215 input_method_->ProcessKeyEventPostIME(reinterpret_cast<XEvent*>(&x_event_), |
| 254 input_method_->ProcessKeyEventPostIME(key, ibus_keyval_, handled); | 216 ibus_keyval_, |
| 217 handled); | |
| 255 return; | 218 return; |
| 256 } | 219 } |
| 257 #endif | 220 |
| 258 KeyEvent key(type_, key_code_, flags_); | 221 // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| 259 if (key_code_ == ui::VKEY_UNKNOWN) { | 222 // See views::InputMethodIBus for details. Never forget to set 'character_' |
| 260 key.set_character(character_); | 223 // and 'unmodified_character_' to support i18n VKs like a French VK! |
| 261 key.set_unmodified_character(unmodified_character_); | |
| 262 } | |
| 263 input_method_->ProcessKeyEventPostIME(key, ibus_keyval_, handled); | |
| 264 } | 224 } |
| 265 | 225 |
| 266 // InputMethodIBus::PendingCreateICRequest implementation --------------------- | 226 // InputMethodIBus::PendingCreateICRequest implementation ----------------- |
| 267 class InputMethodIBus::PendingCreateICRequest { | 227 class InputMethodIBus::PendingCreateICRequest { |
| 268 public: | 228 public: |
| 269 PendingCreateICRequest(InputMethodIBus* input_method, | 229 PendingCreateICRequest(InputMethodIBus* input_method, |
| 270 PendingCreateICRequest** request_ptr); | 230 PendingCreateICRequest** request_ptr); |
| 271 ~PendingCreateICRequest(); | 231 ~PendingCreateICRequest(); |
| 272 | 232 |
| 273 // Abandon this pending key event. Its result will just be discarded. | 233 // Abandon this pending key event. Its result will just be discarded. |
| 274 void abandon() { | 234 void Abandon() { |
| 275 input_method_ = NULL; | 235 input_method_ = NULL; |
| 276 request_ptr_ = NULL; | 236 request_ptr_ = NULL; |
| 277 } | 237 } |
| 278 | 238 |
| 279 // Stores the result input context to |input_method_|, or abandon it if | 239 // Stores the result input context to |input_method_|, or abandon it if |
| 280 // |input_method_| is NULL. | 240 // |input_method_| is NULL. |
| 281 void StoreOrAbandonInputContext(IBusInputContext* ic); | 241 void StoreOrAbandonInputContext(IBusInputContext* ic); |
| 282 | 242 |
| 283 private: | 243 private: |
| 284 InputMethodIBus* input_method_; | 244 InputMethodIBus* input_method_; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 304 if (input_method_) { | 264 if (input_method_) { |
| 305 input_method_->SetContext(ic); | 265 input_method_->SetContext(ic); |
| 306 } else { | 266 } else { |
| 307 // ibus_proxy_destroy() will not really release the object, we still need | 267 // ibus_proxy_destroy() will not really release the object, we still need |
| 308 // to call g_object_unref() explicitly. | 268 // to call g_object_unref() explicitly. |
| 309 ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(ic)); | 269 ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(ic)); |
| 310 g_object_unref(ic); | 270 g_object_unref(ic); |
| 311 } | 271 } |
| 312 } | 272 } |
| 313 | 273 |
| 314 // InputMethodIBus implementation --------------------------------------------- | 274 // InputMethodIBus implementation ----------------------------------------- |
| 315 InputMethodIBus::InputMethodIBus(internal::InputMethodDelegate* delegate) | 275 InputMethodIBus::InputMethodIBus( |
| 276 internal::InputMethodDelegate* delegate) | |
| 316 : context_(NULL), | 277 : context_(NULL), |
| 317 pending_create_ic_request_(NULL), | 278 pending_create_ic_request_(NULL), |
| 318 context_focused_(false), | 279 context_focused_(false), |
| 319 composing_text_(false), | 280 composing_text_(false), |
| 320 composition_changed_(false), | 281 composition_changed_(false), |
| 321 suppress_next_result_(false) { | 282 suppress_next_result_(false) { |
| 322 set_delegate(delegate); | 283 set_delegate(delegate); |
| 323 } | 284 } |
| 324 | 285 |
| 325 InputMethodIBus::~InputMethodIBus() { | 286 InputMethodIBus::~InputMethodIBus() { |
| 326 AbandonAllPendingKeyEvents(); | 287 AbandonAllPendingKeyEvents(); |
| 327 DestroyContext(); | 288 DestroyContext(); |
| 328 | 289 |
| 329 // Disconnect bus signals | 290 // Disconnect bus signals |
| 330 g_signal_handlers_disconnect_by_func( | 291 g_signal_handlers_disconnect_by_func( |
| 331 GetIBus(), reinterpret_cast<gpointer>(OnIBusConnectedThunk), this); | 292 GetIBus(), reinterpret_cast<gpointer>(OnIBusConnectedThunk), this); |
| 332 g_signal_handlers_disconnect_by_func( | 293 g_signal_handlers_disconnect_by_func( |
| 333 GetIBus(), reinterpret_cast<gpointer>(OnIBusDisconnectedThunk), this); | 294 GetIBus(), reinterpret_cast<gpointer>(OnIBusDisconnectedThunk), this); |
| 334 } | 295 } |
| 335 | 296 |
| 336 void InputMethodIBus::OnFocus() { | 297 void InputMethodIBus::Init(const base::NativeWindow& system_toplevel_window) { |
|
James Su
2011/11/24 03:57:03
I think we still need to hook OnFocus()/OnBlur() t
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 337 DCHECK(!widget_focused()); | |
| 338 InputMethodBase::OnFocus(); | |
| 339 UpdateContextFocusState(); | |
| 340 } | |
| 341 | |
| 342 void InputMethodIBus::OnBlur() { | |
| 343 DCHECK(widget_focused()); | |
| 344 ConfirmCompositionText(); | |
| 345 InputMethodBase::OnBlur(); | |
| 346 UpdateContextFocusState(); | |
| 347 } | |
| 348 | |
| 349 void InputMethodIBus::Init(Widget* widget) { | |
| 350 // Initializes the connection to ibus daemon. It may happen asynchronously, | 298 // Initializes the connection to ibus daemon. It may happen asynchronously, |
| 351 // and as soon as the connection is established, the |context_| will be | 299 // and as soon as the connection is established, the |context_| will be |
| 352 // created automatically. | 300 // created automatically. |
| 353 IBusBus* bus = GetIBus(); | 301 IBusBus* bus = GetIBus(); |
| 354 | 302 |
| 355 // connect bus signals | 303 // connect bus signals |
| 356 g_signal_connect(bus, "connected", | 304 g_signal_connect(bus, "connected", |
| 357 G_CALLBACK(OnIBusConnectedThunk), this); | 305 G_CALLBACK(OnIBusConnectedThunk), this); |
| 358 g_signal_connect(bus, "disconnected", | 306 g_signal_connect(bus, "disconnected", |
| 359 G_CALLBACK(OnIBusDisconnectedThunk), this); | 307 G_CALLBACK(OnIBusDisconnectedThunk), this); |
| 360 | 308 |
| 361 // Creates the |context_| if the connection is already established. In such | 309 // Creates the |context_| if the connection is already established. In such |
| 362 // case, we will not get "connected" signal. | 310 // case, we will not get "connected" signal. |
| 363 if (ibus_bus_is_connected(bus)) | 311 if (ibus_bus_is_connected(bus)) |
| 364 CreateContext(); | 312 CreateContext(); |
| 365 | 313 |
| 366 InputMethodBase::Init(widget); | 314 InputMethodBase::Init(system_toplevel_window); |
| 367 } | 315 } |
| 368 | 316 |
| 369 void InputMethodIBus::DispatchKeyEvent(const KeyEvent& key) { | 317 void InputMethodIBus::DispatchKeyEvent(const base::NativeEvent& native_event) { |
| 370 DCHECK(key.type() == ui::ET_KEY_PRESSED || key.type() == ui::ET_KEY_RELEASED); | 318 DCHECK(native_event && (native_event->type == KeyPress || |
| 371 DCHECK(widget_focused()); | 319 native_event->type == KeyRelease)); |
| 320 DCHECK(system_toplevel_window_focused()); | |
| 372 | 321 |
| 373 guint32 ibus_keyval = 0; | 322 guint32 ibus_keyval = 0; |
| 374 guint32 ibus_keycode = 0; | 323 guint32 ibus_keycode = 0; |
| 375 guint32 ibus_state = 0; | 324 guint32 ibus_state = 0; |
| 376 IBusKeyEventFromViewsKeyEvent(key, &ibus_keyval, &ibus_keycode, &ibus_state); | 325 IBusKeyEventFromNativeKeyEvent( |
| 326 native_event, &ibus_keyval, &ibus_keycode, &ibus_state); | |
| 377 | 327 |
| 378 // If |context_| is not usable, then we can only dispatch the key event as is. | 328 // If |context_| is not usable, then we can only dispatch the key event as is. |
| 379 // We also dispatch the key event directly if the current text input type is | 329 // We also dispatch the key event directly if the current text input type is |
| 380 // ui::TEXT_INPUT_TYPE_PASSWORD, to bypass the input method. | 330 // TEXT_INPUT_TYPE_PASSWORD, to bypass the input method. |
| 381 // Note: We need to send the key event to ibus even if the |context_| is not | 331 // Note: We need to send the key event to ibus even if the |context_| is not |
| 382 // enabled, so that ibus can have a chance to enable the |context_|. | 332 // enabled, so that ibus can have a chance to enable the |context_|. |
| 383 if (!context_focused_ || | 333 if (!context_focused_ || |
| 384 GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD) { | 334 GetTextInputType() == TEXT_INPUT_TYPE_PASSWORD) { |
| 385 if (key.type() == ui::ET_KEY_PRESSED) | 335 if (native_event->type == KeyPress) |
| 386 ProcessUnfilteredKeyPressEvent(key, ibus_keyval); | 336 ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); |
| 387 else | 337 else |
| 388 DispatchKeyEventPostIME(key); | 338 DispatchKeyEventPostIME(native_event); |
| 389 return; | 339 return; |
| 390 } | 340 } |
| 391 | 341 |
| 392 PendingKeyEvent* pending_key = new PendingKeyEvent(this, key, ibus_keyval); | 342 PendingKeyEvent* pending_key = |
| 343 new PendingKeyEvent(this, native_event, ibus_keyval); | |
| 393 pending_key_events_.insert(pending_key); | 344 pending_key_events_.insert(pending_key); |
| 394 | 345 |
| 395 // Note: | 346 // Note: |
| 396 // 1. We currently set timeout to -1, because ibus doesn't have a mechanism to | 347 // 1. We currently set timeout to -1, because ibus doesn't have a mechanism to |
| 397 // associate input method results to corresponding key event, thus there is | 348 // associate input method results to corresponding key event, thus there is |
| 398 // actually no way to abandon results generated by a specific key event. So we | 349 // actually no way to abandon results generated by a specific key event. So we |
| 399 // actually cannot abandon a specific key event and its result but accept | 350 // actually cannot abandon a specific key event and its result but accept |
| 400 // following key events and their results. So a timeout to abandon a key event | 351 // following key events and their results. So a timeout to abandon a key event |
| 401 // will not work. | 352 // will not work. |
| 402 // 2. We set GCancellable to NULL, because the operation of cancelling a async | 353 // 2. We set GCancellable to NULL, because the operation of cancelling a async |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 413 context_, | 364 context_, |
| 414 ibus_keyval, ibus_keycode, ibus_state, -1, NULL, | 365 ibus_keyval, ibus_keycode, ibus_state, -1, NULL, |
| 415 reinterpret_cast<GAsyncReadyCallback>(ProcessKeyEventDone), | 366 reinterpret_cast<GAsyncReadyCallback>(ProcessKeyEventDone), |
| 416 pending_key); | 367 pending_key); |
| 417 | 368 |
| 418 // We don't want to suppress the result generated by this key event, but it | 369 // We don't want to suppress the result generated by this key event, but it |
| 419 // may cause problem. See comment in ResetContext() method. | 370 // may cause problem. See comment in ResetContext() method. |
| 420 suppress_next_result_ = false; | 371 suppress_next_result_ = false; |
| 421 } | 372 } |
| 422 | 373 |
| 423 void InputMethodIBus::OnTextInputTypeChanged(View* view) { | 374 void InputMethodIBus::OnTextInputTypeChanged(const TextInputClient* client) { |
| 424 if (context_ && IsViewFocused(view)) { | 375 if (context_ && client && (GetTextInputClient() == client)) { |
|
James Su
2011/11/24 03:57:03
If we have InputMethodBase::IsTextInputClientFocus
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 425 ResetContext(); | 376 ResetContext(); |
| 426 UpdateContextFocusState(); | 377 UpdateContextFocusState(); |
| 427 } | 378 } |
| 428 InputMethodBase::OnTextInputTypeChanged(view); | 379 InputMethodBase::OnTextInputTypeChanged(client); |
| 429 } | 380 } |
| 430 | 381 |
| 431 void InputMethodIBus::OnCaretBoundsChanged(View* view) { | 382 void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) { |
| 432 if (!context_focused_ || !IsViewFocused(view)) | 383 if (!context_focused_ || !client || (GetTextInputClient() != client)) |
|
James Su
2011/11/24 03:57:03
ditto.
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 433 return; | 384 return; |
| 434 | 385 |
| 435 // The current text input type should not be NONE if |context_| is focused. | 386 // The current text input type should not be NONE if |context_| is focused. |
| 436 DCHECK(!IsTextInputTypeNone()); | 387 DCHECK(!IsTextInputTypeNone()); |
| 437 | 388 const gfx::Rect rect = GetTextInputClient()->GetCaretBounds(); |
| 438 gfx::Rect rect = GetTextInputClient()->GetCaretBounds(); | |
| 439 gfx::Point origin = rect.origin(); | |
| 440 gfx::Point end = gfx::Point(rect.right(), rect.bottom()); | |
| 441 | |
| 442 // We need to convert the origin and end points separately, in case the View | |
| 443 // is scaled. | |
| 444 View::ConvertPointToScreen(view, &origin); | |
| 445 View::ConvertPointToScreen(view, &end); | |
| 446 | 389 |
| 447 // This function runs asynchronously. | 390 // This function runs asynchronously. |
| 448 ibus_input_context_set_cursor_location( | 391 ibus_input_context_set_cursor_location( |
| 449 context_, origin.x(), origin.y(), | 392 context_, rect.x(), rect.y(), rect.width(), rect.height()); |
| 450 end.x() - origin.x(), end.y() - origin.y()); | |
| 451 } | 393 } |
| 452 | 394 |
| 453 void InputMethodIBus::CancelComposition(View* view) { | 395 void InputMethodIBus::CancelComposition(const TextInputClient* client) { |
| 454 if (context_focused_ && IsViewFocused(view)) | 396 if (context_focused_ && client && (GetTextInputClient() == client)) |
|
James Su
2011/11/24 03:57:03
ditto.
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 455 ResetContext(); | 397 ResetContext(); |
| 456 } | 398 } |
| 457 | 399 |
| 458 std::string InputMethodIBus::GetInputLocale() { | 400 std::string InputMethodIBus::GetInputLocale() { |
| 459 // Not supported. | 401 // Not supported. |
| 460 return std::string(""); | 402 return ""; |
| 461 } | 403 } |
| 462 | 404 |
| 463 base::i18n::TextDirection InputMethodIBus::GetInputTextDirection() { | 405 base::i18n::TextDirection InputMethodIBus::GetInputTextDirection() { |
| 464 // Not supported. | 406 // Not supported. |
| 465 return base::i18n::UNKNOWN_DIRECTION; | 407 return base::i18n::UNKNOWN_DIRECTION; |
| 466 } | 408 } |
| 467 | 409 |
| 468 bool InputMethodIBus::IsActive() { | 410 bool InputMethodIBus::IsActive() { |
| 469 return true; | 411 return true; |
| 470 } | 412 } |
| 471 | 413 |
| 472 // static | |
| 473 bool InputMethodIBus::IsInputMethodIBusEnabled() { | |
| 474 #if defined(TOUCH_UI) | |
| 475 return true; | |
| 476 #else | |
| 477 return inputmethod_ibus_enabled || | |
| 478 CommandLine::ForCurrentProcess()->HasSwitch( | |
| 479 kEnableInputMethodIBusSwitch); | |
| 480 #endif | |
| 481 } | |
| 482 | |
| 483 // static | |
| 484 void InputMethodIBus::SetEnableInputMethodIBus(bool enabled) { | |
| 485 inputmethod_ibus_enabled = enabled; | |
| 486 } | |
| 487 | |
| 488 void InputMethodIBus::OnWillChangeFocus(View* focused_before, View* focused) { | |
| 489 ConfirmCompositionText(); | |
| 490 } | |
| 491 | |
| 492 void InputMethodIBus::OnDidChangeFocus(View* focused_before, View* focused) { | |
| 493 UpdateContextFocusState(); | |
| 494 | |
| 495 // Force to update caret bounds, in case the View thinks that the caret | |
| 496 // bounds has not changed. | |
| 497 if (context_focused_) | |
| 498 OnCaretBoundsChanged(GetFocusedView()); | |
| 499 } | |
| 500 | |
| 501 void InputMethodIBus::CreateContext() { | 414 void InputMethodIBus::CreateContext() { |
| 502 DCHECK(!context_); | 415 DCHECK(!context_); |
| 503 DCHECK(GetIBus()); | 416 DCHECK(GetIBus()); |
| 504 DCHECK(ibus_bus_is_connected(GetIBus())); | 417 DCHECK(ibus_bus_is_connected(GetIBus())); |
| 505 DCHECK(!pending_create_ic_request_); | 418 DCHECK(!pending_create_ic_request_); |
| 506 | 419 |
| 507 // Creates the input context asynchronously. | 420 // Creates the input context asynchronously. |
| 508 pending_create_ic_request_ = new PendingCreateICRequest( | 421 pending_create_ic_request_ = new PendingCreateICRequest( |
| 509 this, &pending_create_ic_request_); | 422 this, &pending_create_ic_request_); |
| 510 ibus_bus_create_input_context_async( | 423 ibus_bus_create_input_context_async( |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 537 ibus_input_context_set_capabilities(ic, caps); | 450 ibus_input_context_set_capabilities(ic, caps); |
| 538 | 451 |
| 539 UpdateContextFocusState(); | 452 UpdateContextFocusState(); |
| 540 OnInputMethodChanged(); | 453 OnInputMethodChanged(); |
| 541 } | 454 } |
| 542 | 455 |
| 543 void InputMethodIBus::DestroyContext() { | 456 void InputMethodIBus::DestroyContext() { |
| 544 if (pending_create_ic_request_) { | 457 if (pending_create_ic_request_) { |
| 545 DCHECK(!context_); | 458 DCHECK(!context_); |
| 546 // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). | 459 // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). |
| 547 pending_create_ic_request_->abandon(); | 460 pending_create_ic_request_->Abandon(); |
| 548 pending_create_ic_request_ = NULL; | 461 pending_create_ic_request_ = NULL; |
| 549 } else if (context_) { | 462 } else if (context_) { |
| 550 // ibus_proxy_destroy() will not really release the resource of |context_| | 463 // ibus_proxy_destroy() will not really release the resource of |context_| |
| 551 // object. We still need to handle "destroy" signal and call | 464 // object. We still need to handle "destroy" signal and call |
| 552 // g_object_unref() there. | 465 // g_object_unref() there. |
| 553 ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(context_)); | 466 ibus_proxy_destroy(reinterpret_cast<IBusProxy *>(context_)); |
| 554 DCHECK(!context_); | 467 DCHECK(!context_); |
| 555 } | 468 } |
| 556 } | 469 } |
| 557 | 470 |
| 558 void InputMethodIBus::ConfirmCompositionText() { | 471 void InputMethodIBus::ConfirmCompositionText() { |
| 559 ui::TextInputClient* client = GetTextInputClient(); | 472 TextInputClient* client = GetTextInputClient(); |
| 560 if (client && client->HasCompositionText()) | 473 if (client && client->HasCompositionText()) |
| 561 client->ConfirmCompositionText(); | 474 client->ConfirmCompositionText(); |
| 562 | 475 |
| 563 ResetContext(); | 476 ResetContext(); |
| 564 } | 477 } |
| 565 | 478 |
| 566 void InputMethodIBus::ResetContext() { | 479 void InputMethodIBus::ResetContext() { |
| 567 if (!context_focused_ || !GetTextInputClient()) | 480 if (!context_focused_ || !GetTextInputClient()) |
| 568 return; | 481 return; |
| 569 | 482 |
| 570 DCHECK(widget_focused()); | 483 DCHECK(system_toplevel_window_focused()); |
| 571 DCHECK(GetFocusedView()); | |
| 572 | 484 |
| 573 // Because ibus runs in asynchronous mode, the input method may still send us | 485 // Because ibus runs in asynchronous mode, the input method may still send us |
| 574 // results after sending out the reset request, so we use a flag to discard | 486 // results after sending out the reset request, so we use a flag to discard |
| 575 // all results generated by previous key events. But because ibus does not | 487 // all results generated by previous key events. But because ibus does not |
| 576 // have a mechanism to identify each key event and corresponding results, this | 488 // have a mechanism to identify each key event and corresponding results, this |
| 577 // approach will not work for some corner cases. For example if the user types | 489 // approach will not work for some corner cases. For example if the user types |
| 578 // very fast, then the next key event may come in before the |context_| is | 490 // very fast, then the next key event may come in before the |context_| is |
| 579 // really reset. Then we actually cannot know whether or not the next | 491 // really reset. Then we actually cannot know whether or not the next |
| 580 // result should be discard. | 492 // result should be discard. |
| 581 suppress_next_result_ = true; | 493 suppress_next_result_ = true; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 601 | 513 |
| 602 void InputMethodIBus::UpdateContextFocusState() { | 514 void InputMethodIBus::UpdateContextFocusState() { |
| 603 if (!context_) { | 515 if (!context_) { |
| 604 context_focused_ = false; | 516 context_focused_ = false; |
| 605 return; | 517 return; |
| 606 } | 518 } |
| 607 | 519 |
| 608 const bool old_context_focused = context_focused_; | 520 const bool old_context_focused = context_focused_; |
| 609 // Use switch here in case we are going to add more text input types. | 521 // Use switch here in case we are going to add more text input types. |
| 610 switch (GetTextInputType()) { | 522 switch (GetTextInputType()) { |
| 611 case ui::TEXT_INPUT_TYPE_NONE: | 523 case TEXT_INPUT_TYPE_NONE: |
| 612 case ui::TEXT_INPUT_TYPE_PASSWORD: | 524 case TEXT_INPUT_TYPE_PASSWORD: |
| 613 context_focused_ = false; | 525 context_focused_ = false; |
| 614 break; | 526 break; |
| 615 default: | 527 default: |
| 616 context_focused_ = true; | 528 context_focused_ = true; |
| 617 break; | 529 break; |
| 618 } | 530 } |
| 619 | 531 |
| 620 // We only focus in |context_| when the focus is in a normal textfield. | 532 // We only focus in |context_| when the focus is in a normal textfield. |
| 621 // ibus_input_context_focus_{in|out}() run asynchronously. | 533 // ibus_input_context_focus_{in|out}() run asynchronously. |
| 622 if (old_context_focused && !context_focused_) | 534 if (old_context_focused && !context_focused_) |
| 623 ibus_input_context_focus_out(context_); | 535 ibus_input_context_focus_out(context_); |
| 624 else if (!old_context_focused && context_focused_) | 536 else if (!old_context_focused && context_focused_) |
| 625 ibus_input_context_focus_in(context_); | 537 ibus_input_context_focus_in(context_); |
| 626 } | 538 } |
| 627 | 539 |
| 628 void InputMethodIBus::ProcessKeyEventPostIME(const KeyEvent& key, | 540 void InputMethodIBus::ProcessKeyEventPostIME( |
| 629 guint32 ibus_keyval, | 541 const base::NativeEvent& native_event, |
| 630 bool handled) { | 542 guint32 ibus_keyval, |
| 543 bool handled) { | |
| 544 TextInputClient* client = GetTextInputClient(); | |
| 545 | |
| 631 // If we get here without a focused text input client, then it means the key | 546 // If we get here without a focused text input client, then it means the key |
| 632 // event is sent to the global ibus input context. | 547 // event is sent to the fake ibus input context. |
| 633 if (!GetTextInputClient()) { | 548 // TODO(yusukes): Can we remove this check? We no longer use the fake context. |
|
James Su
2011/11/24 03:57:03
As ibus works asynchronously, there is still chanc
Yusuke Sato
2011/11/28 06:29:40
Thanks. Updated the comment.
On 2011/11/24 03:57:
| |
| 634 DispatchKeyEventPostIME(key); | 549 if (!client) { |
| 550 DispatchKeyEventPostIME(native_event); | |
| 635 return; | 551 return; |
| 636 } | 552 } |
| 637 | 553 |
| 638 const View* old_focused_view = GetFocusedView(); | 554 if (native_event->type == KeyPress && handled) |
| 639 | 555 ProcessFilteredKeyPressEvent(native_event); |
| 640 // Same reason as above DCHECK. | |
| 641 DCHECK(old_focused_view); | |
| 642 | |
| 643 if (key.type() == ui::ET_KEY_PRESSED && handled) | |
| 644 ProcessFilteredKeyPressEvent(key); | |
| 645 | 556 |
| 646 // In case the focus was changed by the key event. The |context_| should have | 557 // In case the focus was changed by the key event. The |context_| should have |
| 647 // been reset when the focused view changed. | 558 // been reset when the focused window changed. |
| 648 if (old_focused_view != GetFocusedView()) | 559 if (client != GetTextInputClient()) |
| 649 return; | 560 return; |
| 650 | 561 |
| 651 if (HasInputMethodResult()) | 562 if (HasInputMethodResult()) |
| 652 ProcessInputMethodResult(key, handled); | 563 ProcessInputMethodResult(native_event, handled); |
| 653 | 564 |
| 654 // In case the focus was changed when sending input method results to the | 565 // In case the focus was changed when sending input method results to the |
| 655 // focused View. | 566 // focused window. |
| 656 if (old_focused_view != GetFocusedView()) | 567 if (client != GetTextInputClient()) |
| 657 return; | 568 return; |
| 658 | 569 |
| 659 if (key.type() == ui::ET_KEY_PRESSED && !handled) | 570 if (native_event->type == KeyPress && !handled) |
| 660 ProcessUnfilteredKeyPressEvent(key, ibus_keyval); | 571 ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); |
| 661 else if (key.type() == ui::ET_KEY_RELEASED) | 572 else if (native_event->type == KeyRelease) |
| 662 DispatchKeyEventPostIME(key); | 573 DispatchKeyEventPostIME(native_event); |
| 663 } | 574 } |
| 664 | 575 |
| 665 void InputMethodIBus::ProcessFilteredKeyPressEvent(const KeyEvent& key) { | 576 void InputMethodIBus::ProcessFilteredKeyPressEvent( |
| 666 if (NeedInsertChar()) { | 577 const base::NativeEvent& native_event) { |
| 667 DispatchKeyEventPostIME(key); | 578 if (NeedInsertChar()) |
| 668 } else { | 579 DispatchKeyEventPostIME(native_event); |
| 669 KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, key.flags()); | 580 else |
| 670 DispatchKeyEventPostIME(key); | 581 DispatchFabricatedKeyEventPostIME( |
| 671 } | 582 ET_KEY_PRESSED, |
| 583 VKEY_PROCESSKEY, | |
| 584 EventFlagsFromXFlags(GetKeyEvent(native_event)->state)); | |
| 672 } | 585 } |
| 673 | 586 |
| 674 void InputMethodIBus::ProcessUnfilteredKeyPressEvent(const KeyEvent& key, | 587 void InputMethodIBus::ProcessUnfilteredKeyPressEvent( |
| 675 guint32 ibus_keyval) { | 588 const base::NativeEvent& native_event, guint32 ibus_keyval) { |
| 676 const View* old_focused_view = GetFocusedView(); | 589 // For a fabricated event, ProcessUnfilteredFabricatedKeyPressEvent should be |
| 677 DispatchKeyEventPostIME(key); | 590 // called instead. |
| 591 DCHECK(native_event); | |
| 678 | 592 |
| 679 // We shouldn't dispatch the character anymore if the key event caused focus | 593 TextInputClient* client = GetTextInputClient(); |
| 680 // change. | 594 DispatchKeyEventPostIME(native_event); |
| 681 if (old_focused_view != GetFocusedView()) | 595 |
| 596 // We shouldn't dispatch the character anymore if the key event dispatch | |
| 597 // caused focus change. For example, in the following scenario, | |
| 598 // 1. visit a web page which has a <textarea>. | |
| 599 // 2. click Omnibox. | |
| 600 // 3. enable Korean IME, press A, then press Tab to move the focus to the web | |
| 601 // page. | |
| 602 // We should return here not to send the Tab key event to RWHV. | |
| 603 if (client != GetTextInputClient()) | |
| 682 return; | 604 return; |
| 683 | 605 |
| 684 // Process compose and dead keys | 606 // Process compose and dead keys |
| 685 if (character_composer_.FilterKeyPress(ibus_keyval)) { | 607 if (character_composer_.FilterKeyPress(ibus_keyval)) { |
| 686 string16 composed = character_composer_.composed_character(); | 608 string16 composed = character_composer_.composed_character(); |
| 687 if (!composed.empty()) { | 609 if (!composed.empty()) { |
| 688 ui::TextInputClient* client = GetTextInputClient(); | 610 client = GetTextInputClient(); |
| 689 if (client) | 611 if (client) |
| 690 client->InsertText(composed); | 612 client->InsertText(composed); |
| 691 } | 613 } |
| 692 return; | 614 return; |
| 693 } | 615 } |
| 616 | |
| 694 // If a key event was not filtered by |context_| and |character_composer_|, | 617 // If a key event was not filtered by |context_| and |character_composer_|, |
| 695 // then it means the key event didn't generate any result text. So we need | 618 // then it means the key event didn't generate any result text. So we need |
| 696 // to send corresponding character to the focused text input client. | 619 // to send corresponding character to the focused text input client. |
| 620 client = GetTextInputClient(); | |
| 697 | 621 |
| 698 ui::TextInputClient* client = GetTextInputClient(); | 622 const KeyboardCode key_code = ui::KeyboardCodeFromNative(native_event); |
|
James Su
2011/11/24 03:57:03
move this line into the if (!ch) block below.
Yusuke Sato
2011/11/28 06:29:40
Done.
| |
| 699 char16 ch = key.GetCharacter(); | 623 const uint32 state = |
| 700 if (ch && client) | 624 EventFlagsFromXFlags(GetKeyEvent(native_event)->state); |
| 701 client->InsertChar(ch, key.flags()); | 625 uint16 ch = ui::DefaultSymbolFromXEvent(native_event); |
| 626 if (!ch) | |
| 627 ch = ui::GetCharacterFromKeyCode(key_code, state); | |
| 628 | |
| 629 if (client && ch) | |
| 630 client->InsertChar(ch, state); | |
| 702 } | 631 } |
| 703 | 632 |
| 704 void InputMethodIBus::ProcessInputMethodResult(const KeyEvent& key, | 633 void InputMethodIBus::ProcessUnfilteredFabricatedKeyPressEvent( |
| 705 bool handled) { | 634 EventType type, KeyboardCode key_code, int flags, guint32 ibus_keyval) { |
| 706 ui::TextInputClient* client = GetTextInputClient(); | 635 TextInputClient* client = GetTextInputClient(); |
| 636 DispatchFabricatedKeyEventPostIME(type, key_code, flags); | |
| 637 | |
| 638 if (client != GetTextInputClient()) | |
| 639 return; | |
| 640 | |
| 641 if (character_composer_.FilterKeyPress(ibus_keyval)) { | |
| 642 string16 composed = character_composer_.composed_character(); | |
| 643 if (!composed.empty()) { | |
| 644 client = GetTextInputClient(); | |
| 645 if (client) | |
| 646 client->InsertText(composed); | |
| 647 } | |
| 648 return; | |
| 649 } | |
| 650 | |
| 651 client = GetTextInputClient(); | |
| 652 const uint16 ch = ui::GetCharacterFromKeyCode(key_code, flags); | |
| 653 if (client && ch) | |
| 654 client->InsertChar(ch, flags); | |
| 655 } | |
| 656 | |
| 657 void InputMethodIBus::ProcessInputMethodResult( | |
| 658 const base::NativeEvent& native_event, bool handled) { | |
| 659 TextInputClient* client = GetTextInputClient(); | |
| 707 DCHECK(client); | 660 DCHECK(client); |
| 708 | 661 |
| 709 if (result_text_.length()) { | 662 if (result_text_.length()) { |
| 710 if (handled && NeedInsertChar()) { | 663 if (handled && NeedInsertChar()) { |
| 664 const uint32 state = | |
| 665 EventFlagsFromXFlags(GetKeyEvent(native_event)->state); | |
| 711 for (string16::const_iterator i = result_text_.begin(); | 666 for (string16::const_iterator i = result_text_.begin(); |
| 712 i != result_text_.end(); ++i) { | 667 i != result_text_.end(); ++i) { |
| 713 client->InsertChar(*i, key.flags()); | 668 client->InsertChar(*i, state); |
| 714 } | 669 } |
| 715 } else { | 670 } else { |
| 716 client->InsertText(result_text_); | 671 client->InsertText(result_text_); |
| 717 composing_text_ = false; | 672 composing_text_ = false; |
| 718 } | 673 } |
| 719 } | 674 } |
| 720 | 675 |
| 721 if (composition_changed_ && !IsTextInputTypeNone()) { | 676 if (composition_changed_ && !IsTextInputTypeNone()) { |
| 722 if (composition_.text.length()) { | 677 if (composition_.text.length()) { |
| 723 composing_text_ = true; | 678 composing_text_ = true; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 737 return GetTextInputClient() && | 692 return GetTextInputClient() && |
| 738 (IsTextInputTypeNone() || | 693 (IsTextInputTypeNone() || |
| 739 (!composing_text_ && result_text_.length() == 1)); | 694 (!composing_text_ && result_text_.length() == 1)); |
| 740 } | 695 } |
| 741 | 696 |
| 742 bool InputMethodIBus::HasInputMethodResult() const { | 697 bool InputMethodIBus::HasInputMethodResult() const { |
| 743 return result_text_.length() || composition_changed_; | 698 return result_text_.length() || composition_changed_; |
| 744 } | 699 } |
| 745 | 700 |
| 746 void InputMethodIBus::SendFakeProcessKeyEvent(bool pressed) const { | 701 void InputMethodIBus::SendFakeProcessKeyEvent(bool pressed) const { |
| 747 KeyEvent key(pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED, | 702 DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, |
| 748 ui::VKEY_PROCESSKEY, 0); | 703 VKEY_PROCESSKEY, |
| 749 DispatchKeyEventPostIME(key); | 704 0); |
| 750 } | 705 } |
| 751 | 706 |
| 752 void InputMethodIBus::FinishPendingKeyEvent(PendingKeyEvent* pending_key) { | 707 void InputMethodIBus::FinishPendingKeyEvent(PendingKeyEvent* pending_key) { |
| 753 DCHECK(pending_key_events_.count(pending_key)); | 708 DCHECK(pending_key_events_.count(pending_key)); |
| 754 | 709 |
| 755 // |pending_key| will be deleted in ProcessKeyEventDone(). | 710 // |pending_key| will be deleted in ProcessKeyEventDone(). |
| 756 pending_key_events_.erase(pending_key); | 711 pending_key_events_.erase(pending_key); |
| 757 } | 712 } |
| 758 | 713 |
| 759 void InputMethodIBus::AbandonAllPendingKeyEvents() { | 714 void InputMethodIBus::AbandonAllPendingKeyEvents() { |
| 760 for (std::set<PendingKeyEvent*>::iterator i = pending_key_events_.begin(); | 715 for (std::set<PendingKeyEvent*>::iterator i = pending_key_events_.begin(); |
| 761 i != pending_key_events_.end(); ++i) { | 716 i != pending_key_events_.end(); ++i) { |
| 762 // The object will be deleted in ProcessKeyEventDone(). | 717 // The object will be deleted in ProcessKeyEventDone(). |
| 763 (*i)->abandon(); | 718 (*i)->Abandon(); |
| 764 } | 719 } |
| 765 pending_key_events_.clear(); | 720 pending_key_events_.clear(); |
| 766 } | 721 } |
| 767 | 722 |
| 768 void InputMethodIBus::OnCommitText(IBusInputContext* context, IBusText* text) { | 723 void InputMethodIBus::OnCommitText( |
| 724 IBusInputContext* context, IBusText* text) { | |
| 769 DCHECK_EQ(context_, context); | 725 DCHECK_EQ(context_, context); |
| 770 if (suppress_next_result_ || !text || !text->text) | 726 if (suppress_next_result_ || !text || !text->text) |
| 771 return; | 727 return; |
| 772 | 728 |
| 773 // We need to receive input method result even if the text input type is | 729 // We need to receive input method result even if the text input type is |
| 774 // ui::TEXT_INPUT_TYPE_NONE, to make sure we can always send correct | 730 // TEXT_INPUT_TYPE_NONE, to make sure we can always send correct |
| 775 // character for each key event to the focused text input client. | 731 // character for each key event to the focused text input client. |
| 776 if (!GetTextInputClient()) | 732 if (!GetTextInputClient()) |
| 777 return; | 733 return; |
| 778 | 734 |
| 779 string16 utf16_text(UTF8ToUTF16(text->text)); | 735 string16 utf16_text(UTF8ToUTF16(text->text)); |
| 780 | 736 |
| 781 // Append the text to the buffer, because commit signal might be fired | 737 // Append the text to the buffer, because commit signal might be fired |
| 782 // multiple times when processing a key event. | 738 // multiple times when processing a key event. |
| 783 result_text_.append(utf16_text); | 739 result_text_.append(utf16_text); |
| 784 | 740 |
| 785 // If we are not handling key event, do not bother sending text result if the | 741 // If we are not handling key event, do not bother sending text result if the |
| 786 // focused text input client does not support text input. | 742 // focused text input client does not support text input. |
| 787 if (pending_key_events_.empty() && !IsTextInputTypeNone()) { | 743 if (pending_key_events_.empty() && !IsTextInputTypeNone()) { |
| 788 SendFakeProcessKeyEvent(true); | 744 SendFakeProcessKeyEvent(true); |
| 789 GetTextInputClient()->InsertText(utf16_text); | 745 GetTextInputClient()->InsertText(utf16_text); |
| 790 SendFakeProcessKeyEvent(false); | 746 SendFakeProcessKeyEvent(false); |
| 791 result_text_.clear(); | 747 result_text_.clear(); |
| 792 } | 748 } |
| 793 } | 749 } |
| 794 | 750 |
| 795 void InputMethodIBus::OnForwardKeyEvent(IBusInputContext* context, | 751 void InputMethodIBus::OnForwardKeyEvent(IBusInputContext* context, |
| 796 guint keyval, | 752 guint keyval, |
| 797 guint keycode, | 753 guint keycode, |
| 798 guint state) { | 754 guint state) { |
| 799 DCHECK_EQ(context_, context); | 755 DCHECK_EQ(context_, context); |
| 800 | 756 |
| 801 ui::KeyboardCode key_code = ui::VKEY_UNKNOWN; | 757 KeyboardCode ui_key_code = KeyboardCodeFromXKeysym(keyval); |
| 802 #if defined(USE_AURA) || defined(TOUCH_UI) | 758 if (!ui_key_code) |
| 803 key_code = ui::KeyboardCodeFromXKeysym(keyval); | |
| 804 #elif defined(TOOLKIT_USES_GTK) | |
| 805 key_code = ui::WindowsKeyCodeForGdkKeyCode(keyval); | |
| 806 #endif | |
| 807 | |
| 808 if (!key_code) | |
| 809 return; | 759 return; |
| 810 | 760 |
| 811 KeyEvent key(state & IBUS_RELEASE_MASK ? | 761 const EventType event = |
| 812 ui::ET_KEY_RELEASED : ui::ET_KEY_PRESSED, | 762 (state & IBUS_RELEASE_MASK) ? ET_KEY_RELEASED : ET_KEY_PRESSED; |
| 813 key_code, EventFlagsFromIBusState(state)); | 763 const int flags = EventFlagsFromIBusState(state); |
| 814 | 764 |
| 815 // It is not clear when the input method will forward us a fake key event. | 765 // It is not clear when the input method will forward us a fake key event. |
| 816 // If there is a pending key event, then we may already received some input | 766 // If there is a pending key event, then we may already received some input |
| 817 // method results, so we dispatch this fake key event directly rather than | 767 // method results, so we dispatch this fake key event directly rather than |
| 818 // calling ProcessKeyEventPostIME(), which will clear pending input method | 768 // calling ProcessKeyEventPostIME(), which will clear pending input method |
| 819 // results. | 769 // results. |
| 820 if (key.type() == ui::ET_KEY_PRESSED) | 770 if (event == ET_KEY_PRESSED) |
| 821 ProcessUnfilteredKeyPressEvent(key, keyval); | 771 ProcessUnfilteredFabricatedKeyPressEvent(event, ui_key_code, flags, keyval); |
| 822 else | 772 else |
| 823 DispatchKeyEventPostIME(key); | 773 DispatchFabricatedKeyEventPostIME(event, ui_key_code, flags); |
| 824 } | 774 } |
| 825 | 775 |
| 826 void InputMethodIBus::OnShowPreeditText(IBusInputContext* context) { | 776 void InputMethodIBus::OnShowPreeditText(IBusInputContext* context) { |
| 827 DCHECK_EQ(context_, context); | 777 DCHECK_EQ(context_, context); |
| 828 if (suppress_next_result_ || IsTextInputTypeNone()) | 778 if (suppress_next_result_ || IsTextInputTypeNone()) |
| 829 return; | 779 return; |
| 830 | 780 |
| 831 composing_text_ = true; | 781 composing_text_ = true; |
| 832 } | 782 } |
| 833 | 783 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 873 void InputMethodIBus::OnHidePreeditText(IBusInputContext* context) { | 823 void InputMethodIBus::OnHidePreeditText(IBusInputContext* context) { |
| 874 DCHECK_EQ(context_, context); | 824 DCHECK_EQ(context_, context); |
| 875 if (composition_.text.empty() || IsTextInputTypeNone()) | 825 if (composition_.text.empty() || IsTextInputTypeNone()) |
| 876 return; | 826 return; |
| 877 | 827 |
| 878 // Intentionally leaves |composing_text_| unchanged. | 828 // Intentionally leaves |composing_text_| unchanged. |
| 879 composition_changed_ = true; | 829 composition_changed_ = true; |
| 880 composition_.Clear(); | 830 composition_.Clear(); |
| 881 | 831 |
| 882 if (pending_key_events_.empty()) { | 832 if (pending_key_events_.empty()) { |
| 883 ui::TextInputClient* client = GetTextInputClient(); | 833 TextInputClient* client = GetTextInputClient(); |
| 884 if (client && client->HasCompositionText()) | 834 if (client && client->HasCompositionText()) |
| 885 client->ClearCompositionText(); | 835 client->ClearCompositionText(); |
| 886 composition_changed_ = false; | 836 composition_changed_ = false; |
| 887 } | 837 } |
| 888 } | 838 } |
| 889 | 839 |
| 890 void InputMethodIBus::OnDestroy(IBusInputContext* context) { | 840 void InputMethodIBus::OnDestroy(IBusInputContext* context) { |
| 891 DCHECK_EQ(context_, context); | 841 DCHECK_EQ(context_, context); |
| 892 g_object_unref(context_); | 842 g_object_unref(context_); |
| 893 context_ = NULL; | 843 context_ = NULL; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 951 PendingCreateICRequest* data) { | 901 PendingCreateICRequest* data) { |
| 952 DCHECK_EQ(GetIBus(), bus); | 902 DCHECK_EQ(GetIBus(), bus); |
| 953 DCHECK(data); | 903 DCHECK(data); |
| 954 IBusInputContext* ic = | 904 IBusInputContext* ic = |
| 955 ibus_bus_create_input_context_async_finish(bus, res, NULL); | 905 ibus_bus_create_input_context_async_finish(bus, res, NULL); |
| 956 if (ic) | 906 if (ic) |
| 957 data->StoreOrAbandonInputContext(ic); | 907 data->StoreOrAbandonInputContext(ic); |
| 958 delete data; | 908 delete data; |
| 959 } | 909 } |
| 960 | 910 |
| 961 } // namespace views | 911 } // namespace ui |
| OLD | NEW |