1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/ime/input_method_bridge.h"
7 #include "ui/base/ime/input_method.h"
8 #include "ui/base/ime/input_method_observer.h"
9 #include "ui/events/event.h"
10 #include "ui/gfx/geometry/rect.h"
11 #include "ui/views/view.h"
12 #include "ui/views/widget/widget.h"
16 // InputMethodBridge::HostObserver class ---------------------------------------
18 // An observer class for observing the host input method. When the host input
19 // method is destroyed, it will null out the |host_| field on the
20 // InputMethodBridge object.
21 class InputMethodBridge::HostObserver
: public ui::InputMethodObserver
{
23 explicit HostObserver(InputMethodBridge
* bridge
);
24 ~HostObserver() override
;
26 void OnTextInputTypeChanged(const ui::TextInputClient
* client
) override
{}
27 void OnFocus() override
{}
28 void OnBlur() override
{}
29 void OnCaretBoundsChanged(const ui::TextInputClient
* client
) override
{}
30 void OnTextInputStateChanged(const ui::TextInputClient
* client
) override
{}
31 void OnInputMethodDestroyed(const ui::InputMethod
* input_method
) override
;
32 void OnShowImeIfNeeded() override
{}
35 InputMethodBridge
* bridge_
;
37 DISALLOW_COPY_AND_ASSIGN(HostObserver
);
40 InputMethodBridge::HostObserver::HostObserver(InputMethodBridge
* bridge
)
42 bridge_
->host_
->AddObserver(this);
45 InputMethodBridge::HostObserver::~HostObserver() {
47 bridge_
->host_
->RemoveObserver(this);
50 void InputMethodBridge::HostObserver::OnInputMethodDestroyed(
51 const ui::InputMethod
* input_method
) {
52 DCHECK_EQ(bridge_
->host_
, input_method
);
53 bridge_
->host_
->RemoveObserver(this);
54 bridge_
->host_
= NULL
;
57 // InputMethodBridge class -----------------------------------------------------
59 InputMethodBridge::InputMethodBridge(internal::InputMethodDelegate
* delegate
,
60 ui::InputMethod
* host
,
61 bool shared_input_method
)
63 shared_input_method_(shared_input_method
) {
65 SetDelegate(delegate
);
67 host_observer_
.reset(new HostObserver(this));
70 InputMethodBridge::~InputMethodBridge() {
71 // By the time we get here it's very likely |widget_|'s NativeWidget has been
72 // destroyed. This means any calls to |widget_| that go to the NativeWidget,
73 // such as IsActive(), will crash. SetFocusedTextInputClient() may callback to
74 // this and go into |widget_|. NULL out |widget_| so we don't attempt to use
78 // Host input method might have been destroyed at this point.
80 host_
->DetachTextInputClient(this);
83 void InputMethodBridge::OnFocus() {
86 // Direct the shared IME to send TextInputClient messages to |this| object.
87 if (shared_input_method_
|| !host_
->GetTextInputClient())
88 host_
->SetFocusedTextInputClient(this);
90 // TODO(yusukes): We don't need to call OnTextInputTypeChanged() once we move
91 // text input type tracker code to ui::InputMethodBase.
92 if (GetFocusedView()) {
93 OnTextInputTypeChanged(GetFocusedView());
94 OnCaretBoundsChanged(GetFocusedView());
98 void InputMethodBridge::OnBlur() {
101 if (HasCompositionText()) {
102 ConfirmCompositionText();
103 host_
->CancelComposition(this);
106 if (host_
->GetTextInputClient() == this)
107 host_
->SetFocusedTextInputClient(NULL
);
110 bool InputMethodBridge::OnUntranslatedIMEMessage(const base::NativeEvent
& event
,
111 NativeEventResult
* result
) {
114 return host_
->OnUntranslatedIMEMessage(event
, result
);
117 void InputMethodBridge::DispatchKeyEvent(const ui::KeyEvent
& key
) {
118 DCHECK(key
.type() == ui::ET_KEY_PRESSED
|| key
.type() == ui::ET_KEY_RELEASED
);
120 // We can just dispatch the event here since the |key| is already processed by
121 // the system-wide IME.
122 DispatchKeyEventPostIME(key
);
125 void InputMethodBridge::OnTextInputTypeChanged(View
* view
) {
128 if (IsViewFocused(view
))
129 host_
->OnTextInputTypeChanged(this);
130 InputMethodBase::OnTextInputTypeChanged(view
);
133 void InputMethodBridge::OnCaretBoundsChanged(View
* view
) {
136 if (IsViewFocused(view
) && !IsTextInputTypeNone())
137 host_
->OnCaretBoundsChanged(this);
140 void InputMethodBridge::CancelComposition(View
* view
) {
143 if (IsViewFocused(view
))
144 host_
->CancelComposition(this);
147 void InputMethodBridge::OnInputLocaleChanged() {
150 host_
->OnInputLocaleChanged();
153 std::string
InputMethodBridge::GetInputLocale() {
156 return host_
->GetInputLocale();
159 bool InputMethodBridge::IsActive() {
162 return host_
->IsActive();
165 bool InputMethodBridge::IsCandidatePopupOpen() const {
168 return host_
->IsCandidatePopupOpen();
171 void InputMethodBridge::ShowImeIfNeeded() {
173 host_
->ShowImeIfNeeded();
176 // Overridden from TextInputClient. Forward an event from the system-wide IME
177 // to the text input |client|, which is e.g. views::Textfield.
178 void InputMethodBridge::SetCompositionText(
179 const ui::CompositionText
& composition
) {
180 TextInputClient
* client
= GetTextInputClient();
182 client
->SetCompositionText(composition
);
185 void InputMethodBridge::ConfirmCompositionText() {
186 TextInputClient
* client
= GetTextInputClient();
188 client
->ConfirmCompositionText();
191 void InputMethodBridge::ClearCompositionText() {
192 TextInputClient
* client
= GetTextInputClient();
194 client
->ClearCompositionText();
197 void InputMethodBridge::InsertText(const base::string16
& text
) {
198 TextInputClient
* client
= GetTextInputClient();
200 client
->InsertText(text
);
203 void InputMethodBridge::InsertChar(base::char16 ch
, int flags
) {
204 TextInputClient
* client
= GetTextInputClient();
206 client
->InsertChar(ch
, flags
);
209 gfx::NativeWindow
InputMethodBridge::GetAttachedWindow() const {
210 TextInputClient
* client
= GetTextInputClient();
212 client
->GetAttachedWindow() : static_cast<gfx::NativeWindow
>(NULL
);
215 ui::TextInputType
InputMethodBridge::GetTextInputType() const {
216 TextInputClient
* client
= GetTextInputClient();
217 return client
? client
->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE
;
220 ui::TextInputMode
InputMethodBridge::GetTextInputMode() const {
221 TextInputClient
* client
= GetTextInputClient();
222 return client
? client
->GetTextInputMode() : ui::TEXT_INPUT_MODE_DEFAULT
;
225 int InputMethodBridge::GetTextInputFlags() const {
226 TextInputClient
* client
= GetTextInputClient();
227 return client
? client
->GetTextInputFlags() : 0;
230 bool InputMethodBridge::CanComposeInline() const {
231 TextInputClient
* client
= GetTextInputClient();
232 return client
? client
->CanComposeInline() : true;
235 gfx::Rect
InputMethodBridge::GetCaretBounds() const {
236 TextInputClient
* client
= GetTextInputClient();
240 return client
->GetCaretBounds();
243 bool InputMethodBridge::GetCompositionCharacterBounds(uint32 index
,
244 gfx::Rect
* rect
) const {
246 TextInputClient
* client
= GetTextInputClient();
250 return client
->GetCompositionCharacterBounds(index
, rect
);
253 bool InputMethodBridge::HasCompositionText() const {
254 TextInputClient
* client
= GetTextInputClient();
255 return client
? client
->HasCompositionText() : false;
258 bool InputMethodBridge::GetTextRange(gfx::Range
* range
) const {
259 TextInputClient
* client
= GetTextInputClient();
260 return client
? client
->GetTextRange(range
) : false;
263 bool InputMethodBridge::GetCompositionTextRange(gfx::Range
* range
) const {
264 TextInputClient
* client
= GetTextInputClient();
265 return client
? client
->GetCompositionTextRange(range
) : false;
268 bool InputMethodBridge::GetSelectionRange(gfx::Range
* range
) const {
269 TextInputClient
* client
= GetTextInputClient();
270 return client
? client
->GetSelectionRange(range
) : false;
273 bool InputMethodBridge::SetSelectionRange(const gfx::Range
& range
) {
274 TextInputClient
* client
= GetTextInputClient();
275 return client
? client
->SetSelectionRange(range
) : false;
278 bool InputMethodBridge::DeleteRange(const gfx::Range
& range
) {
279 TextInputClient
* client
= GetTextInputClient();
280 return client
? client
->DeleteRange(range
) : false;
283 bool InputMethodBridge::GetTextFromRange(const gfx::Range
& range
,
284 base::string16
* text
) const {
285 TextInputClient
* client
= GetTextInputClient();
286 return client
? client
->GetTextFromRange(range
, text
) : false;
289 void InputMethodBridge::OnInputMethodChanged() {
290 TextInputClient
* client
= GetTextInputClient();
292 client
->OnInputMethodChanged();
295 bool InputMethodBridge::ChangeTextDirectionAndLayoutAlignment(
296 base::i18n::TextDirection direction
) {
297 TextInputClient
* client
= GetTextInputClient();
299 client
->ChangeTextDirectionAndLayoutAlignment(direction
) : false;
302 void InputMethodBridge::ExtendSelectionAndDelete(size_t before
, size_t after
) {
303 TextInputClient
* client
= GetTextInputClient();
305 client
->ExtendSelectionAndDelete(before
, after
);
308 void InputMethodBridge::EnsureCaretInRect(const gfx::Rect
& rect
) {
309 TextInputClient
* client
= GetTextInputClient();
311 client
->EnsureCaretInRect(rect
);
314 void InputMethodBridge::OnCandidateWindowShown() {
317 void InputMethodBridge::OnCandidateWindowUpdated() {
320 void InputMethodBridge::OnCandidateWindowHidden() {
323 bool InputMethodBridge::IsEditCommandEnabled(int command_id
) {
324 TextInputClient
* client
= GetTextInputClient();
325 return client
? client
->IsEditCommandEnabled(command_id
) : false;
328 void InputMethodBridge::SetEditCommandForNextKeyEvent(int command_id
) {
329 TextInputClient
* client
= GetTextInputClient();
331 client
->SetEditCommandForNextKeyEvent(command_id
);
334 // Overridden from FocusChangeListener.
335 void InputMethodBridge::OnWillChangeFocus(View
* focused_before
, View
* focused
) {
336 if (HasCompositionText()) {
337 ConfirmCompositionText();
338 CancelComposition(focused_before
);
342 void InputMethodBridge::OnDidChangeFocus(View
* focused_before
, View
* focused
) {
343 DCHECK_EQ(GetFocusedView(), focused
);
344 OnTextInputTypeChanged(focused
);
345 OnCaretBoundsChanged(focused
);
348 ui::InputMethod
* InputMethodBridge::GetHostInputMethod() const {