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