| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/ime/input_method_win.h" | 5 #include "ui/views/ime/input_method_win.h" |
| 6 | 6 |
| 7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/win/metro.h" | |
| 11 #include "ui/base/events/event.h" | 10 #include "ui/base/events/event.h" |
| 12 #include "ui/base/events/event_constants.h" | 11 #include "ui/base/events/event_constants.h" |
| 13 #include "ui/base/events/event_utils.h" | 12 #include "ui/base/events/event_utils.h" |
| 14 #include "ui/base/ime/composition_text.h" | 13 #include "ui/base/ime/composition_text.h" |
| 15 #include "ui/base/ime/input_method.h" | 14 #include "ui/base/ime/input_method.h" |
| 16 #include "ui/base/ime/text_input_client.h" | 15 #include "ui/base/ime/text_input_client.h" |
| 17 #include "ui/base/ime/win/tsf_bridge.h" | |
| 18 #include "ui/base/keycodes/keyboard_codes.h" | 16 #include "ui/base/keycodes/keyboard_codes.h" |
| 19 #include "ui/base/win/hwnd_util.h" | 17 #include "ui/base/win/hwnd_util.h" |
| 20 #include "ui/views/win/hwnd_util.h" | |
| 21 | 18 |
| 22 // Extra number of chars before and after selection (or composition) range which | 19 // Extra number of chars before and after selection (or composition) range which |
| 23 // is returned to IME for improving conversion accuracy. | 20 // is returned to IME for improving conversion accuracy. |
| 24 static const size_t kExtraNumberOfChars = 20; | 21 static const size_t kExtraNumberOfChars = 20; |
| 25 | 22 |
| 26 namespace views { | 23 namespace views { |
| 27 | 24 |
| 28 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, | 25 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, |
| 29 HWND hwnd, | 26 HWND hwnd, |
| 30 ui::InputMethod* host) | 27 ui::InputMethod* host) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 42 } | 39 } |
| 43 | 40 |
| 44 void InputMethodWin::Init(Widget* widget) { | 41 void InputMethodWin::Init(Widget* widget) { |
| 45 InputMethodBase::Init(widget); | 42 InputMethodBase::Init(widget); |
| 46 | 43 |
| 47 // Gets the initial input locale and text direction information. | 44 // Gets the initial input locale and text direction information. |
| 48 OnInputLangChange(0, 0); | 45 OnInputLangChange(0, 0); |
| 49 } | 46 } |
| 50 | 47 |
| 51 void InputMethodWin::OnFocus() { | 48 void InputMethodWin::OnFocus() { |
| 52 if (base::win::IsTSFAwareRequired()) { | 49 UpdateIMEState(); |
| 53 if (GetTextInputClient()) { | |
| 54 ui::TSFBridge* tsf_bridge = ui::TSFBridge::GetInstance(); | |
| 55 tsf_bridge->SetFocusedClient(hwnd_, GetTextInputClient()); | |
| 56 } | |
| 57 } else { | |
| 58 // Use switch here in case we are going to add more text input types. | |
| 59 // We disable input method in password field. | |
| 60 switch (GetTextInputType()) { | |
| 61 case ui::TEXT_INPUT_TYPE_NONE: | |
| 62 case ui::TEXT_INPUT_TYPE_PASSWORD: | |
| 63 ime_input_.DisableIME(hwnd_); | |
| 64 break; | |
| 65 default: | |
| 66 ime_input_.EnableIME(hwnd_); | |
| 67 break; | |
| 68 } | |
| 69 OnTextInputTypeChanged(GetFocusedView()); | |
| 70 OnCaretBoundsChanged(GetFocusedView()); | |
| 71 } | |
| 72 } | 50 } |
| 73 | 51 |
| 74 void InputMethodWin::OnBlur() { | 52 void InputMethodWin::OnBlur() { |
| 75 ConfirmCompositionText(); | 53 ConfirmCompositionText(); |
| 76 if (base::win::IsTSFAwareRequired() && GetTextInputClient()) | |
| 77 ui::TSFBridge::GetInstance()->RemoveFocusedClient(GetTextInputClient()); | |
| 78 } | 54 } |
| 79 | 55 |
| 80 void InputMethodWin::DispatchKeyEvent(const ui::KeyEvent& key) { | 56 void InputMethodWin::DispatchKeyEvent(const ui::KeyEvent& key) { |
| 81 // Handles ctrl-shift key to change text direction and layout alignment. | 57 // Handles ctrl-shift key to change text direction and layout alignment. |
| 82 if (ui::ImeInput::IsRTLKeyboardLayoutInstalled() && !IsTextInputTypeNone()) { | 58 if (ui::ImeInput::IsRTLKeyboardLayoutInstalled() && !IsTextInputTypeNone()) { |
| 83 ui::KeyboardCode code = key.key_code(); | 59 ui::KeyboardCode code = key.key_code(); |
| 84 if (key.type() == ui::ET_KEY_PRESSED) { | 60 if (key.type() == ui::ET_KEY_PRESSED) { |
| 85 if (code == ui::VKEY_SHIFT) { | 61 if (code == ui::VKEY_SHIFT) { |
| 86 base::i18n::TextDirection dir; | 62 base::i18n::TextDirection dir; |
| 87 if (ui::ImeInput::IsCtrlShiftPressed(&dir)) | 63 if (ui::ImeInput::IsCtrlShiftPressed(&dir)) |
| 88 pending_requested_direction_ = dir; | 64 pending_requested_direction_ = dir; |
| 89 } else if (code != ui::VKEY_CONTROL) { | 65 } else if (code != ui::VKEY_CONTROL) { |
| 90 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; | 66 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; |
| 91 } | 67 } |
| 92 } else if (key.type() == ui::ET_KEY_RELEASED && | 68 } else if (key.type() == ui::ET_KEY_RELEASED && |
| 93 (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) && | 69 (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) && |
| 94 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) { | 70 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) { |
| 95 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment( | 71 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment( |
| 96 pending_requested_direction_); | 72 pending_requested_direction_); |
| 97 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; | 73 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; |
| 98 } | 74 } |
| 99 } | 75 } |
| 100 | 76 |
| 101 DispatchKeyEventPostIME(key); | 77 DispatchKeyEventPostIME(key); |
| 102 } | 78 } |
| 103 | 79 |
| 104 void InputMethodWin::OnTextInputTypeChanged(View* view) { | 80 void InputMethodWin::OnTextInputTypeChanged(View* view) { |
| 105 if (IsViewFocused(view)) { | 81 if (IsViewFocused(view)) { |
| 106 if (base::win::IsTSFAwareRequired()) { | 82 ime_input_.CancelIME(hwnd_); |
| 107 if (GetTextInputClient()) { | 83 UpdateIMEState(); |
| 108 ui::TSFBridge::GetInstance()->OnTextInputTypeChanged( | |
| 109 GetTextInputClient()); | |
| 110 } | |
| 111 } else { | |
| 112 ime_input_.CancelIME(hwnd_); | |
| 113 // Use switch here in case we are going to add more text input types. | |
| 114 // We disable input method in password field. | |
| 115 switch (GetTextInputType()) { | |
| 116 case ui::TEXT_INPUT_TYPE_NONE: | |
| 117 case ui::TEXT_INPUT_TYPE_PASSWORD: | |
| 118 ime_input_.DisableIME(hwnd_); | |
| 119 break; | |
| 120 default: | |
| 121 ime_input_.EnableIME(hwnd_); | |
| 122 break; | |
| 123 } | |
| 124 OnCaretBoundsChanged(GetFocusedView()); | |
| 125 } | |
| 126 } | 84 } |
| 127 InputMethodBase::OnTextInputTypeChanged(view); | 85 InputMethodBase::OnTextInputTypeChanged(view); |
| 128 } | 86 } |
| 129 | 87 |
| 130 void InputMethodWin::OnCaretBoundsChanged(View* view) { | 88 void InputMethodWin::OnCaretBoundsChanged(View* view) { |
| 131 if (base::win::IsTSFAwareRequired()) { | 89 gfx::Rect rect; |
| 132 ui::TSFBridge::GetInstance()->OnTextLayoutChanged(); | 90 if (!IsViewFocused(view) || !GetCaretBoundsInWidget(&rect)) |
| 133 } else { | 91 return; |
| 134 gfx::Rect rect; | 92 ime_input_.UpdateCaretRect(hwnd_, rect); |
| 135 if (!IsViewFocused(view) || !GetCaretBoundsInWidget(&rect)) | |
| 136 return; | |
| 137 ime_input_.UpdateCaretRect(hwnd_, rect); | |
| 138 } | |
| 139 } | 93 } |
| 140 | 94 |
| 141 void InputMethodWin::CancelComposition(View* view) { | 95 void InputMethodWin::CancelComposition(View* view) { |
| 142 if (IsViewFocused(view)) { | 96 if (IsViewFocused(view)) |
| 143 if (base::win::IsTSFAwareRequired()) { | 97 ime_input_.CancelIME(hwnd_); |
| 144 ui::TSFBridge::GetInstance()->CancelComposition(); | |
| 145 } else { | |
| 146 ime_input_.CancelIME(hwnd_); | |
| 147 } | |
| 148 } | |
| 149 } | 98 } |
| 150 | 99 |
| 151 std::string InputMethodWin::GetInputLocale() { | 100 std::string InputMethodWin::GetInputLocale() { |
| 152 return locale_; | 101 return locale_; |
| 153 } | 102 } |
| 154 | 103 |
| 155 base::i18n::TextDirection InputMethodWin::GetInputTextDirection() { | 104 base::i18n::TextDirection InputMethodWin::GetInputTextDirection() { |
| 156 return direction_; | 105 return direction_; |
| 157 } | 106 } |
| 158 | 107 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 break; | 149 break; |
| 201 } | 150 } |
| 202 return result; | 151 return result; |
| 203 } | 152 } |
| 204 | 153 |
| 205 void InputMethodWin::OnWillChangeFocus(View* focused_before, View* focused) { | 154 void InputMethodWin::OnWillChangeFocus(View* focused_before, View* focused) { |
| 206 ConfirmCompositionText(); | 155 ConfirmCompositionText(); |
| 207 } | 156 } |
| 208 | 157 |
| 209 void InputMethodWin::OnDidChangeFocus(View* focused_before, View* focused) { | 158 void InputMethodWin::OnDidChangeFocus(View* focused_before, View* focused) { |
| 210 if (base::win::IsTSFAwareRequired()) { | 159 UpdateIMEState(); |
| 211 if (GetTextInputClient()) { | |
| 212 ui::TSFBridge::GetInstance()->SetFocusedClient(HWNDForView(focused), | |
| 213 GetTextInputClient()); | |
| 214 } | |
| 215 } else { | |
| 216 // Use switch here in case we are going to add more text input types. | |
| 217 // We disable input method in password field. | |
| 218 switch (GetTextInputType()) { | |
| 219 case ui::TEXT_INPUT_TYPE_NONE: | |
| 220 case ui::TEXT_INPUT_TYPE_PASSWORD: | |
| 221 ime_input_.DisableIME(hwnd_); | |
| 222 break; | |
| 223 default: | |
| 224 ime_input_.EnableIME(hwnd_); | |
| 225 break; | |
| 226 } | |
| 227 OnTextInputTypeChanged(GetFocusedView()); | |
| 228 OnCaretBoundsChanged(GetFocusedView()); | |
| 229 } | |
| 230 } | 160 } |
| 231 | 161 |
| 232 void InputMethodWin::OnInputLangChange(DWORD character_set, | 162 void InputMethodWin::OnInputLangChange(DWORD character_set, |
| 233 HKL input_language_id) { | 163 HKL input_language_id) { |
| 234 active_ = ime_input_.SetInputLanguage(); | 164 active_ = ime_input_.SetInputLanguage(); |
| 235 locale_ = ime_input_.GetInputLanguageName(); | 165 locale_ = ime_input_.GetInputLanguageName(); |
| 236 direction_ = ime_input_.GetTextDirection(); | 166 direction_ = ime_input_.GetTextDirection(); |
| 237 OnInputMethodChanged(); | 167 OnInputMethodChanged(); |
| 238 } | 168 } |
| 239 | 169 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 | 272 |
| 343 // We need to send character events to the focused text input client event if | 273 // We need to send character events to the focused text input client event if |
| 344 // its text input type is ui::TEXT_INPUT_TYPE_NONE. | 274 // its text input type is ui::TEXT_INPUT_TYPE_NONE. |
| 345 if (GetTextInputClient()) { | 275 if (GetTextInputClient()) { |
| 346 GetTextInputClient()->InsertChar(static_cast<char16>(wparam), | 276 GetTextInputClient()->InsertChar(static_cast<char16>(wparam), |
| 347 ui::GetModifiersFromKeyState()); | 277 ui::GetModifiersFromKeyState()); |
| 348 } | 278 } |
| 349 | 279 |
| 350 // Explicitly show the system menu at a good location on [Alt]+[Space]. | 280 // Explicitly show the system menu at a good location on [Alt]+[Space]. |
| 351 // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system | 281 // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system |
| 352 // menu causes undesirable titlebar artifacts in the classic theme. | 282 // menu causes unsdesirable titlebar artifacts in the classic theme. |
| 353 if (message == WM_SYSCHAR && wparam == VK_SPACE) | 283 if (message == WM_SYSCHAR && wparam == VK_SPACE) |
| 354 ui::ShowSystemMenu(hwnd_); | 284 ui::ShowSystemMenu(hwnd_); |
| 355 | 285 |
| 356 return 0; | 286 return 0; |
| 357 } | 287 } |
| 358 | 288 |
| 359 LRESULT InputMethodWin::OnDeadChar( | 289 LRESULT InputMethodWin::OnDeadChar( |
| 360 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { | 290 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
| 361 *handled = TRUE; | 291 *handled = TRUE; |
| 362 | 292 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 reconv->dwCompStrLen = | 357 reconv->dwCompStrLen = |
| 428 client->HasCompositionText() ? target_range.length() : 0; | 358 client->HasCompositionText() ? target_range.length() : 0; |
| 429 reconv->dwCompStrOffset = | 359 reconv->dwCompStrOffset = |
| 430 (target_range.GetMin() - text_range.start()) * sizeof(WCHAR); | 360 (target_range.GetMin() - text_range.start()) * sizeof(WCHAR); |
| 431 reconv->dwTargetStrLen = target_range.length(); | 361 reconv->dwTargetStrLen = target_range.length(); |
| 432 reconv->dwTargetStrOffset = reconv->dwCompStrOffset; | 362 reconv->dwTargetStrOffset = reconv->dwCompStrOffset; |
| 433 | 363 |
| 434 memcpy((char*)reconv + sizeof(RECONVERTSTRING), | 364 memcpy((char*)reconv + sizeof(RECONVERTSTRING), |
| 435 text.c_str(), len * sizeof(WCHAR)); | 365 text.c_str(), len * sizeof(WCHAR)); |
| 436 | 366 |
| 437 // According to Microsoft API document, IMR_RECONVERTSTRING and | 367 // According to Microsft API document, IMR_RECONVERTSTRING and |
| 438 // IMR_DOCUMENTFEED should return reconv, but some applications return | 368 // IMR_DOCUMENTFEED should return reconv, but some applications return |
| 439 // need_size. | 369 // need_size. |
| 440 return reinterpret_cast<LRESULT>(reconv); | 370 return reinterpret_cast<LRESULT>(reconv); |
| 441 } | 371 } |
| 442 | 372 |
| 443 LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) { | 373 LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) { |
| 444 ui::TextInputClient* client = GetTextInputClient(); | 374 ui::TextInputClient* client = GetTextInputClient(); |
| 445 if (!client) | 375 if (!client) |
| 446 return 0; | 376 return 0; |
| 447 | 377 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 return 0; | 440 return 0; |
| 511 | 441 |
| 512 char_positon->pt.x = rect.x(); | 442 char_positon->pt.x = rect.x(); |
| 513 char_positon->pt.y = rect.y(); | 443 char_positon->pt.y = rect.y(); |
| 514 char_positon->cLineHeight = rect.height(); | 444 char_positon->cLineHeight = rect.height(); |
| 515 return 1; // returns non-zero value when succeeded. | 445 return 1; // returns non-zero value when succeeded. |
| 516 } | 446 } |
| 517 | 447 |
| 518 void InputMethodWin::ConfirmCompositionText() { | 448 void InputMethodWin::ConfirmCompositionText() { |
| 519 if (!IsTextInputTypeNone()) { | 449 if (!IsTextInputTypeNone()) { |
| 520 if (base::win::IsTSFAwareRequired()) { | 450 ime_input_.CleanupComposition(hwnd_); |
| 521 // TSFBridge has not implemented ConfirmComposition yet. So here cancel | 451 // Though above line should confirm the client's composition text by sending |
| 522 // the composition instead as a workaround. | 452 // a result text to us, in case the input method and the client are in |
| 523 // TODO(ime): Implement ConfirmComposition for TSF. | 453 // inconsistent states, we check the client's composition state again. |
| 524 ui::TSFBridge::GetInstance()->CancelComposition(); | 454 if (GetTextInputClient()->HasCompositionText()) |
| 525 } else { | 455 GetTextInputClient()->ConfirmCompositionText(); |
| 526 ime_input_.CleanupComposition(hwnd_); | 456 } |
| 527 // Though above line should confirm the client's composition text by | 457 } |
| 528 // sending a result text to us, in case the input method and the client | 458 |
| 529 // are in inconsistent states, we check the client's composition state | 459 void InputMethodWin::UpdateIMEState() { |
| 530 // again. | 460 // Use switch here in case we are going to add more text input types. |
| 531 if (GetTextInputClient()->HasCompositionText()) | 461 // We disable input method in password field. |
| 532 GetTextInputClient()->ConfirmCompositionText(); | 462 switch (GetTextInputType()) { |
| 533 } | 463 case ui::TEXT_INPUT_TYPE_NONE: |
| 464 case ui::TEXT_INPUT_TYPE_PASSWORD: |
| 465 ime_input_.DisableIME(hwnd_); |
| 466 break; |
| 467 default: |
| 468 ime_input_.EnableIME(hwnd_); |
| 469 break; |
| 534 } | 470 } |
| 535 } | 471 } |
| 536 | 472 |
| 537 } // namespace views | 473 } // namespace views |
| OLD | NEW |