1 // Copyright (c) 2013 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/base/ime/input_method_tsf.h"
7 #include "ui/base/ime/text_input_client.h"
8 #include "ui/base/ime/win/tsf_bridge.h"
9 #include "ui/base/ime/win/tsf_event_router.h"
13 class InputMethodTSF::TSFEventObserver : public TSFEventRouterObserver {
15 TSFEventObserver() : is_candidate_popup_open_(false) {}
17 // Returns true if we know for sure that a candidate window (or IME suggest,
19 bool IsCandidatePopupOpen() const { return is_candidate_popup_open_; }
21 // Overridden from TSFEventRouterObserver:
22 virtual void OnCandidateWindowCountChanged(size_t window_count) OVERRIDE {
23 is_candidate_popup_open_ = (window_count != 0);
27 // True if we know for sure that a candidate window is open.
28 bool is_candidate_popup_open_;
30 DISALLOW_COPY_AND_ASSIGN(TSFEventObserver);
33 InputMethodTSF::InputMethodTSF(internal::InputMethodDelegate* delegate,
34 HWND toplevel_window_handle)
35 : InputMethodWin(delegate, toplevel_window_handle),
36 tsf_event_observer_(new TSFEventObserver()),
37 tsf_event_router_(new TSFEventRouter(tsf_event_observer_.get())) {
38 // In non-Aura environment, appropriate callbacks to OnFocus() and OnBlur()
39 // are not implemented yet. To work around this limitation, here we use
40 // "always focused" model.
41 // TODO(ime): Fix the caller of OnFocus() and OnBlur() so that appropriate
42 // focus event will be passed.
43 InputMethodWin::OnFocus();
46 InputMethodTSF::~InputMethodTSF() {}
48 void InputMethodTSF::OnFocus() {
49 // Do not call baseclass' OnFocus() and discard the event being in
50 // "always focused" model. See the comment in the constructor.
51 // TODO(ime): Implement OnFocus once the callers are fixed.
53 tsf_event_router_->SetManager(
54 ui::TSFBridge::GetInstance()->GetThreadManager());
57 void InputMethodTSF::OnBlur() {
58 // Do not call baseclass' OnBlur() and discard the event being in
59 // "always focused" model. See the comment in the constructor.
60 // TODO(ime): Implement OnFocus once the callers are fixed.
62 tsf_event_router_->SetManager(NULL);
65 bool InputMethodTSF::OnUntranslatedIMEMessage(
66 const base::NativeEvent& event, InputMethod::NativeEventResult* result) {
67 LRESULT original_result = 0;
69 // Even when TSF is enabled, following IMM32/Win32 messages must be handled.
70 switch (event.message) {
72 // Some TSF-native TIPs (Text Input Processors) such as ATOK and Mozc
73 // still rely on WM_IME_REQUEST message to implement reverse conversion.
74 original_result = OnImeRequest(
75 event.message, event.wParam, event.lParam, &handled);
79 // ui::InputMethod interface is responsible for handling Win32 character
80 // messages. For instance, we will be here in the following cases.
81 // - TIP is not activated. (e.g, the current language profile is English)
82 // - TIP does not handle and WM_KEYDOWN and WM_KEYDOWN is translated into
83 // WM_CHAR by TranslateMessage API. (e.g, TIP is turned off)
84 // - Another application sends WM_CHAR through SendMessage API.
85 original_result = OnChar(
86 event.hwnd, event.message, event.wParam, event.lParam, &handled);
90 // See the comment in WM_CHAR/WM_SYSCHAR.
91 original_result = OnDeadChar(
92 event.message, event.wParam, event.lParam, &handled);
96 *result = original_result;
100 void InputMethodTSF::OnTextInputTypeChanged(const TextInputClient* client) {
101 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
103 ui::TSFBridge::GetInstance()->CancelComposition();
104 ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(client);
107 void InputMethodTSF::OnCaretBoundsChanged(const TextInputClient* client) {
108 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
110 ui::TSFBridge::GetInstance()->OnTextLayoutChanged();
113 void InputMethodTSF::CancelComposition(const TextInputClient* client) {
114 if (IsTextInputClientFocused(client) && IsWindowFocused(client))
115 ui::TSFBridge::GetInstance()->CancelComposition();
118 void InputMethodTSF::DetachTextInputClient(TextInputClient* client) {
119 InputMethodWin::DetachTextInputClient(client);
120 ui::TSFBridge::GetInstance()->RemoveFocusedClient(client);
123 bool InputMethodTSF::IsCandidatePopupOpen() const {
124 return tsf_event_observer_->IsCandidatePopupOpen();
127 void InputMethodTSF::OnWillChangeFocusedClient(TextInputClient* focused_before,
128 TextInputClient* focused) {
129 if (IsWindowFocused(focused_before)) {
130 ConfirmCompositionText();
131 ui::TSFBridge::GetInstance()->RemoveFocusedClient(focused_before);
135 void InputMethodTSF::OnDidChangeFocusedClient(TextInputClient* focused_before,
136 TextInputClient* focused) {
137 if (IsWindowFocused(focused) && IsTextInputClientFocused(focused)) {
138 ui::TSFBridge::GetInstance()->SetFocusedClient(
139 GetAttachedWindowHandle(focused), focused);
141 // Force to update the input type since client's TextInputStateChanged()
142 // function might not be called if text input types before the client loses
143 // focus and after it acquires focus again are the same.
144 OnTextInputTypeChanged(focused);
146 // Force to update caret bounds, in case the client thinks that the caret
147 // bounds has not changed.
148 OnCaretBoundsChanged(focused);
150 InputMethodWin::OnDidChangeFocusedClient(focused_before, focused);
153 void InputMethodTSF::ConfirmCompositionText() {
154 if (!IsTextInputTypeNone())
155 ui::TSFBridge::GetInstance()->ConfirmComposition();