Chromium Code Reviews| Index: ui/base/ime/input_method_ibus.cc |
| diff --git a/ui/views/ime/input_method_ibus.cc b/ui/base/ime/input_method_ibus.cc |
| similarity index 69% |
| copy from ui/views/ime/input_method_ibus.cc |
| copy to ui/base/ime/input_method_ibus.cc |
| index f9ffe6c2c78725123924152385bd649ce4606d2b..e016d1c9c1fdd798d779a64a20be0662464e86c8 100644 |
| --- a/ui/views/ime/input_method_ibus.cc |
| +++ b/ui/base/ime/input_method_ibus.cc |
| @@ -2,42 +2,39 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "ui/views/ime/input_method_ibus.h" |
| +#include "ui/base/ime/input_method_ibus.h" |
| #include <ibus.h> |
| -#if defined(TOUCH_UI) |
| + |
| +#include <X11/X.h> |
| #include <X11/Xlib.h> |
| #include <X11/Xutil.h> |
| -#endif |
| #include <algorithm> |
| #include <cstring> |
| #include <set> |
| #include <vector> |
| -#include "base/basictypes.h" |
| #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.
|
| +#include "base/basictypes.h" |
| #include "base/i18n/char_iterator.h" |
| #include "base/logging.h" |
| #include "base/string_util.h" |
| #include "base/third_party/icu/icu_utf.h" |
| #include "base/utf_string_conversions.h" |
| +#include "ui/base/events.h" |
| +#include "ui/base/ime/text_input_client.h" |
| #include "ui/base/keycodes/keyboard_codes.h" |
| -#include "ui/gfx/point.h" |
| -#include "ui/gfx/rect.h" |
| -#include "ui/views/events/event.h" |
| -#include "ui/views/widget/widget.h" |
| - |
| -#if defined(USE_AURA) || defined(TOUCH_UI) |
| +#include "ui/base/keycodes/keyboard_code_conversion.h" |
| #include "ui/base/keycodes/keyboard_code_conversion_x.h" |
| -#elif defined(TOOLKIT_USES_GTK) |
| -#include "ui/base/keycodes/keyboard_code_conversion_gtk.h" |
| -#endif |
| +#include "ui/gfx/rect.h" |
| namespace { |
| -// A global flag to switch the InputMethod implementation to InputMethodIBus |
| -bool inputmethod_ibus_enabled = false; |
| +XKeyEvent* GetKeyEvent(XEvent* event) { |
| + DCHECK(event && (event->type == KeyPress || event->type == KeyRelease)); |
| + 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.
|
| +} |
| // Converts ibus key state flags to event flags. |
| int EventFlagsFromIBusState(guint32 state) { |
| @@ -50,54 +47,34 @@ int EventFlagsFromIBusState(guint32 state) { |
| (state & IBUS_BUTTON3_MASK ? ui::EF_RIGHT_BUTTON_DOWN : 0); |
| } |
| -// Converts event flags to ibus key state flags. |
| -guint32 IBusStateFromEventFlags(int flags) { |
| - return (flags & ui::EF_CAPS_LOCK_DOWN ? IBUS_LOCK_MASK : 0) | |
| - (flags & ui::EF_CONTROL_DOWN ? IBUS_CONTROL_MASK : 0) | |
| - (flags & ui::EF_SHIFT_DOWN ? IBUS_SHIFT_MASK : 0) | |
| - (flags & ui::EF_ALT_DOWN ? IBUS_MOD1_MASK : 0) | |
| - (flags & ui::EF_LEFT_BUTTON_DOWN ? IBUS_BUTTON1_MASK : 0) | |
| - (flags & ui::EF_MIDDLE_BUTTON_DOWN ? IBUS_BUTTON2_MASK : 0) | |
| - (flags & ui::EF_RIGHT_BUTTON_DOWN ? IBUS_BUTTON3_MASK : 0); |
| -} |
| - |
| -void IBusKeyEventFromViewsKeyEvent(const views::KeyEvent& key, |
| - guint32* ibus_keyval, |
| - guint32* ibus_keycode, |
| - guint32* ibus_state) { |
| -#if defined(USE_AURA) |
| - // TODO(yusukes): Handle native_event()? |
| - *ibus_keyval = ui::XKeysymForWindowsKeyCode( |
| - key.key_code(), key.IsShiftDown() ^ key.IsCapsLockDown()); |
| - *ibus_keycode = 0; |
| -#elif defined(TOUCH_UI) |
| - if (key.native_event()) { |
| - XKeyEvent* x_key = reinterpret_cast<XKeyEvent*>(key.native_event()); |
| - // Yes, ibus uses X11 keysym. We cannot use XLookupKeysym(), which doesn't |
| - // translate Shift and CapsLock states. |
| - KeySym keysym = NoSymbol; |
| - ::XLookupString(x_key, NULL, 0, &keysym, NULL); |
| - *ibus_keyval = keysym; |
| - *ibus_keycode = x_key->keycode; |
| - } else { |
| - *ibus_keyval = ui::XKeysymForWindowsKeyCode( |
| - key.key_code(), key.IsShiftDown() ^ key.IsCapsLockDown()); |
| - *ibus_keycode = 0; |
| - } |
| -#elif defined(TOOLKIT_USES_GTK) |
| - if (key.gdk_event()) { |
| - GdkEventKey* gdk_key = reinterpret_cast<GdkEventKey*>(key.gdk_event()); |
| - *ibus_keyval = gdk_key->keyval; |
| - *ibus_keycode = gdk_key->hardware_keycode; |
| - } else { |
| - *ibus_keyval = ui::GdkKeyCodeForWindowsKeyCode( |
| - key.key_code(), key.IsShiftDown() ^ key.IsCapsLockDown()); |
| - *ibus_keycode = 0; |
| - } |
| -#endif |
| +// Converts X flags to ibus key state flags. |
| +guint32 IBusStateFromXFlags(unsigned int flags) { |
| + return (flags & LockMask ? IBUS_LOCK_MASK : 0U) | |
| + (flags & ControlMask ? IBUS_CONTROL_MASK : 0U) | |
| + (flags & ShiftMask ? IBUS_SHIFT_MASK : 0U) | |
| + (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.
|
| +} |
| + |
| +// 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.
|
| +guint32 EventFlagsFromXFlags(unsigned int flags) { |
| + return EventFlagsFromIBusState(IBusStateFromXFlags(flags)); |
| +} |
| - *ibus_state = IBusStateFromEventFlags(key.flags()); |
| - if (key.type() == ui::ET_KEY_RELEASED) |
| +void IBusKeyEventFromNativeKeyEvent(const base::NativeEvent& native_event, |
| + guint32* ibus_keyval, |
| + guint32* ibus_keycode, |
| + guint32* ibus_state) { |
| + DCHECK(native_event); // A fabricated event is not supported here. |
| + XKeyEvent* x_key = GetKeyEvent(native_event); |
| + |
| + // Yes, ibus uses X11 keysym. We cannot use XLookupKeysym(), which doesn't |
| + // translate Shift and CapsLock states. |
| + KeySym keysym = NoSymbol; |
| + ::XLookupString(x_key, NULL, 0, &keysym, NULL); |
| + *ibus_keyval = keysym; |
| + *ibus_keycode = x_key->keycode; |
| + *ibus_state = IBusStateFromXFlags(x_key->state); |
| + if (native_event->type == KeyRelease) |
| *ibus_state |= IBUS_RELEASE_MASK; |
| } |
| @@ -174,22 +151,20 @@ void ExtractCompositionTextFromIBusPreedit(IBusText* text, |
| } |
| } |
| -// A switch to enable InputMethodIBus |
| -const char kEnableInputMethodIBusSwitch[] = "enable-inputmethod-ibus"; |
| - |
| } // namespace |
| -namespace views { |
| +namespace ui { |
| -// InputMethodIBus::PendingKeyEvent implementation ---------------------------- |
| +// InputMethodIBus::PendingKeyEvent implementation ------------------------ |
| class InputMethodIBus::PendingKeyEvent { |
| public: |
| - PendingKeyEvent(InputMethodIBus* input_method, const KeyEvent& key, |
| + PendingKeyEvent(InputMethodIBus* input_method, |
| + const base::NativeEvent& native_event, |
| guint32 ibus_keyval); |
| ~PendingKeyEvent(); |
| // Abandon this pending key event. Its result will just be discarded. |
| - void abandon() { input_method_ = NULL; } |
| + void Abandon() { input_method_ = NULL; } |
| InputMethodIBus* input_method() const { return input_method_; } |
| @@ -200,43 +175,31 @@ class InputMethodIBus::PendingKeyEvent { |
| private: |
| InputMethodIBus* input_method_; |
| - // Complete information of a views::KeyEvent. Sadly, views::KeyEvent doesn't |
| - // support copy. |
| - ui::EventType type_; |
| - int flags_; |
| - ui::KeyboardCode key_code_; |
| - uint16 character_; |
| - uint16 unmodified_character_; |
| + // TODO(yusukes): To support a fabricated key event (which is typically from |
| + // a virtual keyboard), we might have to copy event type, event flags, key |
| + // code, 'character_', and 'unmodified_character_'. See views::InputMethodIBus |
| + // for details. |
| - guint32 ibus_keyval_; |
| - |
| -#if defined(TOUCH_UI) |
| - // corresponding XEvent data of a views::KeyEvent. It's a plain struct so we |
| - // can do bitwise copy. |
| + // corresponding XEvent data of a key event. It's a plain struct so we can do |
| + // bitwise copy. |
| XKeyEvent x_event_; |
| -#endif |
| + |
| + const guint32 ibus_keyval_; |
| DISALLOW_COPY_AND_ASSIGN(PendingKeyEvent); |
| }; |
| -InputMethodIBus::PendingKeyEvent::PendingKeyEvent(InputMethodIBus* input_method, |
| - const KeyEvent& key, |
| - guint32 ibus_keyval) |
| +InputMethodIBus::PendingKeyEvent::PendingKeyEvent( |
| + InputMethodIBus* input_method, |
| + const base::NativeEvent& native_event, |
| + guint32 ibus_keyval) |
| : input_method_(input_method), |
| - type_(key.type()), |
| - flags_(key.flags()), |
| - key_code_(key.key_code()), |
| - character_(key.GetCharacter()), |
| - unmodified_character_(key.GetUnmodifiedCharacter()), |
| ibus_keyval_(ibus_keyval) { |
| DCHECK(input_method_); |
| -#if defined(TOUCH_UI) |
| - if (key.native_event()) |
| - x_event_ = *reinterpret_cast<XKeyEvent*>(key.native_event()); |
| - else |
| - memset(&x_event_, 0, sizeof(x_event_)); |
| -#endif |
| + // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| + DCHECK(native_event); |
| + x_event_ = *GetKeyEvent(native_event); |
| } |
| InputMethodIBus::PendingKeyEvent::~PendingKeyEvent() { |
| @@ -248,22 +211,19 @@ void InputMethodIBus::PendingKeyEvent::ProcessPostIME(bool handled) { |
| if (!input_method_) |
| return; |
| -#if defined(TOUCH_UI) |
| if (x_event_.type == KeyPress || x_event_.type == KeyRelease) { |
| - KeyEvent key(reinterpret_cast<XEvent*>(&x_event_)); |
| - input_method_->ProcessKeyEventPostIME(key, ibus_keyval_, handled); |
| + input_method_->ProcessKeyEventPostIME(reinterpret_cast<XEvent*>(&x_event_), |
| + ibus_keyval_, |
| + handled); |
| return; |
| } |
| -#endif |
| - KeyEvent key(type_, key_code_, flags_); |
| - if (key_code_ == ui::VKEY_UNKNOWN) { |
| - key.set_character(character_); |
| - key.set_unmodified_character(unmodified_character_); |
| - } |
| - input_method_->ProcessKeyEventPostIME(key, ibus_keyval_, handled); |
| + |
| + // TODO(yusukes): Support non-native event (from e.g. a virtual keyboard). |
| + // See views::InputMethodIBus for details. Never forget to set 'character_' |
| + // and 'unmodified_character_' to support i18n VKs like a French VK! |
| } |
| -// InputMethodIBus::PendingCreateICRequest implementation --------------------- |
| +// InputMethodIBus::PendingCreateICRequest implementation ----------------- |
| class InputMethodIBus::PendingCreateICRequest { |
| public: |
| PendingCreateICRequest(InputMethodIBus* input_method, |
| @@ -271,7 +231,7 @@ class InputMethodIBus::PendingCreateICRequest { |
| ~PendingCreateICRequest(); |
| // Abandon this pending key event. Its result will just be discarded. |
| - void abandon() { |
| + void Abandon() { |
| input_method_ = NULL; |
| request_ptr_ = NULL; |
| } |
| @@ -311,8 +271,9 @@ void InputMethodIBus::PendingCreateICRequest::StoreOrAbandonInputContext( |
| } |
| } |
| -// InputMethodIBus implementation --------------------------------------------- |
| -InputMethodIBus::InputMethodIBus(internal::InputMethodDelegate* delegate) |
| +// InputMethodIBus implementation ----------------------------------------- |
| +InputMethodIBus::InputMethodIBus( |
| + internal::InputMethodDelegate* delegate) |
| : context_(NULL), |
| pending_create_ic_request_(NULL), |
| context_focused_(false), |
| @@ -333,20 +294,7 @@ InputMethodIBus::~InputMethodIBus() { |
| GetIBus(), reinterpret_cast<gpointer>(OnIBusDisconnectedThunk), this); |
| } |
| -void InputMethodIBus::OnFocus() { |
|
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.
|
| - DCHECK(!widget_focused()); |
| - InputMethodBase::OnFocus(); |
| - UpdateContextFocusState(); |
| -} |
| - |
| -void InputMethodIBus::OnBlur() { |
| - DCHECK(widget_focused()); |
| - ConfirmCompositionText(); |
| - InputMethodBase::OnBlur(); |
| - UpdateContextFocusState(); |
| -} |
| - |
| -void InputMethodIBus::Init(Widget* widget) { |
| +void InputMethodIBus::Init(const base::NativeWindow& system_toplevel_window) { |
| // Initializes the connection to ibus daemon. It may happen asynchronously, |
| // and as soon as the connection is established, the |context_| will be |
| // created automatically. |
| @@ -363,33 +311,36 @@ void InputMethodIBus::Init(Widget* widget) { |
| if (ibus_bus_is_connected(bus)) |
| CreateContext(); |
| - InputMethodBase::Init(widget); |
| + InputMethodBase::Init(system_toplevel_window); |
| } |
| -void InputMethodIBus::DispatchKeyEvent(const KeyEvent& key) { |
| - DCHECK(key.type() == ui::ET_KEY_PRESSED || key.type() == ui::ET_KEY_RELEASED); |
| - DCHECK(widget_focused()); |
| +void InputMethodIBus::DispatchKeyEvent(const base::NativeEvent& native_event) { |
| + DCHECK(native_event && (native_event->type == KeyPress || |
| + native_event->type == KeyRelease)); |
| + DCHECK(system_toplevel_window_focused()); |
| guint32 ibus_keyval = 0; |
| guint32 ibus_keycode = 0; |
| guint32 ibus_state = 0; |
| - IBusKeyEventFromViewsKeyEvent(key, &ibus_keyval, &ibus_keycode, &ibus_state); |
| + IBusKeyEventFromNativeKeyEvent( |
| + native_event, &ibus_keyval, &ibus_keycode, &ibus_state); |
| // If |context_| is not usable, then we can only dispatch the key event as is. |
| // We also dispatch the key event directly if the current text input type is |
| - // ui::TEXT_INPUT_TYPE_PASSWORD, to bypass the input method. |
| + // TEXT_INPUT_TYPE_PASSWORD, to bypass the input method. |
| // Note: We need to send the key event to ibus even if the |context_| is not |
| // enabled, so that ibus can have a chance to enable the |context_|. |
| if (!context_focused_ || |
| - GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD) { |
| - if (key.type() == ui::ET_KEY_PRESSED) |
| - ProcessUnfilteredKeyPressEvent(key, ibus_keyval); |
| + GetTextInputType() == TEXT_INPUT_TYPE_PASSWORD) { |
| + if (native_event->type == KeyPress) |
| + ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); |
| else |
| - DispatchKeyEventPostIME(key); |
| + DispatchKeyEventPostIME(native_event); |
| return; |
| } |
| - PendingKeyEvent* pending_key = new PendingKeyEvent(this, key, ibus_keyval); |
| + PendingKeyEvent* pending_key = |
| + new PendingKeyEvent(this, native_event, ibus_keyval); |
| pending_key_events_.insert(pending_key); |
| // Note: |
| @@ -420,44 +371,35 @@ void InputMethodIBus::DispatchKeyEvent(const KeyEvent& key) { |
| suppress_next_result_ = false; |
| } |
| -void InputMethodIBus::OnTextInputTypeChanged(View* view) { |
| - if (context_ && IsViewFocused(view)) { |
| +void InputMethodIBus::OnTextInputTypeChanged(const TextInputClient* client) { |
| + 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.
|
| ResetContext(); |
| UpdateContextFocusState(); |
| } |
| - InputMethodBase::OnTextInputTypeChanged(view); |
| + InputMethodBase::OnTextInputTypeChanged(client); |
| } |
| -void InputMethodIBus::OnCaretBoundsChanged(View* view) { |
| - if (!context_focused_ || !IsViewFocused(view)) |
| +void InputMethodIBus::OnCaretBoundsChanged(const TextInputClient* client) { |
| + if (!context_focused_ || !client || (GetTextInputClient() != client)) |
|
James Su
2011/11/24 03:57:03
ditto.
Yusuke Sato
2011/11/28 06:29:40
Done.
|
| return; |
| // The current text input type should not be NONE if |context_| is focused. |
| DCHECK(!IsTextInputTypeNone()); |
| - |
| - gfx::Rect rect = GetTextInputClient()->GetCaretBounds(); |
| - gfx::Point origin = rect.origin(); |
| - gfx::Point end = gfx::Point(rect.right(), rect.bottom()); |
| - |
| - // We need to convert the origin and end points separately, in case the View |
| - // is scaled. |
| - View::ConvertPointToScreen(view, &origin); |
| - View::ConvertPointToScreen(view, &end); |
| + const gfx::Rect rect = GetTextInputClient()->GetCaretBounds(); |
| // This function runs asynchronously. |
| ibus_input_context_set_cursor_location( |
| - context_, origin.x(), origin.y(), |
| - end.x() - origin.x(), end.y() - origin.y()); |
| + context_, rect.x(), rect.y(), rect.width(), rect.height()); |
| } |
| -void InputMethodIBus::CancelComposition(View* view) { |
| - if (context_focused_ && IsViewFocused(view)) |
| +void InputMethodIBus::CancelComposition(const TextInputClient* client) { |
| + if (context_focused_ && client && (GetTextInputClient() == client)) |
|
James Su
2011/11/24 03:57:03
ditto.
Yusuke Sato
2011/11/28 06:29:40
Done.
|
| ResetContext(); |
| } |
| std::string InputMethodIBus::GetInputLocale() { |
| // Not supported. |
| - return std::string(""); |
| + return ""; |
| } |
| base::i18n::TextDirection InputMethodIBus::GetInputTextDirection() { |
| @@ -469,35 +411,6 @@ bool InputMethodIBus::IsActive() { |
| return true; |
| } |
| -// static |
| -bool InputMethodIBus::IsInputMethodIBusEnabled() { |
| -#if defined(TOUCH_UI) |
| - return true; |
| -#else |
| - return inputmethod_ibus_enabled || |
| - CommandLine::ForCurrentProcess()->HasSwitch( |
| - kEnableInputMethodIBusSwitch); |
| -#endif |
| -} |
| - |
| -// static |
| -void InputMethodIBus::SetEnableInputMethodIBus(bool enabled) { |
| - inputmethod_ibus_enabled = enabled; |
| -} |
| - |
| -void InputMethodIBus::OnWillChangeFocus(View* focused_before, View* focused) { |
| - ConfirmCompositionText(); |
| -} |
| - |
| -void InputMethodIBus::OnDidChangeFocus(View* focused_before, View* focused) { |
| - UpdateContextFocusState(); |
| - |
| - // Force to update caret bounds, in case the View thinks that the caret |
| - // bounds has not changed. |
| - if (context_focused_) |
| - OnCaretBoundsChanged(GetFocusedView()); |
| -} |
| - |
| void InputMethodIBus::CreateContext() { |
| DCHECK(!context_); |
| DCHECK(GetIBus()); |
| @@ -544,7 +457,7 @@ void InputMethodIBus::DestroyContext() { |
| if (pending_create_ic_request_) { |
| DCHECK(!context_); |
| // |pending_create_ic_request_| will be deleted in CreateInputContextDone(). |
| - pending_create_ic_request_->abandon(); |
| + pending_create_ic_request_->Abandon(); |
| pending_create_ic_request_ = NULL; |
| } else if (context_) { |
| // ibus_proxy_destroy() will not really release the resource of |context_| |
| @@ -556,7 +469,7 @@ void InputMethodIBus::DestroyContext() { |
| } |
| void InputMethodIBus::ConfirmCompositionText() { |
| - ui::TextInputClient* client = GetTextInputClient(); |
| + TextInputClient* client = GetTextInputClient(); |
| if (client && client->HasCompositionText()) |
| client->ConfirmCompositionText(); |
| @@ -567,8 +480,7 @@ void InputMethodIBus::ResetContext() { |
| if (!context_focused_ || !GetTextInputClient()) |
| return; |
| - DCHECK(widget_focused()); |
| - DCHECK(GetFocusedView()); |
| + DCHECK(system_toplevel_window_focused()); |
| // Because ibus runs in asynchronous mode, the input method may still send us |
| // results after sending out the reset request, so we use a flag to discard |
| @@ -608,8 +520,8 @@ void InputMethodIBus::UpdateContextFocusState() { |
| const bool old_context_focused = context_focused_; |
| // Use switch here in case we are going to add more text input types. |
| switch (GetTextInputType()) { |
| - case ui::TEXT_INPUT_TYPE_NONE: |
| - case ui::TEXT_INPUT_TYPE_PASSWORD: |
| + case TEXT_INPUT_TYPE_NONE: |
| + case TEXT_INPUT_TYPE_PASSWORD: |
| context_focused_ = false; |
| break; |
| default: |
| @@ -625,92 +537,135 @@ void InputMethodIBus::UpdateContextFocusState() { |
| ibus_input_context_focus_in(context_); |
| } |
| -void InputMethodIBus::ProcessKeyEventPostIME(const KeyEvent& key, |
| - guint32 ibus_keyval, |
| - bool handled) { |
| +void InputMethodIBus::ProcessKeyEventPostIME( |
| + const base::NativeEvent& native_event, |
| + guint32 ibus_keyval, |
| + bool handled) { |
| + TextInputClient* client = GetTextInputClient(); |
| + |
| // If we get here without a focused text input client, then it means the key |
| - // event is sent to the global ibus input context. |
| - if (!GetTextInputClient()) { |
| - DispatchKeyEventPostIME(key); |
| + // event is sent to the fake ibus input context. |
| + // 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:
|
| + if (!client) { |
| + DispatchKeyEventPostIME(native_event); |
| return; |
| } |
| - const View* old_focused_view = GetFocusedView(); |
| - |
| - // Same reason as above DCHECK. |
| - DCHECK(old_focused_view); |
| - |
| - if (key.type() == ui::ET_KEY_PRESSED && handled) |
| - ProcessFilteredKeyPressEvent(key); |
| + if (native_event->type == KeyPress && handled) |
| + ProcessFilteredKeyPressEvent(native_event); |
| // In case the focus was changed by the key event. The |context_| should have |
| - // been reset when the focused view changed. |
| - if (old_focused_view != GetFocusedView()) |
| + // been reset when the focused window changed. |
| + if (client != GetTextInputClient()) |
| return; |
| if (HasInputMethodResult()) |
| - ProcessInputMethodResult(key, handled); |
| + ProcessInputMethodResult(native_event, handled); |
| // In case the focus was changed when sending input method results to the |
| - // focused View. |
| - if (old_focused_view != GetFocusedView()) |
| + // focused window. |
| + if (client != GetTextInputClient()) |
| return; |
| - if (key.type() == ui::ET_KEY_PRESSED && !handled) |
| - ProcessUnfilteredKeyPressEvent(key, ibus_keyval); |
| - else if (key.type() == ui::ET_KEY_RELEASED) |
| - DispatchKeyEventPostIME(key); |
| + if (native_event->type == KeyPress && !handled) |
| + ProcessUnfilteredKeyPressEvent(native_event, ibus_keyval); |
| + else if (native_event->type == KeyRelease) |
| + DispatchKeyEventPostIME(native_event); |
| } |
| -void InputMethodIBus::ProcessFilteredKeyPressEvent(const KeyEvent& key) { |
| - if (NeedInsertChar()) { |
| - DispatchKeyEventPostIME(key); |
| - } else { |
| - KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, key.flags()); |
| - DispatchKeyEventPostIME(key); |
| - } |
| -} |
| - |
| -void InputMethodIBus::ProcessUnfilteredKeyPressEvent(const KeyEvent& key, |
| - guint32 ibus_keyval) { |
| - const View* old_focused_view = GetFocusedView(); |
| - DispatchKeyEventPostIME(key); |
| - |
| - // We shouldn't dispatch the character anymore if the key event caused focus |
| - // change. |
| - if (old_focused_view != GetFocusedView()) |
| +void InputMethodIBus::ProcessFilteredKeyPressEvent( |
| + const base::NativeEvent& native_event) { |
| + if (NeedInsertChar()) |
| + DispatchKeyEventPostIME(native_event); |
| + else |
| + DispatchFabricatedKeyEventPostIME( |
| + ET_KEY_PRESSED, |
| + VKEY_PROCESSKEY, |
| + EventFlagsFromXFlags(GetKeyEvent(native_event)->state)); |
| +} |
| + |
| +void InputMethodIBus::ProcessUnfilteredKeyPressEvent( |
| + const base::NativeEvent& native_event, guint32 ibus_keyval) { |
| + // For a fabricated event, ProcessUnfilteredFabricatedKeyPressEvent should be |
| + // called instead. |
| + DCHECK(native_event); |
| + |
| + TextInputClient* client = GetTextInputClient(); |
| + DispatchKeyEventPostIME(native_event); |
| + |
| + // We shouldn't dispatch the character anymore if the key event dispatch |
| + // caused focus change. For example, in the following scenario, |
| + // 1. visit a web page which has a <textarea>. |
| + // 2. click Omnibox. |
| + // 3. enable Korean IME, press A, then press Tab to move the focus to the web |
| + // page. |
| + // We should return here not to send the Tab key event to RWHV. |
| + if (client != GetTextInputClient()) |
| return; |
| // Process compose and dead keys |
| if (character_composer_.FilterKeyPress(ibus_keyval)) { |
| string16 composed = character_composer_.composed_character(); |
| if (!composed.empty()) { |
| - ui::TextInputClient* client = GetTextInputClient(); |
| + client = GetTextInputClient(); |
| if (client) |
| client->InsertText(composed); |
| } |
| return; |
| } |
| + |
| // If a key event was not filtered by |context_| and |character_composer_|, |
| // then it means the key event didn't generate any result text. So we need |
| // to send corresponding character to the focused text input client. |
| + client = GetTextInputClient(); |
| + |
| + 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.
|
| + const uint32 state = |
| + EventFlagsFromXFlags(GetKeyEvent(native_event)->state); |
| + uint16 ch = ui::DefaultSymbolFromXEvent(native_event); |
| + if (!ch) |
| + ch = ui::GetCharacterFromKeyCode(key_code, state); |
| - ui::TextInputClient* client = GetTextInputClient(); |
| - char16 ch = key.GetCharacter(); |
| - if (ch && client) |
| - client->InsertChar(ch, key.flags()); |
| + if (client && ch) |
| + client->InsertChar(ch, state); |
| } |
| -void InputMethodIBus::ProcessInputMethodResult(const KeyEvent& key, |
| - bool handled) { |
| - ui::TextInputClient* client = GetTextInputClient(); |
| +void InputMethodIBus::ProcessUnfilteredFabricatedKeyPressEvent( |
| + EventType type, KeyboardCode key_code, int flags, guint32 ibus_keyval) { |
| + TextInputClient* client = GetTextInputClient(); |
| + DispatchFabricatedKeyEventPostIME(type, key_code, flags); |
| + |
| + if (client != GetTextInputClient()) |
| + return; |
| + |
| + if (character_composer_.FilterKeyPress(ibus_keyval)) { |
| + string16 composed = character_composer_.composed_character(); |
| + if (!composed.empty()) { |
| + client = GetTextInputClient(); |
| + if (client) |
| + client->InsertText(composed); |
| + } |
| + return; |
| + } |
| + |
| + client = GetTextInputClient(); |
| + const uint16 ch = ui::GetCharacterFromKeyCode(key_code, flags); |
| + if (client && ch) |
| + client->InsertChar(ch, flags); |
| +} |
| + |
| +void InputMethodIBus::ProcessInputMethodResult( |
| + const base::NativeEvent& native_event, bool handled) { |
| + TextInputClient* client = GetTextInputClient(); |
| DCHECK(client); |
| if (result_text_.length()) { |
| if (handled && NeedInsertChar()) { |
| + const uint32 state = |
| + EventFlagsFromXFlags(GetKeyEvent(native_event)->state); |
| for (string16::const_iterator i = result_text_.begin(); |
| i != result_text_.end(); ++i) { |
| - client->InsertChar(*i, key.flags()); |
| + client->InsertChar(*i, state); |
| } |
| } else { |
| client->InsertText(result_text_); |
| @@ -744,9 +699,9 @@ bool InputMethodIBus::HasInputMethodResult() const { |
| } |
| void InputMethodIBus::SendFakeProcessKeyEvent(bool pressed) const { |
| - KeyEvent key(pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED, |
| - ui::VKEY_PROCESSKEY, 0); |
| - DispatchKeyEventPostIME(key); |
| + DispatchFabricatedKeyEventPostIME(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, |
| + VKEY_PROCESSKEY, |
| + 0); |
| } |
| void InputMethodIBus::FinishPendingKeyEvent(PendingKeyEvent* pending_key) { |
| @@ -760,18 +715,19 @@ void InputMethodIBus::AbandonAllPendingKeyEvents() { |
| for (std::set<PendingKeyEvent*>::iterator i = pending_key_events_.begin(); |
| i != pending_key_events_.end(); ++i) { |
| // The object will be deleted in ProcessKeyEventDone(). |
| - (*i)->abandon(); |
| + (*i)->Abandon(); |
| } |
| pending_key_events_.clear(); |
| } |
| -void InputMethodIBus::OnCommitText(IBusInputContext* context, IBusText* text) { |
| +void InputMethodIBus::OnCommitText( |
| + IBusInputContext* context, IBusText* text) { |
| DCHECK_EQ(context_, context); |
| if (suppress_next_result_ || !text || !text->text) |
| return; |
| // We need to receive input method result even if the text input type is |
| - // ui::TEXT_INPUT_TYPE_NONE, to make sure we can always send correct |
| + // TEXT_INPUT_TYPE_NONE, to make sure we can always send correct |
| // character for each key event to the focused text input client. |
| if (!GetTextInputClient()) |
| return; |
| @@ -798,29 +754,23 @@ void InputMethodIBus::OnForwardKeyEvent(IBusInputContext* context, |
| guint state) { |
| DCHECK_EQ(context_, context); |
| - ui::KeyboardCode key_code = ui::VKEY_UNKNOWN; |
| -#if defined(USE_AURA) || defined(TOUCH_UI) |
| - key_code = ui::KeyboardCodeFromXKeysym(keyval); |
| -#elif defined(TOOLKIT_USES_GTK) |
| - key_code = ui::WindowsKeyCodeForGdkKeyCode(keyval); |
| -#endif |
| - |
| - if (!key_code) |
| + KeyboardCode ui_key_code = KeyboardCodeFromXKeysym(keyval); |
| + if (!ui_key_code) |
| return; |
| - KeyEvent key(state & IBUS_RELEASE_MASK ? |
| - ui::ET_KEY_RELEASED : ui::ET_KEY_PRESSED, |
| - key_code, EventFlagsFromIBusState(state)); |
| + const EventType event = |
| + (state & IBUS_RELEASE_MASK) ? ET_KEY_RELEASED : ET_KEY_PRESSED; |
| + const int flags = EventFlagsFromIBusState(state); |
| // It is not clear when the input method will forward us a fake key event. |
| // If there is a pending key event, then we may already received some input |
| // method results, so we dispatch this fake key event directly rather than |
| // calling ProcessKeyEventPostIME(), which will clear pending input method |
| // results. |
| - if (key.type() == ui::ET_KEY_PRESSED) |
| - ProcessUnfilteredKeyPressEvent(key, keyval); |
| + if (event == ET_KEY_PRESSED) |
| + ProcessUnfilteredFabricatedKeyPressEvent(event, ui_key_code, flags, keyval); |
| else |
| - DispatchKeyEventPostIME(key); |
| + DispatchFabricatedKeyEventPostIME(event, ui_key_code, flags); |
| } |
| void InputMethodIBus::OnShowPreeditText(IBusInputContext* context) { |
| @@ -880,7 +830,7 @@ void InputMethodIBus::OnHidePreeditText(IBusInputContext* context) { |
| composition_.Clear(); |
| if (pending_key_events_.empty()) { |
| - ui::TextInputClient* client = GetTextInputClient(); |
| + TextInputClient* client = GetTextInputClient(); |
| if (client && client->HasCompositionText()) |
| client->ClearCompositionText(); |
| composition_changed_ = false; |
| @@ -958,4 +908,4 @@ void InputMethodIBus::CreateInputContextDone(IBusBus* bus, |
| delete data; |
| } |
| -} // namespace views |
| +} // namespace ui |