Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(448)

Side by Side Diff: ui/base/ime/input_method_win.cc

Issue 166063002: Unify InputMethodIMM32 into InputMethodWin again (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/basictypes.h" 7 #include "base/basictypes.h"
8 #include "ui/base/ime/text_input_client.h" 8 #include "ui/base/ime/text_input_client.h"
9 #include "ui/base/ime/win/tsf_input_scope.h"
9 #include "ui/events/event.h" 10 #include "ui/events/event.h"
10 #include "ui/events/event_constants.h" 11 #include "ui/events/event_constants.h"
11 #include "ui/events/event_utils.h" 12 #include "ui/events/event_utils.h"
12 #include "ui/events/keycodes/keyboard_codes.h" 13 #include "ui/events/keycodes/keyboard_codes.h"
13 #include "ui/gfx/win/hwnd_util.h" 14 #include "ui/gfx/win/hwnd_util.h"
14 15
15 namespace ui { 16 namespace ui {
16 namespace { 17 namespace {
17 18
18 // 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
19 // is returned to IME for improving conversion accuracy. 20 // is returned to IME for improving conversion accuracy.
20 static const size_t kExtraNumberOfChars = 20; 21 static const size_t kExtraNumberOfChars = 20;
21 22
22 } // namespace 23 } // namespace
23 24
24 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, 25 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate,
25 HWND toplevel_window_handle) 26 HWND toplevel_window_handle)
26 : active_(false), 27 : toplevel_window_handle_(toplevel_window_handle),
27 toplevel_window_handle_(toplevel_window_handle),
28 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION), 28 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION),
29 accept_carriage_return_(false) { 29 accept_carriage_return_(false),
30 active_(false),
31 enabled_(false),
32 is_candidate_popup_open_(false),
33 composing_window_handle_(NULL) {
30 SetDelegate(delegate); 34 SetDelegate(delegate);
35 // In non-Aura environment, appropriate callbacks to OnFocus() and OnBlur()
36 // are not implemented yet. To work around this limitation, here we use
37 // "always focused" model.
38 // TODO(ime): Fix the caller of OnFocus() and OnBlur() so that appropriate
39 // focus event will be passed.
40 InputMethodBase::OnFocus();
31 } 41 }
32 42
33 void InputMethodWin::Init(bool focused) { 43 void InputMethodWin::Init(bool focused) {
34 // Gets the initial input locale. 44 // Gets the initial input locale.
35 OnInputLocaleChanged(); 45 OnInputLocaleChanged();
36 46
37 InputMethodBase::Init(focused); 47 InputMethodBase::Init(focused);
38 } 48 }
39 49
50 void InputMethodWin::OnFocus() {
51 // Ignore OnFocus event for "always focused" model. See the comment in the
52 // constructor.
53 // TODO(ime): Implement OnFocus once the callers are fixed.
54 }
55
56 void InputMethodWin::OnBlur() {
57 // Ignore OnBlur event for "always focused" model. See the comment in the
58 // constructor.
59 // TODO(ime): Implement OnFocus once the callers are fixed.
60 }
61
62 bool InputMethodWin::OnUntranslatedIMEMessage(
63 const base::NativeEvent& event,
64 InputMethod::NativeEventResult* result) {
65 LRESULT original_result = 0;
66 BOOL handled = FALSE;
67 switch (event.message) {
68 case WM_IME_SETCONTEXT:
69 original_result = OnImeSetContext(
70 event.hwnd, event.message, event.wParam, event.lParam, &handled);
71 break;
72 case WM_IME_STARTCOMPOSITION:
73 original_result = OnImeStartComposition(
74 event.hwnd, event.message, event.wParam, event.lParam, &handled);
75 break;
76 case WM_IME_COMPOSITION:
77 original_result = OnImeComposition(
78 event.hwnd, event.message, event.wParam, event.lParam, &handled);
79 break;
80 case WM_IME_ENDCOMPOSITION:
81 original_result = OnImeEndComposition(
82 event.hwnd, event.message, event.wParam, event.lParam, &handled);
83 break;
84 case WM_IME_REQUEST:
85 original_result = OnImeRequest(
86 event.message, event.wParam, event.lParam, &handled);
87 break;
88 case WM_CHAR:
89 case WM_SYSCHAR:
90 original_result = OnChar(
91 event.hwnd, event.message, event.wParam, event.lParam, &handled);
92 break;
93 case WM_IME_NOTIFY:
94 original_result = OnImeNotify(
95 event.message, event.wParam, event.lParam, &handled);
96 break;
97 default:
98 NOTREACHED() << "Unknown IME message:" << event.message;
99 break;
100 }
101 if (result)
102 *result = original_result;
103 return !!handled;
104 }
105
40 bool InputMethodWin::DispatchKeyEvent(const ui::KeyEvent& event) { 106 bool InputMethodWin::DispatchKeyEvent(const ui::KeyEvent& event) {
41 if (!event.HasNativeEvent()) 107 if (!event.HasNativeEvent())
42 return DispatchFabricatedKeyEvent(event); 108 return DispatchFabricatedKeyEvent(event);
43 109
44 const base::NativeEvent& native_key_event = event.native_event(); 110 const base::NativeEvent& native_key_event = event.native_event();
45 if (native_key_event.message == WM_CHAR) { 111 if (native_key_event.message == WM_CHAR) {
46 BOOL handled; 112 BOOL handled;
47 OnChar(native_key_event.hwnd, native_key_event.message, 113 OnChar(native_key_event.hwnd, native_key_event.message,
48 native_key_event.wParam, native_key_event.lParam, &handled); 114 native_key_event.wParam, native_key_event.lParam, &handled);
49 return !!handled; // Don't send WM_CHAR for post event processing. 115 return !!handled; // Don't send WM_CHAR for post event processing.
(...skipping 18 matching lines...) Expand all
68 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) { 134 pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) {
69 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment( 135 GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment(
70 pending_requested_direction_); 136 pending_requested_direction_);
71 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; 137 pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
72 } 138 }
73 } 139 }
74 140
75 return DispatchKeyEventPostIME(event); 141 return DispatchKeyEventPostIME(event);
76 } 142 }
77 143
144 void InputMethodWin::OnTextInputTypeChanged(const TextInputClient* client) {
145 if (!IsTextInputClientFocused(client) || !IsWindowFocused(client))
146 return;
147 imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
148 UpdateIMEState();
149 }
150
151 void InputMethodWin::OnCaretBoundsChanged(const TextInputClient* client) {
152 if (!enabled_ || !IsTextInputClientFocused(client) ||
153 !IsWindowFocused(client)) {
154 return;
155 }
156 // The current text input type should not be NONE if |client| is focused.
157 DCHECK(!IsTextInputTypeNone());
158 gfx::Rect screen_bounds(GetTextInputClient()->GetCaretBounds());
159
160 HWND attached_window = GetAttachedWindowHandle(client);
161 // TODO(ime): see comment in TextInputClient::GetCaretBounds(), this
162 // conversion shouldn't be necessary.
163 RECT r = {};
164 GetClientRect(attached_window, &r);
165 POINT window_point = { screen_bounds.x(), screen_bounds.y() };
166 ScreenToClient(attached_window, &window_point);
167 gfx::Rect caret_rect(gfx::Point(window_point.x, window_point.y),
168 screen_bounds.size());
169 imm32_manager_.UpdateCaretRect(attached_window, caret_rect);
170 }
171
172 void InputMethodWin::CancelComposition(const TextInputClient* client) {
173 if (enabled_ && IsTextInputClientFocused(client))
174 imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
175 }
176
78 void InputMethodWin::OnInputLocaleChanged() { 177 void InputMethodWin::OnInputLocaleChanged() {
79 active_ = imm32_manager_.SetInputLanguage(); 178 active_ = imm32_manager_.SetInputLanguage();
80 locale_ = imm32_manager_.GetInputLanguageName(); 179 locale_ = imm32_manager_.GetInputLanguageName();
81 OnInputMethodChanged(); 180 OnInputMethodChanged();
82 } 181 }
83 182
84 std::string InputMethodWin::GetInputLocale() { 183 std::string InputMethodWin::GetInputLocale() {
85 return locale_; 184 return locale_;
86 } 185 }
87 186
88 bool InputMethodWin::IsActive() { 187 bool InputMethodWin::IsActive() {
89 return active_; 188 return active_;
90 } 189 }
91 190
191 bool InputMethodWin::IsCandidatePopupOpen() const {
192 return is_candidate_popup_open_;
193 }
194
195 void InputMethodWin::OnWillChangeFocusedClient(TextInputClient* focused_before,
196 TextInputClient* focused) {
197 if (IsWindowFocused(focused_before))
198 ConfirmCompositionText();
199 }
200
92 void InputMethodWin::OnDidChangeFocusedClient( 201 void InputMethodWin::OnDidChangeFocusedClient(
93 TextInputClient* focused_before, 202 TextInputClient* focused_before,
94 TextInputClient* focused) { 203 TextInputClient* focused) {
204 if (IsWindowFocused(focused)) {
205 // Force to update the input type since client's TextInputStateChanged()
206 // function might not be called if text input types before the client loses
207 // focus and after it acquires focus again are the same.
208 OnTextInputTypeChanged(focused);
209
210 UpdateIMEState();
211
212 // Force to update caret bounds, in case the client thinks that the caret
213 // bounds has not changed.
214 OnCaretBoundsChanged(focused);
215 }
95 if (focused_before != focused) 216 if (focused_before != focused)
96 accept_carriage_return_ = false; 217 accept_carriage_return_ = false;
97 } 218 }
98 219
99 LRESULT InputMethodWin::OnImeRequest(UINT message,
100 WPARAM wparam,
101 LPARAM lparam,
102 BOOL* handled) {
103 *handled = FALSE;
104
105 // Should not receive WM_IME_REQUEST message, if IME is disabled.
106 const ui::TextInputType type = GetTextInputType();
107 if (type == ui::TEXT_INPUT_TYPE_NONE ||
108 type == ui::TEXT_INPUT_TYPE_PASSWORD) {
109 return 0;
110 }
111
112 switch (wparam) {
113 case IMR_RECONVERTSTRING:
114 *handled = TRUE;
115 return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam));
116 case IMR_DOCUMENTFEED:
117 *handled = TRUE;
118 return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam));
119 case IMR_QUERYCHARPOSITION:
120 *handled = TRUE;
121 return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam));
122 default:
123 return 0;
124 }
125 }
126
127 LRESULT InputMethodWin::OnChar(HWND window_handle, 220 LRESULT InputMethodWin::OnChar(HWND window_handle,
128 UINT message, 221 UINT message,
129 WPARAM wparam, 222 WPARAM wparam,
130 LPARAM lparam, 223 LPARAM lparam,
131 BOOL* handled) { 224 BOOL* handled) {
132 *handled = TRUE; 225 *handled = TRUE;
133 226
134 // We need to send character events to the focused text input client event if 227 // We need to send character events to the focused text input client event if
135 // its text input type is ui::TEXT_INPUT_TYPE_NONE. 228 // its text input type is ui::TEXT_INPUT_TYPE_NONE.
136 if (GetTextInputClient()) { 229 if (GetTextInputClient()) {
(...skipping 13 matching lines...) Expand all
150 243
151 // Explicitly show the system menu at a good location on [Alt]+[Space]. 244 // Explicitly show the system menu at a good location on [Alt]+[Space].
152 // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system 245 // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system
153 // menu causes undesirable titlebar artifacts in the classic theme. 246 // menu causes undesirable titlebar artifacts in the classic theme.
154 if (message == WM_SYSCHAR && wparam == VK_SPACE) 247 if (message == WM_SYSCHAR && wparam == VK_SPACE)
155 gfx::ShowSystemMenu(window_handle); 248 gfx::ShowSystemMenu(window_handle);
156 249
157 return 0; 250 return 0;
158 } 251 }
159 252
253 LRESULT InputMethodWin::OnImeSetContext(HWND window_handle,
254 UINT message,
255 WPARAM wparam,
256 LPARAM lparam,
257 BOOL* handled) {
258 if (!!wparam)
259 imm32_manager_.CreateImeWindow(window_handle);
260
261 OnInputMethodChanged();
262 return imm32_manager_.SetImeWindowStyle(
263 window_handle, message, wparam, lparam, handled);
264 }
265
266 LRESULT InputMethodWin::OnImeStartComposition(HWND window_handle,
267 UINT message,
268 WPARAM wparam,
269 LPARAM lparam,
270 BOOL* handled) {
271 // We have to prevent WTL from calling ::DefWindowProc() because the function
272 // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
273 // over-write the position of IME windows.
274 *handled = TRUE;
275
276 // Reset the composition status and create IME windows.
277 composing_window_handle_ = window_handle;
278 imm32_manager_.CreateImeWindow(window_handle);
279 imm32_manager_.ResetComposition(window_handle);
280 return 0;
281 }
282
283 LRESULT InputMethodWin::OnImeComposition(HWND window_handle,
284 UINT message,
285 WPARAM wparam,
286 LPARAM lparam,
287 BOOL* handled) {
288 // We have to prevent WTL from calling ::DefWindowProc() because we do not
289 // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
290 *handled = TRUE;
291
292 // At first, update the position of the IME window.
293 imm32_manager_.UpdateImeWindow(window_handle);
294
295 // Retrieve the result string and its attributes of the ongoing composition
296 // and send it to a renderer process.
297 ui::CompositionText composition;
298 if (imm32_manager_.GetResult(window_handle, lparam, &composition.text)) {
299 if (!IsTextInputTypeNone())
300 GetTextInputClient()->InsertText(composition.text);
301 imm32_manager_.ResetComposition(window_handle);
302 // Fall though and try reading the composition string.
303 // Japanese IMEs send a message containing both GCS_RESULTSTR and
304 // GCS_COMPSTR, which means an ongoing composition has been finished
305 // by the start of another composition.
306 }
307 // Retrieve the composition string and its attributes of the ongoing
308 // composition and send it to a renderer process.
309 if (imm32_manager_.GetComposition(window_handle, lparam, &composition) &&
310 !IsTextInputTypeNone())
311 GetTextInputClient()->SetCompositionText(composition);
312
313 return 0;
314 }
315
316 LRESULT InputMethodWin::OnImeEndComposition(HWND window_handle,
317 UINT message,
318 WPARAM wparam,
319 LPARAM lparam,
320 BOOL* handled) {
321 // Let WTL call ::DefWindowProc() and release its resources.
322 *handled = FALSE;
323
324 composing_window_handle_ = NULL;
325
326 if (!IsTextInputTypeNone() && GetTextInputClient()->HasCompositionText())
327 GetTextInputClient()->ClearCompositionText();
328
329 imm32_manager_.ResetComposition(window_handle);
330 imm32_manager_.DestroyImeWindow(window_handle);
331 return 0;
332 }
333
334 LRESULT InputMethodWin::OnImeNotify(UINT message,
335 WPARAM wparam,
336 LPARAM lparam,
337 BOOL* handled) {
338 *handled = FALSE;
339
340 bool previous_state = is_candidate_popup_open_;
341
342 // Update |is_candidate_popup_open_|, whether a candidate window is open.
343 switch (wparam) {
344 case IMN_OPENCANDIDATE:
345 is_candidate_popup_open_ = true;
346 if (!previous_state)
347 OnCandidateWindowShown();
348 break;
349 case IMN_CLOSECANDIDATE:
350 is_candidate_popup_open_ = false;
351 if (previous_state)
352 OnCandidateWindowHidden();
353 break;
354 case IMN_CHANGECANDIDATE:
355 // TODO(kochi): The IME API expects this event to notify window size change,
356 // while this may fire more often without window resize. There is no generic
357 // way to get bounds of candidate window.
358 OnCandidateWindowUpdated();
359 break;
360 }
361
362 return 0;
363 }
364
365 LRESULT InputMethodWin::OnImeRequest(UINT message,
366 WPARAM wparam,
367 LPARAM lparam,
368 BOOL* handled) {
369 *handled = FALSE;
370
371 // Should not receive WM_IME_REQUEST message, if IME is disabled.
372 const ui::TextInputType type = GetTextInputType();
373 if (type == ui::TEXT_INPUT_TYPE_NONE ||
374 type == ui::TEXT_INPUT_TYPE_PASSWORD) {
375 return 0;
376 }
377
378 switch (wparam) {
379 case IMR_RECONVERTSTRING:
380 *handled = TRUE;
381 return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam));
382 case IMR_DOCUMENTFEED:
383 *handled = TRUE;
384 return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam));
385 case IMR_QUERYCHARPOSITION:
386 *handled = TRUE;
387 return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam));
388 default:
389 return 0;
390 }
391 }
392
160 LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) { 393 LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) {
161 ui::TextInputClient* client = GetTextInputClient(); 394 ui::TextInputClient* client = GetTextInputClient();
162 if (!client) 395 if (!client)
163 return 0; 396 return 0;
164 397
165 gfx::Range text_range; 398 gfx::Range text_range;
166 if (!client->GetTextRange(&text_range) || text_range.is_empty()) 399 if (!client->GetTextRange(&text_range) || text_range.is_empty())
167 return 0; 400 return 0;
168 401
169 bool result = false; 402 bool result = false;
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 if (event.is_char()) { 563 if (event.is_char()) {
331 if (GetTextInputClient()) { 564 if (GetTextInputClient()) {
332 GetTextInputClient()->InsertChar(event.key_code(), 565 GetTextInputClient()->InsertChar(event.key_code(),
333 ui::GetModifiersFromKeyState()); 566 ui::GetModifiersFromKeyState());
334 return true; 567 return true;
335 } 568 }
336 } 569 }
337 return DispatchKeyEventPostIME(event); 570 return DispatchKeyEventPostIME(event);
338 } 571 }
339 572
573 void InputMethodWin::ConfirmCompositionText() {
574 if (composing_window_handle_)
575 imm32_manager_.CleanupComposition(composing_window_handle_);
576
577 if (!IsTextInputTypeNone()) {
578 // Though above line should confirm the client's composition text by sending
579 // a result text to us, in case the input method and the client are in
580 // inconsistent states, we check the client's composition state again.
581 if (GetTextInputClient()->HasCompositionText())
582 GetTextInputClient()->ConfirmCompositionText();
583 }
584 }
585
586 void InputMethodWin::UpdateIMEState() {
587 // Use switch here in case we are going to add more text input types.
588 // We disable input method in password field.
589 const HWND window_handle = GetAttachedWindowHandle(GetTextInputClient());
590 const TextInputType text_input_type = GetTextInputType();
591 const TextInputMode text_input_mode = GetTextInputMode();
592 switch (text_input_type) {
593 case ui::TEXT_INPUT_TYPE_NONE:
594 case ui::TEXT_INPUT_TYPE_PASSWORD:
595 imm32_manager_.DisableIME(window_handle);
596 enabled_ = false;
597 break;
598 default:
599 imm32_manager_.EnableIME(window_handle);
600 enabled_ = true;
601 break;
602 }
603
604 imm32_manager_.SetTextInputMode(window_handle, text_input_mode);
605 tsf_inputscope::SetInputScopeForTsfUnawareWindow(
606 window_handle, text_input_type, text_input_mode);
607 }
608
340 } // namespace ui 609 } // namespace ui
OLDNEW
« ui/base/ime/input_method_win.h ('K') | « ui/base/ime/input_method_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698