/*++ Copyright (c) 2001, Microsoft Corporation Module Name: uiwndhd.cpp Abstract: This file implements the IME UI window handler Class. Author: Revision History: Notes: --*/ #include "private.h" #include "uiwndhd.h" #include "tls.h" #include "profile.h" #include "msime.h" #include "setmode.h" #include "ui.h" #define UIWND_TIMERID_IME_COMPOSITION 0 #define UIWND_TIMERID_IME_SETCONTEXTAFTER 1 #define UIWND_TIMERID_IME_DELAYUNDORECONV 2 /* static */ LRESULT CIMEUIWindowHandler::ImeUIWndProcWorker( HWND hUIWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LONG lRet = 0L; TLS* ptls = TLS::GetTLS(); if (ptls && (ptls->GetSystemInfoFlags() & IME_SYSINFO_WINLOGON)) { if (uMsg == WM_CREATE) return -1L; else return DefWindowProc(hUIWnd, uMsg, wParam, lParam); } switch (uMsg) { case WM_CREATE: UI::OnCreate(hUIWnd); break; case WM_IME_NOTIFY: return ImeUINotifyHandler(hUIWnd, uMsg, wParam, lParam); case WM_ENDSESSION: if (wParam && lParam) { UI::OnDestroy(hUIWnd); break; } case WM_DESTROY: UI::OnDestroy(hUIWnd); break; case WM_IME_SETCONTEXT: case WM_IME_SELECT: case WM_IME_STARTCOMPOSITION: case WM_IME_COMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_TIMER: { UI* pv = (UI*)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE); if (pv == NULL) { DebugMsg(TF_ERROR, TEXT("CIMEUIWindowHandler::ImeUIWndProcWorker. pv==NULL")); break; } HIMC hImc = (HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC); IMCLock imc(hImc); // // Should not return when IMCLock failed. // If application associate NULL hIMC, below method never work. // Inside of each method must validate check of imc object. // // if (FAILED(imc.GetResult())) // { // DebugMsg(TF_ERROR, TEXT("ImeUIWndProcWorker. imc==NULL")); // break; // } switch (uMsg) { case WM_IME_SETCONTEXT: pv->OnImeSetContext(imc, (BOOL)wParam, (DWORD)lParam); KillTimer(hUIWnd, UIWND_TIMERID_IME_SETCONTEXTAFTER); SetTimer(hUIWnd, UIWND_TIMERID_IME_SETCONTEXTAFTER, 300, NULL); break; case WM_IME_SELECT: pv->OnImeSelect((BOOL)wParam); break; case WM_IME_STARTCOMPOSITION: pv->OnImeStartComposition(imc); break; case WM_IME_COMPOSITION: // // use time to delay to calc the size of the window. // if (lParam & GCS_COMPSTR) { pv->OnImeCompositionUpdate(imc); SetTimer(hUIWnd, UIWND_TIMERID_IME_COMPOSITION, 10, NULL); pv->OnSetCompositionTimerStatus(TRUE); } break; case WM_TIMER: switch (wParam) { case UIWND_TIMERID_IME_COMPOSITION: KillTimer(hUIWnd, UIWND_TIMERID_IME_COMPOSITION); pv->OnSetCompositionTimerStatus(FALSE); pv->OnImeCompositionUpdateByTimer(imc); break; case UIWND_TIMERID_IME_SETCONTEXTAFTER: KillTimer(hUIWnd, UIWND_TIMERID_IME_SETCONTEXTAFTER); pv->OnImeSetContextAfter(imc); break; case UIWND_TIMERID_IME_DELAYUNDORECONV: KillTimer(hUIWnd, UIWND_TIMERID_IME_DELAYUNDORECONV); ImeUIDelayedReconvertFuncCall(hUIWnd); break; } break; case WM_IME_ENDCOMPOSITION: KillTimer(hUIWnd, UIWND_TIMERID_IME_COMPOSITION); pv->OnSetCompositionTimerStatus(FALSE); pv->OnImeEndComposition(); break; } } break; default: if (IsMsImeMessage(uMsg)) return ImeUIMsImeHandler(hUIWnd, uMsg, wParam, lParam); else return DefWindowProc(hUIWnd, uMsg, wParam, lParam); } return lRet; } /* static */ LRESULT CIMEUIWindowHandler::ImeUINotifyHandler( HWND hUIWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DebugMsg(TF_FUNC, TEXT("ImeUINotifyHandler")); HRESULT hr; IMCLock imc((HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC)); if (FAILED(hr=imc.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUINotifyHandler. imc==NULL")); return 0L; } IMCCLock imc_ctfime(imc->hCtfImeContext); if (FAILED(hr=imc_ctfime.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUINotifyHandler. imc_ctfime==NULL")); return 0L; } CicInputContext* _pCicContext = imc_ctfime->m_pCicContext; if (_pCicContext == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUINotifyHandler. _pCicContext==NULL")); return 0L; } switch (wParam) { case IMN_SETOPENSTATUS: // // we can track this in SetOpenStatus(). // Don't have to sync when IMM32 is called. // // _pImmIfIME->OnSetOpenStatus(imc); break; case IMN_SETSTATUSWINDOWPOS: case IMN_OPENSTATUSWINDOW: case IMN_CLOSESTATUSWINDOW: break; case IMN_SETCONVERSIONMODE: case IMN_SETSENTENCEMODE: // // we can track this in SetConversionMode(). // Don't have to sync when IMM32 is called. // // _pImmIfIME->OnSetConversionSentenceMode(imc); break; case IMN_OPENCANDIDATE: _pCicContext->m_fOpenCandidateWindow.SetFlag(); _pCicContext->ClearPrevCandidatePos(); // fall through to call OnSetCandidatePos(). case IMN_SETCANDIDATEPOS: case IMN_CHANGECANDIDATE: { TLS* ptls = TLS::GetTLS(); if (ptls == NULL) { DebugMsg(TF_ERROR, TEXT("CIMEUIWindowHandler::ImeUINotifyHandler. ptls==NULL.")); return FALSE; } _pCicContext->OnSetCandidatePos(ptls, imc); } break; case IMN_CLOSECANDIDATE: _pCicContext->m_fOpenCandidateWindow.ResetFlag(); { HWND hDefImeWnd; /* * A-Synchronize call ImmIfIME::ClearDocFeedBuffer * because this method had a protected. */ if (IsWindow(hDefImeWnd=ImmGetDefaultIMEWnd(NULL))) { PostMessage(hDefImeWnd, WM_IME_NOTIFY, IMN_PRIVATE_ONCLEARDOCFEEDBUFFER, (LPARAM)(HIMC)imc); } } break; case IMN_SETCOMPOSITIONWINDOW: _pCicContext->ResetIMECharPosition(); { UI* pv = (UI*)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE); if (pv == NULL) { DebugMsg(TF_ERROR, TEXT("CIMEUIWindowHandler::ImeUINotifyHandler. pv==NULL")); break; } pv->OnImeNotifySetCompositionWindow(imc); ImeUIOnLayoutChange((HIMC)imc); } break; case IMN_SETCOMPOSITIONFONT: { UI* pv = (UI*)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE); if (pv == NULL) { DebugMsg(TF_ERROR, TEXT("CIMEUIWindowHandler::ImeUINotifyHandler. pv==NULL")); break; } pv->OnImeNotifySetCompositionFont(imc); // // Get IME level and call ImeUIOnLayoutChange for only Level1 and Level2 cases. // IME_UIWND_STATE uists; hr = pv->OnPrivateGetContextFlag(imc, _pCicContext->m_fStartComposition.IsSetFlag(), &uists); if (hr == S_OK && ((uists == IME_UIWND_LEVEL1) || (uists == IME_UIWND_LEVEL2))) ImeUIOnLayoutChange((HIMC)imc); } break; case IMN_GUIDELINE: break; case WM_IME_STARTCOMPOSITION: { TLS* ptls = TLS::GetTLS(); if (ptls != NULL) { LANGID langid; CicProfile* _pProfile = ptls->GetCicProfile(); if (_pProfile != NULL) { _pProfile->GetLangId(&langid); _pCicContext->InquireIMECharPosition(langid, imc, NULL); } } } break; case WM_IME_ENDCOMPOSITION: _pCicContext->ResetIMECharPosition(); break; case IMN_PRIVATE_ONLAYOUTCHANGE: ImeUIOnLayoutChange((HIMC)lParam); break; case IMN_PRIVATE_ONCLEARDOCFEEDBUFFER: ImeUIPrivateHandler(uMsg, wParam, lParam); break; case IMN_PRIVATE_GETCONTEXTFLAG: case IMN_PRIVATE_GETCANDRECTFROMCOMPOSITION: case IMN_PRIVATE_GETTEXTEXT: { UI* pv = (UI*)GetWindowLongPtr(hUIWnd, IMMGWLP_PRIVATE); if (pv == NULL) { DebugMsg(TF_ERROR, TEXT("CIMEUIWindowHandler::ImeUINotifyHandler. pv==NULL")); break; } switch (wParam) { case IMN_PRIVATE_GETCONTEXTFLAG: { IME_UIWND_STATE uists; pv->OnPrivateGetContextFlag(imc, _pCicContext->m_fStartComposition.IsSetFlag(), &uists); return (LRESULT)uists; } break; case IMN_PRIVATE_GETCANDRECTFROMCOMPOSITION: return pv->OnPrivateGetCandRectFromComposition(imc, (UIComposition::CandRectFromComposition*)lParam); case IMN_PRIVATE_GETTEXTEXT: { pv->OnPrivateGetTextExtent(imc, (UIComposition::TEXTEXT*)lParam); return 1L; } } } break; case IMN_PRIVATE_STARTLAYOUTCHANGE: ImeUIOnLayoutChange((HIMC)imc); break; case IMN_PRIVATE_DELAYRECONVERTFUNCCALL: SetTimer(hUIWnd, UIWND_TIMERID_IME_DELAYUNDORECONV, 100, NULL); break; case IMN_PRIVATE_GETUIWND: return (LRESULT)hUIWnd; } return 0L; } /* static */ LRESULT CIMEUIWindowHandler::ImeUIDelayedReconvertFuncCall( HWND hUIWnd) { DebugMsg(TF_FUNC, TEXT("ImeUINotifyHandler")); HRESULT hr; IMCLock imc((HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC)); if (FAILED(hr=imc.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIDelayedReconvertFuncCall. imc==NULL")); return 0L; } IMCCLock imc_ctfime(imc->hCtfImeContext); if (FAILED(hr=imc_ctfime.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIDelayedReconvertFuncCall. imc_ctfime==NULL")); return 0L; } CicInputContext* _pCicContext = imc_ctfime->m_pCicContext; if (_pCicContext == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIDelayedReconvertFuncCall. _pCicContext==NULL")); return 0L; } _pCicContext->DelayedReconvertFuncCall(imc); return 0L; } /* static */ LRESULT CIMEUIWindowHandler::ImeUIMsImeHandler( HWND hUIWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (uMsg == WM_MSIME_MOUSE) { return ImeUIMsImeMouseHandler(hUIWnd, uMsg, wParam, lParam); } else if (uMsg == WM_MSIME_MODEBIAS) { return ImeUIMsImeModeBiasHandler(hUIWnd, wParam, lParam); } else if (uMsg == WM_MSIME_RECONVERTREQUEST) { return ImeUIMsImeReconvertRequest(hUIWnd, uMsg, wParam, lParam); } else if (uMsg == WM_MSIME_SERVICE) { TLS* ptls = TLS::GetTLS(); if (ptls != NULL) { LANGID langid; CicProfile* _pProfile = ptls->GetCicProfile(); if (_pProfile != NULL) { _pProfile->GetLangId(&langid); if (PRIMARYLANGID(langid) == LANG_KOREAN) return 0L; } } return 1L; // Win32 Layer support WM_MSIME_xxxx message. } return 0L; } /* static */ LRESULT CIMEUIWindowHandler::ImeUIMsImeMouseHandler( HWND hUIWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) /*++ Method: WM_MSIME_MOUSE Routine Description: Mouse Operation on Composition String Arguments: wParam - Mouse operation code. LOBYTE(LOWORD(wParam)) IMEMOUSE_VERSION IMEMOUSE_NONE IMEMOUSE_LDOWN IMEMOUSE_RDOWN IMEMOUSE_MDOWN IMEMOUSE_WUP IMEMOUSE_WDOWN HIBYTE(LOWORD(wParam)) Mouse Position HIWORD(wParam) Clicked position lParam - Input Context handle (HIMC). Return Value: Returns 1 if IME handled this message. IMEMOUSERET_NOTHANDLED if IME did not handled this message. --*/ { DebugMsg(TF_FUNC, TEXT("ImeUIMsImeMouseHandler")); ULONG dwBtnStatus; // special case: version check if (LOBYTE(LOWORD(wParam)) == IMEMOUSE_VERSION) return 1; // we support version 1.0 HRESULT hr; IMCLock imc((HIMC)lParam); if (FAILED(hr=imc.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeMouseHandler. imc==NULL")); return IMEMOUSERET_NOTHANDLED; } IMCCLock imc_ctfime(imc->hCtfImeContext); if (FAILED(hr=imc_ctfime.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeMouseHandler. imc_ctfime==NULL")); return IMEMOUSERET_NOTHANDLED; } CicInputContext* _pCicContext = imc_ctfime->m_pCicContext; if (_pCicContext == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeMouseHandler. _pCicContext==NULL")); return IMEMOUSERET_NOTHANDLED; } ULONG uEdge = HIWORD(wParam); ULONG uQuadrant = HIBYTE(LOWORD(wParam)); ULONG dwBtnStatusIme = LOBYTE(LOWORD(wParam)); // // need to xlate dwBtnStatus from WM_MSIME_MOUSE flags to WM_MOUSE flags // dwBtnStatus = 0; if (dwBtnStatusIme & IMEMOUSE_LDOWN) { dwBtnStatus |= MK_LBUTTON; } if (dwBtnStatusIme & IMEMOUSE_MDOWN) { dwBtnStatus |= MK_MBUTTON; } if (dwBtnStatusIme & IMEMOUSE_RDOWN) { dwBtnStatus |= MK_RBUTTON; } // mouse wheel needs to be xlated from IMEMOUSE_WUP/IMEMOUSE_WDOWN to WHEEL_DELTA units if (dwBtnStatusIme & IMEMOUSE_WUP) { dwBtnStatus |= (WHEEL_DELTA << 16); } else if (dwBtnStatusIme & IMEMOUSE_WDOWN) { dwBtnStatus |= (((unsigned long)(-WHEEL_DELTA)) << 16); } return _pCicContext->MsImeMouseHandler(uEdge, uQuadrant, dwBtnStatus, imc); } /*++ Method: CIMEUIWindowHandler::ImeUIMsImeModeBiasHandler Routine Description: Handles WM_MSIME_MODEBIAS messages sent to the ui window. Arguments: wParam - [in] operation: get version, get mode, set mode lParam - [in] for set mode, the new bias otherwise ignored Return Value: If wParam is MODEBIAS_GETVERSION, returns version number of interface. If wParam is MODEBIAS_SETVALUE, returns non-zero value if succeeded. Returns 0 if fail. If wParam is MODEBIAS_GETVALUE, returns current bias mode. --*/ /* static */ LRESULT CIMEUIWindowHandler::ImeUIMsImeModeBiasHandler( HWND hUIWnd, WPARAM wParam, LPARAM lParam) { DebugMsg(TF_FUNC, TEXT("ImeUIMsImeModeBiasHandler")); if (wParam == MODEBIAS_GETVERSION) return 1; // version 1 HRESULT hr; IMCLock imc((HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC)); if (FAILED(hr=imc.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeModeBiasHandler. imc==NULL")); return 0; } IMCCLock imc_ctfime(imc->hCtfImeContext); if (FAILED(hr=imc_ctfime.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeModeBiasHandler. imc_ctfime==NULL")); return 0; } CicInputContext* _pCicContext = imc_ctfime->m_pCicContext; if (_pCicContext == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeModeBiasHandler. _pCicContext==NULL")); return 0; } GUID guidModeBias; switch (wParam) { case MODEBIAS_GETVALUE: guidModeBias = _pCicContext->m_ModeBias.GetModeBias(); return _pCicContext->m_ModeBias.ConvertModeBias(guidModeBias); case MODEBIAS_SETVALUE: // check lParam if (lParam != MODEBIASMODE_DEFAULT && lParam != MODEBIASMODE_FILENAME && lParam != MODEBIASMODE_DIGIT && lParam != MODEBIASMODE_URLHISTORY ) { Assert(0); // bogus mode bias! return 0; // failure } // set the new value guidModeBias = _pCicContext->m_ModeBias.ConvertModeBias(lParam); _pCicContext->m_ModeBias.SetModeBias(guidModeBias); _pCicContext->m_fOnceModeChanged.SetFlag(); // let cicero know the mode bias has changed Interface_Attach iccb = _pCicContext->GetInputContextOwnerSink(); iccb->OnAttributeChange(GUID_PROP_MODEBIAS); return 1; // success } Assert(0); // should never get here; bogus wParam return 0; } /* static */ LRESULT CIMEUIWindowHandler::ImeUIPrivateHandler( UINT uMsg, WPARAM wParam, LPARAM lParam) /*++ Method: CIMEUIWindowHandler::ImeUIPrivateHandler Routine Description: Handles WM_PRIVATE_xxx messages sent to the ui window. Arguments: lParam - [in] HIMC : input context handle Return Value: --*/ { DebugMsg(TF_FUNC, TEXT("ImeUIPrivateHandler")); HRESULT hr; IMCLock imc((HIMC)lParam); if (FAILED(hr=imc.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIPrivateHandler. imc==NULL")); return 0; } IMCCLock imc_ctfime(imc->hCtfImeContext); if (FAILED(hr=imc_ctfime.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIPrivateHandler. imc_ctfime==NULL")); return 0; } CicInputContext* _pCicContext = imc_ctfime->m_pCicContext; if (_pCicContext == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIPrivateHandler. _pCicContext==NULL")); return 0; } if (wParam == IMN_PRIVATE_ONCLEARDOCFEEDBUFFER) { // // Clear DocFeed buffer // Find GUID_PROP_MSIMTF_READONLY property and SetText(NULL). // _pCicContext->ClearDocFeedBuffer(imc); // TF_ES_SYNC } return S_OK; } /* static */ LRESULT CIMEUIWindowHandler::ImeUIOnLayoutChange(HIMC hIMC) { DebugMsg(TF_FUNC, TEXT("OnLayoutChange")); HRESULT hr; IMCLock imc(hIMC); if (FAILED(hr=imc.GetResult())) { DebugMsg(TF_ERROR, TEXT("OnLayoutChange. imc==NULL")); return 0; } IMCCLock imc_ctfime(imc->hCtfImeContext); if (FAILED(hr=imc_ctfime.GetResult())) { DebugMsg(TF_ERROR, TEXT("OnLayoutChange. imc_ctfime==NULL")); return 0; } CicInputContext* _pCicContext = imc_ctfime->m_pCicContext; if (_pCicContext == NULL) { DebugMsg(TF_ERROR, TEXT("OnLayoutChange. _pCicContext==NULL")); return 0; } Interface_Attach iccb = _pCicContext->GetInputContextOwnerSink(); iccb->AddRef(); /* * Repositioning candidate window */ iccb->OnLayoutChange(); iccb->Release(); return S_OK; } /* static */ LRESULT CIMEUIWindowHandler::ImeUIMsImeReconvertRequest( HWND hUIWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DebugMsg(TF_FUNC, TEXT("ImeUIMsImeReconvertRequest")); if (wParam == FID_RECONVERT_VERSION) { // they're asking for version # so return something return 1L; } HRESULT hr; IMCLock imc((HIMC)GetWindowLongPtr(hUIWnd, IMMGWLP_IMC)); if (FAILED(hr=imc.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeReconvertRequest. imc==NULL")); return 0L; } IMCCLock imc_ctfime(imc->hCtfImeContext); if (FAILED(hr=imc_ctfime.GetResult())) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeReconvertRequest. imc_ctfime==NULL")); return 0L; } CicInputContext* _pCicContext = imc_ctfime->m_pCicContext; if (_pCicContext == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeReconvertRequest. _pCicContext==NULL")); return 0L; } TLS* ptls = TLS::GetTLS(); if (ptls == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeReconvertRequest. ptls==NULL.")); return 0L; } ITfThreadMgr_P* ptim_P = ptls->GetTIM(); if (ptim_P == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeReconvertRequest. ptim_P==NULL.")); return 0L; } UINT cp = CP_ACP; CicProfile* _pProfile = ptls->GetCicProfile(); if (_pProfile == NULL) { DebugMsg(TF_ERROR, TEXT("ImeUIMsImeReconvertRequest. _pProfile==NULL.")); return 0L; } _pProfile->GetCodePageA(&cp); _pCicContext->SetupReconvertString(imc, ptim_P, cp, WM_MSIME_RECONVERT, FALSE); _pCicContext->EndReconvertString(imc); return 1L; }