OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 "views/ime/input_method_win.h" |
| 6 |
| 7 #include "base/basictypes.h" |
| 8 #include "base/logging.h" |
| 9 #include "base/string_util.h" |
| 10 #include "ui/base/keycodes/keyboard_codes.h" |
| 11 #include "views/events/event.h" |
| 12 |
| 13 namespace views { |
| 14 |
| 15 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate) |
| 16 : active_(false), |
| 17 direction_(base::i18n::UNKNOWN_DIRECTION), |
| 18 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION) { |
| 19 set_delegate(delegate); |
| 20 } |
| 21 |
| 22 InputMethodWin::~InputMethodWin() { |
| 23 if (widget()) |
| 24 ime_input_.DisableIME(hwnd()); |
| 25 } |
| 26 |
| 27 void InputMethodWin::Init(Widget* widget) { |
| 28 InputMethodBase::Init(widget); |
| 29 |
| 30 // Gets the initial input locale and text direction information. |
| 31 OnInputLangChange(0, 0); |
| 32 } |
| 33 |
| 34 void InputMethodWin::DispatchKeyEvent(const KeyEvent& key) { |
| 35 // Handles ctrl-shift key to change text direction and layout alignment. |
| 36 if (ui::ImeInput::IsRTLKeyboardLayoutInstalled() && |
| 37 IsClientSupportTextInput()) { |
| 38 ui::KeyboardCode code = key.key_code(); |
| 39 if (key.type() == ui::ET_KEY_PRESSED) { |
| 40 if (code == ui::VKEY_SHIFT) { |
| 41 base::i18n::TextDirection dir; |
| 42 if (ui::ImeInput::IsCtrlShiftPressed(&dir)) |
| 43 pending_requested_direction_ = dir; |
| 44 } else if (code != ui::VKEY_CONTROL) { |
| 45 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; |
| 46 } |
| 47 } else if (key.type() == ui::ET_KEY_RELEASED && |
| 48 (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) && |
| 49 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) { |
| 50 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment( |
| 51 pending_requested_direction_); |
| 52 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; |
| 53 } |
| 54 } |
| 55 |
| 56 DispatchKeyEventPostIME(key); |
| 57 } |
| 58 |
| 59 void InputMethodWin::OnTextInputTypeChanged(View* view) { |
| 60 if (IsViewFocused(view)) { |
| 61 ime_input_.CancelIME(hwnd()); |
| 62 UpdateIMEState(); |
| 63 } |
| 64 } |
| 65 |
| 66 void InputMethodWin::OnCaretBoundsChanged(View* view) { |
| 67 gfx::Rect rect; |
| 68 if (!IsViewFocused(view) || !GetCaretBoundsInWidget(&rect)) |
| 69 return; |
| 70 ime_input_.UpdateCaretRect(hwnd(), rect); |
| 71 } |
| 72 |
| 73 void InputMethodWin::CancelComposition(View* view) { |
| 74 if (IsViewFocused(view)) |
| 75 ime_input_.CancelIME(hwnd()); |
| 76 } |
| 77 |
| 78 std::string InputMethodWin::GetInputLocale() { |
| 79 return locale_; |
| 80 } |
| 81 |
| 82 base::i18n::TextDirection InputMethodWin::GetInputTextDirection() { |
| 83 return direction_; |
| 84 } |
| 85 |
| 86 bool InputMethodWin::IsActive() { |
| 87 return active_; |
| 88 } |
| 89 |
| 90 void InputMethodWin::FocusedViewWillChange() { |
| 91 ConfirmCompositionText(); |
| 92 } |
| 93 |
| 94 void InputMethodWin::FocusedViewDidChange() { |
| 95 UpdateIMEState(); |
| 96 } |
| 97 |
| 98 void InputMethodWin::OnSetFocus() { |
| 99 if (!widget_focused()) { |
| 100 set_widget_focused(true); |
| 101 UpdateIMEState(); |
| 102 } |
| 103 } |
| 104 |
| 105 void InputMethodWin::OnKillFocus() { |
| 106 if (widget_focused()) { |
| 107 ConfirmCompositionText(); |
| 108 set_widget_focused(false); |
| 109 } |
| 110 } |
| 111 |
| 112 void InputMethodWin::OnInputLangChange(DWORD character_set, |
| 113 HKL input_language_id) { |
| 114 active_ = ime_input_.SetInputLanguage(); |
| 115 locale_ = ime_input_.GetInputLanguageName(); |
| 116 direction_ = ime_input_.GetTextDirection(); |
| 117 OnInputMethodChanged(); |
| 118 } |
| 119 |
| 120 LRESULT InputMethodWin::OnImeSetContext( |
| 121 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
| 122 active_ = (wparam == TRUE); |
| 123 if (active_) |
| 124 ime_input_.CreateImeWindow(hwnd()); |
| 125 |
| 126 OnInputMethodChanged(); |
| 127 return ime_input_.SetImeWindowStyle(hwnd(), message, wparam, lparam, handled); |
| 128 } |
| 129 |
| 130 LRESULT InputMethodWin::OnImeStartComposition( |
| 131 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
| 132 // We have to prevent WTL from calling ::DefWindowProc() because the function |
| 133 // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to |
| 134 // over-write the position of IME windows. |
| 135 *handled = TRUE; |
| 136 |
| 137 if (!IsClientSupportTextInput()) |
| 138 return 0; |
| 139 |
| 140 // Reset the composition status and create IME windows. |
| 141 ime_input_.CreateImeWindow(hwnd()); |
| 142 ime_input_.ResetComposition(hwnd()); |
| 143 return 0; |
| 144 } |
| 145 |
| 146 LRESULT InputMethodWin::OnImeComposition( |
| 147 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
| 148 // We have to prevent WTL from calling ::DefWindowProc() because we do not |
| 149 // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages. |
| 150 *handled = TRUE; |
| 151 |
| 152 if (!IsClientSupportTextInput()) |
| 153 return 0; |
| 154 |
| 155 // At first, update the position of the IME window. |
| 156 ime_input_.UpdateImeWindow(hwnd()); |
| 157 |
| 158 // Retrieve the result string and its attributes of the ongoing composition |
| 159 // and send it to a renderer process. |
| 160 ui::CompositionText composition; |
| 161 if (ime_input_.GetResult(hwnd(), lparam, &composition.text)) { |
| 162 GetTextInputClient()->InsertText(composition.text); |
| 163 ime_input_.ResetComposition(hwnd()); |
| 164 // Fall though and try reading the composition string. |
| 165 // Japanese IMEs send a message containing both GCS_RESULTSTR and |
| 166 // GCS_COMPSTR, which means an ongoing composition has been finished |
| 167 // by the start of another composition. |
| 168 } |
| 169 // Retrieve the composition string and its attributes of the ongoing |
| 170 // composition and send it to a renderer process. |
| 171 if (ime_input_.GetComposition(hwnd(), lparam, &composition)) |
| 172 GetTextInputClient()->SetCompositionText(composition); |
| 173 |
| 174 return 0; |
| 175 } |
| 176 |
| 177 LRESULT InputMethodWin::OnImeEndComposition( |
| 178 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
| 179 // Let WTL call ::DefWindowProc() and release its resources. |
| 180 *handled = FALSE; |
| 181 |
| 182 if (!IsClientSupportTextInput()) |
| 183 return 0; |
| 184 |
| 185 if (GetTextInputClient()->HasCompositionText()) |
| 186 GetTextInputClient()->ClearCompositionText(); |
| 187 |
| 188 ime_input_.ResetComposition(hwnd()); |
| 189 ime_input_.DestroyImeWindow(hwnd()); |
| 190 return 0; |
| 191 } |
| 192 |
| 193 LRESULT InputMethodWin::OnChar( |
| 194 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
| 195 *handled = TRUE; |
| 196 |
| 197 if (!IsClientSupportTextInput()) |
| 198 return 0; |
| 199 |
| 200 int flags = 0; |
| 201 flags |= (::GetKeyState(VK_MENU) & 0x80)? ui::EF_ALT_DOWN : 0; |
| 202 flags |= (::GetKeyState(VK_SHIFT) & 0x80)? ui::EF_SHIFT_DOWN : 0; |
| 203 flags |= (::GetKeyState(VK_CONTROL) & 0x80)? ui::EF_CONTROL_DOWN : 0; |
| 204 GetTextInputClient()->InsertChar(static_cast<char16>(wparam), flags); |
| 205 return 0; |
| 206 } |
| 207 |
| 208 LRESULT InputMethodWin::OnDeadChar( |
| 209 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
| 210 *handled = TRUE; |
| 211 |
| 212 if (!IsClientSupportTextInput()) |
| 213 return 0; |
| 214 |
| 215 // Shows the dead character as a composition text, so that the user can know |
| 216 // what dead key was pressed. |
| 217 ui::CompositionText composition; |
| 218 composition.text.assign(1, static_cast<char16>(wparam)); |
| 219 composition.selection = ui::Range(0, 1); |
| 220 composition.underlines.push_back( |
| 221 ui::CompositionUnderline(0, 1, SK_ColorBLACK, false)); |
| 222 GetTextInputClient()->SetCompositionText(composition); |
| 223 return 0; |
| 224 } |
| 225 |
| 226 void InputMethodWin::ConfirmCompositionText() { |
| 227 if (IsClientSupportTextInput()) { |
| 228 ime_input_.CleanupComposition(hwnd()); |
| 229 // Though above line should confirm the client's composition text by sending |
| 230 // a result text to us, in case the input method and the client are in |
| 231 // inconsistent states, we check the client's composition state again. |
| 232 if (GetTextInputClient()->HasCompositionText()) |
| 233 GetTextInputClient()->ConfirmCompositionText(); |
| 234 } |
| 235 } |
| 236 |
| 237 void InputMethodWin::UpdateIMEState() { |
| 238 // We disable input method for password field. |
| 239 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_TEXT) |
| 240 ime_input_.EnableIME(hwnd()); |
| 241 else |
| 242 ime_input_.DisableIME(hwnd()); |
| 243 } |
| 244 |
| 245 } // namespace views |
OLD | NEW |