| Index: ui/base/ime/remote_input_method_win.cc
|
| diff --git a/ui/base/ime/remote_input_method_win.cc b/ui/base/ime/remote_input_method_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b3be2b5edeb15e1414d3af89b51fa22804ce3e56
|
| --- /dev/null
|
| +++ b/ui/base/ime/remote_input_method_win.cc
|
| @@ -0,0 +1,344 @@
|
| +// Copyright (c) 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/remote_input_method_win.h"
|
| +
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "ui/base/ime/input_method.h"
|
| +#include "ui/base/ime/input_method_delegate.h"
|
| +#include "ui/base/ime/remote_input_method_delegate_win.h"
|
| +#include "ui/base/ime/text_input_client.h"
|
| +#include "ui/base/ime/win/tsf_input_scope.h"
|
| +#include "ui/events/event.h"
|
| +#include "ui/events/event_utils.h"
|
| +#include "ui/gfx/rect.h"
|
| +
|
| +namespace ui {
|
| +namespace {
|
| +
|
| +const LANGID kFallbackLangID =
|
| + MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT);
|
| +
|
| +InputMethod* g_public_interface_ = NULL;
|
| +RemoteInputMethodPrivateWin* g_private_interface_ = NULL;
|
| +
|
| +void RegisterInstance(InputMethod* public_interface,
|
| + RemoteInputMethodPrivateWin* private_interface) {
|
| + CHECK(g_public_interface_ == NULL)
|
| + << "Only one instance is supported at the same time";
|
| + CHECK(g_private_interface_ == NULL)
|
| + << "Only one instance is supported at the same time";
|
| + g_public_interface_ = public_interface;
|
| + g_private_interface_ = private_interface;
|
| +}
|
| +
|
| +RemoteInputMethodPrivateWin* GetPrivate(InputMethod* public_interface) {
|
| + if (g_public_interface_ != public_interface)
|
| + return NULL;
|
| + return g_private_interface_;
|
| +}
|
| +
|
| +void UnregisterInstance(InputMethod* public_interface) {
|
| + RemoteInputMethodPrivateWin* private_interface = GetPrivate(public_interface);
|
| + if (g_public_interface_ == public_interface &&
|
| + g_private_interface_ == private_interface) {
|
| + g_public_interface_ = NULL;
|
| + g_private_interface_ = NULL;
|
| + }
|
| +}
|
| +
|
| +std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) {
|
| + wchar_t buffer[16] = {};
|
| +
|
| + //|chars_written| includes NUL terminator.
|
| + const int chars_written =
|
| + GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer));
|
| + if (chars_written <= 1 || arraysize(buffer) < chars_written)
|
| + return std::string();
|
| + std::string result;
|
| + WideToUTF8(buffer, chars_written - 1, &result);
|
| + return result;
|
| +}
|
| +
|
| +std::vector<int32> GetInputScopesAsInt(TextInputType text_input_type,
|
| + TextInputMode text_input_mode) {
|
| + std::vector<int32> result;
|
| + // An empty vector represents |text_input_type| is TEXT_INPUT_TYPE_NONE.
|
| + if (text_input_type == TEXT_INPUT_TYPE_NONE)
|
| + return result;
|
| +
|
| + const std::vector<InputScope>& input_scopes =
|
| + tsf_inputscope::GetInputScopes(text_input_type, text_input_mode);
|
| + result.reserve(input_scopes.size());
|
| + for (size_t i = 0; i < input_scopes.size(); ++i)
|
| + result.push_back(static_cast<int32>(input_scopes[i]));
|
| + return result;
|
| +}
|
| +
|
| +std::vector<gfx::Rect> GetCompositionCharacterBounds(
|
| + const TextInputClient* client) {
|
| + if (!client)
|
| + return std::vector<gfx::Rect>();
|
| +
|
| + if (!client->HasCompositionText()) {
|
| + std::vector<gfx::Rect> caret;
|
| + caret.push_back(client->GetCaretBounds());
|
| + return caret;
|
| + }
|
| +
|
| + std::vector<gfx::Rect> bounds;
|
| + for (uint32 i = 0;; ++i) {
|
| + gfx::Rect rect;
|
| + if (!client->GetCompositionCharacterBounds(i, &rect))
|
| + break;
|
| + bounds.push_back(rect);
|
| + }
|
| + return bounds;
|
| +}
|
| +
|
| +class RemoteInputMethodWin : public InputMethod,
|
| + public RemoteInputMethodPrivateWin {
|
| + public:
|
| + explicit RemoteInputMethodWin(internal::InputMethodDelegate* delegate)
|
| + : delegate_(delegate),
|
| + remote_delegate_(NULL),
|
| + text_input_client_(NULL),
|
| + is_candidate_popup_open_(false),
|
| + is_ime_(false),
|
| + langid_(kFallbackLangID) {
|
| + RegisterInstance(this, this);
|
| + }
|
| +
|
| + virtual ~RemoteInputMethodWin() {
|
| + UnregisterInstance(this);
|
| + }
|
| +
|
| + private:
|
| + // Overridden from InputMethod:
|
| + virtual void SetDelegate(internal::InputMethodDelegate* delegate) OVERRIDE {
|
| + delegate_ = delegate;
|
| + }
|
| +
|
| + virtual void Init(bool focused) OVERRIDE {}
|
| +
|
| + virtual void OnFocus() OVERRIDE {}
|
| +
|
| + virtual void OnBlur() OVERRIDE {}
|
| +
|
| + virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
|
| + NativeEventResult* result) OVERRIDE {
|
| + return false;
|
| + }
|
| +
|
| + virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE {
|
| + std::vector<int32> prev_input_scopes;
|
| + std::swap(input_scopes_, prev_input_scopes);
|
| + std::vector<gfx::Rect> prev_bounds;
|
| + std::swap(composition_character_bounds_, prev_bounds);
|
| + if (client) {
|
| + input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
|
| + client->GetTextInputMode());
|
| + composition_character_bounds_ = GetCompositionCharacterBounds(client);
|
| + }
|
| +
|
| + text_input_client_ = client;
|
| +
|
| + if (!remote_delegate_ || (prev_input_scopes == input_scopes_ &&
|
| + prev_bounds == composition_character_bounds_))
|
| + return;
|
| + remote_delegate_->OnTextInputClientUpdated(input_scopes_,
|
| + composition_character_bounds_);
|
| + }
|
| +
|
| + virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE {
|
| + if (text_input_client_ != client)
|
| + return;
|
| + SetFocusedTextInputClient(NULL);
|
| + }
|
| +
|
| + virtual TextInputClient* GetTextInputClient() const OVERRIDE {
|
| + return text_input_client_;
|
| + }
|
| +
|
| + virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE {
|
| + if (event.HasNativeEvent()) {
|
| + const base::NativeEvent& native_key_event = event.native_event();
|
| + if (native_key_event.message != WM_CHAR)
|
| + return false;
|
| + if (!text_input_client_)
|
| + return false;
|
| + text_input_client_->InsertChar(
|
| + static_cast<char16>(native_key_event.wParam),
|
| + ui::GetModifiersFromKeyState());
|
| + return true;
|
| + }
|
| +
|
| + if (event.is_char()) {
|
| + if (text_input_client_) {
|
| + text_input_client_->InsertChar(event.key_code(),
|
| + ui::GetModifiersFromKeyState());
|
| + }
|
| + return true;
|
| + }
|
| + if (!delegate_)
|
| + return false;
|
| + return delegate_->DispatchFabricatedKeyEventPostIME(event.type(),
|
| + event.key_code(),
|
| + event.flags());
|
| + }
|
| +
|
| + virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
|
| + if (!text_input_client_ || text_input_client_ != client)
|
| + return;
|
| + std::vector<int32> prev_input_scopes;
|
| + std::swap(input_scopes_, prev_input_scopes);
|
| + input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
|
| + client->GetTextInputMode());
|
| + if (input_scopes_ != prev_input_scopes && remote_delegate_) {
|
| + remote_delegate_->OnTextInputClientUpdated(
|
| + input_scopes_, composition_character_bounds_);
|
| + }
|
| + }
|
| +
|
| + virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
|
| + if (!text_input_client_ || text_input_client_ != client)
|
| + return;
|
| + std::vector<gfx::Rect> prev_rects;
|
| + std::swap(composition_character_bounds_, prev_rects);
|
| + composition_character_bounds_ = GetCompositionCharacterBounds(client);
|
| + if (composition_character_bounds_ != prev_rects && remote_delegate_) {
|
| + remote_delegate_->OnTextInputClientUpdated(
|
| + input_scopes_, composition_character_bounds_);
|
| + }
|
| + }
|
| +
|
| + virtual void CancelComposition(const TextInputClient* client) OVERRIDE {
|
| + if (CanSendRemoteNotification(client))
|
| + remote_delegate_->CancelComposition();
|
| + }
|
| +
|
| + virtual void OnInputLocaleChanged() OVERRIDE {
|
| + // not supported.
|
| + }
|
| +
|
| + virtual std::string GetInputLocale() OVERRIDE {
|
| + const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT);
|
| + std::string language =
|
| + GetLocaleString(locale_id, LOCALE_SISO639LANGNAME);
|
| + if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty())
|
| + return language;
|
| + const std::string& region =
|
| + GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME);
|
| + if (region.empty())
|
| + return language;
|
| + return language.append(1, '-').append(region);
|
| + }
|
| +
|
| + virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE {
|
| + switch (PRIMARYLANGID(langid_)) {
|
| + case LANG_ARABIC:
|
| + case LANG_HEBREW:
|
| + case LANG_PERSIAN:
|
| + case LANG_SYRIAC:
|
| + case LANG_UIGHUR:
|
| + case LANG_URDU:
|
| + return base::i18n::RIGHT_TO_LEFT;
|
| + default:
|
| + return base::i18n::LEFT_TO_RIGHT;
|
| + }
|
| + }
|
| +
|
| + virtual bool IsActive() OVERRIDE {
|
| + return true; // always turned on
|
| + }
|
| +
|
| + virtual TextInputType GetTextInputType() const OVERRIDE {
|
| + return text_input_client_ ? text_input_client_->GetTextInputType()
|
| + : TEXT_INPUT_TYPE_NONE;
|
| + }
|
| +
|
| + virtual TextInputMode GetTextInputMode() const OVERRIDE {
|
| + return text_input_client_ ? text_input_client_->GetTextInputMode()
|
| + : TEXT_INPUT_MODE_DEFAULT;
|
| + }
|
| +
|
| + virtual bool CanComposeInline() const OVERRIDE {
|
| + return text_input_client_ ? text_input_client_->CanComposeInline() : true;
|
| + }
|
| +
|
| + virtual bool IsCandidatePopupOpen() const OVERRIDE {
|
| + return is_candidate_popup_open_;
|
| + }
|
| +
|
| + virtual void AddObserver(InputMethodObserver* observer) OVERRIDE {
|
| + // not supported.
|
| + NOTREACHED();
|
| + }
|
| +
|
| + virtual void RemoveObserver(InputMethodObserver* observer) OVERRIDE {
|
| + // not supported.
|
| + NOTREACHED();
|
| + }
|
| +
|
| + // Overridden from RemoteInputMethodPrivateWin:
|
| + virtual void SetRemoteDelegate(
|
| + internal::RemoteInputMethodDelegateWin* delegate) OVERRIDE{
|
| + remote_delegate_ = delegate;
|
| +
|
| + // Sync initial state.
|
| + if (remote_delegate_) {
|
| + remote_delegate_->OnTextInputClientUpdated(
|
| + input_scopes_, composition_character_bounds_);
|
| + }
|
| + }
|
| +
|
| + virtual void OnCandidatePopupChanged(bool visible) OVERRIDE {
|
| + is_candidate_popup_open_ = visible;
|
| + }
|
| +
|
| + virtual void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) OVERRIDE {
|
| + // Note: Currently |is_ime| is not utilized yet.
|
| + const bool changed = (langid_ != langid);
|
| + langid_ = langid;
|
| + if (changed && GetTextInputClient())
|
| + GetTextInputClient()->OnInputMethodChanged();
|
| + }
|
| +
|
| + bool CanSendRemoteNotification(
|
| + const TextInputClient* text_input_client) const {
|
| + return text_input_client_ &&
|
| + text_input_client_ == text_input_client &&
|
| + remote_delegate_;
|
| + }
|
| +
|
| + internal::InputMethodDelegate* delegate_;
|
| + internal::RemoteInputMethodDelegateWin* remote_delegate_;
|
| +
|
| + TextInputClient* text_input_client_;
|
| + std::vector<int32> input_scopes_;
|
| + std::vector<gfx::Rect> composition_character_bounds_;
|
| + bool is_candidate_popup_open_;
|
| + bool is_ime_;
|
| + LANGID langid_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {}
|
| +
|
| +// static
|
| +scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
|
| + internal::InputMethodDelegate* delegate) {
|
| + return scoped_ptr<InputMethod>(new RemoteInputMethodWin(delegate));
|
| +}
|
| +
|
| +// static
|
| +RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get(
|
| + InputMethod* input_method) {
|
| + return GetPrivate(input_method);
|
| +}
|
| +
|
| +} // namespace ui
|
|
|