// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/base/ime/input_method_auralinux.h"
#include "base/environment.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/events/event.h"
namespace ui {
InputMethodAuraLinux::InputMethodAuraLinux(
internal::InputMethodDelegate* delegate)
: allowed_to_fire_vkey_process_key_(false), vkey_processkey_flags_(0) {
SetDelegate(delegate);
}
InputMethodAuraLinux::~InputMethodAuraLinux() {}
// 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);
}
}
bool InputMethodAuraLinux::OnUntranslatedIMEMessage(
const base::NativeEvent& event,
NativeEventResult* result) {
return false;
}
bool InputMethodAuraLinux::DispatchKeyEvent(const ui::KeyEvent& event) {
DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED);
DCHECK(system_toplevel_window_focused());
// 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;
}
}
return handled;
}
void InputMethodAuraLinux::OnTextInputTypeChanged(
const TextInputClient* client) {
if (!IsTextInputClientFocused(client))
return;
input_method_context_->Reset();
// 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());
}
void InputMethodAuraLinux::CancelComposition(const TextInputClient* client) {
if (!IsTextInputClientFocused(client))
return;
input_method_context_->Reset();
input_method_context_->OnTextInputTypeChanged(client->GetTextInputType());
}
void InputMethodAuraLinux::OnInputLocaleChanged() {
}
std::string InputMethodAuraLinux::GetInputLocale() {
return "";
}
bool InputMethodAuraLinux::IsActive() {
// InputMethodAuraLinux is always ready and up.
return true;
}
bool InputMethodAuraLinux::IsCandidatePopupOpen() const {
// There seems no way to detect candidate windows or any popups.
return false;
}
// Overriden from ui::LinuxInputMethodContextDelegate
void InputMethodAuraLinux::OnCommit(const base::string16& text) {
MaybeFireProcessKey();
if (!IsTextInputTypeNone())
GetTextInputClient()->InsertText(text);
}
void InputMethodAuraLinux::OnPreeditChanged(
const CompositionText& composition_text) {
MaybeFireProcessKey();
TextInputClient* text_input_client = GetTextInputClient();
if (text_input_client)
text_input_client->SetCompositionText(composition_text);
}
void InputMethodAuraLinux::OnPreeditEnd() {
MaybeFireProcessKey();
TextInputClient* text_input_client = GetTextInputClient();
if (text_input_client && text_input_client->HasCompositionText())
text_input_client->ClearCompositionText();
}
void InputMethodAuraLinux::OnPreeditStart() {
MaybeFireProcessKey();
}
// Overridden from InputMethodBase.
void InputMethodAuraLinux::OnDidChangeFocusedClient(
TextInputClient* focused_before,
TextInputClient* focused) {
input_method_context_->Reset();
input_method_context_->OnTextInputTypeChanged(
focused ? focused->GetTextInputType() : TEXT_INPUT_TYPE_NONE);
InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
}
// Helper functions to support VKEY_PROCESSKEY.
void InputMethodAuraLinux::AllowToFireProcessKey(const ui::KeyEvent& event) {
allowed_to_fire_vkey_process_key_ = true;
vkey_processkey_flags_ = event.flags();
}
void InputMethodAuraLinux::MaybeFireProcessKey() {
if (!allowed_to_fire_vkey_process_key_)
return;
const ui::KeyEvent fabricated_event(ET_KEY_PRESSED,
VKEY_PROCESSKEY,
vkey_processkey_flags_,
false); // is_char
DispatchKeyEventPostIME(fabricated_event);
StopFiringProcessKey();
}
void InputMethodAuraLinux::StopFiringProcessKey() {
allowed_to_fire_vkey_process_key_ = false;
vkey_processkey_flags_ = 0;
}
} // namespace ui