1491 lines
43 KiB
C++
1491 lines
43 KiB
C++
#include "FanyDefines.h"
|
|
#include "Globals.h"
|
|
#include "Private.h"
|
|
#include "MetasequoiaIME.h"
|
|
#include "CandidateWindow.h"
|
|
#include "CandidateListUIPresenter.h"
|
|
#include "CompositionProcessorEngine.h"
|
|
#include "MetasequoiaIMEBaseStructure.h"
|
|
#include "define.h"
|
|
#include <cwchar>
|
|
#include <debugapi.h>
|
|
#include <intsafe.h>
|
|
#include <minwindef.h>
|
|
#include <winuser.h>
|
|
#include "Ipc.h"
|
|
#include "fmt/xchar.h"
|
|
#include "FanyUtils.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMetasequoiaIME 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 CMetasequoiaIME::_HandleCandidateFinalize(TfEditCookie ec, _In_ ITfContext *pContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CStringRange keyStrokebuffer = _pCompositionProcessorEngine->GetKeystrokeBuffer();
|
|
DWORD_PTR keystrokeBufLen = keyStrokebuffer.GetLength();
|
|
DWORD_PTR candidateLen = keystrokeBufLen;
|
|
CStringRange candidateString(keyStrokebuffer);
|
|
|
|
OutputDebugString(fmt::format(L"create_word, keystrokeBuffer: {}", keyStrokebuffer.ToWString()).c_str());
|
|
|
|
// _pCandidateListUIPresenter would be null in uwp/metro apps
|
|
if (nullptr == _pCandidateListUIPresenter)
|
|
{
|
|
// goto NoPresenter;
|
|
}
|
|
|
|
if (candidateLen)
|
|
{
|
|
struct FanyImeNamedpipeDataToTsf *receivedData = TryReadDataFromServerPipeWithTimeout();
|
|
if (receivedData->msg_type == Global::DataFromServerMsgType::OutofRange) // Candidate index out of range
|
|
{
|
|
return hr;
|
|
}
|
|
else if (receivedData->msg_type == Global::DataFromServerMsgType::Normal) // 只有正常情况下才会上屏
|
|
{
|
|
GlobalIme::word_for_creating_word = L"";
|
|
OutputDebugString(fmt::format(L"create_word, normal???").c_str());
|
|
candidateString.Set(receivedData->candidate_string, wcslen(receivedData->candidate_string));
|
|
hr = _AddComposingAndChar(ec, pContext, &candidateString);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
/* 处理造词的逻辑 */
|
|
// 先把拼音拿到,将其和上屏的汉字串比较一下,
|
|
// - 如果分词后发现是纯拼音,
|
|
// - 并且没有使用辅助码,
|
|
// - 并且上屏的汉字串的拼音比起实际输入的拼音要短,则认为是造词
|
|
// TSF 端需要做的事情是,将 composingString
|
|
// 替换成造词的状态,即把选中的汉字串替换相应的拼音部分,同时,其他的拼音部分保持不变
|
|
// Server 端自己会判断并处理的
|
|
else if (receivedData->msg_type == Global::DataFromServerMsgType::NeedToCreateWord)
|
|
{
|
|
/* 更新 TSF 的 preedit 的前面的部分为已选定的拼音,并且,去除辅助码部分 */
|
|
std::wstring data = receivedData->candidate_string;
|
|
if (data.find(L',') != std::wstring::npos)
|
|
{
|
|
/* pureFullPinyin 一直都是最初的那个完整的拼音 */
|
|
std::wstring pureFullPinyin = data.substr(0, data.find(L','));
|
|
std::wstring curWord = data.substr(data.find(L',') + 1);
|
|
OutputDebugString(
|
|
fmt::format(L"create_word, pureFullPinyin: {}, curWord: {}\n", pureFullPinyin, curWord).c_str());
|
|
GlobalIme::word_for_creating_word = curWord;
|
|
CCompositionProcessorEngine *pCompositionProcessorEngine = nullptr;
|
|
pCompositionProcessorEngine = _pCompositionProcessorEngine;
|
|
|
|
//
|
|
// 计算出现在的拼音部分,比如,server 端传过来了 davsai 和 大塚,那么,TSF 端的拼音部分就是 ai
|
|
//
|
|
std::wstring preeditStr =
|
|
pureFullPinyin.substr(FanyUtils::count_utf8_chars(FanyUtils::wstring_to_string(curWord)) * 2);
|
|
|
|
DWORD_PTR vKeyLen = pCompositionProcessorEngine->GetVirtualKeyLength();
|
|
|
|
for (DWORD_PTR i = 0; i < vKeyLen; i++)
|
|
{
|
|
DWORD_PTR curVkeyLen = pCompositionProcessorEngine->GetVirtualKeyLength();
|
|
if (curVkeyLen)
|
|
{
|
|
pCompositionProcessorEngine->RemoveVirtualKey(curVkeyLen - 1);
|
|
}
|
|
}
|
|
for (DWORD_PTR i = 0; i < preeditStr.length(); i++)
|
|
{
|
|
pCompositionProcessorEngine->AddVirtualKey(preeditStr[i]);
|
|
}
|
|
|
|
if (pCompositionProcessorEngine->GetVirtualKeyLength())
|
|
{
|
|
_HandleCompositionInputWorker(pCompositionProcessorEngine, ec, pContext);
|
|
}
|
|
else
|
|
{
|
|
_HandleCancel(ec, pContext);
|
|
}
|
|
}
|
|
OutputDebugString(
|
|
fmt::format(L"create_word: current word part {}\n", GlobalIme::word_for_creating_word).c_str());
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
NoPresenter:
|
|
|
|
_HandleComplete(ec, pContext);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _HandleCandidateFinalizeForVKReturn
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CMetasequoiaIME::_HandleCandidateFinalizeForVKReturn(TfEditCookie ec, _In_ ITfContext *pContext)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CStringRange keyStrokebuffer = _pCompositionProcessorEngine->GetKeystrokeBuffer();
|
|
DWORD_PTR keystrokeBufLen = keyStrokebuffer.GetLength();
|
|
DWORD_PTR candidateLen = keystrokeBufLen;
|
|
CStringRange candidateString(keyStrokebuffer);
|
|
|
|
if (nullptr == _pCandidateListUIPresenter)
|
|
{
|
|
// goto NoPresenter;
|
|
}
|
|
|
|
#ifdef FANY_DEBUG
|
|
std::wstring msg(candidateString.Get(), candidateLen);
|
|
OutputDebugString(msg.c_str());
|
|
#endif
|
|
|
|
if (candidateLen)
|
|
{
|
|
hr = _AddComposingAndChar(ec, pContext, &candidateString);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
NoPresenter:
|
|
|
|
_HandleComplete(ec, pContext);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _HandleCandidateConvert
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CMetasequoiaIME::_HandleCandidateConvert(TfEditCookie ec, _In_ ITfContext *pContext)
|
|
{
|
|
return _HandleCandidateWorker(ec, pContext);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _HandleCandidateWorker
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CMetasequoiaIME::_HandleCandidateWorker(TfEditCookie ec, _In_ ITfContext *pContext)
|
|
{
|
|
HRESULT hrReturn = E_FAIL;
|
|
DWORD_PTR candidateLen = 0;
|
|
const WCHAR *pCandidateString = nullptr;
|
|
BSTR pbstr = nullptr;
|
|
CStringRange candidateString;
|
|
CMetasequoiaImeArray<CCandidateListItem> 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) // NOTICE: always no
|
|
{
|
|
_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()) // NOTICE: always 0
|
|
{
|
|
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)) // NOTICE: always false
|
|
{
|
|
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);
|
|
|
|
#ifdef FANY_DEBUG
|
|
OutputDebugString(fmt::format(L"Fany here candidateString = {}", candidateString.Get()).c_str());
|
|
#endif
|
|
|
|
OutputDebugString(fmt::format(L"Create word here?").c_str());
|
|
|
|
// 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
|
|
{
|
|
// When VK_SPACE, number(for selecting candidate) comes here
|
|
hrReturn = _HandleCandidateFinalize(ec, pContext);
|
|
}
|
|
|
|
if (pbstr)
|
|
{
|
|
SysFreeString(pbstr);
|
|
}
|
|
|
|
Exit:
|
|
return hrReturn;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _HandleCandidateArrowKey
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CMetasequoiaIME::_HandleCandidateArrowKey( //
|
|
TfEditCookie ec, //
|
|
_In_ ITfContext *pContext, //
|
|
_In_ KEYSTROKE_FUNCTION keyFunction //
|
|
)
|
|
{
|
|
ec;
|
|
pContext;
|
|
|
|
_pCandidateListUIPresenter->AdviseUIChangedByArrowKey(keyFunction);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _HandleCandidateSelectByNumber
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CMetasequoiaIME::_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 CMetasequoiaIME::_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 CMetasequoiaIME::_HandlePhraseArrowKey(TfEditCookie ec, _In_ ITfContext *pContext,
|
|
_In_ KEYSTROKE_FUNCTION keyFunction)
|
|
{
|
|
ec;
|
|
pContext;
|
|
|
|
_pCandidateListUIPresenter->AdviseUIChangedByArrowKey(keyFunction);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _HandlePhraseSelectByNumber
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CMetasequoiaIME::_HandlePhraseSelectByNumber(TfEditCookie ec, _In_ ITfContext *pContext, _In_ UINT uCode)
|
|
{
|
|
// isSelectAsNumber starts from 0
|
|
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_ CMetasequoiaIME *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::MetasequoiaIMEGuidCandUIElement;
|
|
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))
|
|
{
|
|
OutputDebugString(L"MakeCandidateWindow failed\n");
|
|
// goto Exit;
|
|
}
|
|
|
|
// Show(_isShowMode);
|
|
|
|
RECT rcTextExt;
|
|
if (SUCCEEDED(_GetTextExt(&rcTextExt)))
|
|
{
|
|
Global::Point[0] = rcTextExt.left;
|
|
Global::Point[1] = rcTextExt.bottom;
|
|
_LayoutChangeNotification(&rcTextExt);
|
|
}
|
|
|
|
Exit:
|
|
if (FAILED(hr))
|
|
{
|
|
_EndCandidateList();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _EndCandidateList
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCandidateListUIPresenter::_EndCandidateList()
|
|
{
|
|
EndUIElement();
|
|
|
|
/* 告诉 Server 端隐藏候选框窗口 */
|
|
DisposeCandidateWindow();
|
|
|
|
_EndLayout();
|
|
}
|
|
|
|
void CCandidateListUIPresenter::_NotifyUI()
|
|
{
|
|
CStringRange keyStringBuffer = _pTextService->GetCompositionProcessorEngine()->GetKeystrokeBuffer();
|
|
std::wstring pinyinString(keyStringBuffer.Get(), keyStringBuffer.GetLength());
|
|
Global::PinyinLength = pinyinString.length();
|
|
WriteDataToSharedMemory( //
|
|
Global::Keycode, //
|
|
Global::wch, //
|
|
Global::ModifiersDown, //
|
|
Global::Point, //
|
|
Global::PinyinLength, //
|
|
Global::PinyinString, //
|
|
0b111111 //
|
|
);
|
|
SendShowCandidateWndEventToUIProcess();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _SetText
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCandidateListUIPresenter::_SetText(_In_ CMetasequoiaImeArray<CCandidateListItem> *pCandidateList,
|
|
BOOL isAddFindKeyCode)
|
|
{
|
|
AddCandidateToCandidateListUI(pCandidateList, isAddFindKeyCode);
|
|
|
|
SetPageIndexWithScrollInfo(pCandidateList);
|
|
|
|
if (_isShowMode)
|
|
{
|
|
// _pCandidateWnd->_InvalidateRect();
|
|
_NotifyUI();
|
|
}
|
|
else
|
|
{
|
|
_updatedFlags =
|
|
TF_CLUIE_COUNT | TF_CLUIE_SELECTION | TF_CLUIE_STRING | TF_CLUIE_PAGEINDEX | TF_CLUIE_CURRENTPAGE;
|
|
_UpdateUIElement();
|
|
}
|
|
}
|
|
|
|
void CCandidateListUIPresenter::AddCandidateToCandidateListUI( //
|
|
_In_ CMetasequoiaImeArray<CCandidateListItem> *pCandidateList, //
|
|
BOOL isAddFindKeyCode //
|
|
)
|
|
{
|
|
for (UINT index = 0; index < pCandidateList->Count(); index++)
|
|
{
|
|
_pCandidateWnd->_AddString(pCandidateList->GetAt(index), isAddFindKeyCode);
|
|
}
|
|
}
|
|
|
|
void CCandidateListUIPresenter::SetPageIndexWithScrollInfo( //
|
|
_In_ CMetasequoiaImeArray<CCandidateListItem> *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();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _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();
|
|
_NotifyUI();
|
|
}
|
|
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)
|
|
{
|
|
}
|
|
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();
|
|
_NotifyUI();
|
|
}
|
|
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)
|
|
{
|
|
// OutputDebugString(L"LayoutChangeNotification\n");
|
|
#ifdef FANY_DEBUG
|
|
// TODO: Log _LayoutChangeNotification firefox cnt: Global::firefox_like_cnt
|
|
#endif
|
|
WriteDataToSharedMemory( //
|
|
Global::Keycode, //
|
|
Global::wch, //
|
|
0, //
|
|
Global::Point, //
|
|
Global::PinyinLength, //
|
|
Global::PinyinString, //
|
|
0b001000 //
|
|
);
|
|
SendMoveCandidateWndEventToUIProcess();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _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_ CMetasequoiaImeArray<CCandidateListItem> &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: {
|
|
// Page prev
|
|
_MovePage(MOVEUP_ONE);
|
|
break;
|
|
}
|
|
case FUNCTION_MOVE_PAGE_DOWN: {
|
|
// Page next
|
|
_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;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
// MakeCandidateWindow
|
|
//
|
|
// Create the candidate window
|
|
//----------------------------------------------------------------------------
|
|
|
|
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(), _pTextService);
|
|
|
|
if (_pCandidateWnd == nullptr)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
HWND parentWndHandle = nullptr;
|
|
ITfContextView *pView = nullptr;
|
|
if (SUCCEEDED(pContextDocument->GetActiveView(&pView)))
|
|
{
|
|
// pView->GetWnd(&parentWndHandle);
|
|
if (FAILED(pView->GetWnd(&parentWndHandle)) || (parentWndHandle == nullptr))
|
|
{
|
|
parentWndHandle = GetFocus();
|
|
}
|
|
}
|
|
|
|
if (!_pCandidateWnd->_Create(_atom, wndWidth, parentWndHandle))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
void CCandidateListUIPresenter::DisposeCandidateWindow()
|
|
{
|
|
if (nullptr == _pCandidateWnd)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Hide the global candidate window
|
|
//
|
|
// ShowWindow(Global::MainWindowHandle, SW_HIDE);
|
|
// HWND UIHwnd = FindWindow(L"global_candidate_window", NULL);
|
|
// UINT WM_HIDE_MAIN_WINDOW = RegisterWindowMessage(L"WM_HIDE_MAIN_WINDOW");
|
|
SendHideCandidateWndEventToUIProcess();
|
|
|
|
_pCandidateWnd->_Destroy();
|
|
|
|
delete _pCandidateWnd;
|
|
_pCandidateWnd = nullptr;
|
|
}
|