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 |