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/base/ime/input_method_win.h" | 5 #include "ui/base/ime/input_method_win.h" |
6 | 6 |
7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
9 #include "base/command_line.h" | |
9 #include "base/profiler/scoped_tracker.h" | 10 #include "base/profiler/scoped_tracker.h" |
10 #include "ui/base/ime/text_input_client.h" | 11 #include "ui/base/ime/text_input_client.h" |
11 #include "ui/base/ime/win/tsf_input_scope.h" | 12 #include "ui/base/ime/win/tsf_input_scope.h" |
13 #include "ui/base/ui_base_switches.h" | |
12 #include "ui/events/event.h" | 14 #include "ui/events/event.h" |
13 #include "ui/events/event_constants.h" | 15 #include "ui/events/event_constants.h" |
14 #include "ui/events/event_utils.h" | 16 #include "ui/events/event_utils.h" |
15 #include "ui/events/keycodes/keyboard_codes.h" | 17 #include "ui/events/keycodes/keyboard_codes.h" |
16 #include "ui/gfx/win/dpi.h" | 18 #include "ui/gfx/win/dpi.h" |
17 #include "ui/gfx/win/hwnd_util.h" | 19 #include "ui/gfx/win/hwnd_util.h" |
18 | 20 |
19 namespace ui { | 21 namespace ui { |
20 namespace { | 22 namespace { |
21 | 23 |
22 // Extra number of chars before and after selection (or composition) range which | 24 // Extra number of chars before and after selection (or composition) range which |
23 // is returned to IME for improving conversion accuracy. | 25 // is returned to IME for improving conversion accuracy. |
24 static const size_t kExtraNumberOfChars = 20; | 26 static const size_t kExtraNumberOfChars = 20; |
25 | 27 |
26 } // namespace | 28 } // namespace |
27 | 29 |
28 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, | 30 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, |
29 HWND toplevel_window_handle) | 31 HWND toplevel_window_handle) |
30 : toplevel_window_handle_(toplevel_window_handle), | 32 : toplevel_window_handle_(toplevel_window_handle), |
31 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION), | 33 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION), |
32 accept_carriage_return_(false), | 34 accept_carriage_return_(false), |
33 enabled_(false), | 35 enabled_(false), |
34 is_candidate_popup_open_(false), | 36 is_candidate_popup_open_(false), |
35 composing_window_handle_(NULL), | 37 composing_window_handle_(NULL) { |
36 suppress_next_char_(false) { | |
37 SetDelegate(delegate); | 38 SetDelegate(delegate); |
38 } | 39 } |
39 | 40 |
40 void InputMethodWin::OnFocus() { | 41 void InputMethodWin::OnFocus() { |
41 InputMethodBase::OnFocus(); | 42 InputMethodBase::OnFocus(); |
42 if (GetTextInputClient()) | 43 if (GetTextInputClient()) |
43 UpdateIMEState(); | 44 UpdateIMEState(); |
44 } | 45 } |
45 | 46 |
46 void InputMethodWin::OnBlur() { | 47 void InputMethodWin::OnBlur() { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
98 return !!handled; | 99 return !!handled; |
99 } | 100 } |
100 | 101 |
101 void InputMethodWin::DispatchKeyEvent(ui::KeyEvent* event) { | 102 void InputMethodWin::DispatchKeyEvent(ui::KeyEvent* event) { |
102 if (!event->HasNativeEvent()) { | 103 if (!event->HasNativeEvent()) { |
103 DispatchFabricatedKeyEvent(event); | 104 DispatchFabricatedKeyEvent(event); |
104 return; | 105 return; |
105 } | 106 } |
106 | 107 |
107 const base::NativeEvent& native_key_event = event->native_event(); | 108 const base::NativeEvent& native_key_event = event->native_event(); |
109 BOOL handled = FALSE; | |
108 if (native_key_event.message == WM_CHAR) { | 110 if (native_key_event.message == WM_CHAR) { |
109 BOOL handled; | |
110 OnChar(native_key_event.hwnd, native_key_event.message, | 111 OnChar(native_key_event.hwnd, native_key_event.message, |
111 native_key_event.wParam, native_key_event.lParam, &handled); | 112 native_key_event.wParam, native_key_event.lParam, &handled); |
112 if (handled) | 113 if (handled) |
113 event->StopPropagation(); | 114 event->StopPropagation(); |
114 return; | 115 return; |
115 } | 116 } |
117 | |
118 std::vector<MSG> char_msgs; | |
119 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
120 switches::kEnableMergeKeyCharEvents)) { | |
121 // Combines the WM_KEY* and WM_CHAR messages in the event processing flow | |
122 // which is necessary to let Chrome IME extension to process the key event | |
123 // and perform corresponding IME actions. | |
124 // Chrome IME extension may wants to consume certain key events based on | |
125 // the character information of WM_CHAR messages. Holding WM_KEY* messages | |
126 // until WM_CHAR is processed by the IME extension is not feasible because | |
127 // there is no way to know wether there will or not be a WM_CHAR following | |
128 // the WM_KEY*. | |
129 // Chrome never handles dead chars so it is safe to remove/ignore | |
130 // WM_*DEADCHAR messages. | |
131 MSG msg; | |
132 while (::PeekMessage(&msg, native_key_event.hwnd, WM_CHAR, WM_DEADCHAR, | |
133 PM_REMOVE)) { | |
134 if (msg.message == WM_CHAR) | |
135 char_msgs.push_back(msg); | |
136 } | |
137 while (::PeekMessage(&msg, native_key_event.hwnd, WM_SYSCHAR, | |
138 WM_SYSDEADCHAR, PM_REMOVE)) { | |
139 if (msg.message == WM_SYSCHAR) | |
140 char_msgs.push_back(msg); | |
141 } | |
142 } | |
143 | |
116 // Handles ctrl-shift key to change text direction and layout alignment. | 144 // Handles ctrl-shift key to change text direction and layout alignment. |
117 if (ui::IMM32Manager::IsRTLKeyboardLayoutInstalled() && | 145 if (ui::IMM32Manager::IsRTLKeyboardLayoutInstalled() && |
118 !IsTextInputTypeNone()) { | 146 !IsTextInputTypeNone()) { |
119 // TODO: shouldn't need to generate a KeyEvent here. | 147 // TODO: shouldn't need to generate a KeyEvent here. |
120 const ui::KeyEvent key(native_key_event); | 148 const ui::KeyEvent key(native_key_event); |
121 ui::KeyboardCode code = key.key_code(); | 149 ui::KeyboardCode code = key.key_code(); |
122 if (key.type() == ui::ET_KEY_PRESSED) { | 150 if (key.type() == ui::ET_KEY_PRESSED) { |
123 if (code == ui::VKEY_SHIFT) { | 151 if (code == ui::VKEY_SHIFT) { |
124 base::i18n::TextDirection dir; | 152 base::i18n::TextDirection dir; |
125 if (ui::IMM32Manager::IsCtrlShiftPressed(&dir)) | 153 if (ui::IMM32Manager::IsCtrlShiftPressed(&dir)) |
126 pending_requested_direction_ = dir; | 154 pending_requested_direction_ = dir; |
127 } else if (code != ui::VKEY_CONTROL) { | 155 } else if (code != ui::VKEY_CONTROL) { |
128 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; | 156 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; |
129 } | 157 } |
130 } else if (key.type() == ui::ET_KEY_RELEASED && | 158 } else if (key.type() == ui::ET_KEY_RELEASED && |
131 (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) && | 159 (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) && |
132 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) { | 160 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) { |
133 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment( | 161 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment( |
134 pending_requested_direction_); | 162 pending_requested_direction_); |
135 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; | 163 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; |
136 } | 164 } |
137 } | 165 } |
138 | 166 |
167 // If only 1 WM_CHAR per the key event, set it as the character of it. | |
168 if (char_msgs.size() == 1) | |
169 event->set_character(static_cast<base::char16>(char_msgs[0].wParam)); | |
ananta
2015/09/22 19:27:30
Is this code correct?. The wParams in WM_KEYDOWN a
Shu Chen
2015/09/23 05:21:09
This code is correct. WM_CHAR's wParam carries the
| |
170 | |
139 ui::EventDispatchDetails details = DispatchKeyEventPostIME(event); | 171 ui::EventDispatchDetails details = DispatchKeyEventPostIME(event); |
140 if (!details.dispatcher_destroyed) | 172 if (details.dispatcher_destroyed || details.target_destroyed || |
141 suppress_next_char_ = event->stopped_propagation(); | 173 event->stopped_propagation()) { |
174 return; | |
175 } | |
176 | |
177 for (size_t i = 0; i < char_msgs.size(); ++i) { | |
178 MSG msg = char_msgs[i]; | |
179 OnChar(msg.hwnd, msg.message, msg.wParam, msg.lParam, &handled); | |
180 } | |
142 } | 181 } |
143 | 182 |
144 void InputMethodWin::OnTextInputTypeChanged(const TextInputClient* client) { | 183 void InputMethodWin::OnTextInputTypeChanged(const TextInputClient* client) { |
145 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) | 184 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) |
146 return; | 185 return; |
147 imm32_manager_.CancelIME(toplevel_window_handle_); | 186 imm32_manager_.CancelIME(toplevel_window_handle_); |
148 UpdateIMEState(); | 187 UpdateIMEState(); |
149 } | 188 } |
150 | 189 |
151 void InputMethodWin::OnCaretBoundsChanged(const TextInputClient* client) { | 190 void InputMethodWin::OnCaretBoundsChanged(const TextInputClient* client) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 UINT message, | 256 UINT message, |
218 WPARAM wparam, | 257 WPARAM wparam, |
219 LPARAM lparam, | 258 LPARAM lparam, |
220 BOOL* handled) { | 259 BOOL* handled) { |
221 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | 260 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
222 tracked_objects::ScopedTracker tracking_profile( | 261 tracked_objects::ScopedTracker tracking_profile( |
223 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 InputMethodWin::OnChar")); | 262 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 InputMethodWin::OnChar")); |
224 | 263 |
225 *handled = TRUE; | 264 *handled = TRUE; |
226 | 265 |
227 if (suppress_next_char_) { | |
228 suppress_next_char_ = false; | |
229 return 0; | |
230 } | |
231 | |
232 // We need to send character events to the focused text input client event if | 266 // We need to send character events to the focused text input client event if |
233 // its text input type is ui::TEXT_INPUT_TYPE_NONE. | 267 // its text input type is ui::TEXT_INPUT_TYPE_NONE. |
234 if (GetTextInputClient()) { | 268 if (GetTextInputClient()) { |
235 const base::char16 kCarriageReturn = L'\r'; | 269 const base::char16 kCarriageReturn = L'\r'; |
236 const base::char16 ch = static_cast<base::char16>(wparam); | 270 const base::char16 ch = static_cast<base::char16>(wparam); |
237 // A mask to determine the previous key state from |lparam|. The value is 1 | 271 // A mask to determine the previous key state from |lparam|. The value is 1 |
238 // if the key is down before the message is sent, or it is 0 if the key is | 272 // if the key is down before the message is sent, or it is 0 if the key is |
239 // up. | 273 // up. |
240 const uint32 kPrevKeyDownBit = 0x40000000; | 274 const uint32 kPrevKeyDownBit = 0x40000000; |
241 if (ch == kCarriageReturn && !(lparam & kPrevKeyDownBit)) | 275 if (ch == kCarriageReturn && !(lparam & kPrevKeyDownBit)) |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
580 // window. So we can safely assume that |attached_window_handle| is ready for | 614 // window. So we can safely assume that |attached_window_handle| is ready for |
581 // receiving keyboard input as long as it is an active window. This works well | 615 // receiving keyboard input as long as it is an active window. This works well |
582 // even when the |attached_window_handle| becomes active but has not received | 616 // even when the |attached_window_handle| becomes active but has not received |
583 // WM_FOCUS yet. | 617 // WM_FOCUS yet. |
584 return toplevel_window_handle_ && | 618 return toplevel_window_handle_ && |
585 GetActiveWindow() == toplevel_window_handle_; | 619 GetActiveWindow() == toplevel_window_handle_; |
586 } | 620 } |
587 | 621 |
588 void InputMethodWin::DispatchFabricatedKeyEvent(ui::KeyEvent* event) { | 622 void InputMethodWin::DispatchFabricatedKeyEvent(ui::KeyEvent* event) { |
589 if (event->is_char()) { | 623 if (event->is_char()) { |
590 if (suppress_next_char_) { | |
591 suppress_next_char_ = false; | |
592 return; | |
593 } | |
594 if (GetTextInputClient()) { | 624 if (GetTextInputClient()) { |
595 GetTextInputClient()->InsertChar( | 625 GetTextInputClient()->InsertChar( |
596 static_cast<base::char16>(event->key_code()), | 626 static_cast<base::char16>(event->key_code()), |
597 ui::GetModifiersFromKeyState()); | 627 ui::GetModifiersFromKeyState()); |
598 return; | 628 return; |
599 } | 629 } |
600 } | 630 } |
601 ignore_result(DispatchKeyEventPostIME(event)); | 631 ignore_result(DispatchKeyEventPostIME(event)); |
602 } | 632 } |
603 | 633 |
(...skipping 27 matching lines...) Expand all Loading... | |
631 enabled_ = true; | 661 enabled_ = true; |
632 break; | 662 break; |
633 } | 663 } |
634 | 664 |
635 imm32_manager_.SetTextInputMode(window_handle, text_input_mode); | 665 imm32_manager_.SetTextInputMode(window_handle, text_input_mode); |
636 tsf_inputscope::SetInputScopeForTsfUnawareWindow( | 666 tsf_inputscope::SetInputScopeForTsfUnawareWindow( |
637 window_handle, text_input_type, text_input_mode); | 667 window_handle, text_input_type, text_input_mode); |
638 } | 668 } |
639 | 669 |
640 } // namespace ui | 670 } // namespace ui |
OLD | NEW |