// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "Private.h" #include "SampleIME.h" #include "CandidateWindow.h" #include "CandidateListUIPresenter.h" #include "CompositionProcessorEngine.h" #include "SampleIMEBaseStructure.h" ////////////////////////////////////////////////////////////////////// // // CSampleIME candidate key handler methods // ////////////////////////////////////////////////////////////////////// const int MOVEUP_ONE = -1; const int MOVEDOWN_ONE = 1; const int MOVETO_TOP = 0; const int MOVETO_BOTTOM = -1; //+--------------------------------------------------------------------------- // // _HandleCandidateFinalize // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandleCandidateFinalize(TfEditCookie ec, _In_ ITfContext *pContext) { HRESULT hr = S_OK; DWORD_PTR candidateLen = 0; const WCHAR* pCandidateString = nullptr; CStringRange candidateString; if (nullptr == _pCandidateListUIPresenter) { goto NoPresenter; } candidateLen = _pCandidateListUIPresenter->_GetSelectedCandidateString(&pCandidateString); candidateString.Set(pCandidateString, candidateLen); if (candidateLen) { hr = _AddComposingAndChar(ec, pContext, &candidateString); if (FAILED(hr)) { return hr; } } NoPresenter: _HandleComplete(ec, pContext); return hr; } //+--------------------------------------------------------------------------- // // _HandleCandidateConvert // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandleCandidateConvert(TfEditCookie ec, _In_ ITfContext *pContext) { return _HandleCandidateWorker(ec, pContext); } //+--------------------------------------------------------------------------- // // _HandleCandidateWorker // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandleCandidateWorker(TfEditCookie ec, _In_ ITfContext *pContext) { HRESULT hrReturn = E_FAIL; DWORD_PTR candidateLen = 0; const WCHAR* pCandidateString = nullptr; BSTR pbstr = nullptr; CStringRange candidateString; CSampleImeArray candidatePhraseList; if (nullptr == _pCandidateListUIPresenter) { hrReturn = S_OK; goto Exit; } candidateLen = _pCandidateListUIPresenter->_GetSelectedCandidateString(&pCandidateString); if (0 == candidateLen) { hrReturn = S_FALSE; goto Exit; } candidateString.Set(pCandidateString, candidateLen); BOOL fMakePhraseFromText = _pCompositionProcessorEngine->IsMakePhraseFromText(); if (fMakePhraseFromText) { _pCompositionProcessorEngine->GetCandidateStringInConverted(candidateString, &candidatePhraseList); LCID locale = _pCompositionProcessorEngine->GetLocale(); _pCandidateListUIPresenter->RemoveSpecificCandidateFromList(locale, candidatePhraseList, candidateString); } // We have a candidate list if candidatePhraseList.Cnt is not 0 // If we are showing reverse conversion, use CCandidateListUIPresenter CANDIDATE_MODE tempCandMode = CANDIDATE_NONE; CCandidateListUIPresenter* pTempCandListUIPresenter = nullptr; if (candidatePhraseList.Count()) { tempCandMode = CANDIDATE_WITH_NEXT_COMPOSITION; pTempCandListUIPresenter = new (std::nothrow) CCandidateListUIPresenter(this, Global::AtomCandidateWindow, CATEGORY_CANDIDATE, _pCompositionProcessorEngine->GetCandidateListIndexRange(), FALSE); if (nullptr == pTempCandListUIPresenter) { hrReturn = E_OUTOFMEMORY; goto Exit; } } // call _Start*Line for CCandidateListUIPresenter or CReadingLine // we don't cache the document manager object so get it from pContext. ITfDocumentMgr* pDocumentMgr = nullptr; HRESULT hrStartCandidateList = E_FAIL; if (pContext->GetDocumentMgr(&pDocumentMgr) == S_OK) { ITfRange* pRange = nullptr; if (_pComposition->GetRange(&pRange) == S_OK) { if (pTempCandListUIPresenter) { hrStartCandidateList = pTempCandListUIPresenter->_StartCandidateList(_tfClientId, pDocumentMgr, pContext, ec, pRange, _pCompositionProcessorEngine->GetCandidateWindowWidth()); } pRange->Release(); } pDocumentMgr->Release(); } // set up candidate list if it is being shown if (SUCCEEDED(hrStartCandidateList)) { pTempCandListUIPresenter->_SetTextColor(RGB(0, 0x80, 0), GetSysColor(COLOR_WINDOW)); // Text color is green pTempCandListUIPresenter->_SetFillColor((HBRUSH)(COLOR_WINDOW+1)); // Background color is window pTempCandListUIPresenter->_SetText(&candidatePhraseList, FALSE); // Add composing character hrReturn = _AddComposingAndChar(ec, pContext, &candidateString); // close candidate list if (_pCandidateListUIPresenter) { _pCandidateListUIPresenter->_EndCandidateList(); delete _pCandidateListUIPresenter; _pCandidateListUIPresenter = nullptr; _candidateMode = CANDIDATE_NONE; _isCandidateWithWildcard = FALSE; } if (hrReturn == S_OK) { // copy temp candidate _pCandidateListUIPresenter = pTempCandListUIPresenter; _candidateMode = tempCandMode; _isCandidateWithWildcard = FALSE; } } else { hrReturn = _HandleCandidateFinalize(ec, pContext); } if (pbstr) { SysFreeString(pbstr); } Exit: return hrReturn; } //+--------------------------------------------------------------------------- // // _HandleCandidateArrowKey // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandleCandidateArrowKey(TfEditCookie ec, _In_ ITfContext *pContext, _In_ KEYSTROKE_FUNCTION keyFunction) { ec; pContext; _pCandidateListUIPresenter->AdviseUIChangedByArrowKey(keyFunction); return S_OK; } //+--------------------------------------------------------------------------- // // _HandleCandidateSelectByNumber // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandleCandidateSelectByNumber(TfEditCookie ec, _In_ ITfContext *pContext, _In_ UINT uCode) { int iSelectAsNumber = _pCompositionProcessorEngine->GetCandidateListIndexRange()->GetIndex(uCode); if (iSelectAsNumber == -1) { return S_FALSE; } if (_pCandidateListUIPresenter) { if (_pCandidateListUIPresenter->_SetSelectionInPage(iSelectAsNumber)) { return _HandleCandidateConvert(ec, pContext); } } return S_FALSE; } //+--------------------------------------------------------------------------- // // _HandlePhraseFinalize // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandlePhraseFinalize(TfEditCookie ec, _In_ ITfContext *pContext) { HRESULT hr = S_OK; DWORD phraseLen = 0; const WCHAR* pPhraseString = nullptr; phraseLen = (DWORD)_pCandidateListUIPresenter->_GetSelectedCandidateString(&pPhraseString); CStringRange phraseString; phraseString.Set(pPhraseString, phraseLen); if (phraseLen) { if ((hr = _AddCharAndFinalize(ec, pContext, &phraseString)) != S_OK) { return hr; } } _HandleComplete(ec, pContext); return S_OK; } //+--------------------------------------------------------------------------- // // _HandlePhraseArrowKey // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandlePhraseArrowKey(TfEditCookie ec, _In_ ITfContext *pContext, _In_ KEYSTROKE_FUNCTION keyFunction) { ec; pContext; _pCandidateListUIPresenter->AdviseUIChangedByArrowKey(keyFunction); return S_OK; } //+--------------------------------------------------------------------------- // // _HandlePhraseSelectByNumber // //---------------------------------------------------------------------------- HRESULT CSampleIME::_HandlePhraseSelectByNumber(TfEditCookie ec, _In_ ITfContext *pContext, _In_ UINT uCode) { int iSelectAsNumber = _pCompositionProcessorEngine->GetCandidateListIndexRange()->GetIndex(uCode); if (iSelectAsNumber == -1) { return S_FALSE; } if (_pCandidateListUIPresenter) { if (_pCandidateListUIPresenter->_SetSelectionInPage(iSelectAsNumber)) { return _HandlePhraseFinalize(ec, pContext); } } return S_FALSE; } ////////////////////////////////////////////////////////////////////// // // CCandidateListUIPresenter class // ////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CCandidateListUIPresenter::CCandidateListUIPresenter(_In_ CSampleIME *pTextService, ATOM atom, KEYSTROKE_CATEGORY Category, _In_ CCandidateRange *pIndexRange, BOOL hideWindow) : CTfTextLayoutSink(pTextService) { _atom = atom; _pIndexRange = pIndexRange; _parentWndHandle = nullptr; _pCandidateWnd = nullptr; _Category = Category; _updatedFlags = 0; _uiElementId = (DWORD)-1; _isShowMode = TRUE; // store return value from BeginUIElement _hideWindow = hideWindow; // Hide window flag from [Configuration] CandidateList.Phrase.HideWindow _pTextService = pTextService; _pTextService->AddRef(); _refCount = 1; } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CCandidateListUIPresenter::~CCandidateListUIPresenter() { _EndCandidateList(); _pTextService->Release(); } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::IUnknown::QueryInterface // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::QueryInterface(REFIID riid, _Outptr_ void **ppvObj) { if (CTfTextLayoutSink::QueryInterface(riid, ppvObj) == S_OK) { return S_OK; } if (ppvObj == nullptr) { return E_INVALIDARG; } *ppvObj = nullptr; if (IsEqualIID(riid, IID_ITfUIElement) || IsEqualIID(riid, IID_ITfCandidateListUIElement)) { *ppvObj = (ITfCandidateListUIElement*)this; } else if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfCandidateListUIElementBehavior)) { *ppvObj = (ITfCandidateListUIElementBehavior*)this; } else if (IsEqualIID(riid, __uuidof(ITfIntegratableCandidateListUIElement))) { *ppvObj = (ITfIntegratableCandidateListUIElement*)this; } if (*ppvObj) { AddRef(); return S_OK; } return E_NOINTERFACE; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::IUnknown::AddRef // //---------------------------------------------------------------------------- STDAPI_(ULONG) CCandidateListUIPresenter::AddRef() { CTfTextLayoutSink::AddRef(); return ++_refCount; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::IUnknown::Release // //---------------------------------------------------------------------------- STDAPI_(ULONG) CCandidateListUIPresenter::Release() { CTfTextLayoutSink::Release(); LONG cr = --_refCount; assert(_refCount >= 0); if (_refCount == 0) { delete this; } return cr; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::ITfUIElement::GetDescription // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetDescription(BSTR *pbstr) { if (pbstr) { *pbstr = SysAllocString(L"Cand"); } return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::ITfUIElement::GetGUID // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetGUID(GUID *pguid) { *pguid = Global::SampleIMEGuidCandUIElement; return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::ITfUIElement::Show // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::Show(BOOL showCandidateWindow) { if (showCandidateWindow) { ToShowCandidateWindow(); } else { ToHideCandidateWindow(); } return S_OK; } HRESULT CCandidateListUIPresenter::ToShowCandidateWindow() { if (_hideWindow) { _pCandidateWnd->_Show(FALSE); } else { _MoveWindowToTextExt(); _pCandidateWnd->_Show(TRUE); } return S_OK; } HRESULT CCandidateListUIPresenter::ToHideCandidateWindow() { if (_pCandidateWnd) { _pCandidateWnd->_Show(FALSE); } _updatedFlags = TF_CLUIE_SELECTION | TF_CLUIE_CURRENTPAGE; _UpdateUIElement(); return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::ITfUIElement::IsShown // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::IsShown(BOOL *pIsShow) { *pIsShow = _pCandidateWnd->_IsWindowVisible(); return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::GetUpdatedFlags // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetUpdatedFlags(DWORD *pdwFlags) { *pdwFlags = _updatedFlags; return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::GetDocumentMgr // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetDocumentMgr(ITfDocumentMgr **ppdim) { *ppdim = nullptr; return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::GetCount // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetCount(UINT *pCandidateCount) { if (_pCandidateWnd) { *pCandidateCount = _pCandidateWnd->_GetCount(); } else { *pCandidateCount = 0; } return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::GetSelection // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetSelection(UINT *pSelectedCandidateIndex) { if (_pCandidateWnd) { *pSelectedCandidateIndex = _pCandidateWnd->_GetSelection(); } else { *pSelectedCandidateIndex = 0; } return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::GetString // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetString(UINT uIndex, BSTR *pbstr) { if (!_pCandidateWnd || (uIndex > _pCandidateWnd->_GetCount())) { return E_FAIL; } DWORD candidateLen = 0; const WCHAR* pCandidateString = nullptr; candidateLen = _pCandidateWnd->_GetCandidateString(uIndex, &pCandidateString); *pbstr = (candidateLen == 0) ? nullptr : SysAllocStringLen(pCandidateString, candidateLen); return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::GetPageIndex // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetPageIndex(UINT *pIndex, UINT uSize, UINT *puPageCnt) { if (!_pCandidateWnd) { if (pIndex) { *pIndex = 0; } *puPageCnt = 0; return S_OK; } return _pCandidateWnd->_GetPageIndex(pIndex, uSize, puPageCnt); } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::SetPageIndex // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::SetPageIndex(UINT *pIndex, UINT uPageCnt) { if (!_pCandidateWnd) { return E_FAIL; } return _pCandidateWnd->_SetPageIndex(pIndex, uPageCnt); } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElement::GetCurrentPage // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetCurrentPage(UINT *puPage) { if (!_pCandidateWnd) { *puPage = 0; return S_OK; } return _pCandidateWnd->_GetCurrentPage(puPage); } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElementBehavior::SetSelection // It is related of the mouse clicking behavior upon the suggestion window //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::SetSelection(UINT nIndex) { if (_pCandidateWnd) { _pCandidateWnd->_SetSelection(nIndex); } return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElementBehavior::Finalize // It is related of the mouse clicking behavior upon the suggestion window //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::Finalize(void) { _CandidateChangeNotification(CAND_ITEM_SELECT); return S_OK; } //+--------------------------------------------------------------------------- // // ITfCandidateListUIElementBehavior::Abort // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::Abort(void) { return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // ITfIntegratableCandidateListUIElement::SetIntegrationStyle // To show candidateNumbers on the suggestion window //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::SetIntegrationStyle(GUID guidIntegrationStyle) { return (guidIntegrationStyle == GUID_INTEGRATIONSTYLE_SEARCHBOX) ? S_OK : E_NOTIMPL; } //+--------------------------------------------------------------------------- // // ITfIntegratableCandidateListUIElement::GetSelectionStyle // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::GetSelectionStyle(_Out_ TfIntegratableCandidateListSelectionStyle *ptfSelectionStyle) { *ptfSelectionStyle = STYLE_ACTIVE_SELECTION; return S_OK; } //+--------------------------------------------------------------------------- // // ITfIntegratableCandidateListUIElement::OnKeyDown // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::OnKeyDown(_In_ WPARAM wParam, _In_ LPARAM lParam, _Out_ BOOL *pIsEaten) { wParam; lParam; *pIsEaten = TRUE; return S_OK; } //+--------------------------------------------------------------------------- // // ITfIntegratableCandidateListUIElement::ShowCandidateNumbers // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::ShowCandidateNumbers(_Out_ BOOL *pIsShow) { *pIsShow = TRUE; return S_OK; } //+--------------------------------------------------------------------------- // // ITfIntegratableCandidateListUIElement::FinalizeExactCompositionString // //---------------------------------------------------------------------------- STDAPI CCandidateListUIPresenter::FinalizeExactCompositionString() { return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // _StartCandidateList // //---------------------------------------------------------------------------- HRESULT CCandidateListUIPresenter::_StartCandidateList(TfClientId tfClientId, _In_ ITfDocumentMgr *pDocumentMgr, _In_ ITfContext *pContextDocument, TfEditCookie ec, _In_ ITfRange *pRangeComposition, UINT wndWidth) { pDocumentMgr;tfClientId; HRESULT hr = E_FAIL; if (FAILED(_StartLayout(pContextDocument, ec, pRangeComposition))) { goto Exit; } BeginUIElement(); hr = MakeCandidateWindow(pContextDocument, wndWidth); if (FAILED(hr)) { goto Exit; } Show(_isShowMode); RECT rcTextExt; if (SUCCEEDED(_GetTextExt(&rcTextExt))) { _LayoutChangeNotification(&rcTextExt); } Exit: if (FAILED(hr)) { _EndCandidateList(); } return hr; } //+--------------------------------------------------------------------------- // // _EndCandidateList // //---------------------------------------------------------------------------- void CCandidateListUIPresenter::_EndCandidateList() { EndUIElement(); DisposeCandidateWindow(); _EndLayout(); } //+--------------------------------------------------------------------------- // // _SetText // //---------------------------------------------------------------------------- void CCandidateListUIPresenter::_SetText(_In_ CSampleImeArray *pCandidateList, BOOL isAddFindKeyCode) { AddCandidateToCandidateListUI(pCandidateList, isAddFindKeyCode); SetPageIndexWithScrollInfo(pCandidateList); if (_isShowMode) { _pCandidateWnd->_InvalidateRect(); } else { _updatedFlags = TF_CLUIE_COUNT | TF_CLUIE_SELECTION | TF_CLUIE_STRING | TF_CLUIE_PAGEINDEX | TF_CLUIE_CURRENTPAGE; _UpdateUIElement(); } } void CCandidateListUIPresenter::AddCandidateToCandidateListUI(_In_ CSampleImeArray *pCandidateList, BOOL isAddFindKeyCode) { for (UINT index = 0; index < pCandidateList->Count(); index++) { _pCandidateWnd->_AddString(pCandidateList->GetAt(index), isAddFindKeyCode); } } void CCandidateListUIPresenter::SetPageIndexWithScrollInfo(_In_ CSampleImeArray *pCandidateList) { UINT candCntInPage = _pIndexRange->Count(); UINT bufferSize = pCandidateList->Count() / candCntInPage + 1; UINT* puPageIndex = new (std::nothrow) UINT[ bufferSize ]; if (puPageIndex != nullptr) { for (UINT i = 0; i < bufferSize; i++) { puPageIndex[i] = i * candCntInPage; } _pCandidateWnd->_SetPageIndex(puPageIndex, bufferSize); delete [] puPageIndex; } _pCandidateWnd->_SetScrollInfo(pCandidateList->Count(), candCntInPage); // nMax:range of max, nPage:number of items in page } //+--------------------------------------------------------------------------- // // _ClearList // //---------------------------------------------------------------------------- void CCandidateListUIPresenter::_ClearList() { _pCandidateWnd->_ClearList(); _pCandidateWnd->_InvalidateRect(); } //+--------------------------------------------------------------------------- // // _SetTextColor // _SetFillColor // //---------------------------------------------------------------------------- void CCandidateListUIPresenter::_SetTextColor(COLORREF crColor, COLORREF crBkColor) { _pCandidateWnd->_SetTextColor(crColor, crBkColor); } void CCandidateListUIPresenter::_SetFillColor(HBRUSH hBrush) { _pCandidateWnd->_SetFillColor(hBrush); } //+--------------------------------------------------------------------------- // // _GetSelectedCandidateString // //---------------------------------------------------------------------------- DWORD_PTR CCandidateListUIPresenter::_GetSelectedCandidateString(_Outptr_result_maybenull_ const WCHAR **ppwchCandidateString) { return _pCandidateWnd->_GetSelectedCandidateString(ppwchCandidateString); } //+--------------------------------------------------------------------------- // // _MoveSelection // //---------------------------------------------------------------------------- BOOL CCandidateListUIPresenter::_MoveSelection(_In_ int offSet) { BOOL ret = _pCandidateWnd->_MoveSelection(offSet, TRUE); if (ret) { if (_isShowMode) { _pCandidateWnd->_InvalidateRect(); } else { _updatedFlags = TF_CLUIE_SELECTION; _UpdateUIElement(); } } return ret; } //+--------------------------------------------------------------------------- // // _SetSelection // //---------------------------------------------------------------------------- BOOL CCandidateListUIPresenter::_SetSelection(_In_ int selectedIndex) { BOOL ret = _pCandidateWnd->_SetSelection(selectedIndex, TRUE); if (ret) { if (_isShowMode) { _pCandidateWnd->_InvalidateRect(); } else { _updatedFlags = TF_CLUIE_SELECTION | TF_CLUIE_CURRENTPAGE; _UpdateUIElement(); } } return ret; } //+--------------------------------------------------------------------------- // // _MovePage // //---------------------------------------------------------------------------- BOOL CCandidateListUIPresenter::_MovePage(_In_ int offSet) { BOOL ret = _pCandidateWnd->_MovePage(offSet, TRUE); if (ret) { if (_isShowMode) { _pCandidateWnd->_InvalidateRect(); } else { _updatedFlags = TF_CLUIE_SELECTION | TF_CLUIE_CURRENTPAGE; _UpdateUIElement(); } } return ret; } //+--------------------------------------------------------------------------- // // _MoveWindowToTextExt // //---------------------------------------------------------------------------- void CCandidateListUIPresenter::_MoveWindowToTextExt() { RECT rc; if (FAILED(_GetTextExt(&rc))) { return; } _pCandidateWnd->_Move(rc.left, rc.bottom); } //+--------------------------------------------------------------------------- // // _LayoutChangeNotification // //---------------------------------------------------------------------------- VOID CCandidateListUIPresenter::_LayoutChangeNotification(_In_ RECT *lpRect) { RECT rectCandidate = {0, 0, 0, 0}; POINT ptCandidate = {0, 0}; _pCandidateWnd->_GetClientRect(&rectCandidate); _pCandidateWnd->_GetWindowExtent(lpRect, &rectCandidate, &ptCandidate); _pCandidateWnd->_Move(ptCandidate.x, ptCandidate.y); } //+--------------------------------------------------------------------------- // // _LayoutDestroyNotification // //---------------------------------------------------------------------------- VOID CCandidateListUIPresenter::_LayoutDestroyNotification() { _EndCandidateList(); } //+--------------------------------------------------------------------------- // // _CandidateChangeNotifiction // //---------------------------------------------------------------------------- HRESULT CCandidateListUIPresenter::_CandidateChangeNotification(_In_ enum CANDWND_ACTION action) { HRESULT hr = E_FAIL; TfClientId tfClientId = _pTextService->_GetClientId(); ITfThreadMgr* pThreadMgr = nullptr; ITfDocumentMgr* pDocumentMgr = nullptr; ITfContext* pContext = nullptr; _KEYSTROKE_STATE KeyState; KeyState.Category = _Category; KeyState.Function = FUNCTION_FINALIZE_CANDIDATELIST; if (CAND_ITEM_SELECT != action) { goto Exit; } pThreadMgr = _pTextService->_GetThreadMgr(); if (nullptr == pThreadMgr) { goto Exit; } hr = pThreadMgr->GetFocus(&pDocumentMgr); if (FAILED(hr)) { goto Exit; } hr = pDocumentMgr->GetTop(&pContext); if (FAILED(hr)) { pDocumentMgr->Release(); goto Exit; } CKeyHandlerEditSession *pEditSession = new (std::nothrow) CKeyHandlerEditSession(_pTextService, pContext, 0, 0, KeyState); if (nullptr != pEditSession) { HRESULT hrSession = S_OK; hr = pContext->RequestEditSession(tfClientId, pEditSession, TF_ES_SYNC | TF_ES_READWRITE, &hrSession); if (hrSession == TF_E_SYNCHRONOUS || hrSession == TS_E_READONLY) { hr = pContext->RequestEditSession(tfClientId, pEditSession, TF_ES_ASYNC | TF_ES_READWRITE, &hrSession); } pEditSession->Release(); } pContext->Release(); pDocumentMgr->Release(); Exit: return hr; } //+--------------------------------------------------------------------------- // // _CandWndCallback // //---------------------------------------------------------------------------- // static HRESULT CCandidateListUIPresenter::_CandWndCallback(_In_ void *pv, _In_ enum CANDWND_ACTION action) { CCandidateListUIPresenter* fakeThis = (CCandidateListUIPresenter*)pv; return fakeThis->_CandidateChangeNotification(action); } //+--------------------------------------------------------------------------- // // _UpdateUIElement // //---------------------------------------------------------------------------- HRESULT CCandidateListUIPresenter::_UpdateUIElement() { HRESULT hr = S_OK; ITfThreadMgr* pThreadMgr = _pTextService->_GetThreadMgr(); if (nullptr == pThreadMgr) { return S_OK; } ITfUIElementMgr* pUIElementMgr = nullptr; hr = pThreadMgr->QueryInterface(IID_ITfUIElementMgr, (void **)&pUIElementMgr); if (hr == S_OK) { pUIElementMgr->UpdateUIElement(_uiElementId); pUIElementMgr->Release(); } return S_OK; } //+--------------------------------------------------------------------------- // // OnSetThreadFocus // //---------------------------------------------------------------------------- HRESULT CCandidateListUIPresenter::OnSetThreadFocus() { if (_isShowMode) { Show(TRUE); } return S_OK; } //+--------------------------------------------------------------------------- // // OnKillThreadFocus // //---------------------------------------------------------------------------- HRESULT CCandidateListUIPresenter::OnKillThreadFocus() { if (_isShowMode) { Show(FALSE); } return S_OK; } void CCandidateListUIPresenter::RemoveSpecificCandidateFromList(_In_ LCID Locale, _Inout_ CSampleImeArray &candidateList, _In_ CStringRange &candidateString) { for (UINT index = 0; index < candidateList.Count();) { CCandidateListItem* pLI = candidateList.GetAt(index); if (CStringRange::Compare(Locale, &candidateString, &pLI->_ItemString) == CSTR_EQUAL) { candidateList.RemoveAt(index); continue; } index++; } } void CCandidateListUIPresenter::AdviseUIChangedByArrowKey(_In_ KEYSTROKE_FUNCTION arrowKey) { switch (arrowKey) { case FUNCTION_MOVE_UP: { _MoveSelection(MOVEUP_ONE); break; } case FUNCTION_MOVE_DOWN: { _MoveSelection(MOVEDOWN_ONE); break; } case FUNCTION_MOVE_PAGE_UP: { _MovePage(MOVEUP_ONE); break; } case FUNCTION_MOVE_PAGE_DOWN: { _MovePage(MOVEDOWN_ONE); break; } case FUNCTION_MOVE_PAGE_TOP: { _SetSelection(MOVETO_TOP); break; } case FUNCTION_MOVE_PAGE_BOTTOM: { _SetSelection(MOVETO_BOTTOM); break; } default: break; } } HRESULT CCandidateListUIPresenter::BeginUIElement() { HRESULT hr = S_OK; ITfThreadMgr* pThreadMgr = _pTextService->_GetThreadMgr(); if (nullptr ==pThreadMgr) { hr = E_FAIL; goto Exit; } ITfUIElementMgr* pUIElementMgr = nullptr; hr = pThreadMgr->QueryInterface(IID_ITfUIElementMgr, (void **)&pUIElementMgr); if (hr == S_OK) { pUIElementMgr->BeginUIElement(this, &_isShowMode, &_uiElementId); pUIElementMgr->Release(); } Exit: return hr; } HRESULT CCandidateListUIPresenter::EndUIElement() { HRESULT hr = S_OK; ITfThreadMgr* pThreadMgr = _pTextService->_GetThreadMgr(); if ((nullptr == pThreadMgr) || (-1 == _uiElementId)) { hr = E_FAIL; goto Exit; } ITfUIElementMgr* pUIElementMgr = nullptr; hr = pThreadMgr->QueryInterface(IID_ITfUIElementMgr, (void **)&pUIElementMgr); if (hr == S_OK) { pUIElementMgr->EndUIElement(_uiElementId); pUIElementMgr->Release(); } Exit: return hr; } HRESULT CCandidateListUIPresenter::MakeCandidateWindow(_In_ ITfContext *pContextDocument, _In_ UINT wndWidth) { HRESULT hr = S_OK; if (nullptr != _pCandidateWnd) { return hr; } _pCandidateWnd = new (std::nothrow) CCandidateWindow(_CandWndCallback, this, _pIndexRange, _pTextService->_IsStoreAppMode()); if (_pCandidateWnd == nullptr) { hr = E_OUTOFMEMORY; goto Exit; } HWND parentWndHandle = nullptr; ITfContextView* pView = nullptr; if (SUCCEEDED(pContextDocument->GetActiveView(&pView))) { pView->GetWnd(&parentWndHandle); } if (!_pCandidateWnd->_Create(_atom, wndWidth, parentWndHandle)) { hr = E_OUTOFMEMORY; goto Exit; } Exit: return hr; } void CCandidateListUIPresenter::DisposeCandidateWindow() { if (nullptr == _pCandidateWnd) { return; } _pCandidateWnd->_Destroy(); delete _pCandidateWnd; _pCandidateWnd = nullptr; }