| 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/profiler/scoped_tracker.h" | 9 #include "base/profiler/scoped_tracker.h" |
| 10 #include "ui/base/ime/text_input_client.h" | 10 #include "ui/base/ime/text_input_client.h" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 | 25 |
| 26 } // namespace | 26 } // namespace |
| 27 | 27 |
| 28 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, | 28 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, |
| 29 HWND toplevel_window_handle) | 29 HWND toplevel_window_handle) |
| 30 : toplevel_window_handle_(toplevel_window_handle), | 30 : toplevel_window_handle_(toplevel_window_handle), |
| 31 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION), | 31 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION), |
| 32 accept_carriage_return_(false), | 32 accept_carriage_return_(false), |
| 33 enabled_(false), | 33 enabled_(false), |
| 34 is_candidate_popup_open_(false), | 34 is_candidate_popup_open_(false), |
| 35 composing_window_handle_(NULL), | 35 composing_window_handle_(NULL) { |
| 36 suppress_next_char_(false) { | |
| 37 SetDelegate(delegate); | 36 SetDelegate(delegate); |
| 38 } | 37 } |
| 39 | 38 |
| 40 void InputMethodWin::OnFocus() { | 39 void InputMethodWin::OnFocus() { |
| 41 InputMethodBase::OnFocus(); | 40 InputMethodBase::OnFocus(); |
| 42 if (GetTextInputClient()) | 41 if (GetTextInputClient()) |
| 43 UpdateIMEState(); | 42 UpdateIMEState(); |
| 44 } | 43 } |
| 45 | 44 |
| 46 void InputMethodWin::OnBlur() { | 45 void InputMethodWin::OnBlur() { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 *result = original_result; | 96 *result = original_result; |
| 98 return !!handled; | 97 return !!handled; |
| 99 } | 98 } |
| 100 | 99 |
| 101 void InputMethodWin::DispatchKeyEvent(ui::KeyEvent* event) { | 100 void InputMethodWin::DispatchKeyEvent(ui::KeyEvent* event) { |
| 102 if (!event->HasNativeEvent()) { | 101 if (!event->HasNativeEvent()) { |
| 103 DispatchFabricatedKeyEvent(event); | 102 DispatchFabricatedKeyEvent(event); |
| 104 return; | 103 return; |
| 105 } | 104 } |
| 106 | 105 |
| 106 std::vector<MSG> char_msgs; |
| 107 const base::NativeEvent& native_key_event = event->native_event(); | 107 const base::NativeEvent& native_key_event = event->native_event(); |
| 108 // Peek & remove the following messages in the message queue. |
| 109 // - WM_CHAR (0x0102) |
| 110 // - WM_DEADCHAR (0x0103) |
| 111 // - WM_SYSCHAR (0x0106) |
| 112 // - WM_SYSDEADCHAR (0x0107) |
| 113 // And only process WM_CHAR & WM_SYSCHAR message in browser. |
| 114 // This is to combine the WM_KEY* and WM_CHAR messages in the event |
| 115 // processing flow which is necessary to let Chrome IME extension to process |
| 116 // the key event and perform corresponding IME actions. |
| 117 // Chrome IME extension may wants to consume certain key events based on |
| 118 // the character information of WM_CHAR messages. Holding WM_KEY* messages |
| 119 // until WM_CHAR is processed by the IME extension is not feasible because |
| 120 // there is no way to know wether there will or not be a WM_CHAR following |
| 121 // the WM_KEY*. |
| 122 // Chrome never handles dead chars so it is safe to remove/ignore |
| 123 // WM_*DEADCHAR messages. |
| 124 MSG msg; |
| 125 while (::PeekMessage(&msg, native_key_event.hwnd, WM_CHAR, WM_DEADCHAR, |
| 126 PM_REMOVE)) { |
| 127 if (msg.message == WM_CHAR) |
| 128 char_msgs.push_back(msg); |
| 129 } |
| 130 while (::PeekMessage(&msg, native_key_event.hwnd, WM_SYSCHAR, WM_SYSDEADCHAR, |
| 131 PM_REMOVE)) { |
| 132 if (msg.message == WM_SYSCHAR) |
| 133 char_msgs.push_back(msg); |
| 134 } |
| 135 |
| 136 BOOL handled = FALSE; |
| 108 if (native_key_event.message == WM_CHAR) { | 137 if (native_key_event.message == WM_CHAR) { |
| 109 BOOL handled; | |
| 110 OnChar(native_key_event.hwnd, native_key_event.message, | 138 OnChar(native_key_event.hwnd, native_key_event.message, |
| 111 native_key_event.wParam, native_key_event.lParam, &handled); | 139 native_key_event.wParam, native_key_event.lParam, &handled); |
| 112 if (handled) | 140 if (handled) |
| 113 event->StopPropagation(); | 141 event->StopPropagation(); |
| 114 return; | 142 return; |
| 115 } | 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. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 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 |
| 139 ui::EventDispatchDetails details = DispatchKeyEventPostIME(event); | 167 ui::EventDispatchDetails details = DispatchKeyEventPostIME(event); |
| 140 if (!details.dispatcher_destroyed) | 168 if (details.dispatcher_destroyed || details.target_destroyed || |
| 141 suppress_next_char_ = event->stopped_propagation(); | 169 event->stopped_propagation()) { |
| 170 return; |
| 171 } |
| 172 |
| 173 for (size_t i = 0; i < char_msgs.size(); ++i) { |
| 174 msg = char_msgs[i]; |
| 175 OnChar(msg.hwnd, msg.message, msg.wParam, msg.lParam, &handled); |
| 176 } |
| 142 } | 177 } |
| 143 | 178 |
| 144 void InputMethodWin::OnTextInputTypeChanged(const TextInputClient* client) { | 179 void InputMethodWin::OnTextInputTypeChanged(const TextInputClient* client) { |
| 145 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) | 180 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client)) |
| 146 return; | 181 return; |
| 147 imm32_manager_.CancelIME(toplevel_window_handle_); | 182 imm32_manager_.CancelIME(toplevel_window_handle_); |
| 148 UpdateIMEState(); | 183 UpdateIMEState(); |
| 149 } | 184 } |
| 150 | 185 |
| 151 void InputMethodWin::OnCaretBoundsChanged(const TextInputClient* client) { | 186 void InputMethodWin::OnCaretBoundsChanged(const TextInputClient* client) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 UINT message, | 252 UINT message, |
| 218 WPARAM wparam, | 253 WPARAM wparam, |
| 219 LPARAM lparam, | 254 LPARAM lparam, |
| 220 BOOL* handled) { | 255 BOOL* handled) { |
| 221 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. | 256 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed. |
| 222 tracked_objects::ScopedTracker tracking_profile( | 257 tracked_objects::ScopedTracker tracking_profile( |
| 223 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 InputMethodWin::OnChar")); | 258 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 InputMethodWin::OnChar")); |
| 224 | 259 |
| 225 *handled = TRUE; | 260 *handled = TRUE; |
| 226 | 261 |
| 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 | 262 // 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. | 263 // its text input type is ui::TEXT_INPUT_TYPE_NONE. |
| 234 if (GetTextInputClient()) { | 264 if (GetTextInputClient()) { |
| 235 const base::char16 kCarriageReturn = L'\r'; | 265 const base::char16 kCarriageReturn = L'\r'; |
| 236 const base::char16 ch = static_cast<base::char16>(wparam); | 266 const base::char16 ch = static_cast<base::char16>(wparam); |
| 237 // A mask to determine the previous key state from |lparam|. The value is 1 | 267 // 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 | 268 // if the key is down before the message is sent, or it is 0 if the key is |
| 239 // up. | 269 // up. |
| 240 const uint32 kPrevKeyDownBit = 0x40000000; | 270 const uint32 kPrevKeyDownBit = 0x40000000; |
| 241 if (ch == kCarriageReturn && !(lparam & kPrevKeyDownBit)) | 271 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 | 610 // 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 | 611 // 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 | 612 // even when the |attached_window_handle| becomes active but has not received |
| 583 // WM_FOCUS yet. | 613 // WM_FOCUS yet. |
| 584 return toplevel_window_handle_ && | 614 return toplevel_window_handle_ && |
| 585 GetActiveWindow() == toplevel_window_handle_; | 615 GetActiveWindow() == toplevel_window_handle_; |
| 586 } | 616 } |
| 587 | 617 |
| 588 void InputMethodWin::DispatchFabricatedKeyEvent(ui::KeyEvent* event) { | 618 void InputMethodWin::DispatchFabricatedKeyEvent(ui::KeyEvent* event) { |
| 589 if (event->is_char()) { | 619 if (event->is_char()) { |
| 590 if (suppress_next_char_) { | |
| 591 suppress_next_char_ = false; | |
| 592 return; | |
| 593 } | |
| 594 if (GetTextInputClient()) { | 620 if (GetTextInputClient()) { |
| 595 GetTextInputClient()->InsertChar( | 621 GetTextInputClient()->InsertChar( |
| 596 static_cast<base::char16>(event->key_code()), | 622 static_cast<base::char16>(event->key_code()), |
| 597 ui::GetModifiersFromKeyState()); | 623 ui::GetModifiersFromKeyState()); |
| 598 return; | 624 return; |
| 599 } | 625 } |
| 600 } | 626 } |
| 601 ignore_result(DispatchKeyEventPostIME(event)); | 627 ignore_result(DispatchKeyEventPostIME(event)); |
| 602 } | 628 } |
| 603 | 629 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 631 enabled_ = true; | 657 enabled_ = true; |
| 632 break; | 658 break; |
| 633 } | 659 } |
| 634 | 660 |
| 635 imm32_manager_.SetTextInputMode(window_handle, text_input_mode); | 661 imm32_manager_.SetTextInputMode(window_handle, text_input_mode); |
| 636 tsf_inputscope::SetInputScopeForTsfUnawareWindow( | 662 tsf_inputscope::SetInputScopeForTsfUnawareWindow( |
| 637 window_handle, text_input_type, text_input_mode); | 663 window_handle, text_input_type, text_input_mode); |
| 638 } | 664 } |
| 639 | 665 |
| 640 } // namespace ui | 666 } // namespace ui |
| OLD | NEW |