clang/win: Add remaining tracking bugs for -Wno flags.
[chromium-blink-merge.git] / ui / base / ime / input_method_auralinux.cc
blob7f70b5e292109874ad6c96b14f26f9b6ef7bbe13
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.
5 #include "ui/base/ime/input_method_auralinux.h"
7 #include "base/auto_reset.h"
8 #include "base/environment.h"
9 #include "ui/base/ime/linux/linux_input_method_context_factory.h"
10 #include "ui/base/ime/text_input_client.h"
11 #include "ui/events/event.h"
13 namespace ui {
15 InputMethodAuraLinux::InputMethodAuraLinux(
16 internal::InputMethodDelegate* delegate)
17 : text_input_type_(TEXT_INPUT_TYPE_NONE),
18 is_sync_mode_(false),
19 composition_changed_(false),
20 suppress_next_result_(false) {
21 SetDelegate(delegate);
22 context_ =
23 LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
24 this, false);
25 context_simple_ =
26 LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
27 this, true);
30 InputMethodAuraLinux::~InputMethodAuraLinux() {}
32 LinuxInputMethodContext* InputMethodAuraLinux::GetContextForTesting(
33 bool is_simple) {
34 return is_simple ? context_simple_.get() : context_.get();
37 // Overriden from InputMethod.
39 bool InputMethodAuraLinux::OnUntranslatedIMEMessage(
40 const base::NativeEvent& event,
41 NativeEventResult* result) {
42 return false;
45 bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) {
46 DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
47 DCHECK(system_toplevel_window_focused());
49 // If no text input client, do nothing.
50 if (!GetTextInputClient())
51 return DispatchKeyEventPostIME(event);
53 suppress_next_result_ = false;
54 composition_changed_ = false;
55 result_text_.clear();
57 bool filtered = false;
59 base::AutoReset<bool> flipper(&is_sync_mode_, true);
60 if (text_input_type_ != TEXT_INPUT_TYPE_NONE &&
61 text_input_type_ != TEXT_INPUT_TYPE_PASSWORD) {
62 filtered = context_->DispatchKeyEvent(event);
63 } else {
64 filtered = context_simple_->DispatchKeyEvent(event);
68 if (event.type() == ui::ET_KEY_PRESSED && filtered) {
69 if (NeedInsertChar())
70 DispatchKeyEventPostIME(event);
71 else if (HasInputMethodResult())
72 SendFakeProcessKeyEvent(event.flags());
74 // Don't send VKEY_PROCESSKEY event if there is no result text or
75 // composition. This is to workaround the weird behavior of IBus with US
76 // keyboard, which mutes the keydown and later fake a new keydown with IME
77 // result in sync mode. In that case, user would expect only
78 // keydown/keypress/keyup event without an initial 229 keydown event.
81 TextInputClient* client = GetTextInputClient();
82 // Processes the result text before composition for sync mode.
83 if (!result_text_.empty()) {
84 if (filtered && NeedInsertChar()) {
85 for (const auto ch : result_text_)
86 client->InsertChar(ch, event.flags());
87 } else {
88 // If |filtered| is false, that means the IME wants to commit some text
89 // but still release the key to the application. For example, Korean IME
90 // handles ENTER key to confirm its composition but still release it for
91 // the default behavior (e.g. trigger search, etc.)
92 // In such case, don't do InsertChar because a key should only trigger the
93 // keydown event once.
94 client->InsertText(result_text_);
98 if (composition_changed_ && !IsTextInputTypeNone()) {
99 // If composition changed, does SetComposition if composition is not empty.
100 // And ClearComposition if composition is empty.
101 if (!composition_.text.empty())
102 client->SetCompositionText(composition_);
103 else if (result_text_.empty())
104 client->ClearCompositionText();
107 // Makes sure the cached composition is cleared after committing any text or
108 // cleared composition.
109 if (!client->HasCompositionText())
110 composition_.Clear();
112 if (!filtered) {
113 DispatchKeyEventPostIME(event);
114 if (event.type() == ui::ET_KEY_PRESSED) {
115 // If a key event was not filtered by |context_| or |context_simple_|,
116 // then it means the key event didn't generate any result text. For some
117 // cases, the key event may still generate a valid character, eg. a
118 // control-key event (ctrl-a, return, tab, etc.). We need to send the
119 // character to the focused text input client by calling
120 // TextInputClient::InsertChar().
121 // Note: don't use |client| and use GetTextInputClient() here because
122 // DispatchKeyEventPostIME may cause the current text input client change.
123 base::char16 ch = event.GetCharacter();
124 if (ch && GetTextInputClient())
125 GetTextInputClient()->InsertChar(ch, event.flags());
129 return true;
132 void InputMethodAuraLinux::UpdateContextFocusState() {
133 bool old_text_input_type = text_input_type_;
134 text_input_type_ = GetTextInputType();
136 // We only focus in |context_| when the focus is in a textfield.
137 if (old_text_input_type != TEXT_INPUT_TYPE_NONE &&
138 text_input_type_ == TEXT_INPUT_TYPE_NONE) {
139 context_->Blur();
140 } else if (old_text_input_type == TEXT_INPUT_TYPE_NONE &&
141 text_input_type_ != TEXT_INPUT_TYPE_NONE) {
142 context_->Focus();
145 // |context_simple_| can be used in any textfield, including password box, and
146 // even if the focused text input client's text input type is
147 // ui::TEXT_INPUT_TYPE_NONE.
148 if (GetTextInputClient())
149 context_simple_->Focus();
150 else
151 context_simple_->Blur();
154 void InputMethodAuraLinux::OnTextInputTypeChanged(
155 const TextInputClient* client) {
156 UpdateContextFocusState();
157 InputMethodBase::OnTextInputTypeChanged(client);
158 // TODO(yoichio): Support inputmode HTML attribute.
161 void InputMethodAuraLinux::OnCaretBoundsChanged(const TextInputClient* client) {
162 if (!IsTextInputClientFocused(client))
163 return;
164 context_->SetCursorLocation(GetTextInputClient()->GetCaretBounds());
167 void InputMethodAuraLinux::CancelComposition(const TextInputClient* client) {
168 if (!IsTextInputClientFocused(client))
169 return;
170 ResetContext();
173 void InputMethodAuraLinux::ResetContext() {
174 if (!GetTextInputClient())
175 return;
177 // To prevent any text from being committed when resetting the |context_|;
178 is_sync_mode_ = true;
179 suppress_next_result_ = true;
181 context_->Reset();
182 context_simple_->Reset();
184 // Some input methods may not honour the reset call. Focusing out/in the
185 // |context_| to make sure it gets reset correctly.
186 if (text_input_type_ != TEXT_INPUT_TYPE_NONE) {
187 context_->Blur();
188 context_->Focus();
191 composition_.Clear();
192 result_text_.clear();
193 is_sync_mode_ = false;
194 composition_changed_ = false;
197 void InputMethodAuraLinux::OnInputLocaleChanged() {
200 std::string InputMethodAuraLinux::GetInputLocale() {
201 return "";
204 bool InputMethodAuraLinux::IsActive() {
205 // InputMethodAuraLinux is always ready and up.
206 return true;
209 bool InputMethodAuraLinux::IsCandidatePopupOpen() const {
210 // There seems no way to detect candidate windows or any popups.
211 return false;
214 // Overriden from ui::LinuxInputMethodContextDelegate
216 void InputMethodAuraLinux::OnCommit(const base::string16& text) {
217 if (suppress_next_result_ || !GetTextInputClient()) {
218 suppress_next_result_ = false;
219 return;
222 if (is_sync_mode_) {
223 // Append the text to the buffer, because commit signal might be fired
224 // multiple times when processing a key event.
225 result_text_.append(text);
226 } else if (!IsTextInputTypeNone()) {
227 // If we are not handling key event, do not bother sending text result if
228 // the focused text input client does not support text input.
229 SendFakeProcessKeyEvent(0);
230 GetTextInputClient()->InsertText(text);
231 composition_.Clear();
235 void InputMethodAuraLinux::OnPreeditChanged(
236 const CompositionText& composition_text) {
237 if (suppress_next_result_ || IsTextInputTypeNone())
238 return;
240 composition_ = composition_text;
242 if (is_sync_mode_) {
243 if (!composition_.text.empty() || !composition_text.text.empty())
244 composition_changed_ = true;
245 } else {
246 SendFakeProcessKeyEvent(0);
247 GetTextInputClient()->SetCompositionText(composition_text);
251 void InputMethodAuraLinux::OnPreeditEnd() {
252 if (suppress_next_result_ || IsTextInputTypeNone())
253 return;
255 if (is_sync_mode_) {
256 if (!composition_.text.empty()) {
257 composition_.Clear();
258 composition_changed_ = true;
260 } else {
261 TextInputClient* client = GetTextInputClient();
262 if (client && client->HasCompositionText()) {
263 SendFakeProcessKeyEvent(0);
264 client->ClearCompositionText();
266 composition_.Clear();
270 // Overridden from InputMethodBase.
272 void InputMethodAuraLinux::OnFocus() {
273 InputMethodBase::OnFocus();
274 UpdateContextFocusState();
277 void InputMethodAuraLinux::OnBlur() {
278 ConfirmCompositionText();
279 InputMethodBase::OnBlur();
280 UpdateContextFocusState();
283 void InputMethodAuraLinux::OnWillChangeFocusedClient(
284 TextInputClient* focused_before,
285 TextInputClient* focused) {
286 ConfirmCompositionText();
289 void InputMethodAuraLinux::OnDidChangeFocusedClient(
290 TextInputClient* focused_before,
291 TextInputClient* focused) {
292 UpdateContextFocusState();
294 // Force to update caret bounds, in case the View thinks that the caret
295 // bounds has not changed.
296 if (text_input_type_ != TEXT_INPUT_TYPE_NONE)
297 OnCaretBoundsChanged(GetTextInputClient());
299 InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
302 // private
304 bool InputMethodAuraLinux::HasInputMethodResult() {
305 return !result_text_.empty() || composition_changed_;
308 bool InputMethodAuraLinux::NeedInsertChar() const {
309 return IsTextInputTypeNone() ||
310 (!composition_changed_ && composition_.text.empty() &&
311 result_text_.length() == 1);
314 void InputMethodAuraLinux::SendFakeProcessKeyEvent(int flags) const {
315 DispatchKeyEventPostIME(
316 KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, flags));
319 void InputMethodAuraLinux::ConfirmCompositionText() {
320 TextInputClient* client = GetTextInputClient();
321 if (client && client->HasCompositionText())
322 client->ConfirmCompositionText();
324 ResetContext();
327 } // namespace ui