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