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

Unified 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: add more tests and support verify event sequence. 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/base/ime/input_method_auralinux.h ('k') | ui/base/ime/input_method_auralinux_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/base/ime/input_method_auralinux.cc
diff --git a/ui/base/ime/input_method_auralinux.cc b/ui/base/ime/input_method_auralinux.cc
index f5d4bee59a4cf01377bcb2b16920c94b233ab7aa..2887634c21bbb2b8acd0c42c05c1db7f639df8b0 100644
--- a/ui/base/ime/input_method_auralinux.cc
+++ b/ui/base/ime/input_method_auralinux.cc
@@ -4,6 +4,7 @@
#include "ui/base/ime/input_method_auralinux.h"
+#include "base/auto_reset.h"
#include "base/environment.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
#include "ui/base/ime/text_input_client.h"
@@ -13,32 +14,32 @@ namespace ui {
InputMethodAuraLinux::InputMethodAuraLinux(
internal::InputMethodDelegate* delegate)
- : allowed_to_fire_vkey_process_key_(false), vkey_processkey_flags_(0) {
+ : text_input_type_(TEXT_INPUT_TYPE_NONE),
+ is_sync_mode_(false),
+ composition_changed_(false),
+ suppress_next_result_(false) {
SetDelegate(delegate);
+ context_ =
+ LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
+ this, false);
+ context_simple_ =
+ LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
+ this, true);
}
InputMethodAuraLinux::~InputMethodAuraLinux() {}
+LinuxInputMethodContext* InputMethodAuraLinux::GetContextForTesting(
+ bool is_simple) {
+ return is_simple ? context_simple_.get() : context_.get();
+}
+
// Overriden from InputMethod.
void InputMethodAuraLinux::Init(bool focused) {
- CHECK(LinuxInputMethodContextFactory::instance())
- << "This failure was likely caused because "
- << "ui::InitializeInputMethod(ForTesting) was not called "
- << "before instantiating this class.";
- input_method_context_ =
- LinuxInputMethodContextFactory::instance()->CreateInputMethodContext(
- this);
- CHECK(input_method_context_.get());
-
InputMethodBase::Init(focused);
- if (focused) {
- input_method_context_->OnTextInputTypeChanged(
- GetTextInputClient() ?
- GetTextInputClient()->GetTextInputType() :
- TEXT_INPUT_TYPE_TEXT);
- }
+ UpdateContextFocusState();
}
bool InputMethodAuraLinux::OnUntranslatedIMEMessage(
@@ -51,53 +52,149 @@ bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) {
DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
DCHECK(system_toplevel_window_focused());
+ TextInputClient* client = GetTextInputClient();
// If no text input client, do nothing.
- if (!GetTextInputClient())
+ if (!client)
return DispatchKeyEventPostIME(event);
- // Let an IME handle the key event first, and allow to fire a VKEY_PROCESSKEY
- // event for keydown events. Note that DOM Level 3 Events Sepc requires that
- // only keydown events fire keyCode=229 events and not for keyup events.
- if (event.type() == ET_KEY_PRESSED &&
- (event.flags() & ui::EF_IME_FABRICATED_KEY) == 0)
- AllowToFireProcessKey(event);
- if (input_method_context_->DispatchKeyEvent(event))
- return true;
- StopFiringProcessKey();
-
- // Otherwise, insert the character.
- const bool handled = DispatchKeyEventPostIME(event);
- if (event.type() == ET_KEY_PRESSED && GetTextInputClient()) {
- const uint16 ch = event.GetCharacter();
- if (ch) {
- GetTextInputClient()->InsertChar(ch, event.flags());
- return true;
+ suppress_next_result_ = false;
+ composition_changed_ = false;
+ result_text_.clear();
+
+ bool filtered = false;
+ {
+ base::AutoReset<bool> flipper(&is_sync_mode_, true);
+ if (text_input_type_ != TEXT_INPUT_TYPE_NONE &&
+ text_input_type_ != TEXT_INPUT_TYPE_PASSWORD) {
+ filtered = context_->DispatchKeyEvent(event);
+ } else {
+ filtered = context_simple_->DispatchKeyEvent(event);
+ }
+ }
+
+ if (event.type() == ui::ET_KEY_PRESSED && filtered) {
+ if (NeedInsertChar())
+ DispatchKeyEventPostIME(event);
+ else if (HasInputMethodResult())
+ SendFakeProcessKeyEvent(event.flags());
+
+ // Don't send VKEY_PROCESSKEY event if there is no result text or
+ // composition. This is to workaround the weird behavior of IBus with US
+ // keyboard, which mutes the keydown and later fake a new keydown with IME
+ // result in sync mode. In that case, user would expect only
+ // keydown/keypress/keyup event without an initial 229 keydown event.
+ }
+
+ // Processes the result text before composition for sync mode.
+ if (!result_text_.empty()) {
+ if (filtered && NeedInsertChar()) {
+ for (const auto ch : result_text_)
+ client->InsertChar(ch, event.flags());
+ } else {
+ // If |filtered| is false, that means the IME wants to commit some text
+ // but still release the key to the application. For example, Korean IME
+ // handles ENTER key to confirm its composition but still release it for
+ // the default behavior (e.g. trigger search, etc.)
+ // In such case, don't do InsertChar because a key should only trigger the
+ // keydown event once.
+ client->InsertText(result_text_);
+ }
+ }
+
+ if (composition_changed_ && !IsTextInputTypeNone()) {
+ // If composition changed, does SetComposition if composition is not empty.
+ // And ClearComposition if composition is empty.
+ if (!composition_.text.empty())
+ client->SetCompositionText(composition_);
+ else if (result_text_.empty())
+ client->ClearCompositionText();
+ }
+
+ // Makes sure the cached composition is cleared after committing any text or
+ // cleared composition.
+ if (!result_text_.empty() && !composition_.text.empty())
+ composition_.Clear();
James Su 2015/04/12 14:50:33 According to our discussion, we need to keep compo
Shu Chen 2015/04/13 01:48:44 Done. Test also updated.
+
+ if (!filtered) {
+ DispatchKeyEventPostIME(event);
+ if (event.type() == ui::ET_KEY_PRESSED) {
+ // If a key event was not filtered by |context_| or |context_simple_|,
+ // then it means the key event didn't generate any result text. For some
+ // cases, the key event may still generate a valid character, eg. a
+ // control-key event (ctrl-a, return, tab, etc.). We need to send the
+ // character to the focused text input client by calling
+ // TextInputClient::InsertChar().
+ base::char16 ch = event.GetCharacter();
+ if (ch && client)
+ client->InsertChar(ch, event.flags());
}
}
- return handled;
+
+ return true;
+}
+
+void InputMethodAuraLinux::UpdateContextFocusState() {
+ bool old_text_input_type = text_input_type_;
+ text_input_type_ = GetTextInputType();
+
+ // We only focus in |context_| when the focus is in a textfield.
+ if (old_text_input_type != TEXT_INPUT_TYPE_NONE &&
+ text_input_type_ == TEXT_INPUT_TYPE_NONE) {
+ context_->Blur();
+ } else if (old_text_input_type == TEXT_INPUT_TYPE_NONE &&
+ text_input_type_ != TEXT_INPUT_TYPE_NONE) {
+ context_->Focus();
+ }
+
+ // |context_simple_| can be used in any textfield, including password box, and
+ // even if the focused text input client's text input type is
+ // ui::TEXT_INPUT_TYPE_NONE.
+ if (GetTextInputClient())
+ context_simple_->Focus();
+ else
+ context_simple_->Blur();
}
void InputMethodAuraLinux::OnTextInputTypeChanged(
const TextInputClient* client) {
- if (!IsTextInputClientFocused(client))
- return;
- input_method_context_->Reset();
+ UpdateContextFocusState();
// TODO(yoichio): Support inputmode HTML attribute.
- input_method_context_->OnTextInputTypeChanged(client->GetTextInputType());
}
void InputMethodAuraLinux::OnCaretBoundsChanged(const TextInputClient* client) {
if (!IsTextInputClientFocused(client))
return;
- input_method_context_->OnCaretBoundsChanged(
- GetTextInputClient()->GetCaretBounds());
+ context_->SetCursorLocation(GetTextInputClient()->GetCaretBounds());
}
void InputMethodAuraLinux::CancelComposition(const TextInputClient* client) {
if (!IsTextInputClientFocused(client))
return;
- input_method_context_->Reset();
- input_method_context_->OnTextInputTypeChanged(client->GetTextInputType());
+ ResetContext();
+}
+
+void InputMethodAuraLinux::ResetContext() {
+ if (!GetTextInputClient())
+ return;
+
+ // To prevent any text from being committed when resetting the |context_|;
+ is_sync_mode_ = true;
+ suppress_next_result_ = true;
+
+ context_->Reset();
+ context_simple_->Reset();
+
+ // Some input methods may not honour the reset call. Focusing out/in the
+ // |context_| to make sure it gets reset correctly.
+ if (text_input_type_ != TEXT_INPUT_TYPE_NONE) {
+ context_->Blur();
+ context_->Focus();
+ }
+
+ composition_.Clear();
+ result_text_.clear();
+ is_sync_mode_ = false;
+ composition_changed_ = false;
}
void InputMethodAuraLinux::OnInputLocaleChanged() {
@@ -120,63 +217,114 @@ bool InputMethodAuraLinux::IsCandidatePopupOpen() const {
// Overriden from ui::LinuxInputMethodContextDelegate
void InputMethodAuraLinux::OnCommit(const base::string16& text) {
- MaybeFireProcessKey();
- if (!IsTextInputTypeNone())
+ if (suppress_next_result_ || !GetTextInputClient()) {
+ suppress_next_result_ = false;
+ return;
+ }
+
+ if (is_sync_mode_) {
+ // Append the text to the buffer, because commit signal might be fired
+ // multiple times when processing a key event.
+ result_text_.append(text);
+ } else if (!IsTextInputTypeNone()) {
+ // If we are not handling key event, do not bother sending text result if
+ // the focused text input client does not support text input.
+ SendFakeProcessKeyEvent(0);
GetTextInputClient()->InsertText(text);
+ composition_.Clear();
+ }
}
void InputMethodAuraLinux::OnPreeditChanged(
const CompositionText& composition_text) {
- MaybeFireProcessKey();
- TextInputClient* text_input_client = GetTextInputClient();
- if (text_input_client)
- text_input_client->SetCompositionText(composition_text);
+ if (suppress_next_result_ || IsTextInputTypeNone())
+ return;
+
+ composition_ = composition_text;
+
+ if (is_sync_mode_) {
+ if (!composition_.text.empty() || !composition_text.text.empty())
+ composition_changed_ = true;
+ } else {
+ SendFakeProcessKeyEvent(0);
+ GetTextInputClient()->SetCompositionText(composition_text);
+ }
}
void InputMethodAuraLinux::OnPreeditEnd() {
- MaybeFireProcessKey();
- TextInputClient* text_input_client = GetTextInputClient();
- if (text_input_client && text_input_client->HasCompositionText())
- text_input_client->ClearCompositionText();
-}
+ if (suppress_next_result_ || IsTextInputTypeNone())
+ return;
-void InputMethodAuraLinux::OnPreeditStart() {
- MaybeFireProcessKey();
+ if (is_sync_mode_) {
+ if (!composition_.text.empty()) {
+ composition_.Clear();
+ composition_changed_ = true;
+ }
+ } else {
+ TextInputClient* client = GetTextInputClient();
+ if (client && client->HasCompositionText()) {
+ SendFakeProcessKeyEvent(0);
+ client->ClearCompositionText();
+ }
+ composition_.Clear();
+ }
}
// Overridden from InputMethodBase.
+void InputMethodAuraLinux::OnFocus() {
+ InputMethodBase::OnFocus();
+ UpdateContextFocusState();
+}
+
+void InputMethodAuraLinux::OnBlur() {
+ ConfirmCompositionText();
+ InputMethodBase::OnBlur();
+ UpdateContextFocusState();
+}
+
+void InputMethodAuraLinux::OnWillChangeFocusedClient(
+ TextInputClient* focused_before,
+ TextInputClient* focused) {
+ ConfirmCompositionText();
+}
+
void InputMethodAuraLinux::OnDidChangeFocusedClient(
TextInputClient* focused_before,
TextInputClient* focused) {
- input_method_context_->Reset();
- input_method_context_->OnTextInputTypeChanged(
- focused ? focused->GetTextInputType() : TEXT_INPUT_TYPE_NONE);
+ UpdateContextFocusState();
+
+ // Force to update caret bounds, in case the View thinks that the caret
+ // bounds has not changed.
+ if (text_input_type_ != TEXT_INPUT_TYPE_NONE)
+ OnCaretBoundsChanged(GetTextInputClient());
InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
}
-// Helper functions to support VKEY_PROCESSKEY.
+// private
-void InputMethodAuraLinux::AllowToFireProcessKey(const ui::KeyEvent& event) {
- allowed_to_fire_vkey_process_key_ = true;
- vkey_processkey_flags_ = event.flags();
+bool InputMethodAuraLinux::HasInputMethodResult() {
+ return !result_text_.empty() || composition_changed_;
}
-void InputMethodAuraLinux::MaybeFireProcessKey() {
- if (!allowed_to_fire_vkey_process_key_)
- return;
+bool InputMethodAuraLinux::NeedInsertChar() const {
+ return IsTextInputTypeNone() ||
+ (!composition_changed_ && composition_.text.empty() &&
+ result_text_.length() == 1);
+}
- const ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
- VKEY_PROCESSKEY,
- vkey_processkey_flags_);
- DispatchKeyEventPostIME(fabricated_event);
- StopFiringProcessKey();
+void InputMethodAuraLinux::SendFakeProcessKeyEvent(int flags) const {
+ DispatchKeyEventPostIME(
+ KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, flags));
}
-void InputMethodAuraLinux::StopFiringProcessKey() {
- allowed_to_fire_vkey_process_key_ = false;
- vkey_processkey_flags_ = 0;
+void InputMethodAuraLinux::ConfirmCompositionText() {
+ TextInputClient* client = GetTextInputClient();
+ if (client && client->HasCompositionText())
+ client->ConfirmCompositionText();
+
+ ResetContext();
}
} // namespace ui
« no previous file with comments | « ui/base/ime/input_method_auralinux.h ('k') | ui/base/ime/input_method_auralinux_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698