// Copyright (c) 2012 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/views/ime/input_method_bridge.h" #include "ui/base/events/event.h" #include "ui/base/ime/input_method.h" #include "ui/gfx/rect.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" namespace views { InputMethodBridge::InputMethodBridge(internal::InputMethodDelegate* delegate, ui::InputMethod* host, bool shared_input_method) : host_(host), shared_input_method_(shared_input_method), context_focused_(false) { DCHECK(host_); SetDelegate(delegate); } InputMethodBridge::~InputMethodBridge() { // By the time we get here it's very likely |widget_|'s NativeWidget has been // destroyed. This means any calls to |widget_| that go to the NativeWidget, // such as IsActive(), will crash. SetFocusedTextInputClient() may callback to // this and go into |widget_|. NULL out |widget_| so we don't attempt to use // it. DetachFromWidget(); if (host_->GetTextInputClient() == this) host_->SetFocusedTextInputClient(NULL); } void InputMethodBridge::OnFocus() { // Direct the shared IME to send TextInputClient messages to |this| object. if (shared_input_method_ || !host_->GetTextInputClient()) host_->SetFocusedTextInputClient(this); // TODO(yusukes): We don't need to call OnTextInputTypeChanged() once we move // text input type tracker code to ui::InputMethodBase. if (GetFocusedView()) OnTextInputTypeChanged(GetFocusedView()); } void InputMethodBridge::OnBlur() { if (HasCompositionText()) { ConfirmCompositionText(); host_->CancelComposition(this); } if (host_->GetTextInputClient() == this) host_->SetFocusedTextInputClient(NULL); } bool InputMethodBridge::OnUntranslatedIMEMessage(const base::NativeEvent& event, NativeEventResult* result) { return host_->OnUntranslatedIMEMessage(event, result); } void InputMethodBridge::DispatchKeyEvent(const ui::KeyEvent& key) { DCHECK(key.type() == ui::ET_KEY_PRESSED || key.type() == ui::ET_KEY_RELEASED); // We can just dispatch the event here since the |key| is already processed by // the system-wide IME. DispatchKeyEventPostIME(key); } void InputMethodBridge::OnTextInputTypeChanged(View* view) { if (IsViewFocused(view)) host_->OnTextInputTypeChanged(this); InputMethodBase::OnTextInputTypeChanged(view); } void InputMethodBridge::OnCaretBoundsChanged(View* view) { if (IsViewFocused(view) && !IsTextInputTypeNone()) host_->OnCaretBoundsChanged(this); } void InputMethodBridge::CancelComposition(View* view) { if (IsViewFocused(view)) host_->CancelComposition(this); } void InputMethodBridge::OnInputLocaleChanged() { return host_->OnInputLocaleChanged(); } std::string InputMethodBridge::GetInputLocale() { return host_->GetInputLocale(); } base::i18n::TextDirection InputMethodBridge::GetInputTextDirection() { return host_->GetInputTextDirection(); } bool InputMethodBridge::IsActive() { return host_->IsActive(); } bool InputMethodBridge::IsCandidatePopupOpen() const { return host_->IsCandidatePopupOpen(); } // Overridden from TextInputClient. Forward an event from the system-wide IME // to the text input |client|, which is e.g. views::NativeTextfieldViews. void InputMethodBridge::SetCompositionText( const ui::CompositionText& composition) { TextInputClient* client = GetTextInputClient(); if (client) client->SetCompositionText(composition); } void InputMethodBridge::ConfirmCompositionText() { TextInputClient* client = GetTextInputClient(); if (client) client->ConfirmCompositionText(); } void InputMethodBridge::ClearCompositionText() { TextInputClient* client = GetTextInputClient(); if (client) client->ClearCompositionText(); } void InputMethodBridge::InsertText(const string16& text) { TextInputClient* client = GetTextInputClient(); if (client) client->InsertText(text); } void InputMethodBridge::InsertChar(char16 ch, int flags) { TextInputClient* client = GetTextInputClient(); if (client) client->InsertChar(ch, flags); } gfx::NativeWindow InputMethodBridge::GetAttachedWindow() const { TextInputClient* client = GetTextInputClient(); return client ? client->GetAttachedWindow() : static_cast(NULL); } ui::TextInputType InputMethodBridge::GetTextInputType() const { TextInputClient* client = GetTextInputClient(); return client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE; } ui::TextInputMode InputMethodBridge::GetTextInputMode() const { TextInputClient* client = GetTextInputClient(); return client ? client->GetTextInputMode() : ui::TEXT_INPUT_MODE_DEFAULT; } bool InputMethodBridge::CanComposeInline() const { TextInputClient* client = GetTextInputClient(); return client ? client->CanComposeInline() : true; } gfx::Rect InputMethodBridge::GetCaretBounds() { TextInputClient* client = GetTextInputClient(); if (!client) return gfx::Rect(); return client->GetCaretBounds(); } bool InputMethodBridge::GetCompositionCharacterBounds(uint32 index, gfx::Rect* rect) { DCHECK(rect); TextInputClient* client = GetTextInputClient(); if (!client) return false; return client->GetCompositionCharacterBounds(index, rect); } bool InputMethodBridge::HasCompositionText() { TextInputClient* client = GetTextInputClient(); return client ? client->HasCompositionText() : false; } bool InputMethodBridge::GetTextRange(ui::Range* range) { TextInputClient* client = GetTextInputClient(); return client ? client->GetTextRange(range) : false; } bool InputMethodBridge::GetCompositionTextRange(ui::Range* range) { TextInputClient* client = GetTextInputClient(); return client ? client->GetCompositionTextRange(range) : false; } bool InputMethodBridge::GetSelectionRange(ui::Range* range) { TextInputClient* client = GetTextInputClient(); return client ? client->GetSelectionRange(range) : false; } bool InputMethodBridge::SetSelectionRange(const ui::Range& range) { TextInputClient* client = GetTextInputClient(); return client ? client->SetSelectionRange(range) : false; } bool InputMethodBridge::DeleteRange(const ui::Range& range) { TextInputClient* client = GetTextInputClient(); return client ? client->DeleteRange(range) : false; } bool InputMethodBridge::GetTextFromRange( const ui::Range& range, string16* text) { TextInputClient* client = GetTextInputClient(); return client ? client->GetTextFromRange(range, text) : false; } void InputMethodBridge::OnInputMethodChanged() { TextInputClient* client = GetTextInputClient(); if (client) client->OnInputMethodChanged(); } bool InputMethodBridge::ChangeTextDirectionAndLayoutAlignment( base::i18n::TextDirection direction) { TextInputClient* client = GetTextInputClient(); return client ? client->ChangeTextDirectionAndLayoutAlignment(direction) : false; } void InputMethodBridge::ExtendSelectionAndDelete(size_t before, size_t after) { TextInputClient* client = GetTextInputClient(); if (client) client->ExtendSelectionAndDelete(before, after); } void InputMethodBridge::EnsureCaretInRect(const gfx::Rect& rect) { TextInputClient* client = GetTextInputClient(); if (client) client->EnsureCaretInRect(rect); } // Overridden from FocusChangeListener. void InputMethodBridge::OnWillChangeFocus(View* focused_before, View* focused) { if (HasCompositionText()) { ConfirmCompositionText(); CancelComposition(focused_before); } } void InputMethodBridge::OnDidChangeFocus(View* focused_before, View* focused) { DCHECK_EQ(GetFocusedView(), focused); OnTextInputTypeChanged(focused); OnCaretBoundsChanged(focused); } ui::InputMethod* InputMethodBridge::GetHostInputMethod() const { return host_; } } // namespace views