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

Side by Side Diff: ui/views/controls/textfield/native_textfield_win.cc

Issue 11305002: Support TSF related event handling on NativeTextField (Closed) Base URL: http://git.chromium.org/chromium/src.git@findbar_fix
Patch Set: Address comments Created 8 years, 1 month 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
« no previous file with comments | « ui/views/controls/textfield/native_textfield_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/views/controls/textfield/native_textfield_win.h" 5 #include "ui/views/controls/textfield/native_textfield_win.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/i18n/case_conversion.h" 9 #include "base/i18n/case_conversion.h"
10 #include "base/i18n/rtl.h" 10 #include "base/i18n/rtl.h"
11 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
13 #include "base/win/metro.h" 13 #include "base/win/metro.h"
14 #include "base/win/windows_version.h" 14 #include "base/win/windows_version.h"
15 #include "grit/ui_strings.h" 15 #include "grit/ui_strings.h"
16 #include "skia/ext/skia_utils_win.h" 16 #include "skia/ext/skia_utils_win.h"
17 #include "ui/base/accessibility/accessible_view_state.h" 17 #include "ui/base/accessibility/accessible_view_state.h"
18 #include "ui/base/clipboard/clipboard.h" 18 #include "ui/base/clipboard/clipboard.h"
19 #include "ui/base/clipboard/scoped_clipboard_writer.h" 19 #include "ui/base/clipboard/scoped_clipboard_writer.h"
20 #include "ui/base/events/event.h" 20 #include "ui/base/events/event.h"
21 #include "ui/base/keycodes/keyboard_codes.h" 21 #include "ui/base/keycodes/keyboard_codes.h"
22 #include "ui/base/ime/win/tsf_bridge.h"
22 #include "ui/base/l10n/l10n_util.h" 23 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/l10n/l10n_util_win.h" 24 #include "ui/base/l10n/l10n_util_win.h"
24 #include "ui/base/native_theme/native_theme_win.h" 25 #include "ui/base/native_theme/native_theme_win.h"
25 #include "ui/base/range/range.h" 26 #include "ui/base/range/range.h"
26 #include "ui/base/win/mouse_wheel_util.h" 27 #include "ui/base/win/mouse_wheel_util.h"
27 #include "ui/views/controls/label.h" 28 #include "ui/views/controls/label.h"
28 #include "ui/views/controls/menu/menu_item_view.h" 29 #include "ui/views/controls/menu/menu_item_view.h"
29 #include "ui/views/controls/menu/menu_model_adapter.h" 30 #include "ui/views/controls/menu/menu_model_adapter.h"
30 #include "ui/views/controls/menu/menu_runner.h" 31 #include "ui/views/controls/menu/menu_runner.h"
31 #include "ui/views/controls/native/native_view_host.h" 32 #include "ui/views/controls/native/native_view_host.h"
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 NativeTextfieldWin::NativeTextfieldWin(Textfield* textfield) 89 NativeTextfieldWin::NativeTextfieldWin(Textfield* textfield)
89 : textfield_(textfield), 90 : textfield_(textfield),
90 tracking_double_click_(false), 91 tracking_double_click_(false),
91 double_click_time_(0), 92 double_click_time_(0),
92 can_discard_mousemove_(false), 93 can_discard_mousemove_(false),
93 contains_mouse_(false), 94 contains_mouse_(false),
94 ime_discard_composition_(false), 95 ime_discard_composition_(false),
95 ime_composition_start_(0), 96 ime_composition_start_(0),
96 ime_composition_length_(0), 97 ime_composition_length_(0),
97 container_view_(new NativeViewHost), 98 container_view_(new NativeViewHost),
98 bg_color_(0) { 99 bg_color_(0),
100 ALLOW_THIS_IN_INITIALIZER_LIST(
101 tsf_event_router_(base::win::IsTsfAwareRequired() ?
102 new ui::TsfEventRouter(this) : NULL)) {
99 if (!loaded_libarary_module_) { 103 if (!loaded_libarary_module_) {
100 // msftedit.dll is RichEdit ver 4.1. 104 // msftedit.dll is RichEdit ver 4.1.
101 // This version is available from WinXP SP1 and has TSF support. 105 // This version is available from WinXP SP1 and has TSF support.
102 loaded_libarary_module_ = LoadLibrary(L"msftedit.dll"); 106 loaded_libarary_module_ = LoadLibrary(L"msftedit.dll");
103 } 107 }
104 108
105 DWORD style = kDefaultEditStyle | ES_AUTOHSCROLL; 109 DWORD style = kDefaultEditStyle | ES_AUTOHSCROLL;
106 if (textfield_->style() & Textfield::STYLE_OBSCURED) 110 if (textfield_->style() & Textfield::STYLE_OBSCURED)
107 style |= ES_PASSWORD; 111 style |= ES_PASSWORD;
108 112
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 } 341 }
338 342
339 gfx::NativeView NativeTextfieldWin::GetTestingHandle() const { 343 gfx::NativeView NativeTextfieldWin::GetTestingHandle() const {
340 return m_hWnd; 344 return m_hWnd;
341 } 345 }
342 346
343 bool NativeTextfieldWin::IsIMEComposing() const { 347 bool NativeTextfieldWin::IsIMEComposing() const {
344 // Retrieve the length of the composition string to check if an IME is 348 // Retrieve the length of the composition string to check if an IME is
345 // composing text. (If this length is > 0 then an IME is being used to compose 349 // composing text. (If this length is > 0 then an IME is being used to compose
346 // text.) 350 // text.)
351 if (base::win::IsTsfAwareRequired())
352 return tsf_event_router_->IsImeComposing();
353
347 HIMC imm_context = ImmGetContext(m_hWnd); 354 HIMC imm_context = ImmGetContext(m_hWnd);
348 if (!imm_context) 355 if (!imm_context)
349 return false; 356 return false;
350 357
351 const int composition_size = ImmGetCompositionString(imm_context, GCS_COMPSTR, 358 const int composition_size = ImmGetCompositionString(imm_context, GCS_COMPSTR,
352 NULL, 0); 359 NULL, 0);
353 ImmReleaseContext(m_hWnd, imm_context); 360 ImmReleaseContext(m_hWnd, imm_context);
354 return composition_size > 0; 361 return composition_size > 0;
355 } 362 }
356 363
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 case IDS_APP_UNDO: Undo(); break; 468 case IDS_APP_UNDO: Undo(); break;
462 case IDS_APP_CUT: Cut(); break; 469 case IDS_APP_CUT: Cut(); break;
463 case IDS_APP_COPY: Copy(); break; 470 case IDS_APP_COPY: Copy(); break;
464 case IDS_APP_PASTE: Paste(); break; 471 case IDS_APP_PASTE: Paste(); break;
465 case IDS_APP_SELECT_ALL: SelectAll(false); break; 472 case IDS_APP_SELECT_ALL: SelectAll(false); break;
466 default: NOTREACHED(); break; 473 default: NOTREACHED(); break;
467 } 474 }
468 OnAfterPossibleChange(true); 475 OnAfterPossibleChange(true);
469 } 476 }
470 477
478 void NativeTextfieldWin::OnTextUpdated(const ui::Range& composition_range) {
479 if (ime_discard_composition_) {
480 ime_composition_start_ = composition_range.start();
481 ime_composition_length_ = composition_range.length();
482 } else {
483 ime_composition_start_ = 0;
484 ime_composition_length_ = 0;
485 }
486 OnAfterPossibleChange(false);
487 text_before_change_.clear();
488 }
489
490 void NativeTextfieldWin::OnImeStartCompositionInternal() {
491 // Users may press alt+shift or control+shift keys to change their keyboard
492 // layouts. So, we retrieve the input locale identifier everytime we start
493 // an IME composition.
494 int language_id = PRIMARYLANGID(GetKeyboardLayout(0));
495 ime_discard_composition_ =
496 language_id == LANG_JAPANESE || language_id == LANG_CHINESE;
497 ime_composition_start_ = 0;
498 ime_composition_length_ = 0;
499 }
500
501 void NativeTextfieldWin::OnImeEndCompositionInternal() {
502 // Bug 11863: Korean IMEs send a WM_IME_ENDCOMPOSITION message without
503 // sending any WM_IME_COMPOSITION messages when a user deletes all
504 // composition characters, i.e. a composition string becomes empty. To handle
505 // this case, we need to update the find results when a composition is
506 // finished or canceled.
507 textfield_->SyncText();
508 }
509
510 void NativeTextfieldWin::OnTsfStartComposition() {
511 OnImeStartCompositionInternal();
512 }
513
514 void NativeTextfieldWin::OnTsfEndComposition() {
515 OnImeEndCompositionInternal();
516 }
517
471 void NativeTextfieldWin::InitializeAccessibilityInfo() { 518 void NativeTextfieldWin::InitializeAccessibilityInfo() {
472 // Set the accessible state. 519 // Set the accessible state.
473 accessibility_state_ = 0; 520 accessibility_state_ = 0;
474 521
475 base::win::ScopedComPtr<IAccPropServices> pAccPropServices; 522 base::win::ScopedComPtr<IAccPropServices> pAccPropServices;
476 HRESULT hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER, 523 HRESULT hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
477 IID_IAccPropServices, reinterpret_cast<void**>(&pAccPropServices)); 524 IID_IAccPropServices, reinterpret_cast<void**>(&pAccPropServices));
478 if (!SUCCEEDED(hr)) 525 if (!SUCCEEDED(hr))
479 return; 526 return;
480 527
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
569 ui::Clipboard::GetForCurrentThread(), 616 ui::Clipboard::GetForCurrentThread(),
570 ui::Clipboard::BUFFER_STANDARD); 617 ui::Clipboard::BUFFER_STANDARD);
571 scw.WriteText(text); 618 scw.WriteText(text);
572 } 619 }
573 } 620 }
574 621
575 LRESULT NativeTextfieldWin::OnCreate(const CREATESTRUCTW* /*create_struct*/) { 622 LRESULT NativeTextfieldWin::OnCreate(const CREATESTRUCTW* /*create_struct*/) {
576 if (base::win::IsTsfAwareRequired()) { 623 if (base::win::IsTsfAwareRequired()) {
577 // Enable TSF support of RichEdit. 624 // Enable TSF support of RichEdit.
578 SetEditStyle(SES_USECTF, SES_USECTF); 625 SetEditStyle(SES_USECTF, SES_USECTF);
626
627 // When TSF is enabled, OnTextUpdated() may be called without any previous
628 // call that would have indicated the start of an editing session. In order
629 // to guarantee we've always called OnBeforePossibleChange() before
630 // OnAfterPossibleChange(), we therefore call that here. Note that multiple
631 // (i.e. unmatched) calls to this function in a row are safe.
632 OnBeforePossibleChange();
579 } 633 }
580 SetMsgHandled(FALSE); 634 SetMsgHandled(FALSE);
581 return 0; 635 return 0;
582 } 636 }
583 637
584 void NativeTextfieldWin::OnCut() { 638 void NativeTextfieldWin::OnCut() {
585 if (textfield_->read_only() || textfield_->IsObscured()) 639 if (textfield_->read_only() || textfield_->IsObscured())
586 return; 640 return;
587 641
588 OnCopy(); 642 OnCopy();
(...skipping 21 matching lines...) Expand all
610 // WM_IME_CHAR message while it is processing a WM_IME_COMPOSITION message. 664 // WM_IME_CHAR message while it is processing a WM_IME_COMPOSITION message.
611 // Since view controls don't need WM_IME_CHAR messages, we prevent WM_IME_CHAR 665 // Since view controls don't need WM_IME_CHAR messages, we prevent WM_IME_CHAR
612 // messages from being dispatched to view controls via the CallWindowProc() 666 // messages from being dispatched to view controls via the CallWindowProc()
613 // call. 667 // call.
614 return 0; 668 return 0;
615 } 669 }
616 670
617 LRESULT NativeTextfieldWin::OnImeStartComposition(UINT message, 671 LRESULT NativeTextfieldWin::OnImeStartComposition(UINT message,
618 WPARAM wparam, 672 WPARAM wparam,
619 LPARAM lparam) { 673 LPARAM lparam) {
620 // Users may press alt+shift or control+shift keys to change their keyboard 674 OnImeStartCompositionInternal();
621 // layouts. So, we retrieve the input locale identifier everytime we start
622 // an IME composition.
623 int language_id = PRIMARYLANGID(GetKeyboardLayout(0));
624 ime_discard_composition_ =
625 language_id == LANG_JAPANESE || language_id == LANG_CHINESE;
626 ime_composition_start_ = 0;
627 ime_composition_length_ = 0;
628
629 return DefWindowProc(message, wparam, lparam); 675 return DefWindowProc(message, wparam, lparam);
630 } 676 }
631 677
632 LRESULT NativeTextfieldWin::OnImeComposition(UINT message, 678 LRESULT NativeTextfieldWin::OnImeComposition(UINT message,
633 WPARAM wparam, 679 WPARAM wparam,
634 LPARAM lparam) { 680 LPARAM lparam) {
635 text_before_change_.clear(); 681 text_before_change_.clear();
636 LRESULT result = DefWindowProc(message, wparam, lparam); 682 LRESULT result = DefWindowProc(message, wparam, lparam);
637 683
638 ime_composition_start_ = 0; 684 ime_composition_start_ = 0;
(...skipping 26 matching lines...) Expand all
665 // setting the edit's text directly, which can cancel the current IME 711 // setting the edit's text directly, which can cancel the current IME
666 // composition or cause other adverse affects. So we set |should_redraw_text| 712 // composition or cause other adverse affects. So we set |should_redraw_text|
667 // to false. 713 // to false.
668 OnAfterPossibleChange(false); 714 OnAfterPossibleChange(false);
669 return result; 715 return result;
670 } 716 }
671 717
672 LRESULT NativeTextfieldWin::OnImeEndComposition(UINT message, 718 LRESULT NativeTextfieldWin::OnImeEndComposition(UINT message,
673 WPARAM wparam, 719 WPARAM wparam,
674 LPARAM lparam) { 720 LPARAM lparam) {
675 // Bug 11863: Korean IMEs send a WM_IME_ENDCOMPOSITION message without 721 OnImeEndCompositionInternal();
676 // sending any WM_IME_COMPOSITION messages when a user deletes all
677 // composition characters, i.e. a composition string becomes empty. To handle
678 // this case, we need to update the find results when a composition is
679 // finished or canceled.
680 textfield_->SyncText();
681 return DefWindowProc(message, wparam, lparam); 722 return DefWindowProc(message, wparam, lparam);
682 } 723 }
683 724
684 LRESULT NativeTextfieldWin::OnPointerDown(UINT message, WPARAM wparam, 725 LRESULT NativeTextfieldWin::OnPointerDown(UINT message, WPARAM wparam,
685 LPARAM lparam) { 726 LPARAM lparam) {
686 SetFocus(); 727 SetFocus();
687 SetMsgHandled(FALSE); 728 SetMsgHandled(FALSE);
688 return 0; 729 return 0;
689 } 730 }
690 731
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after
1004 1045
1005 void NativeTextfieldWin::OnSetFocus(HWND hwnd) { 1046 void NativeTextfieldWin::OnSetFocus(HWND hwnd) {
1006 SetMsgHandled(FALSE); // We still want the default processing of the message. 1047 SetMsgHandled(FALSE); // We still want the default processing of the message.
1007 1048
1008 views::FocusManager* focus_manager = textfield_->GetFocusManager(); 1049 views::FocusManager* focus_manager = textfield_->GetFocusManager();
1009 if (!focus_manager) { 1050 if (!focus_manager) {
1010 NOTREACHED(); 1051 NOTREACHED();
1011 return; 1052 return;
1012 } 1053 }
1013 focus_manager->SetFocusedView(textfield_); 1054 focus_manager->SetFocusedView(textfield_);
1055
1056 if (!base::win::IsTsfAwareRequired()) {
1057 return;
1058 }
1059
1060 DefWindowProc();
1061
1062 // Document manager created by RichEdit can be obtained only after
1063 // WM_SET_FOCUS event is handled.
1064 tsf_event_router_->SetManager(
1065 ui::TsfBridge::GetInstance()->GetThreadManager());
1066 SetMsgHandled(TRUE);
1067 }
1068
1069 void NativeTextfieldWin::OnKillFocus(HWND hwnd) {
1070 if(tsf_event_router_)
1071 tsf_event_router_->SetManager(NULL);
1014 } 1072 }
1015 1073
1016 void NativeTextfieldWin::OnSysChar(TCHAR ch, UINT repeat_count, UINT flags) { 1074 void NativeTextfieldWin::OnSysChar(TCHAR ch, UINT repeat_count, UINT flags) {
1017 // Nearly all alt-<xxx> combos result in beeping rather than doing something 1075 // Nearly all alt-<xxx> combos result in beeping rather than doing something
1018 // useful, so we discard most. Exceptions: 1076 // useful, so we discard most. Exceptions:
1019 // * ctrl-alt-<xxx>, which is sometimes important, generates WM_CHAR instead 1077 // * ctrl-alt-<xxx>, which is sometimes important, generates WM_CHAR instead
1020 // of WM_SYSCHAR, so it doesn't need to be handled here. 1078 // of WM_SYSCHAR, so it doesn't need to be handled here.
1021 // * alt-space gets translated by the default WM_SYSCHAR handler to a 1079 // * alt-space gets translated by the default WM_SYSCHAR handler to a
1022 // WM_SYSCOMMAND to open the application context menu, so we need to allow 1080 // WM_SYSCOMMAND to open the application context menu, so we need to allow
1023 // it through. 1081 // it through.
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1216 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); 1274 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
1217 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); 1275 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
1218 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); 1276 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
1219 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); 1277 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
1220 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); 1278 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
1221 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, 1279 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
1222 IDS_APP_SELECT_ALL); 1280 IDS_APP_SELECT_ALL);
1223 } 1281 }
1224 1282
1225 } // namespace views 1283 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/textfield/native_textfield_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698