| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "ui/base/ime/input_method_tsf.h" | |
| 6 | |
| 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" | |
| 10 | |
| 11 namespace ui { | |
| 12 | |
| 13 class InputMethodTSF::TSFEventObserver : public TSFEventRouterObserver { | |
| 14 public: | |
| 15 TSFEventObserver() : is_candidate_popup_open_(false) {} | |
| 16 | |
| 17 // Returns true if we know for sure that a candidate window (or IME suggest, | |
| 18 // etc.) is open. | |
| 19 bool IsCandidatePopupOpen() const { return is_candidate_popup_open_; } | |
| 20 | |
| 21 // Overridden from TSFEventRouterObserver: | |
| 22 virtual void OnCandidateWindowCountChanged(size_t window_count) OVERRIDE { | |
| 23 is_candidate_popup_open_ = (window_count != 0); | |
| 24 } | |
| 25 | |
| 26 private: | |
| 27 // True if we know for sure that a candidate window is open. | |
| 28 bool is_candidate_popup_open_; | |
| 29 | |
| 30 DISALLOW_COPY_AND_ASSIGN(TSFEventObserver); | |
| 31 }; | |
| 32 | |
| 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(); | |
| 44 } | |
| 45 | |
| 46 InputMethodTSF::~InputMethodTSF() {} | |
| 47 | |
| 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. | |
| 52 | |
| 53 tsf_event_router_->SetManager( | |
| 54 ui::TSFBridge::GetInstance()->GetThreadManager()); | |
| 55 } | |
| 56 | |
| 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. | |
| 61 | |
| 62 tsf_event_router_->SetManager(NULL); | |
| 63 } | |
| 64 | |
| 65 bool InputMethodTSF::OnUntranslatedIMEMessage( | |
| 66 const base::NativeEvent& event, InputMethod::NativeEventResult* result) { | |
| 67 LRESULT original_result = 0; | |
| 68 BOOL handled = FALSE; | |
| 69 // Even when TSF is enabled, following IMM32/Win32 messages must be handled. | |
| 70 switch (event.message) { | |
| 71 case WM_IME_REQUEST: | |
| 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); | |
| 76 break; | |
| 77 case WM_CHAR: | |
| 78 case WM_SYSCHAR: | |
| 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); | |
| 87 break; | |
| 88 case WM_DEADCHAR: | |
| 89 case WM_SYSDEADCHAR: | |
| 90 // See the comment in WM_CHAR/WM_SYSCHAR. | |
| 91 original_result = OnDeadChar( | |
| 92 event.message, event.wParam, event.lParam, &handled); | |
| 93 break; | |
| 94 } | |
| 95 if (result) | |
| 96 *result = original_result; | |
| 97 return !!handled; | |
| 98 } | |
| 99 | |
| 100 void InputMethodTSF::OnTextInputTypeChanged(const TextInputClient* client) { | |
| 101 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) | |
| 102 return; | |
| 103 ui::TSFBridge::GetInstance()->CancelComposition(); | |
| 104 ui::TSFBridge::GetInstance()->OnTextInputTypeChanged(client); | |
| 105 } | |
| 106 | |
| 107 void InputMethodTSF::OnCaretBoundsChanged(const TextInputClient* client) { | |
| 108 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) | |
| 109 return; | |
| 110 ui::TSFBridge::GetInstance()->OnTextLayoutChanged(); | |
| 111 } | |
| 112 | |
| 113 void InputMethodTSF::CancelComposition(const TextInputClient* client) { | |
| 114 if (IsTextInputClientFocused(client) && IsWindowFocused(client)) | |
| 115 ui::TSFBridge::GetInstance()->CancelComposition(); | |
| 116 } | |
| 117 | |
| 118 void InputMethodTSF::DetachTextInputClient(TextInputClient* client) { | |
| 119 InputMethodWin::DetachTextInputClient(client); | |
| 120 ui::TSFBridge::GetInstance()->RemoveFocusedClient(client); | |
| 121 } | |
| 122 | |
| 123 bool InputMethodTSF::IsCandidatePopupOpen() const { | |
| 124 return tsf_event_observer_->IsCandidatePopupOpen(); | |
| 125 } | |
| 126 | |
| 127 void InputMethodTSF::OnWillChangeFocusedClient(TextInputClient* focused_before, | |
| 128 TextInputClient* focused) { | |
| 129 if (IsWindowFocused(focused_before)) { | |
| 130 ConfirmCompositionText(); | |
| 131 ui::TSFBridge::GetInstance()->RemoveFocusedClient(focused_before); | |
| 132 } | |
| 133 } | |
| 134 | |
| 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); | |
| 140 | |
| 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); | |
| 145 | |
| 146 // Force to update caret bounds, in case the client thinks that the caret | |
| 147 // bounds has not changed. | |
| 148 OnCaretBoundsChanged(focused); | |
| 149 } | |
| 150 InputMethodWin::OnDidChangeFocusedClient(focused_before, focused); | |
| 151 } | |
| 152 | |
| 153 void InputMethodTSF::ConfirmCompositionText() { | |
| 154 if (!IsTextInputTypeNone()) | |
| 155 ui::TSFBridge::GetInstance()->ConfirmComposition(); | |
| 156 } | |
| 157 | |
| 158 } // namespace ui | |
| OLD | NEW |