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

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: addressed nona's comments. 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
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..7592ae61750ede965e62bd93c12a2fa818e74ede 100644
--- a/ui/base/ime/input_method_auralinux.cc
+++ b/ui/base/ime/input_method_auralinux.cc
@@ -11,34 +11,43 @@
namespace ui {
+namespace {
+
+class ScopedBooleanFlipper {
yukawa 2015/04/08 22:26:48 Can we use base::AutoReset in //src/base/auto_rese
Shu Chen 2015/04/09 01:16:32 Done.
+ public:
+ ScopedBooleanFlipper(bool* v) : v_(v) { DCHECK(!*v_); *v_ = true; }
+ ~ScopedBooleanFlipper() { *v_ = false; }
+ private:
+ bool* v_;
+};
+
+} // namespace
+
InputMethodAuraLinux::InputMethodAuraLinux(
internal::InputMethodDelegate* delegate)
- : allowed_to_fire_vkey_process_key_(false), vkey_processkey_flags_(0) {
+ : context_focused_(false), handling_key_event_(false),
+ composing_text_(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(
@@ -50,54 +59,128 @@ bool InputMethodAuraLinux::OnUntranslatedIMEMessage(
bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) {
DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
DCHECK(system_toplevel_window_focused());
+ suppress_next_result_ = false;
// If no text input client, do nothing.
if (!GetTextInputClient())
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;
+ composition_changed_ = false;
+ result_text_.clear();
+
+ bool filtered = false;
+ {
+ ScopedBooleanFlipper flipper(&handling_key_event_);
+ if (context_focused_)
+ filtered = context_->DispatchKeyEvent(event);
+ else
+ filtered = context_simple_->DispatchKeyEvent(event);
+ }
+
+ if (event.type() == ui::ET_KEY_PRESSED && filtered) {
+ if (NeedInsertChar()) {
+ DispatchKeyEventPostIME(event);
+ } else {
+ ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_PROCESSKEY, event.flags());
+ DispatchKeyEventPostIME(key);
}
}
- return handled;
+
+ // If has input result process the result.
+ if (result_text_.length() || composition_changed_)
yukawa 2015/04/08 22:26:49 I slightly prefer string::empty(). How about this?
Shu Chen 2015/04/09 01:16:32 Done.
+ ProcessInputMethodResult(event, filtered);
+
+ if (event.type() == ui::ET_KEY_PRESSED && !filtered) {
+ DispatchKeyEventPostIME(event);
+
+ // 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();
+ TextInputClient* client = GetTextInputClient();
+ if (ch && client)
+ client->InsertChar(ch, event.flags());
+ } else if (event.type() == ui::ET_KEY_RELEASED && !filtered) {
+ DispatchKeyEventPostIME(event);
+ }
James Su 2015/04/09 08:40:02 add a comment somewhere to clarify that filtered k
+
+ return true;
+}
+
+void InputMethodAuraLinux::UpdateContextFocusState() {
+ bool old_context_focused = context_focused_;
+ // Use switch here in case we are going to add more text input types.
+ switch (GetTextInputType()) {
+ case ui::TEXT_INPUT_TYPE_NONE:
+ case ui::TEXT_INPUT_TYPE_PASSWORD:
Seigo Nonaka 2015/04/08 17:15:40 Probably off the topic but I just noticed the issu
yukawa 2015/04/08 22:26:49 Sounds good. But I think it's OK to try it later
Shu Chen 2015/04/09 01:16:33 I would also prefer to consider it in a separated
+ context_focused_ = false;
+ break;
+ default:
+ context_focused_ = true;
+ break;
+ }
+
+ // We only focus in |context_| when the focus is in a normal textfield.
+ if (old_context_focused && !context_focused_)
+ context_->Blur();
+ else if (!old_context_focused && context_focused_)
+ 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();
+ DCHECK(!composing_text_);
+ 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;
+
+ DCHECK(!handling_key_event_);
Seigo Nonaka 2015/04/08 17:15:40 ditto?
Shu Chen 2015/04/09 01:16:32 Done.
+
+ // To prevent any text from being committed when resetting the |context_|;
+ handling_key_event_ = 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 (context_focused_) {
+ context_->Blur();
+ context_->Focus();
+ }
+
+ composition_.Clear();
+ result_text_.clear();
+ handling_key_event_ = false;
+ composing_text_ = false;
+ composition_changed_ = false;
}
void InputMethodAuraLinux::OnInputLocaleChanged() {
@@ -120,63 +203,146 @@ bool InputMethodAuraLinux::IsCandidatePopupOpen() const {
// Overriden from ui::LinuxInputMethodContextDelegate
void InputMethodAuraLinux::OnCommit(const base::string16& text) {
- MaybeFireProcessKey();
- if (!IsTextInputTypeNone())
+ if (suppress_next_result_) {
+ suppress_next_result_ = false;
+ return;
+ }
+ if (!GetTextInputClient())
+ return;
+
+ if (!composing_text_ && !text.length())
yukawa 2015/04/08 22:26:48 I slightly prefer string::empty(). How about this?
Shu Chen 2015/04/09 01:16:32 Done.
+ return;
+
+ // Append the text to the buffer, because commit signal might be fired
+ // multiple times when processing a key event.
+ result_text_.append(text);
+
+ // If we are not handling key event, do not bother sending text result if the
+ // focused text input client does not support text input.
+ if (!handling_key_event_ && !IsTextInputTypeNone()) {
+ SendFakeProcessKeyEvent(true);
GetTextInputClient()->InsertText(text);
+ }
+}
+
+void InputMethodAuraLinux::OnPreeditStart() {
+ if (suppress_next_result_ || IsTextInputTypeNone())
+ return;
+
+ composing_text_ = true;
}
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;
+
+ if (!composition_.text.length() && !composition_text.text.length())
yukawa 2015/04/08 22:26:48 I slightly prefer string::empty(). How about this?
Shu Chen 2015/04/09 01:16:32 Done.
+ return;
+
+ composition_ = composition_text;
+ composition_changed_ = true;
+ if (composition_.text.length())
yukawa 2015/04/08 22:26:48 I slightly prefer string::empty(). How about this?
Shu Chen 2015/04/09 01:16:32 Done.
+ composing_text_ = true;
+
+ if (!handling_key_event_ && !IsTextInputTypeNone()) {
+ SendFakeProcessKeyEvent(true);
+ GetTextInputClient()->SetCompositionText(composition_);
+ }
}
void InputMethodAuraLinux::OnPreeditEnd() {
- MaybeFireProcessKey();
- TextInputClient* text_input_client = GetTextInputClient();
- if (text_input_client && text_input_client->HasCompositionText())
- text_input_client->ClearCompositionText();
-}
+ if (composition_.text.empty() || IsTextInputTypeNone())
+ return;
-void InputMethodAuraLinux::OnPreeditStart() {
- MaybeFireProcessKey();
+ composition_changed_ = true;
+ composition_.Clear();
+
+ if (!handling_key_event_) {
+ TextInputClient* client = GetTextInputClient();
+ if (client && client->HasCompositionText())
+ client->ClearCompositionText();
+ }
}
// 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 (context_focused_)
+ OnCaretBoundsChanged(GetTextInputClient());
InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
}
-// Helper functions to support VKEY_PROCESSKEY.
+// private
+
+void InputMethodAuraLinux::ProcessInputMethodResult(const KeyEvent& key,
+ bool filtered) {
+ TextInputClient* client = GetTextInputClient();
+ DCHECK(client);
+
+ if (result_text_.length()) {
yukawa 2015/04/08 22:26:48 I slightly prefer string::empty(). How about this?
Shu Chen 2015/04/09 01:16:32 Done.
+ if (filtered && NeedInsertChar()) {
+ for (base::string16::const_iterator i = result_text_.begin();
yukawa 2015/04/08 22:26:48 How about using range-based for? for (const auto
Shu Chen 2015/04/09 01:16:32 Done.
+ i != result_text_.end(); ++i) {
+ client->InsertChar(*i, key.flags());
+ }
+ } else {
+ client->InsertText(result_text_);
+ composing_text_ = false;
+ }
+ }
-void InputMethodAuraLinux::AllowToFireProcessKey(const ui::KeyEvent& event) {
- allowed_to_fire_vkey_process_key_ = true;
- vkey_processkey_flags_ = event.flags();
+ if (composition_changed_ && !IsTextInputTypeNone()) {
+ if (composition_.text.length()) {
yukawa 2015/04/08 22:26:49 I slightly prefer string::empty(). How about this?
Shu Chen 2015/04/09 01:16:32 Done.
+ composing_text_ = true;
+ client->SetCompositionText(composition_);
+ } else if (result_text_.empty()) {
+ client->ClearCompositionText();
+ }
+ }
}
-void InputMethodAuraLinux::MaybeFireProcessKey() {
- if (!allowed_to_fire_vkey_process_key_)
- return;
+bool InputMethodAuraLinux::NeedInsertChar() const {
+ return IsTextInputTypeNone() ||
+ (!composing_text_ && result_text_.length() == 1);
+}
- const ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
- VKEY_PROCESSKEY,
- vkey_processkey_flags_);
- DispatchKeyEventPostIME(fabricated_event);
- StopFiringProcessKey();
+void InputMethodAuraLinux::SendFakeProcessKeyEvent(bool pressed) const {
+ KeyEvent key(pressed ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
+ ui::VKEY_PROCESSKEY, 0);
+ DispatchKeyEventPostIME(key);
}
-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

Powered by Google App Engine
This is Rietveld 408576698