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 |