From 2379791d20a6deb02313369f785eb26aa2b8a082 Mon Sep 17 00:00:00 2001 From: "shanjian%netscape.com" Date: Tue, 1 Oct 2002 02:47:41 +0000 Subject: [PATCH] #36975 Moving caret in convert mode using mouse Mouse event support for IME is added in this patch. r=yokoyama, sr=blizzard git-svn-id: svn://10.0.0.236/trunk@130870 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/widget/src/windows/nsWindow.cpp | 213 +++++++++++++++++------- mozilla/widget/src/windows/nsWindow.h | 24 ++- 2 files changed, 173 insertions(+), 64 deletions(-) diff --git a/mozilla/widget/src/windows/nsWindow.cpp b/mozilla/widget/src/windows/nsWindow.cpp index 36d6b9f60d0..0ea666a3def 100644 --- a/mozilla/widget/src/windows/nsWindow.cpp +++ b/mozilla/widget/src/windows/nsWindow.cpp @@ -110,6 +110,7 @@ #include "nsIFile.h" #include "prprf.h" +#include "prmem.h" static const char *kMozHeapDumpMessageString = "MOZ_HeapDump"; @@ -410,6 +411,16 @@ static PRBool is_vk_down(int vk) } \ } +#define NS_IMM_GETDEFAULTIMEWND(hWnd, phDefWnd) \ + { \ + if (nsToolkit::gAIMMApp) \ + return nsToolkit::gAIMMApp->GetDefaultIMEWnd(hWnd, phDefWnd); \ + else { \ + nsIMM& theIMM = nsIMM::LoadModule(); \ + *(phDefWnd) = (HWND)theIMM.GetDefaultIMEWnd(hWnd); \ + } \ + } + #else /* !MOZ_AIMM */ #define NS_IMM_GETCOMPOSITIONSTRING(hIMC, dwIndex, pBuf, dwBufLen, compStrLen) \ @@ -496,6 +507,11 @@ static PRBool is_vk_down(int vk) dwProp = (DWORD)theIMM.GetProperty(hKL, dwIndex); \ } +#define NS_IMM_GETDEFAULTIMEWND(hWnd, phDefWnd) \ + { \ + nsIMM& theIMM = nsIMM::LoadModule(); \ + *(phDefWnd) = theIMM.GetDefaultIMEWnd(hWnd); \ + } #endif /* MOZ_AIMM */ // @@ -777,19 +793,20 @@ nsWindow::nsWindow() : nsBaseWidget() mOldStyle = 0; mOldExStyle = 0; - mIMEProperty = 0; - mIMEIsComposing = PR_FALSE; + mIMEProperty = 0; + mIMEIsComposing = PR_FALSE; mIMEIsStatusChanged = PR_FALSE; - mIMECompString = NULL; - mIMECompUnicode = NULL; - mIMEAttributeString = NULL; - mIMEAttributeStringSize = 0; - mIMEAttributeStringLength = 0; - mIMECompClauseString = NULL; - mIMECompClauseStringSize = 0; - mIMECompClauseStringLength = 0; - mIMEReconvertUnicode = NULL; - mLeadByte = '\0'; + mIMECompString = NULL; + mIMECompUnicode = NULL; + mIMEAttributeString = NULL; + mIMEAttributeStringSize = 0; + mIMEAttributeStringLength = 0; + mIMECompClauseString = NULL; + mIMECompClauseStringSize = 0; + mIMECompClauseStringLength = 0; + mIMEReconvertUnicode = NULL; + mLeadByte = '\0'; + mIMECompCharPos = nsnull; static BOOL gbInitGlobalValue = FALSE; if(! gbInitGlobalValue) { @@ -3946,17 +3963,9 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT //SetFocus(); // this is bad //RelayMouseEvent(msg,wParam, lParam); { -#if IME_MOUSE_EVENT_SUPPORT // check whether IME window do mouse operation - if (mIMEIsComposing && nsWindow::uWM_MSIME_MOUSE) { - POINT ptPos; - ptPos.x = (short)LOWORD(lParam); - ptPos.y = (short)HIWORD(lParam); - if (IMECompositionHitTest(NS_MOUSE_LEFT_BUTTON_DOWN, &ptPos)) - if (HandleMouseActionOfIME(IMEMOUSE_LDOWN)) - break; - } -#endif + if (IMEMouseHandling(NS_MOUSE_LEFT_BUTTON_DOWN, IMEMOUSE_LDOWN, lParam)) + break; result = DispatchMouseEvent(NS_MOUSE_LEFT_BUTTON_DOWN, wParam); DispatchPendingEvents(); } break; @@ -3982,17 +3991,9 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT case WM_MBUTTONDOWN: { -#if IME_MOUSE_EVENT_SUPPORT // check whether IME window do mouse operation - if (mIMEIsComposing && nsWindow::uWM_MSIME_MOUSE) { - POINT ptPos; - ptPos.x = (short)LOWORD(lParam); - ptPos.y = (short)HIWORD(lParam); - if (IMECompositionHitTest(NS_MOUSE_MIDDLE_BUTTON_DOWN, &ptPos)) - if (HandleMouseActionOfIME(IMEMOUSE_MDOWN)) - break; - } -#endif + if (IMEMouseHandling(NS_MOUSE_MIDDLE_BUTTON_DOWN, IMEMOUSE_MDOWN, lParam)) + break; result = DispatchMouseEvent(NS_MOUSE_MIDDLE_BUTTON_DOWN, wParam); DispatchPendingEvents(); } break; @@ -4008,17 +4009,9 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT case WM_RBUTTONDOWN: { -#if IME_MOUSE_EVENT_SUPPORT // check whether IME window do mouse operation - if (mIMEIsComposing && nsWindow::uWM_MSIME_MOUSE) { - POINT ptPos; - ptPos.x = (short)LOWORD(lParam); - ptPos.y = (short)HIWORD(lParam); - if (IMECompositionHitTest(NS_MOUSE_RIGHT_BUTTON_DOWN, &ptPos)) - if (HandleMouseActionOfIME(IMEMOUSE_RDOWN)) - break; - } -#endif + if (IMEMouseHandling(NS_MOUSE_RIGHT_BUTTON_DOWN, IMEMOUSE_RDOWN, lParam)) + break; result = DispatchMouseEvent(NS_MOUSE_RIGHT_BUTTON_DOWN, wParam); DispatchPendingEvents(); } break; @@ -5753,6 +5746,24 @@ nsWindow::HandleTextEvent(HIMC hIMEContext,PRBool aCheckAttr) SetCaretPos( candForm.ptCurrentPos.x, candForm.ptCurrentPos.y); DestroyCaret(); } + + // Record previous composing char position + // The cursor is always on the right char before it, but not nessarily on the + // left of next char, as what happens in wrapping. + if (mIMECursorPosition && + mIMECompCharPos && + mIMECursorPosition < IME_MAX_CHAR_POS) { + mIMECompCharPos[mIMECursorPosition-1].right = event.theReply.mCursorPosition.x; + mIMECompCharPos[mIMECursorPosition-1].top = event.theReply.mCursorPosition.y; + mIMECompCharPos[mIMECursorPosition-1].bottom = event.theReply.mCursorPosition.YMost(); + if (mIMECompCharPos[mIMECursorPosition-1].top != event.theReply.mCursorPosition.y) { + // wrapping, invalidate left position + mIMECompCharPos[mIMECursorPosition-1].left = -1; + } + mIMECompCharPos[mIMECursorPosition].left = event.theReply.mCursorPosition.x; + mIMECompCharPos[mIMECursorPosition].top = event.theReply.mCursorPosition.y; + mIMECompCharPos[mIMECursorPosition].bottom = event.theReply.mCursorPosition.YMost(); + } } else { // for some reason we don't know yet, theReply may contains invalid result // need more debugging in nsCaret to find out the reason @@ -5803,11 +5814,20 @@ nsWindow::HandleStartComposition(HIMC hIMEContext) } NS_IMM_SETCANDIDATEWINDOW(hIMEContext, &candForm); + + mIMECompCharPos = (RECT*)PR_MALLOC(IME_MAX_CHAR_POS*sizeof(RECT)); + if (mIMECompCharPos) { + memset(mIMECompCharPos, -1, sizeof(RECT)*IME_MAX_CHAR_POS); + mIMECompCharPos[0].left = event.theReply.mCursorPosition.x; + mIMECompCharPos[0].top = event.theReply.mCursorPosition.y; + mIMECompCharPos[0].bottom = event.theReply.mCursorPosition.YMost(); + } } else { // for some reason we don't know yet, theReply may contains invalid result // need more debugging in nsCaret to find out the reason // the best we can do now is to ignore the invalid result } + NS_RELEASE(event.widget); if(nsnull == mIMECompString) @@ -5840,6 +5860,8 @@ nsWindow::HandleEndComposition(void) event.compositionMessage = NS_COMPOSITION_END; (void)DispatchWindowEvent(&event); NS_RELEASE(event.widget); + PR_FREEIF(mIMECompCharPos); + mIMECompCharPos = nsnull; mIMEIsComposing = PR_FALSE; } @@ -6586,10 +6608,37 @@ NS_IMETHODIMP nsWindow::ResetInputState() } -#if IME_MOUSE_EVENT_SUPPORT +#define PT_IN_RECT(pt, rc) ((pt).x>(rc).left && (pt).x <(rc).right && (pt).y>(rc).top && (pt).y<(rc).bottom) + // Mouse operation of IME +PRBool +nsWindow::IMEMouseHandling(PRUint32 aEventType, PRInt32 aAction, LPARAM lParam) +{ + POINT ptPos; + ptPos.x = (short)LOWORD(lParam); + ptPos.y = (short)HIWORD(lParam); + + if (mIMEIsComposing && nsWindow::uWM_MSIME_MOUSE) { + if (IMECompositionHitTest(aEventType, &ptPos)) + if (HandleMouseActionOfIME(aAction, &ptPos)) + return PR_TRUE; + } else { + HWND parentWnd = ::GetParent(mWnd); + if (parentWnd) { + nsWindow* parentWidget = GetNSWindowPtr(parentWnd); + if (parentWidget->mIMEIsComposing && nsWindow::uWM_MSIME_MOUSE) { + if (parentWidget->IMECompositionHitTest(aEventType, &ptPos)) + if (parentWidget->HandleMouseActionOfIME(aAction, &ptPos)) + return PR_TRUE; + } + } + } + return PR_FALSE; +} + + PRBool -nsWindow::HandleMouseActionOfIME(int aAction) +nsWindow::HandleMouseActionOfIME(int aAction, POINT *ptPos) { PRBool IsHandle = PR_FALSE; @@ -6600,15 +6649,32 @@ nsWindow::HandleMouseActionOfIME(int aAction) int positioning = 0; int offset = 0; - // get location of each compositon charactors - // calcurate positioning and offset + // char : JCH1|JCH2|JCH3 + // offset: 0011 1122 2233 + // positioning: 2301 2301 2301 + + // Note: hitText has been done, so no check of mIMECompCharPos + // and composing char maximum limit is necessary. + for (PRInt32 i = 0; i < mIMECompUnicode->Length(); i++) { + if (PT_IN_RECT(*ptPos, mIMECompCharPos[i])) + break; + } + offset = i; + if (ptPos->x - mIMECompCharPos[i].left > mIMECompCharPos[i].right - ptPos->x) + offset++; + + positioning = (ptPos->x - mIMECompCharPos[i].left) * 4 / + (mIMECompCharPos[i].right - mIMECompCharPos[i].left); + positioning = (positioning + 2) % 4; // send MS_MSIME_MOUSE message to default IME window. + HWND imeWnd; + NS_IMM_GETDEFAULTIMEWND(mWnd, &imeWnd); #ifdef MOZ_UNICODE - if (nsToolkit::mSendMessage(mWnd, nsWindow::uWM_MSIME_MOUSE, MAKELONG(MAKEWORD(aAction, positioning), offset), (LPARAM) hIMC) == 1) + if (nsToolkit::mSendMessage(imeWnd, nsWindow::uWM_MSIME_MOUSE, MAKELONG(MAKEWORD(aAction, positioning), offset), (LPARAM) hIMC) == 1) #else - if (::SendMessage(mWnd, nsWindow::uWM_MSIME_MOUSE, MAKELONG(MAKEWORD(aAction, positioning), offset), (LPARAM) hIMC) == 1) + if (::SendMessage(imeWnd, nsWindow::uWM_MSIME_MOUSE, MAKELONG(MAKEWORD(aAction, positioning), offset), (LPARAM) hIMC) == 1) #endif IsHandle = PR_TRUE; } @@ -6623,18 +6689,45 @@ PRBool nsWindow::IMECompositionHitTest(PRUint32 aEventType, POINT * ptPos) { PRBool IsHit = PR_FALSE; - COMPOSITIONFORM cpForm; + if (mIMECompCharPos){ + // figure out how many char in composing string, + // but keep it below the limit we can handle + PRInt32 len = mIMECompUnicode->Length(); + if (len > IME_MAX_CHAR_POS) + len = IME_MAX_CHAR_POS; + + PRInt32 i; + PRInt32 aveWidth = 0; + // found per char width + for (i = 0; i < len; i++) { + if (mIMECompCharPos[i].left >= 0 && mIMECompCharPos[i].right > 0) { + aveWidth = mIMECompCharPos[i].right - mIMECompCharPos[i].left; + break; + } + } + + // validate each rect and test + for (i = 0; i < len; i++) { + if (mIMECompCharPos[i].left < 0) { + if (i != 0 && mIMECompCharPos[i-1].top == mIMECompCharPos[i].top) + mIMECompCharPos[i].left = mIMECompCharPos[i-1].right; + else + mIMECompCharPos[i].left = mIMECompCharPos[i].right - aveWidth; + } + if (mIMECompCharPos[i].right < 0) + mIMECompCharPos[i].right = mIMECompCharPos[i].left + aveWidth; + if (mIMECompCharPos[i].top < 0) { + mIMECompCharPos[i].top = mIMECompCharPos[i-1].top; + mIMECompCharPos[i].bottom = mIMECompCharPos[i-1].bottom; + } + + if (PT_IN_RECT(*ptPos, mIMECompCharPos[i])) { + IsHit = PR_TRUE; + break; + } + } + } - if (mWnd) { - HIMC hIMC = NULL; - NS_IMM_GETCONTEXT(mWnd, hIMC); - if (hIMC) { - GetCompositionWindowPos(hIMC, aEventType, &cpForm); - if (PtInRect(&cpForm.rcArea, *ptPos)) - IsHit = PR_TRUE; - } - NS_IMM_RELEASECONTEXT(mWnd, hIMC); - } return IsHit; } @@ -6669,8 +6762,6 @@ void nsWindow::GetCompositionWindowPos(HIMC hIMC, PRUint32 aEventType, COMPOSITI cpForm->rcArea.bottom = cpForm->ptCurrentPos.y + event.theReply.mCursorPosition.height; } -#endif - // This function is called on a timer to do the flashing. It simply toggles the flash // status until the window comes to the foreground. static VOID CALLBACK nsGetAttentionTimerFunc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) { diff --git a/mozilla/widget/src/windows/nsWindow.h b/mozilla/widget/src/windows/nsWindow.h index 51bea41817a..b1403583104 100644 --- a/mozilla/widget/src/windows/nsWindow.h +++ b/mozilla/widget/src/windows/nsWindow.h @@ -65,6 +65,8 @@ struct IAccessible; #include "nsIAccessibleEventListener.h" #endif +#define IME_MAX_CHAR_POS 64 + #define NSRGB_2_COLOREF(color) \ RGB(NS_GET_R(color),NS_GET_G(color),NS_GET_B(color)) #define COLOREF_2_NSRGB(color) \ @@ -88,7 +90,7 @@ class nsIMM typedef LONG (CALLBACK *SetCompFontPtr) (HIMC, PLOGFONT); typedef LONG (CALLBACK *GetCompWindowPtr) (HIMC,LPCOMPOSITIONFORM); typedef LONG (CALLBACK *GetPropertyPtr) (HKL, DWORD); - + typedef LONG (CALLBACK *GetDefaultIMEWndPtr) (HWND); public: static nsIMM& LoadModule() { @@ -144,6 +146,9 @@ public: mGetProperty=(mInstance) ? (GetPropertyPtr)GetProcAddress(mInstance,"ImmGetProperty") : 0; NS_ASSERTION(mGetProperty!=NULL,"nsIMM.ImmGetProperty failed."); + + mGetDefaultIMEWnd=(mInstance) ? (GetDefaultIMEWndPtr)GetProcAddress(mInstance,"ImmGetDefaultIMEWnd") : 0; + NS_ASSERTION(mGetDefaultIMEWnd!=NULL,"nsIMM.ImmGetDefaultIMEWnd failed."); } ~nsIMM() { @@ -165,6 +170,7 @@ public: mSetCompositionFontW=0; mSetCompositionFontW=0; mGetProperty=0; + mGetDefaultIMEWnd=0; } LONG GetCompositionStringA(HIMC h,DWORD d1,LPVOID v,DWORD d2) { @@ -227,6 +233,10 @@ public: return (mGetProperty) ? mGetProperty(hKL, dwIndex) : 0L; } + LONG GetDefaultIMEWnd(HWND hWnd) { + return (mGetDefaultIMEWnd) ? mGetDefaultIMEWnd(hWnd) : 0L; + } + private: HINSTANCE mInstance; @@ -245,6 +255,7 @@ private: SetCompFontPtr mSetCompositionFontW; GetCompWindowPtr mGetCompositionWindow; GetPropertyPtr mGetProperty; + GetDefaultIMEWndPtr mGetDefaultIMEWnd; }; /** @@ -363,6 +374,11 @@ public: NS_IMETHOD ResetInputState(); + PRBool IMEMouseHandling(PRUint32 aEventType, PRInt32 aAction, LPARAM lParam); + PRBool IMECompositionHitTest(PRUint32 aEventType, POINT * ptPos); + PRBool HandleMouseActionOfIME(PRInt32 aAction, POINT* ptPos); + void GetCompositionWindowPos(HIMC hIMC, PRUint32 aEventType, COMPOSITIONFORM *cpForm); + HWND mBorderlessParent; // nsSwitchToUIThread interface @@ -529,8 +545,10 @@ protected: PRInt32 mIMECompClauseStringLength; PRInt32 mIMECompClauseStringSize; long mIMECursorPosition; - - PRUnichar* mIMEReconvertUnicode; // reconvert string + PRUnichar* mIMEReconvertUnicode; // reconvert string + + // For describing composing frame + RECT* mIMECompCharPos; static UINT gCurrentKeyboardCP; static HKL gKeyboardLayout;