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/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 virtual ~HostObserver();
26 virtual void OnTextInputTypeChanged(
27 const ui::TextInputClient
* client
) override
{}
28 virtual void OnFocus() override
{}
29 virtual void OnBlur() override
{}
30 virtual void OnCaretBoundsChanged(
31 const ui::TextInputClient
* client
) override
{}
32 virtual void OnTextInputStateChanged(
33 const ui::TextInputClient
* client
) override
{}
34 virtual void OnInputMethodDestroyed(
35 const ui::InputMethod
* input_method
) override
;
36 virtual void OnShowImeIfNeeded() override
{}
39 InputMethodBridge
* bridge_
;
41 DISALLOW_COPY_AND_ASSIGN(HostObserver
);
44 InputMethodBridge::HostObserver::HostObserver(InputMethodBridge
* bridge
)
46 bridge_
->host_
->AddObserver(this);
49 InputMethodBridge::HostObserver::~HostObserver() {
51 bridge_
->host_
->RemoveObserver(this);
54 void InputMethodBridge::HostObserver::OnInputMethodDestroyed(
55 const ui::InputMethod
* input_method
) {
56 DCHECK_EQ(bridge_
->host_
, input_method
);
57 bridge_
->host_
->RemoveObserver(this);
58 bridge_
->host_
= NULL
;
61 // InputMethodBridge class -----------------------------------------------------
63 InputMethodBridge::InputMethodBridge(internal::InputMethodDelegate
* delegate
,
64 ui::InputMethod
* host
,
65 bool shared_input_method
)
67 shared_input_method_(shared_input_method
) {
69 SetDelegate(delegate
);
71 host_observer_
.reset(new HostObserver(this));
74 InputMethodBridge::~InputMethodBridge() {
75 // By the time we get here it's very likely |widget_|'s NativeWidget has been
76 // destroyed. This means any calls to |widget_| that go to the NativeWidget,
77 // such as IsActive(), will crash. SetFocusedTextInputClient() may callback to
78 // this and go into |widget_|. NULL out |widget_| so we don't attempt to use
82 // Host input method might have been destroyed at this point.
84 host_
->DetachTextInputClient(this);
87 void InputMethodBridge::OnFocus() {
90 // Direct the shared IME to send TextInputClient messages to |this| object.
91 if (shared_input_method_
|| !host_
->GetTextInputClient())
92 host_
->SetFocusedTextInputClient(this);
94 // TODO(yusukes): We don't need to call OnTextInputTypeChanged() once we move
95 // text input type tracker code to ui::InputMethodBase.
96 if (GetFocusedView()) {
97 OnTextInputTypeChanged(GetFocusedView());
98 OnCaretBoundsChanged(GetFocusedView());
102 void InputMethodBridge::OnBlur() {
105 if (HasCompositionText()) {
106 ConfirmCompositionText();
107 host_
->CancelComposition(this);
110 if (host_
->GetTextInputClient() == this)
111 host_
->SetFocusedTextInputClient(NULL
);
114 bool InputMethodBridge::OnUntranslatedIMEMessage(const base::NativeEvent
& event
,
115 NativeEventResult
* result
) {
118 return host_
->OnUntranslatedIMEMessage(event
, result
);
121 void InputMethodBridge::DispatchKeyEvent(const ui::KeyEvent
& key
) {
122 DCHECK(key
.type() == ui::ET_KEY_PRESSED
|| key
.type() == ui::ET_KEY_RELEASED
);
124 // We can just dispatch the event here since the |key| is already processed by
125 // the system-wide IME.
126 DispatchKeyEventPostIME(key
);
129 void InputMethodBridge::OnTextInputTypeChanged(View
* view
) {
132 if (IsViewFocused(view
))
133 host_
->OnTextInputTypeChanged(this);
134 InputMethodBase::OnTextInputTypeChanged(view
);
137 void InputMethodBridge::OnCaretBoundsChanged(View
* view
) {
140 if (IsViewFocused(view
) && !IsTextInputTypeNone())
141 host_
->OnCaretBoundsChanged(this);
144 void InputMethodBridge::CancelComposition(View
* view
) {
147 if (IsViewFocused(view
))
148 host_
->CancelComposition(this);
151 void InputMethodBridge::OnInputLocaleChanged() {
154 host_
->OnInputLocaleChanged();
157 std::string
InputMethodBridge::GetInputLocale() {
160 return host_
->GetInputLocale();
163 bool InputMethodBridge::IsActive() {
166 return host_
->IsActive();
169 bool InputMethodBridge::IsCandidatePopupOpen() const {
172 return host_
->IsCandidatePopupOpen();
175 void InputMethodBridge::ShowImeIfNeeded() {
177 host_
->ShowImeIfNeeded();
180 // Overridden from TextInputClient. Forward an event from the system-wide IME
181 // to the text input |client|, which is e.g. views::Textfield.
182 void InputMethodBridge::SetCompositionText(
183 const ui::CompositionText
& composition
) {
184 TextInputClient
* client
= GetTextInputClient();
186 client
->SetCompositionText(composition
);
189 void InputMethodBridge::ConfirmCompositionText() {
190 TextInputClient
* client
= GetTextInputClient();
192 client
->ConfirmCompositionText();
195 void InputMethodBridge::ClearCompositionText() {
196 TextInputClient
* client
= GetTextInputClient();
198 client
->ClearCompositionText();
201 void InputMethodBridge::InsertText(const base::string16
& text
) {
202 TextInputClient
* client
= GetTextInputClient();
204 client
->InsertText(text
);
207 void InputMethodBridge::InsertChar(base::char16 ch
, int flags
) {
208 TextInputClient
* client
= GetTextInputClient();
210 client
->InsertChar(ch
, flags
);
213 gfx::NativeWindow
InputMethodBridge::GetAttachedWindow() const {
214 TextInputClient
* client
= GetTextInputClient();
216 client
->GetAttachedWindow() : static_cast<gfx::NativeWindow
>(NULL
);
219 ui::TextInputType
InputMethodBridge::GetTextInputType() const {
220 TextInputClient
* client
= GetTextInputClient();
221 return client
? client
->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE
;
224 ui::TextInputMode
InputMethodBridge::GetTextInputMode() const {
225 TextInputClient
* client
= GetTextInputClient();
226 return client
? client
->GetTextInputMode() : ui::TEXT_INPUT_MODE_DEFAULT
;
229 int InputMethodBridge::GetTextInputFlags() const {
230 TextInputClient
* client
= GetTextInputClient();
231 return client
? client
->GetTextInputFlags() : 0;
234 bool InputMethodBridge::CanComposeInline() const {
235 TextInputClient
* client
= GetTextInputClient();
236 return client
? client
->CanComposeInline() : true;
239 gfx::Rect
InputMethodBridge::GetCaretBounds() const {
240 TextInputClient
* client
= GetTextInputClient();
244 return client
->GetCaretBounds();
247 bool InputMethodBridge::GetCompositionCharacterBounds(uint32 index
,
248 gfx::Rect
* rect
) const {
250 TextInputClient
* client
= GetTextInputClient();
254 return client
->GetCompositionCharacterBounds(index
, rect
);
257 bool InputMethodBridge::HasCompositionText() const {
258 TextInputClient
* client
= GetTextInputClient();
259 return client
? client
->HasCompositionText() : false;
262 bool InputMethodBridge::GetTextRange(gfx::Range
* range
) const {
263 TextInputClient
* client
= GetTextInputClient();
264 return client
? client
->GetTextRange(range
) : false;
267 bool InputMethodBridge::GetCompositionTextRange(gfx::Range
* range
) const {
268 TextInputClient
* client
= GetTextInputClient();
269 return client
? client
->GetCompositionTextRange(range
) : false;
272 bool InputMethodBridge::GetSelectionRange(gfx::Range
* range
) const {
273 TextInputClient
* client
= GetTextInputClient();
274 return client
? client
->GetSelectionRange(range
) : false;
277 bool InputMethodBridge::SetSelectionRange(const gfx::Range
& range
) {
278 TextInputClient
* client
= GetTextInputClient();
279 return client
? client
->SetSelectionRange(range
) : false;
282 bool InputMethodBridge::DeleteRange(const gfx::Range
& range
) {
283 TextInputClient
* client
= GetTextInputClient();
284 return client
? client
->DeleteRange(range
) : false;
287 bool InputMethodBridge::GetTextFromRange(const gfx::Range
& range
,
288 base::string16
* text
) const {
289 TextInputClient
* client
= GetTextInputClient();
290 return client
? client
->GetTextFromRange(range
, text
) : false;
293 void InputMethodBridge::OnInputMethodChanged() {
294 TextInputClient
* client
= GetTextInputClient();
296 client
->OnInputMethodChanged();
299 bool InputMethodBridge::ChangeTextDirectionAndLayoutAlignment(
300 base::i18n::TextDirection direction
) {
301 TextInputClient
* client
= GetTextInputClient();
303 client
->ChangeTextDirectionAndLayoutAlignment(direction
) : false;
306 void InputMethodBridge::ExtendSelectionAndDelete(size_t before
, size_t after
) {
307 TextInputClient
* client
= GetTextInputClient();
309 client
->ExtendSelectionAndDelete(before
, after
);
312 void InputMethodBridge::EnsureCaretInRect(const gfx::Rect
& rect
) {
313 TextInputClient
* client
= GetTextInputClient();
315 client
->EnsureCaretInRect(rect
);
318 void InputMethodBridge::OnCandidateWindowShown() {
321 void InputMethodBridge::OnCandidateWindowUpdated() {
324 void InputMethodBridge::OnCandidateWindowHidden() {
327 bool InputMethodBridge::IsEditingCommandEnabled(int command_id
) {
331 void InputMethodBridge::ExecuteEditingCommand(int 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 {