| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/base/ime/input_method_linux_x11.h" | |
| 6 | |
| 7 #include "base/environment.h" | |
| 8 #include "ui/base/ime/linux/linux_input_method_context_factory.h" | |
| 9 #include "ui/base/ime/text_input_client.h" | |
| 10 #include "ui/events/event.h" | |
| 11 | |
| 12 namespace ui { | |
| 13 | |
| 14 InputMethodLinuxX11::InputMethodLinuxX11( | |
| 15 internal::InputMethodDelegate* delegate) { | |
| 16 SetDelegate(delegate); | |
| 17 } | |
| 18 | |
| 19 InputMethodLinuxX11::~InputMethodLinuxX11() {} | |
| 20 | |
| 21 // static | |
| 22 void InputMethodLinuxX11::Initialize() { | |
| 23 // Force a IBus IM context to run in synchronous mode. | |
| 24 // | |
| 25 // Background: IBus IM context runs by default in asynchronous mode. In | |
| 26 // this mode, gtk_im_context_filter_keypress() consumes all the key events | |
| 27 // and returns true while asynchronously sending the event to an underlying | |
| 28 // IME implementation. When the event has not actually been consumed by | |
| 29 // the underlying IME implementation, the context pushes the event back to | |
| 30 // the GDK event queue marking the event as already handled by the IBus IM | |
| 31 // context. | |
| 32 // | |
| 33 // The problem here is that those pushed-back GDK events are never handled | |
| 34 // when base::MessagePumpX11 is used, which only handles X events. So, we | |
| 35 // make a IBus IM context run in synchronous mode by setting an environment | |
| 36 // variable. This is only the interface to change the mode. | |
| 37 // | |
| 38 // Another possible solution is to use GDK event loop instead of X event | |
| 39 // loop. | |
| 40 // | |
| 41 // Since there is no reentrant version of setenv(3C), it's a caller's duty | |
| 42 // to avoid race conditions. This function should be called in the main | |
| 43 // thread on a very early stage, and supposed to be called from | |
| 44 // ui::InitializeInputMethod(). | |
| 45 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
| 46 env->SetVar("IBUS_ENABLE_SYNC_MODE", "1"); | |
| 47 } | |
| 48 | |
| 49 // Overriden from InputMethod. | |
| 50 | |
| 51 void InputMethodLinuxX11::Init(bool focused) { | |
| 52 CHECK(LinuxInputMethodContextFactory::instance()); | |
| 53 input_method_context_ = | |
| 54 LinuxInputMethodContextFactory::instance()->CreateInputMethodContext( | |
| 55 this); | |
| 56 CHECK(input_method_context_.get()); | |
| 57 | |
| 58 InputMethodBase::Init(focused); | |
| 59 | |
| 60 if (focused) { | |
| 61 input_method_context_->OnTextInputTypeChanged( | |
| 62 GetTextInputClient() ? | |
| 63 GetTextInputClient()->GetTextInputType() : | |
| 64 TEXT_INPUT_TYPE_TEXT); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 bool InputMethodLinuxX11::OnUntranslatedIMEMessage( | |
| 69 const base::NativeEvent& event, | |
| 70 NativeEventResult* result) { | |
| 71 return false; | |
| 72 } | |
| 73 | |
| 74 bool InputMethodLinuxX11::DispatchKeyEvent(const ui::KeyEvent& event) { | |
| 75 DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED); | |
| 76 DCHECK(system_toplevel_window_focused()); | |
| 77 | |
| 78 // If no text input client, do nothing. | |
| 79 if (!GetTextInputClient()) | |
| 80 return DispatchKeyEventPostIME(event); | |
| 81 | |
| 82 // Let an IME handle the key event first. | |
| 83 if (input_method_context_->DispatchKeyEvent(event)) { | |
| 84 if (event.type() == ET_KEY_PRESSED) { | |
| 85 const ui::KeyEvent fabricated_event(ET_KEY_PRESSED, | |
| 86 VKEY_PROCESSKEY, | |
| 87 event.flags(), | |
| 88 false); // is_char | |
| 89 DispatchKeyEventPostIME(fabricated_event); | |
| 90 } | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 // Otherwise, insert the character. | |
| 95 const bool handled = DispatchKeyEventPostIME(event); | |
| 96 if (event.type() == ET_KEY_PRESSED && GetTextInputClient()) { | |
| 97 const uint16 ch = event.GetCharacter(); | |
| 98 if (ch) { | |
| 99 GetTextInputClient()->InsertChar(ch, event.flags()); | |
| 100 return true; | |
| 101 } | |
| 102 } | |
| 103 return handled; | |
| 104 } | |
| 105 | |
| 106 void InputMethodLinuxX11::OnTextInputTypeChanged( | |
| 107 const TextInputClient* client) { | |
| 108 if (!IsTextInputClientFocused(client)) | |
| 109 return; | |
| 110 input_method_context_->Reset(); | |
| 111 // TODO(yoichio): Support inputmode HTML attribute. | |
| 112 input_method_context_->OnTextInputTypeChanged(client->GetTextInputType()); | |
| 113 } | |
| 114 | |
| 115 void InputMethodLinuxX11::OnCaretBoundsChanged(const TextInputClient* client) { | |
| 116 if (!IsTextInputClientFocused(client)) | |
| 117 return; | |
| 118 input_method_context_->OnCaretBoundsChanged( | |
| 119 GetTextInputClient()->GetCaretBounds()); | |
| 120 } | |
| 121 | |
| 122 void InputMethodLinuxX11::CancelComposition(const TextInputClient* client) { | |
| 123 if (!IsTextInputClientFocused(client)) | |
| 124 return; | |
| 125 input_method_context_->Reset(); | |
| 126 input_method_context_->OnTextInputTypeChanged(client->GetTextInputType()); | |
| 127 } | |
| 128 | |
| 129 void InputMethodLinuxX11::OnInputLocaleChanged() { | |
| 130 } | |
| 131 | |
| 132 std::string InputMethodLinuxX11::GetInputLocale() { | |
| 133 return ""; | |
| 134 } | |
| 135 | |
| 136 base::i18n::TextDirection InputMethodLinuxX11::GetInputTextDirection() { | |
| 137 return input_method_context_->GetInputTextDirection(); | |
| 138 } | |
| 139 | |
| 140 bool InputMethodLinuxX11::IsActive() { | |
| 141 // InputMethodLinuxX11 is always ready and up. | |
| 142 return true; | |
| 143 } | |
| 144 | |
| 145 bool InputMethodLinuxX11::IsCandidatePopupOpen() const { | |
| 146 // There seems no way to detect candidate windows or any popups. | |
| 147 return false; | |
| 148 } | |
| 149 | |
| 150 // Overriden from ui::LinuxInputMethodContextDelegate | |
| 151 | |
| 152 void InputMethodLinuxX11::OnCommit(const base::string16& text) { | |
| 153 TextInputClient* text_input_client = GetTextInputClient(); | |
| 154 if (text_input_client) | |
| 155 text_input_client->InsertText(text); | |
| 156 } | |
| 157 | |
| 158 void InputMethodLinuxX11::OnPreeditChanged( | |
| 159 const CompositionText& composition_text) { | |
| 160 TextInputClient* text_input_client = GetTextInputClient(); | |
| 161 if (text_input_client) | |
| 162 text_input_client->SetCompositionText(composition_text); | |
| 163 } | |
| 164 | |
| 165 void InputMethodLinuxX11::OnPreeditEnd() { | |
| 166 TextInputClient* text_input_client = GetTextInputClient(); | |
| 167 if (text_input_client && text_input_client->HasCompositionText()) | |
| 168 text_input_client->ClearCompositionText(); | |
| 169 } | |
| 170 | |
| 171 void InputMethodLinuxX11::OnPreeditStart() {} | |
| 172 | |
| 173 // Overridden from InputMethodBase. | |
| 174 | |
| 175 void InputMethodLinuxX11::OnDidChangeFocusedClient( | |
| 176 TextInputClient* focused_before, | |
| 177 TextInputClient* focused) { | |
| 178 input_method_context_->Reset(); | |
| 179 input_method_context_->OnTextInputTypeChanged( | |
| 180 focused ? focused->GetTextInputType() : TEXT_INPUT_TYPE_NONE); | |
| 181 | |
| 182 InputMethodBase::OnDidChangeFocusedClient(focused_before, focused); | |
| 183 } | |
| 184 | |
| 185 } // namespace ui | |
| OLD | NEW |