Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / base / ime / input_method_auralinux.cc
blob2ae42d73c71ccaff22b278fdcb9da7eaca65f86b
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 void InputMethodAuraLinux::Init(bool focused) {
40 InputMethodBase::Init(focused);
42 UpdateContextFocusState();
45 bool InputMethodAuraLinux::OnUntranslatedIMEMessage(
46 const base::NativeEvent& event,
47 NativeEventResult* result) {
48 return false;
51 bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) {
52 DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
53 DCHECK(system_toplevel_window_focused());
55 // If no text input client, do nothing.
56 if (!GetTextInputClient())
57 return DispatchKeyEventPostIME(event);
59 suppress_next_result_ = false;
60 composition_changed_ = false;
61 result_text_.clear();
63 bool filtered = false;
65 base::AutoReset<bool> flipper(&is_sync_mode_, true);
66 if (text_input_type_ != TEXT_INPUT_TYPE_NONE &&
67 text_input_type_ != TEXT_INPUT_TYPE_PASSWORD) {
68 filtered = context_->DispatchKeyEvent(event);
69 } else {
70 filtered = context_simple_->DispatchKeyEvent(event);
74 if (event.type() == ui::ET_KEY_PRESSED && filtered) {
75 if (NeedInsertChar())
76 DispatchKeyEventPostIME(event);
77 else if (HasInputMethodResult())
78 SendFakeProcessKeyEvent(event.flags());
80 // Don't send VKEY_PROCESSKEY event if there is no result text or
81 // composition. This is to workaround the weird behavior of IBus with US
82 // keyboard, which mutes the keydown and later fake a new keydown with IME
83 // result in sync mode. In that case, user would expect only
84 // keydown/keypress/keyup event without an initial 229 keydown event.
87 TextInputClient* client = GetTextInputClient();
88 // Processes the result text before composition for sync mode.
89 if (!result_text_.empty()) {
90 if (filtered && NeedInsertChar()) {
91 for (const auto ch : result_text_)
92 client->InsertChar(ch, event.flags());
93 } else {
94 // If |filtered| is false, that means the IME wants to commit some text
95 // but still release the key to the application. For example, Korean IME
96 // handles ENTER key to confirm its composition but still release it for
97 // the default behavior (e.g. trigger search, etc.)
98 // In such case, don't do InsertChar because a key should only trigger the
99 // keydown event once.
100 client->InsertText(result_text_);
104 if (composition_changed_ && !IsTextInputTypeNone()) {
105 // If composition changed, does SetComposition if composition is not empty.
106 // And ClearComposition if composition is empty.
107 if (!composition_.text.empty())
108 client->SetCompositionText(composition_);
109 else if (result_text_.empty())
110 client->ClearCompositionText();
113 // Makes sure the cached composition is cleared after committing any text or
114 // cleared composition.
115 if (!client->HasCompositionText())
116 composition_.Clear();
118 if (!filtered) {
119 DispatchKeyEventPostIME(event);
120 if (event.type() == ui::ET_KEY_PRESSED) {
121 // If a key event was not filtered by |context_| or |context_simple_|,
122 // then it means the key event didn't generate any result text. For some
123 // cases, the key event may still generate a valid character, eg. a
124 // control-key event (ctrl-a, return, tab, etc.). We need to send the
125 // character to the focused text input client by calling
126 // TextInputClient::InsertChar().
127 // Note: don't use |client| and use GetTextInputClient() here because
128 // DispatchKeyEventPostIME may cause the current text input client change.
129 base::char16 ch = event.GetCharacter();
130 if (ch && GetTextInputClient())
131 GetTextInputClient()->InsertChar(ch, event.flags());
135 return true;
138 void InputMethodAuraLinux::UpdateContextFocusState() {
139 bool old_text_input_type = text_input_type_;
140 text_input_type_ = GetTextInputType();
142 // We only focus in |context_| when the focus is in a textfield.
143 if (old_text_input_type != TEXT_INPUT_TYPE_NONE &&
144 text_input_type_ == TEXT_INPUT_TYPE_NONE) {
145 context_->Blur();
146 } else if (old_text_input_type == TEXT_INPUT_TYPE_NONE &&
147 text_input_type_ != TEXT_INPUT_TYPE_NONE) {
148 context_->Focus();
151 // |context_simple_| can be used in any textfield, including password box, and
152 // even if the focused text input client's text input type is
153 // ui::TEXT_INPUT_TYPE_NONE.
154 if (GetTextInputClient())
155 context_simple_->Focus();
156 else
157 context_simple_->Blur();
160 void InputMethodAuraLinux::OnTextInputTypeChanged(
161 const TextInputClient* client) {
162 UpdateContextFocusState();
163 // TODO(yoichio): Support inputmode HTML attribute.
166 void InputMethodAuraLinux::OnCaretBoundsChanged(const TextInputClient* client) {
167 if (!IsTextInputClientFocused(client))
168 return;
169 context_->SetCursorLocation(GetTextInputClient()->GetCaretBounds());
172 void InputMethodAuraLinux::CancelComposition(const TextInputClient* client) {
173 if (!IsTextInputClientFocused(client))
174 return;
175 ResetContext();
178 void InputMethodAuraLinux::ResetContext() {
179 if (!GetTextInputClient())
180 return;
182 // To prevent any text from being committed when resetting the |context_|;
183 is_sync_mode_ = true;
184 suppress_next_result_ = true;
186 context_->Reset();
187 context_simple_->Reset();
189 // Some input methods may not honour the reset call. Focusing out/in the
190 // |context_| to make sure it gets reset correctly.
191 if (text_input_type_ != TEXT_INPUT_TYPE_NONE) {
192 context_->Blur();
193 context_->Focus();
196 composition_.Clear();
197 result_text_.clear();
198 is_sync_mode_ = false;
199 composition_changed_ = false;
202 void InputMethodAuraLinux::OnInputLocaleChanged() {
205 std::string InputMethodAuraLinux::GetInputLocale() {
206 return "";
209 bool InputMethodAuraLinux::IsActive() {
210 // InputMethodAuraLinux is always ready and up.
211 return true;
214 bool InputMethodAuraLinux::IsCandidatePopupOpen() const {
215 // There seems no way to detect candidate windows or any popups.
216 return false;
219 // Overriden from ui::LinuxInputMethodContextDelegate
221 void InputMethodAuraLinux::OnCommit(const base::string16& text) {
222 if (suppress_next_result_ || !GetTextInputClient()) {
223 suppress_next_result_ = false;
224 return;
227 if (is_sync_mode_) {
228 // Append the text to the buffer, because commit signal might be fired
229 // multiple times when processing a key event.
230 result_text_.append(text);
231 } else if (!IsTextInputTypeNone()) {
232 // If we are not handling key event, do not bother sending text result if
233 // the focused text input client does not support text input.
234 SendFakeProcessKeyEvent(0);
235 GetTextInputClient()->InsertText(text);
236 composition_.Clear();
240 void InputMethodAuraLinux::OnPreeditChanged(
241 const CompositionText& composition_text) {
242 if (suppress_next_result_ || IsTextInputTypeNone())
243 return;
245 composition_ = composition_text;
247 if (is_sync_mode_) {
248 if (!composition_.text.empty() || !composition_text.text.empty())
249 composition_changed_ = true;
250 } else {
251 SendFakeProcessKeyEvent(0);
252 GetTextInputClient()->SetCompositionText(composition_text);
256 void InputMethodAuraLinux::OnPreeditEnd() {
257 if (suppress_next_result_ || IsTextInputTypeNone())
258 return;
260 if (is_sync_mode_) {
261 if (!composition_.text.empty()) {
262 composition_.Clear();
263 composition_changed_ = true;
265 } else {
266 TextInputClient* client = GetTextInputClient();
267 if (client && client->HasCompositionText()) {
268 SendFakeProcessKeyEvent(0);
269 client->ClearCompositionText();
271 composition_.Clear();
275 // Overridden from InputMethodBase.
277 void InputMethodAuraLinux::OnFocus() {
278 InputMethodBase::OnFocus();
279 UpdateContextFocusState();
282 void InputMethodAuraLinux::OnBlur() {
283 ConfirmCompositionText();
284 InputMethodBase::OnBlur();
285 UpdateContextFocusState();
288 void InputMethodAuraLinux::OnWillChangeFocusedClient(
289 TextInputClient* focused_before,
290 TextInputClient* focused) {
291 ConfirmCompositionText();
294 void InputMethodAuraLinux::OnDidChangeFocusedClient(
295 TextInputClient* focused_before,
296 TextInputClient* focused) {
297 UpdateContextFocusState();
299 // Force to update caret bounds, in case the View thinks that the caret
300 // bounds has not changed.
301 if (text_input_type_ != TEXT_INPUT_TYPE_NONE)
302 OnCaretBoundsChanged(GetTextInputClient());
304 InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
307 // private
309 bool InputMethodAuraLinux::HasInputMethodResult() {
310 return !result_text_.empty() || composition_changed_;
313 bool InputMethodAuraLinux::NeedInsertChar() const {
314 return IsTextInputTypeNone() ||
315 (!composition_changed_ && composition_.text.empty() &&
316 result_text_.length() == 1);
319 void InputMethodAuraLinux::SendFakeProcessKeyEvent(int flags) const {
320 DispatchKeyEventPostIME(
321 KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, flags));
324 void InputMethodAuraLinux::ConfirmCompositionText() {
325 TextInputClient* client = GetTextInputClient();
326 if (client && client->HasCompositionText())
327 client->ConfirmCompositionText();
329 ResetContext();
332 } // namespace ui