Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(696)

Side by Side Diff: ui/base/ime/input_method_auralinux.cc

Issue 1068093002: Refactoring for InputMethodAuraLinux. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removes unexpected 229 keydown for non-IME users. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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/base/ime/input_method_auralinux.h" 5 #include "ui/base/ime/input_method_auralinux.h"
6 6
7 #include "base/auto_reset.h"
7 #include "base/environment.h" 8 #include "base/environment.h"
8 #include "ui/base/ime/linux/linux_input_method_context_factory.h" 9 #include "ui/base/ime/linux/linux_input_method_context_factory.h"
9 #include "ui/base/ime/text_input_client.h" 10 #include "ui/base/ime/text_input_client.h"
10 #include "ui/events/event.h" 11 #include "ui/events/event.h"
11 12
12 namespace ui { 13 namespace ui {
13 14
14 InputMethodAuraLinux::InputMethodAuraLinux( 15 InputMethodAuraLinux::InputMethodAuraLinux(
15 internal::InputMethodDelegate* delegate) 16 internal::InputMethodDelegate* delegate)
16 : allowed_to_fire_vkey_process_key_(false), vkey_processkey_flags_(0) { 17 : text_input_type_(TEXT_INPUT_TYPE_NONE),
18 handling_key_event_(false),
19 composing_text_(false),
James Su 2015/04/09 08:40:02 I think this variable can be eliminated. Let's dis
Shu Chen 2015/04/10 05:26:52 Done.
20 composition_changed_(false),
21 suppress_next_result_(false) {
17 SetDelegate(delegate); 22 SetDelegate(delegate);
23 context_ =
24 LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
25 this, false);
26 context_simple_ =
27 LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
28 this, true);
18 } 29 }
19 30
20 InputMethodAuraLinux::~InputMethodAuraLinux() {} 31 InputMethodAuraLinux::~InputMethodAuraLinux() {}
21 32
33 LinuxInputMethodContext* InputMethodAuraLinux::GetContextForTesting(
34 bool is_simple) {
35 return is_simple ? context_simple_.get() : context_.get();
36 }
37
22 // Overriden from InputMethod. 38 // Overriden from InputMethod.
23 39
24 void InputMethodAuraLinux::Init(bool focused) { 40 void InputMethodAuraLinux::Init(bool focused) {
25 CHECK(LinuxInputMethodContextFactory::instance())
26 << "This failure was likely caused because "
27 << "ui::InitializeInputMethod(ForTesting) was not called "
28 << "before instantiating this class.";
29 input_method_context_ =
30 LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
31 this);
32 CHECK(input_method_context_.get());
33
34 InputMethodBase::Init(focused); 41 InputMethodBase::Init(focused);
35 42
36 if (focused) { 43 UpdateContextFocusState();
37 input_method_context_->OnTextInputTypeChanged(
38 GetTextInputClient() ?
39 GetTextInputClient()->GetTextInputType() :
40 TEXT_INPUT_TYPE_TEXT);
41 }
42 } 44 }
43 45
44 bool InputMethodAuraLinux::OnUntranslatedIMEMessage( 46 bool InputMethodAuraLinux::OnUntranslatedIMEMessage(
45 const base::NativeEvent& event, 47 const base::NativeEvent& event,
46 NativeEventResult* result) { 48 NativeEventResult* result) {
47 return false; 49 return false;
48 } 50 }
49 51
50 bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) { 52 bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) {
51 DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED); 53 DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
52 DCHECK(system_toplevel_window_focused()); 54 DCHECK(system_toplevel_window_focused());
55 suppress_next_result_ = false;
53 56
54 // If no text input client, do nothing. 57 // If no text input client, do nothing.
55 if (!GetTextInputClient()) 58 if (!GetTextInputClient())
56 return DispatchKeyEventPostIME(event); 59 return DispatchKeyEventPostIME(event);
57 60
58 // Let an IME handle the key event first, and allow to fire a VKEY_PROCESSKEY 61 composition_changed_ = false;
59 // event for keydown events. Note that DOM Level 3 Events Sepc requires that 62 result_text_.clear();
60 // only keydown events fire keyCode=229 events and not for keyup events.
61 if (event.type() == ET_KEY_PRESSED &&
62 (event.flags() & ui::EF_IME_FABRICATED_KEY) == 0)
63 AllowToFireProcessKey(event);
64 if (input_method_context_->DispatchKeyEvent(event))
65 return true;
66 StopFiringProcessKey();
67 63
68 // Otherwise, insert the character. 64 bool filtered = false;
69 const bool handled = DispatchKeyEventPostIME(event); 65 {
70 if (event.type() == ET_KEY_PRESSED && GetTextInputClient()) { 66 base::AutoReset<bool> flipper(&handling_key_event_, true);
71 const uint16 ch = event.GetCharacter(); 67 if (text_input_type_ != TEXT_INPUT_TYPE_NONE &&
72 if (ch) { 68 text_input_type_ != TEXT_INPUT_TYPE_PASSWORD)
73 GetTextInputClient()->InsertChar(ch, event.flags()); 69 filtered = context_->DispatchKeyEvent(event);
74 return true; 70 else
71 filtered = context_simple_->DispatchKeyEvent(event);
72 }
73
74 if (event.type() == ui::ET_KEY_PRESSED && filtered) {
75 if (NeedInsertChar()) {
76 DispatchKeyEventPostIME(event);
77 } else if (HasInputMethodResult()) {
78 ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, event.flags());
79 DispatchKeyEventPostIME(key);
75 } 80 }
76 } 81 }
77 return handled; 82
83 // If has input result process the result.
84 if (HasInputMethodResult())
85 ProcessInputMethodResult(event, filtered);
86
87 if (event.type() == ui::ET_KEY_PRESSED && !filtered) {
88 DispatchKeyEventPostIME(event);
89
90 // If a key event was not filtered by |context_| or |context_simple_|, then
91 // it means the key event didn't generate any result text. For some cases,
92 // the key event may still generate a valid character, eg. a control-key
93 // event (ctrl-a, return, tab, etc.). We need to send the character to the
94 // focused text input client by calling TextInputClient::InsertChar().
95 base::char16 ch = event.GetCharacter();
96 TextInputClient* client = GetTextInputClient();
97 if (ch && client)
98 client->InsertChar(ch, event.flags());
99 } else if (event.type() == ui::ET_KEY_RELEASED && !filtered) {
100 DispatchKeyEventPostIME(event);
101 }
102
James Su 2015/04/09 08:40:02 How about add comment to explain why we don't send
Shu Chen 2015/04/10 05:26:52 Done.
103 return true;
104 }
105
106 void InputMethodAuraLinux::UpdateContextFocusState() {
107 bool old_text_input_type = text_input_type_;
108 text_input_type_ = GetTextInputType();
109
110 // We only focus in |context_| when the focus is in a textfield.
111 if (old_text_input_type != TEXT_INPUT_TYPE_NONE &&
112 text_input_type_ == TEXT_INPUT_TYPE_NONE) {
113 context_->Blur();
114 } else if (old_text_input_type == TEXT_INPUT_TYPE_NONE &&
115 text_input_type_ != TEXT_INPUT_TYPE_NONE) {
116 context_->Focus();
117 }
118
119 // |context_simple_| can be used in any textfield, including password box, and
120 // even if the focused text input client's text input type is
121 // ui::TEXT_INPUT_TYPE_NONE.
122 if (GetTextInputClient())
123 context_simple_->Focus();
124 else
125 context_simple_->Blur();
78 } 126 }
79 127
80 void InputMethodAuraLinux::OnTextInputTypeChanged( 128 void InputMethodAuraLinux::OnTextInputTypeChanged(
81 const TextInputClient* client) { 129 const TextInputClient* client) {
82 if (!IsTextInputClientFocused(client)) 130 DCHECK(!composing_text_);
83 return; 131 UpdateContextFocusState();
84 input_method_context_->Reset();
85 // TODO(yoichio): Support inputmode HTML attribute. 132 // TODO(yoichio): Support inputmode HTML attribute.
86 input_method_context_->OnTextInputTypeChanged(client->GetTextInputType());
87 } 133 }
88 134
89 void InputMethodAuraLinux::OnCaretBoundsChanged(const TextInputClient* client) { 135 void InputMethodAuraLinux::OnCaretBoundsChanged(const TextInputClient* client) {
90 if (!IsTextInputClientFocused(client)) 136 if (!IsTextInputClientFocused(client))
91 return; 137 return;
92 input_method_context_->OnCaretBoundsChanged( 138 context_->SetCursorLocation(GetTextInputClient()->GetCaretBounds());
93 GetTextInputClient()->GetCaretBounds());
94 } 139 }
95 140
96 void InputMethodAuraLinux::CancelComposition(const TextInputClient* client) { 141 void InputMethodAuraLinux::CancelComposition(const TextInputClient* client) {
97 if (!IsTextInputClientFocused(client)) 142 if (!IsTextInputClientFocused(client))
98 return; 143 return;
99 input_method_context_->Reset(); 144 ResetContext();
100 input_method_context_->OnTextInputTypeChanged(client->GetTextInputType()); 145 }
146
147 void InputMethodAuraLinux::ResetContext() {
148 if (!GetTextInputClient())
149 return;
150
151 // To prevent any text from being committed when resetting the |context_|;
152 handling_key_event_ = true;
153 suppress_next_result_ = true;
154
155 context_->Reset();
156 context_simple_->Reset();
157
158 // Some input methods may not honour the reset call. Focusing out/in the
159 // |context_| to make sure it gets reset correctly.
160 if (text_input_type_ != TEXT_INPUT_TYPE_NONE) {
161 context_->Blur();
162 context_->Focus();
163 }
164
165 composition_.Clear();
166 result_text_.clear();
167 handling_key_event_ = false;
168 composing_text_ = false;
169 composition_changed_ = false;
101 } 170 }
102 171
103 void InputMethodAuraLinux::OnInputLocaleChanged() { 172 void InputMethodAuraLinux::OnInputLocaleChanged() {
104 } 173 }
105 174
106 std::string InputMethodAuraLinux::GetInputLocale() { 175 std::string InputMethodAuraLinux::GetInputLocale() {
107 return ""; 176 return "";
108 } 177 }
109 178
110 bool InputMethodAuraLinux::IsActive() { 179 bool InputMethodAuraLinux::IsActive() {
111 // InputMethodAuraLinux is always ready and up. 180 // InputMethodAuraLinux is always ready and up.
112 return true; 181 return true;
113 } 182 }
114 183
115 bool InputMethodAuraLinux::IsCandidatePopupOpen() const { 184 bool InputMethodAuraLinux::IsCandidatePopupOpen() const {
116 // There seems no way to detect candidate windows or any popups. 185 // There seems no way to detect candidate windows or any popups.
117 return false; 186 return false;
118 } 187 }
119 188
120 // Overriden from ui::LinuxInputMethodContextDelegate 189 // Overriden from ui::LinuxInputMethodContextDelegate
121 190
122 void InputMethodAuraLinux::OnCommit(const base::string16& text) { 191 void InputMethodAuraLinux::OnCommit(const base::string16& text) {
123 MaybeFireProcessKey(); 192 if (suppress_next_result_) {
124 if (!IsTextInputTypeNone()) 193 suppress_next_result_ = false;
194 return;
195 }
196 if (!GetTextInputClient())
197 return;
198
199 if (!composing_text_ && text.empty())
200 return;
201
202 // Append the text to the buffer, because commit signal might be fired
203 // multiple times when processing a key event.
204 result_text_.append(text);
205
206 // If we are not handling key event, do not bother sending text result if the
207 // focused text input client does not support text input.
208 if (!handling_key_event_ && !IsTextInputTypeNone()) {
209 SendFakeProcessKeyEvent(true);
125 GetTextInputClient()->InsertText(text); 210 GetTextInputClient()->InsertText(text);
211 }
212 }
213
214 void InputMethodAuraLinux::OnPreeditStart() {
215 if (suppress_next_result_ || IsTextInputTypeNone())
216 return;
217
218 composing_text_ = true;
126 } 219 }
127 220
128 void InputMethodAuraLinux::OnPreeditChanged( 221 void InputMethodAuraLinux::OnPreeditChanged(
129 const CompositionText& composition_text) { 222 const CompositionText& composition_text) {
130 MaybeFireProcessKey(); 223 if (suppress_next_result_ || IsTextInputTypeNone())
131 TextInputClient* text_input_client = GetTextInputClient(); 224 return;
132 if (text_input_client) 225
133 text_input_client->SetCompositionText(composition_text); 226 if (composition_.text.empty() && composition_text.text.empty())
227 return;
228
229 composition_ = composition_text;
230 composition_changed_ = true;
231 if (!composition_.text.empty())
232 composing_text_ = true;
233
234 if (!handling_key_event_ && !IsTextInputTypeNone()) {
235 SendFakeProcessKeyEvent(true);
236 GetTextInputClient()->SetCompositionText(composition_);
237 }
134 } 238 }
135 239
136 void InputMethodAuraLinux::OnPreeditEnd() { 240 void InputMethodAuraLinux::OnPreeditEnd() {
137 MaybeFireProcessKey(); 241 if (composition_.text.empty() || IsTextInputTypeNone())
138 TextInputClient* text_input_client = GetTextInputClient(); 242 return;
139 if (text_input_client && text_input_client->HasCompositionText())
140 text_input_client->ClearCompositionText();
141 }
142 243
143 void InputMethodAuraLinux::OnPreeditStart() { 244 composition_changed_ = true;
144 MaybeFireProcessKey(); 245 composition_.Clear();
246
247 if (!handling_key_event_) {
248 TextInputClient* client = GetTextInputClient();
249 if (client && client->HasCompositionText())
250 client->ClearCompositionText();
251 }
145 } 252 }
146 253
147 // Overridden from InputMethodBase. 254 // Overridden from InputMethodBase.
148 255
256 void InputMethodAuraLinux::OnFocus() {
257 InputMethodBase::OnFocus();
258 UpdateContextFocusState();
259 }
260
261 void InputMethodAuraLinux::OnBlur() {
262 ConfirmCompositionText();
263 InputMethodBase::OnBlur();
264 UpdateContextFocusState();
265 }
266
267 void InputMethodAuraLinux::OnWillChangeFocusedClient(
268 TextInputClient* focused_before,
269 TextInputClient* focused) {
270 ConfirmCompositionText();
271 }
272
149 void InputMethodAuraLinux::OnDidChangeFocusedClient( 273 void InputMethodAuraLinux::OnDidChangeFocusedClient(
150 TextInputClient* focused_before, 274 TextInputClient* focused_before,
151 TextInputClient* focused) { 275 TextInputClient* focused) {
152 input_method_context_->Reset(); 276 UpdateContextFocusState();
153 input_method_context_->OnTextInputTypeChanged( 277
154 focused ? focused->GetTextInputType() : TEXT_INPUT_TYPE_NONE); 278 // Force to update caret bounds, in case the View thinks that the caret
279 // bounds has not changed.
280 if (text_input_type_ != TEXT_INPUT_TYPE_NONE)
281 OnCaretBoundsChanged(GetTextInputClient());
155 282
156 InputMethodBase::OnDidChangeFocusedClient(focused_before, focused); 283 InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
157 } 284 }
158 285
159 // Helper functions to support VKEY_PROCESSKEY. 286 // private
160 287
161 void InputMethodAuraLinux::AllowToFireProcessKey(const ui::KeyEvent& event) { 288 bool InputMethodAuraLinux::HasInputMethodResult() {
162 allowed_to_fire_vkey_process_key_ = true; 289 return !result_text_.empty() || composition_changed_;
163 vkey_processkey_flags_ = event.flags();
164 } 290 }
165 291
166 void InputMethodAuraLinux::MaybeFireProcessKey() { 292 void InputMethodAuraLinux::ProcessInputMethodResult(const KeyEvent& key,
167 if (!allowed_to_fire_vkey_process_key_) 293 bool filtered) {
168 return; 294 TextInputClient* client = GetTextInputClient();
295 DCHECK(client);
169 296
170 const ui::KeyEvent fabricated_event(ET_KEY_PRESSED, 297 if (!result_text_.empty()) {
171 VKEY_PROCESSKEY, 298 if (filtered && NeedInsertChar()) {
172 vkey_processkey_flags_); 299 for (const auto ch : result_text_)
173 DispatchKeyEventPostIME(fabricated_event); 300 client->InsertChar(ch, key.flags());
174 StopFiringProcessKey(); 301 } else {
302 client->InsertText(result_text_);
303 composing_text_ = false;
304 }
305 }
306
307 if (composition_changed_ && !IsTextInputTypeNone()) {
308 if (!composition_.text.empty()) {
309 composing_text_ = true;
310 client->SetCompositionText(composition_);
311 } else if (result_text_.empty()) {
312 client->ClearCompositionText();
313 }
314 }
175 } 315 }
176 316
177 void InputMethodAuraLinux::StopFiringProcessKey() { 317 bool InputMethodAuraLinux::NeedInsertChar() const {
178 allowed_to_fire_vkey_process_key_ = false; 318 return IsTextInputTypeNone() ||
179 vkey_processkey_flags_ = 0; 319 (!composing_text_ && result_text_.length() == 1);
320 }
321
322 void InputMethodAuraLinux::SendFakeProcessKeyEvent(bool pressed) const {
323 KeyEvent key(pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
324 ui::VKEY_PROCESSKEY, 0);
325 DispatchKeyEventPostIME(key);
326 }
327
328 void InputMethodAuraLinux::ConfirmCompositionText() {
329 TextInputClient* client = GetTextInputClient();
330 if (client && client->HasCompositionText())
331 client->ConfirmCompositionText();
332
333 ResetContext();
180 } 334 }
181 335
182 } // namespace ui 336 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698