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