OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "views/ime/input_method_win.h" | 5 #include "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 "ui/base/keycodes/keyboard_codes.h" | 10 #include "ui/base/keycodes/keyboard_codes.h" |
11 #include "views/events/event.h" | 11 #include "views/events/event.h" |
12 | 12 |
13 // Extra number of chars before and after selection (or composition) range which | |
14 // is returned to IME for improving conversion accuracy. | |
15 static const size_t kExtraNumberOfChars = 20; | |
16 | |
13 namespace views { | 17 namespace views { |
14 | 18 |
15 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate) | 19 InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate) |
16 : active_(false), | 20 : active_(false), |
17 direction_(base::i18n::UNKNOWN_DIRECTION), | 21 direction_(base::i18n::UNKNOWN_DIRECTION), |
18 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION) { | 22 pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION) { |
19 set_delegate(delegate); | 23 set_delegate(delegate); |
20 } | 24 } |
21 | 25 |
22 InputMethodWin::~InputMethodWin() { | 26 InputMethodWin::~InputMethodWin() { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 break; | 112 break; |
109 case WM_IME_STARTCOMPOSITION: | 113 case WM_IME_STARTCOMPOSITION: |
110 result = OnImeStartComposition(message, w_param, l_param, handled); | 114 result = OnImeStartComposition(message, w_param, l_param, handled); |
111 break; | 115 break; |
112 case WM_IME_COMPOSITION: | 116 case WM_IME_COMPOSITION: |
113 result = OnImeComposition(message, w_param, l_param, handled); | 117 result = OnImeComposition(message, w_param, l_param, handled); |
114 break; | 118 break; |
115 case WM_IME_ENDCOMPOSITION: | 119 case WM_IME_ENDCOMPOSITION: |
116 result = OnImeEndComposition(message, w_param, l_param, handled); | 120 result = OnImeEndComposition(message, w_param, l_param, handled); |
117 break; | 121 break; |
122 case WM_IME_REQUEST: | |
123 result = OnImeRequest(message, w_param, l_param, handled); | |
124 break; | |
118 case WM_CHAR: | 125 case WM_CHAR: |
119 case WM_SYSCHAR: | 126 case WM_SYSCHAR: |
120 result = OnChar(message, w_param, l_param, handled); | 127 result = OnChar(message, w_param, l_param, handled); |
121 break; | 128 break; |
122 case WM_DEADCHAR: | 129 case WM_DEADCHAR: |
123 case WM_SYSDEADCHAR: | 130 case WM_SYSDEADCHAR: |
124 result = OnDeadChar(message, w_param, l_param, handled); | 131 result = OnDeadChar(message, w_param, l_param, handled); |
125 break; | 132 break; |
126 default: | 133 default: |
127 NOTREACHED() << "Unknown IME message:" << message; | 134 NOTREACHED() << "Unknown IME message:" << message; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 return 0; | 219 return 0; |
213 | 220 |
214 if (GetTextInputClient()->HasCompositionText()) | 221 if (GetTextInputClient()->HasCompositionText()) |
215 GetTextInputClient()->ClearCompositionText(); | 222 GetTextInputClient()->ClearCompositionText(); |
216 | 223 |
217 ime_input_.ResetComposition(hwnd()); | 224 ime_input_.ResetComposition(hwnd()); |
218 ime_input_.DestroyImeWindow(hwnd()); | 225 ime_input_.DestroyImeWindow(hwnd()); |
219 return 0; | 226 return 0; |
220 } | 227 } |
221 | 228 |
229 LRESULT InputMethodWin::OnImeRequest( | |
230 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { | |
231 *handled = FALSE; | |
232 | |
233 // Should not receive WM_IME_REQUEST message, if IME is disabled. | |
234 const ui::TextInputType type = GetTextInputType(); | |
235 if (type == ui::TEXT_INPUT_TYPE_NONE || | |
236 type == ui::TEXT_INPUT_TYPE_PASSWORD) { | |
237 return 0; | |
238 } | |
239 | |
240 switch (wparam) { | |
241 case IMR_RECONVERTSTRING: | |
242 *handled = TRUE; | |
243 return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam)); | |
244 case IMR_DOCUMENTFEED: | |
245 *handled = TRUE; | |
246 return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam)); | |
247 default: | |
248 return 0; | |
249 } | |
250 } | |
251 | |
222 LRESULT InputMethodWin::OnChar( | 252 LRESULT InputMethodWin::OnChar( |
223 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { | 253 UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) { |
224 *handled = TRUE; | 254 *handled = TRUE; |
225 | 255 |
226 // We need to send character events to the focused text input client event if | 256 // We need to send character events to the focused text input client event if |
227 // its text input type is ui::TEXT_INPUT_TYPE_NONE. | 257 // its text input type is ui::TEXT_INPUT_TYPE_NONE. |
228 if (!GetTextInputClient()) | 258 if (!GetTextInputClient()) |
229 return 0; | 259 return 0; |
230 | 260 |
231 int flags = 0; | 261 int flags = 0; |
(...skipping 15 matching lines...) Expand all Loading... | |
247 // what dead key was pressed. | 277 // what dead key was pressed. |
248 ui::CompositionText composition; | 278 ui::CompositionText composition; |
249 composition.text.assign(1, static_cast<char16>(wparam)); | 279 composition.text.assign(1, static_cast<char16>(wparam)); |
250 composition.selection = ui::Range(0, 1); | 280 composition.selection = ui::Range(0, 1); |
251 composition.underlines.push_back( | 281 composition.underlines.push_back( |
252 ui::CompositionUnderline(0, 1, SK_ColorBLACK, false)); | 282 ui::CompositionUnderline(0, 1, SK_ColorBLACK, false)); |
253 GetTextInputClient()->SetCompositionText(composition); | 283 GetTextInputClient()->SetCompositionText(composition); |
254 return 0; | 284 return 0; |
255 } | 285 } |
256 | 286 |
287 LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) { | |
288 TextInputClient* client = GetTextInputClient(); | |
289 if (!client) | |
290 return 0; | |
291 | |
292 ui::Range text_range; | |
293 if (!client->GetTextRange(&text_range) || text_range.is_empty()) | |
294 return 0; | |
295 | |
296 bool result = false; | |
297 ui::Range target_range; | |
298 if (client->HasCompositionText()) | |
299 result = client->GetCompositionTextRange(&target_range); | |
300 | |
301 if (!result || target_range.is_empty()) { | |
302 if (!client->GetSelectionRange(&target_range) || | |
303 !target_range.IsValid()) { | |
304 return 0; | |
305 } | |
306 } | |
307 | |
308 if (!text_range.Contains(target_range)) | |
309 return 0; | |
310 | |
311 if (target_range.GetMin() - text_range.start() > kExtraNumberOfChars) | |
312 text_range.set_start(target_range.GetMin() - kExtraNumberOfChars); | |
313 | |
314 if (text_range.end() - target_range.GetMax() > kExtraNumberOfChars) | |
315 text_range.set_end(target_range.GetMax() + kExtraNumberOfChars); | |
316 | |
317 size_t len = text_range.length(); | |
318 size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR); | |
319 | |
320 if (!reconv) | |
321 return need_size; | |
322 | |
323 if (reconv->dwSize < need_size) | |
324 return 0; | |
325 | |
326 string16 text; | |
327 if (!GetTextInputClient()->GetTextFromRange(text_range, &text)) | |
328 return 0; | |
James Su
2011/10/28 18:16:04
nit: DCHECK_EQ(text_range.length(), text.length())
Peng
2011/10/28 19:13:06
Done.
| |
329 | |
330 reconv->dwVersion = 0; | |
331 reconv->dwStrLen = len; | |
332 reconv->dwStrOffset = sizeof(RECONVERTSTRING); | |
333 reconv->dwCompStrLen = | |
334 client->HasCompositionText() ? target_range.length() : 0; | |
335 reconv->dwCompStrOffset = | |
336 (target_range.GetMin() - text_range.start()) * sizeof(WCHAR); | |
337 reconv->dwTargetStrLen = target_range.length(); | |
338 reconv->dwTargetStrOffset = reconv->dwCompStrOffset; | |
339 | |
340 memcpy((char*)reconv + sizeof(RECONVERTSTRING), | |
341 text.c_str(), len * sizeof(WCHAR)); | |
James Su
2011/10/28 18:16:04
nit: alignment.
Peng
2011/10/28 19:13:06
Done.
| |
342 | |
343 return reinterpret_cast<LRESULT>(reconv); | |
344 } | |
345 | |
346 LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) { | |
347 TextInputClient* client = GetTextInputClient(); | |
348 if (!client) | |
349 return 0; | |
350 | |
351 // If there is a composition string already, we don't allow reconversion. | |
352 if (client->HasCompositionText()) | |
353 return 0; | |
354 | |
355 ui::Range text_range; | |
356 if (!client->GetTextRange(&text_range) || text_range.is_empty()) | |
357 return 0; | |
358 | |
359 ui::Range selection_range; | |
360 if (!client->GetSelectionRange(&selection_range) || | |
361 selection_range.is_empty()) { | |
362 return 0; | |
363 } | |
364 | |
365 DCHECK(text_range.Contains(selection_range)); | |
366 | |
367 size_t len = selection_range.length(); | |
368 size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR); | |
369 | |
370 if (!reconv) | |
371 return need_size; | |
372 | |
373 if (reconv->dwSize < need_size) | |
374 return 0; | |
375 | |
376 // Because we don't not support IME adjusts the reconvert range right now and | |
377 // returning extra content may have privacy issue. So in the first step, we | |
378 // don't return exrat content. | |
James Su
2011/10/28 18:16:04
I'd suggest to remove this paragraph. As I said re
Peng
2011/10/28 19:13:06
Done.
| |
379 // TODO(penghuang): support IME adjusts the reconvert range. | |
James Su
2011/10/28 18:16:04
Just: // TODO(penghuang): Return some extra contex
Peng
2011/10/28 19:13:06
Done.
| |
380 string16 text; | |
381 if (!GetTextInputClient()->GetTextFromRange(selection_range, &text)) | |
382 return 0; | |
James Su
2011/10/28 18:16:04
nit: DCHECK_EQ(selection_range.length(), text.leng
Peng
2011/10/28 19:13:06
Done.
| |
383 | |
384 reconv->dwVersion = 0; | |
385 reconv->dwStrLen = len; | |
386 reconv->dwStrOffset = sizeof(RECONVERTSTRING); | |
387 reconv->dwCompStrLen = len; | |
388 reconv->dwCompStrOffset = 0; | |
389 reconv->dwTargetStrLen = len; | |
390 reconv->dwTargetStrOffset = 0; | |
391 | |
392 memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING), | |
393 text.c_str(), len * sizeof(WCHAR)); | |
James Su
2011/10/28 18:16:04
nit: alignment.
Peng
2011/10/28 19:13:06
Done.
| |
394 | |
395 return reinterpret_cast<LRESULT>(reconv); | |
James Su
2011/10/28 18:16:04
If you insistent on returning the pointer here, I'
Peng
2011/10/28 19:13:06
Done.
| |
396 } | |
397 | |
257 void InputMethodWin::ConfirmCompositionText() { | 398 void InputMethodWin::ConfirmCompositionText() { |
258 if (!IsTextInputTypeNone()) { | 399 if (!IsTextInputTypeNone()) { |
259 ime_input_.CleanupComposition(hwnd()); | 400 ime_input_.CleanupComposition(hwnd()); |
260 // Though above line should confirm the client's composition text by sending | 401 // Though above line should confirm the client's composition text by sending |
261 // a result text to us, in case the input method and the client are in | 402 // a result text to us, in case the input method and the client are in |
262 // inconsistent states, we check the client's composition state again. | 403 // inconsistent states, we check the client's composition state again. |
263 if (GetTextInputClient()->HasCompositionText()) | 404 if (GetTextInputClient()->HasCompositionText()) |
264 GetTextInputClient()->ConfirmCompositionText(); | 405 GetTextInputClient()->ConfirmCompositionText(); |
265 } | 406 } |
266 } | 407 } |
267 | 408 |
268 void InputMethodWin::UpdateIMEState() { | 409 void InputMethodWin::UpdateIMEState() { |
269 // Use switch here in case we are going to add more text input types. | 410 // Use switch here in case we are going to add more text input types. |
270 // We disable input method in password field. | 411 // We disable input method in password field. |
271 switch (GetTextInputType()) { | 412 switch (GetTextInputType()) { |
272 case ui::TEXT_INPUT_TYPE_NONE: | 413 case ui::TEXT_INPUT_TYPE_NONE: |
273 case ui::TEXT_INPUT_TYPE_PASSWORD: | 414 case ui::TEXT_INPUT_TYPE_PASSWORD: |
274 ime_input_.DisableIME(hwnd()); | 415 ime_input_.DisableIME(hwnd()); |
275 break; | 416 break; |
276 default: | 417 default: |
277 ime_input_.EnableIME(hwnd()); | 418 ime_input_.EnableIME(hwnd()); |
278 break; | 419 break; |
279 } | 420 } |
280 } | 421 } |
281 | 422 |
282 } // namespace views | 423 } // namespace views |
OLD | NEW |