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