Changeset 24285 in webkit
- Timestamp:
- Jul 14, 2007 1:21:24 AM (17 years ago)
- Location:
- trunk/WebKit/win
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebKit/win/ChangeLog
r24252 r24285 1 2007-07-13 Oliver Hunt <oliver@apple.com> 2 3 Reviewed by Darin and Alexey. 4 5 Fix for <rdar://problem/5231528> Inline input of International text (IME) 6 http://bugs.webkit.org/show_bug.cgi?id=14331 7 8 This patch adds IME support to WebKit/win, it currently does not support 9 reconversion (<rdar://problem/5334818>) and has issues with the chinese 10 IMEs (<rdar://problem/5334826>) 11 12 * WebEditorClient.cpp: 13 (WebEditorClient::respondToChangedSelection): 14 (WebEditorClient::handleInputMethodKeypress): 15 Prevent the initial keydown for an IME from triggering a keypressed event 16 * WebView.cpp: 17 (WebView::WebView): 18 (WebView::keyUp): 19 (WebView::keyDown): 20 (WebViewWndProc): 21 (IMMDict::dict): 22 (IMMDict::IMMDict): 23 Dynamic loader for IME libraries 24 25 (WebView::getIMMContext): 26 (WebView::releaseIMMContext): 27 (WebView::prepareCandidateWindow): 28 (selectionInsideMarkedText): 29 (setSelectionToEndOfRange): 30 (WebView::resetIME): 31 (WebView::updateSelectionForIME): 32 (WebView::selectionChanged): 33 (getCompositionString): 34 (compositionToUnderlines): 35 Helper functions 36 37 (WebView::onIMEStartComposition): 38 (WebView::onIMEComposition): 39 (WebView::onIMEEndComposition): 40 (WebView::onIMEChar): 41 (WebView::onIMENotify): 42 (WebView::onIMERequest): 43 (WebView::onIMESelect): 44 (WebView::onIMESetContext): 45 IME event handling, so far most of these are not implemented, but the bulk of functionality 46 is performed the the composition event handlers 47 * WebView.h: 48 1 49 2007-07-12 Alice Liu <alice.liu@apple.com> 2 50 -
trunk/WebKit/win/WebEditorClient.cpp
r23455 r24285 211 211 void WebEditorClient::respondToChangedSelection() 212 212 { 213 notImplemented();213 m_webView->selectionChanged(); 214 214 } 215 215 … … 598 598 } 599 599 600 void WebEditorClient::handleInputMethodKeypress(KeyboardEvent*) 601 { 600 void WebEditorClient::handleInputMethodKeypress(KeyboardEvent* evt) 601 { 602 // The key press that triggers an IME triggers a WM_KEYDOWN with VK_PROCESSKEY 603 // so we intercept and prevent the keypress from occurring 604 if (evt->keyEvent() && evt->keyEvent()->WindowsKeyCode() == VK_PROCESSKEY) 605 evt->setDefaultHandled(); 602 606 } 603 607 -
trunk/WebKit/win/WebView.cpp
r24166 r24285 91 91 #include <CFNetwork/CFURLProtocolPriv.h> 92 92 #include <tchar.h> 93 #include <dimm.h> 93 94 #include <windowsx.h> 94 95 #include <ShlObj.h> … … 136 137 , m_smartInsertDeleteEnabled(false) 137 138 , m_didClose(false) 139 , m_inIMEComposition(0) 138 140 , m_toolTipHwnd(0) 139 141 { … … 857 859 } 858 860 861 // Don't process keyDown events during IME composition 862 if (m_inIMEComposition) 863 return false; 864 859 865 PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, m_currentCharacterCode); 860 866 Frame* frame = m_page->focusController()->focusedOrMainFrame(); … … 987 993 return false; 988 994 995 // Don't process keyDown events during IME composition 996 if (m_inIMEComposition) 997 return false; 998 989 999 PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, m_currentCharacterCode); 990 1000 Frame* frame = m_page->focusController()->focusedOrMainFrame(); … … 1235 1245 // and we need to clear out the focused target. 1236 1246 FocusController* focusController = webView->page()->focusController(); 1247 webView->resetIME(focusController->focusedOrMainFrame()); 1237 1248 if (GetAncestor(hWnd, GA_ROOT) != GetFocus()) { 1238 1249 if (Frame* frame = focusController->focusedFrame()) { … … 1306 1317 break; 1307 1318 } 1319 1320 case WM_IME_STARTCOMPOSITION: 1321 handled = webView->onIMEStartComposition(); 1322 break; 1323 case WM_IME_REQUEST: 1324 webView->onIMERequest(wParam, lParam, &lResult); 1325 break; 1326 case WM_IME_COMPOSITION: 1327 handled = webView->onIMEComposition(lParam); 1328 break; 1329 case WM_IME_ENDCOMPOSITION: 1330 handled = webView->onIMEEndComposition(); 1331 break; 1332 case WM_IME_CHAR: 1333 handled = webView->onIMEChar(wParam, lParam); 1334 break; 1335 case WM_IME_NOTIFY: 1336 handled = webView->onIMENotify(wParam, lParam, &lResult); 1337 break; 1338 case WM_IME_SELECT: 1339 handled = webView->onIMESelect(wParam, lParam); 1340 break; 1341 case WM_IME_SETCONTEXT: 1342 handled = webView->onIMESetContext(wParam, lParam); 1343 break; 1308 1344 case WM_SETCURSOR: 1309 1345 if (lastSetCursor) { … … 3599 3635 } 3600 3636 3637 class IMMDict { 3638 typedef HIMC (CALLBACK *getContextPtr)(HWND); 3639 typedef BOOL (CALLBACK *releaseContextPtr)(HWND, HIMC); 3640 typedef LONG (CALLBACK *getCompositionStringPtr)(HIMC, DWORD, LPVOID, DWORD); 3641 typedef BOOL (CALLBACK *setCandidateWindowPtr)(HIMC, LPCANDIDATEFORM); 3642 typedef BOOL (CALLBACK *setOpenStatusPtr)(HIMC, BOOL); 3643 typedef BOOL (CALLBACK *notifyIMEPtr)(HIMC, DWORD, DWORD, DWORD); 3644 3645 public: 3646 getContextPtr getContext; 3647 releaseContextPtr releaseContext; 3648 getCompositionStringPtr getCompositionString; 3649 setCandidateWindowPtr setCandidateWindow; 3650 setOpenStatusPtr setOpenStatus; 3651 notifyIMEPtr notifyIME; 3652 static const IMMDict& dict(); 3653 private: 3654 IMMDict(); 3655 HMODULE m_instance; 3656 }; 3657 3658 const IMMDict& IMMDict::dict() 3659 { 3660 static IMMDict instance; 3661 return instance; 3662 } 3663 3664 IMMDict::IMMDict() 3665 { 3666 m_instance = ::LoadLibrary(TEXT("IMM32.DLL")); 3667 getContext = reinterpret_cast<getContextPtr>(::GetProcAddress(m_instance, "ImmGetContext")); 3668 ASSERT(getContext); 3669 releaseContext = reinterpret_cast<releaseContextPtr>(::GetProcAddress(m_instance, "ImmReleaseContext")); 3670 ASSERT(releaseContext); 3671 getCompositionString = reinterpret_cast<getCompositionStringPtr>(::GetProcAddress(m_instance, "ImmGetCompositionStringW")); 3672 ASSERT(getCompositionString); 3673 setCandidateWindow = reinterpret_cast<setCandidateWindowPtr>(::GetProcAddress(m_instance, "ImmSetCandidateWindow")); 3674 ASSERT(setCandidateWindow); 3675 setOpenStatus = reinterpret_cast<setOpenStatusPtr>(::GetProcAddress(m_instance, "ImmSetOpenStatus")); 3676 ASSERT(setOpenStatus); 3677 notifyIME = reinterpret_cast<notifyIMEPtr>(::GetProcAddress(m_instance, "ImmNotifyIME")); 3678 ASSERT(notifyIME); 3679 } 3680 3681 HIMC WebView::getIMMContext() 3682 { 3683 HIMC context = IMMDict::dict().getContext(m_viewWindow); 3684 ASSERT(context); 3685 return context; 3686 } 3687 3688 void WebView::releaseIMMContext(HIMC hIMC) 3689 { 3690 if (!hIMC) 3691 return; 3692 IMMDict::dict().releaseContext(m_viewWindow, hIMC); 3693 } 3694 3695 void WebView::prepareCandidateWindow(Frame* targetFrame, HIMC hInputContext) 3696 { 3697 IntRect caret; 3698 if (RefPtr<Range> range = targetFrame->selectionController()->selection().toRange()) { 3699 ExceptionCode ec = 0; 3700 RefPtr<Range> tempRange = range->cloneRange(ec); 3701 caret = targetFrame->firstRectForRange(tempRange.get()); 3702 } 3703 caret = targetFrame->view()->contentsToWindow(caret); 3704 CANDIDATEFORM form; 3705 form.dwIndex = 0; 3706 form.dwStyle = CFS_CANDIDATEPOS; 3707 form.ptCurrentPos.x = caret.x(); 3708 form.ptCurrentPos.y = caret.y() + caret.height(); 3709 form.rcArea.top = 0; 3710 form.rcArea.bottom = 0; 3711 form.rcArea.left = 0; 3712 form.rcArea.right = 0; 3713 IMMDict::dict().setCandidateWindow(hInputContext, &form); 3714 } 3715 3716 static bool markedTextContainsSelection(Range* markedTextRange, Range* selection) 3717 { 3718 ExceptionCode ec = 0; 3719 3720 ASSERT(markedTextRange->startContainer(ec) == markedTextRange->endContainer(ec)); 3721 3722 if (selection->startContainer(ec) != markedTextRange->startContainer(ec)) 3723 return false; 3724 3725 if (selection->endContainer(ec) != markedTextRange->endContainer(ec)) 3726 return false; 3727 3728 if (selection->startOffset(ec) < markedTextRange->startOffset(ec)) 3729 return false; 3730 3731 if (selection->endOffset(ec) > markedTextRange->endOffset(ec)) 3732 return false; 3733 3734 return true; 3735 } 3736 3737 static void setSelectionToEndOfRange(Frame* targetFrame, Range* sourceRange) 3738 { 3739 ExceptionCode ec = 0; 3740 Node* caretContainer = sourceRange->endContainer(ec); 3741 unsigned caretOffset = sourceRange->endOffset(ec); 3742 RefPtr<Range> range = targetFrame->document()->createRange(); 3743 range->setStart(caretContainer, caretOffset, ec); 3744 range->setEnd(caretContainer, caretOffset, ec); 3745 targetFrame->editor()->unmarkText(); 3746 targetFrame->selectionController()->setSelectedRange(range.get(), WebCore::DOWNSTREAM, true, ec); 3747 } 3748 3749 void WebView::resetIME(Frame* targetFrame) 3750 { 3751 if (targetFrame) 3752 targetFrame->editor()->unmarkText(); 3753 3754 if (HIMC hInputContext = getIMMContext()) { 3755 IMMDict::dict().notifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0); 3756 releaseIMMContext(hInputContext); 3757 } 3758 } 3759 3760 void WebView::updateSelectionForIME() 3761 { 3762 Frame* targetFrame = m_page->focusController()->focusedOrMainFrame(); 3763 if (!targetFrame || !targetFrame->markedTextRange()) 3764 return; 3765 3766 if (targetFrame->editor()->ignoreMarkedTextSelectionChange()) 3767 return; 3768 3769 RefPtr<Range> selectionRange = targetFrame->selectionController()->selection().toRange(); 3770 if (!selectionRange || !markedTextContainsSelection(targetFrame->markedTextRange(), selectionRange.get())) 3771 resetIME(targetFrame); 3772 } 3773 3774 void WebView::selectionChanged() 3775 { 3776 updateSelectionForIME(); 3777 } 3778 3779 bool WebView::onIMEStartComposition() 3780 { 3781 m_inIMEComposition++; 3782 Frame* targetFrame = m_page->focusController()->focusedOrMainFrame(); 3783 if (!targetFrame) 3784 return true; 3785 3786 //Tidy up in case the last IME composition was not correctly terminated 3787 targetFrame->editor()->unmarkText(); 3788 3789 HIMC hInputContext = getIMMContext(); 3790 prepareCandidateWindow(targetFrame, hInputContext); 3791 releaseIMMContext(hInputContext); 3792 return true; 3793 } 3794 3795 static bool getCompositionString(HIMC hInputContext, DWORD type, String& result) 3796 { 3797 int compositionLength = IMMDict::dict().getCompositionString(hInputContext, type, 0, 0); 3798 if (compositionLength <= 0) 3799 return false; 3800 Vector<UChar> compositionBuffer(compositionLength / 2); 3801 compositionLength = IMMDict::dict().getCompositionString(hInputContext, type, (LPVOID)compositionBuffer.data(), compositionLength); 3802 result = String(compositionBuffer, compositionLength / 2); 3803 ASSERT(!compositionLength || compositionBuffer[0]); 3804 ASSERT(!compositionLength || compositionBuffer[compositionLength / 2 - 1]); 3805 return true; 3806 } 3807 3808 static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, 3809 unsigned startOffset, Vector<MarkedTextUnderline>& underlines) 3810 { 3811 if (!clauses.size()) 3812 return; 3813 3814 const size_t numBoundaries = clauses.size() - 1; 3815 underlines.resize(numBoundaries); 3816 for (unsigned i = 0; i < numBoundaries; i++) { 3817 underlines[i].startOffset = startOffset + clauses[i]; 3818 underlines[i].endOffset = startOffset + clauses[i + 1]; 3819 BYTE attribute = attributes[clauses[i]]; 3820 underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED; 3821 underlines[i].color = Color(0,0,0); 3822 } 3823 } 3824 3825 bool WebView::onIMEComposition(LPARAM lparam) 3826 { 3827 HIMC hInputContext = getIMMContext(); 3828 if (!hInputContext) 3829 return true; 3830 3831 Frame* targetFrame = m_page->focusController()->focusedOrMainFrame(); 3832 if (!targetFrame || !targetFrame->editor()->canEdit()) 3833 return true; 3834 3835 prepareCandidateWindow(targetFrame, hInputContext); 3836 targetFrame->editor()->setIgnoreMarkedTextSelectionChange(true); 3837 3838 // if we had marked text already, we need to make sure to replace 3839 // that, instead of the selection/caret 3840 targetFrame->editor()->selectMarkedText(); 3841 3842 if (lparam & GCS_RESULTSTR || !lparam) { 3843 String compositionString; 3844 if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam) 3845 goto cleanup; 3846 3847 targetFrame->editor()->replaceMarkedText(compositionString); 3848 RefPtr<Range> sourceRange = targetFrame->selectionController()->selection().toRange(); 3849 setSelectionToEndOfRange(targetFrame, sourceRange.get()); 3850 } else if (lparam) { 3851 String compositionString; 3852 if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString)) 3853 goto cleanup; 3854 3855 targetFrame->editor()->replaceMarkedText(compositionString); 3856 3857 ExceptionCode ec = 0; 3858 RefPtr<Range> sourceRange = targetFrame->selectionController()->selection().toRange(); 3859 if (!sourceRange) 3860 goto cleanup; 3861 3862 Node* startContainer = sourceRange->startContainer(ec); 3863 const String& str = startContainer->textContent(); 3864 for (unsigned i = 0; i < str.length(); i++) 3865 ASSERT(str[i]); 3866 3867 unsigned startOffset = sourceRange->startOffset(ec); 3868 RefPtr<Range> range = targetFrame->document()->createRange(); 3869 range->setStart(startContainer, startOffset, ec); 3870 range->setEnd(startContainer, startOffset + compositionString.length(), ec); 3871 3872 // Composition string attributes 3873 int numAttributes = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPATTR, 0, 0); 3874 Vector<BYTE> attributes(numAttributes); 3875 IMMDict::dict().getCompositionString(hInputContext, GCS_COMPATTR, attributes.data(), numAttributes); 3876 3877 // Get clauses 3878 int numClauses = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, 0, 0); 3879 Vector<DWORD> clauses(numClauses / sizeof(DWORD)); 3880 IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, clauses.data(), numClauses); 3881 Vector<MarkedTextUnderline> underlines; 3882 compositionToUnderlines(clauses, attributes, startOffset, underlines); 3883 targetFrame->setMarkedTextRange(range.get(), underlines); 3884 if (targetFrame->markedTextRange()) 3885 targetFrame->selectRangeInMarkedText(LOWORD(IMMDict::dict().getCompositionString(hInputContext, GCS_CURSORPOS, 0, 0)), 0); 3886 } 3887 cleanup: 3888 targetFrame->editor()->setIgnoreMarkedTextSelectionChange(false); 3889 return true; 3890 } 3891 3892 bool WebView::onIMEEndComposition() 3893 { 3894 if (m_inIMEComposition) 3895 m_inIMEComposition--; 3896 Frame* targetFrame = m_page->focusController()->focusedOrMainFrame(); 3897 if (!targetFrame) 3898 return true; 3899 targetFrame->editor()->unmarkText(); 3900 return true; 3901 } 3902 3903 bool WebView::onIMEChar(WPARAM, LPARAM) 3904 { 3905 return true; 3906 } 3907 3908 bool WebView::onIMENotify(WPARAM, LPARAM, LRESULT*) 3909 { 3910 return false; 3911 } 3912 3913 bool WebView::onIMERequest(WPARAM, LPARAM, LRESULT*) 3914 { 3915 return false; 3916 } 3917 3918 bool WebView::onIMESelect(WPARAM, LPARAM) 3919 { 3920 return false; 3921 } 3922 3923 bool WebView::onIMESetContext(WPARAM, LPARAM) 3924 { 3925 return false; 3926 } 3927 3601 3928 class EnumTextMatches : public IEnumTextMatches 3602 3929 { -
trunk/WebKit/win/WebView.h
r24022 r24285 636 636 void setProhibitsMainFrameScrolling(bool = true); 637 637 638 bool onIMEStartComposition(); 639 bool onIMEComposition(LPARAM); 640 bool onIMEEndComposition(); 641 bool onIMEChar(WPARAM, LPARAM); 642 bool onIMENotify(WPARAM, LPARAM, LRESULT*); 643 bool onIMERequest(WPARAM, LPARAM, LRESULT*); 644 bool onIMESelect(WPARAM, LPARAM); 645 bool onIMESetContext(WPARAM, LPARAM); 646 void selectionChanged(); 647 void resetIME(WebCore::Frame*); 648 638 649 HRESULT registerDragDrop(); 639 650 HRESULT revokeDragDrop(); … … 656 667 657 668 protected: 658 static bool allowSiteSpecificHacks() { return s_allowSiteSpecificHacks; } 669 HIMC getIMMContext(); 670 void releaseIMMContext(HIMC); 671 static bool allowSiteSpecificHacks() { return s_allowSiteSpecificHacks; } 659 672 void preflightSpellChecker(); 660 673 bool continuousCheckingAllowed(); 661 674 void initializeCacheSizesIfNecessary(); 662 675 void initializeToolTipWindow(); 663 676 void prepareCandidateWindow(WebCore::Frame*, HIMC); 677 void updateSelectionForIME(); 664 678 ULONG m_refCount; 665 679 WebCore::String m_groupName; … … 701 715 bool m_smartInsertDeleteEnabled; 702 716 bool m_didClose; 703 717 unsigned m_inIMEComposition; 704 718 HWND m_toolTipHwnd; 705 719 WebCore::String m_toolTip;
Note: See TracChangeset
for help on using the changeset viewer.