HRESULT CTextService::_HandleCharacterKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam) { if (!_IsComposing()) _StartComposition(pContext); // // create an instance of the candidate list class. // if (_pCandidateList == NULL) _pCandidateList = new CCandidateList(this); // // The document manager object is not cached. Get it from pContext. // ITfDocumentMgr *pDocumentMgr; if (pContext->GetDocumentMgr(&pDocumentMgr) == S_OK) { // // get the composition range. // ITfRange *pRange; if (_pComposition->GetRange(&pRange) == S_OK) { _pCandidateList->_StartCandidateList(_tfClientId, pDocumentMgr, pContext, ec, pRange); pRange->Release(); } pDocumentMgr->Release(); } if (_IsComposing()) _TerminateComposition(ec, pContext); return S_OK; }
HRESULT CTextService::_HandleCharacterKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam) { ITfRange *pRangeComposition; TF_SELECTION tfSelection; ULONG cFetched; WCHAR ch; BOOL fCovered; // Start the new compositon if there is no composition. OutputDebugString("test compositing"); if (!_IsComposing()) _StartComposition(pContext); OutputDebugString("after test compositing"); // // Assign VK_ value to the char. So the inserted the character is always // uppercase. // ch = (WCHAR)wParam; // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // is the insertion point covered by a composition? if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto Exit; } } // insert the text // use SetText here instead of InsertTextAtSelection because a composition was already started //Don't allow to the app to adjust the insertion point inside the composition if (tfSelection.range->SetText(ec, 0, &ch, 1) != S_OK) goto Exit; // update the selection, make it an insertion point just past // the inserted text. tfSelection.range->Collapse(ec, TF_ANCHOR_END); pContext->SetSelection(ec, 1, &tfSelection); // // set the display attribute to the composition range. // _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeInput); Exit: tfSelection.range->Release(); return S_OK; }
HRESULT CDIME::_ProbeCompositionRangeNotification(_In_ TfEditCookie ec, _In_ ITfContext *pContext) { debugPrint(L"CDIME::_ProbeCompositionRangeNotification(), \n"); HRESULT hr = S_OK; if(!_IsComposing()) _StartComposition(pContext); hr = E_FAIL; ULONG fetched = 0; TF_SELECTION tfSelection; if ( pContext == nullptr || (hr = pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) != S_OK || fetched != 1 ||tfSelection.range==nullptr) { _TerminateComposition(ec,pContext); return hr; } tfSelection.range->Release(); ITfRange *pRange; ITfContextView* pContextView; ITfDocumentMgr* pDocumgr; if (_pComposition&&SUCCEEDED(_pComposition->GetRange(&pRange)) && pRange) { if(pContext && SUCCEEDED(pContext->GetActiveView(&pContextView)) && pContextView) { if(pContext && SUCCEEDED( pContext->GetDocumentMgr(&pDocumgr)) && pDocumgr && _pThreadMgr &&_pUIPresenter) { ITfDocumentMgr* pFocusDocuMgr; _pThreadMgr->GetFocus(&pFocusDocuMgr); if(pFocusDocuMgr == pDocumgr) { _pUIPresenter->_StartLayout(pContext, ec, pRange); _pUIPresenter->_MoveUIWindowsToTextExt(); } else _pUIPresenter->ClearNotify(); pDocumgr->Release(); } pContextView->Release(); } pRange->Release(); } _TerminateComposition(ec,pContext); return hr; }
/* Update Composition */ void WeaselTSF::_UpdateComposition(ITfContext *pContext) { // get commit string from server std::wstring commit; weasel::Status status; weasel::Config config; auto context = std::make_shared<weasel::Context>(); weasel::ResponseParser parser(&commit, context.get(), &status, &config); bool ok = m_client.GetResponseData(std::ref(parser)); if (ok) { bool composing = _IsComposing(); if (!commit.empty()) { // 修复顶字上屏的吞字问题: // 顶字上屏(如五笔 4 码上屏时),当候选词数 > 1 时, // 第 5 码输入时会将首选项顶屏。 // 此时由于第五码的输入,composition 应是开启的,同时也要在输入处插入顶字。 // 这里先关闭上一个字的 composition,然后为后续输入开启一个新 composition。 // 有点 dirty 但是 it works ... if (composing) { _EndComposition(pContext); composing = false; } _InsertText(pContext, commit); } if (status.composing && !composing) { if (!_fCUASWorkaroundTested) { /* Test if we need to apply the workaround */ _UpdateCompositionWindow(pContext); } else if (!_fCUASWorkaroundEnabled || config.inline_preedit) { /* Workaround not applied, update candidate window position at this point. */ _UpdateCompositionWindow(pContext); } _StartComposition(pContext, _fCUASWorkaroundEnabled && !config.inline_preedit); } else if (!status.composing && composing) { _EndComposition(pContext); composing = false; } if (composing && config.inline_preedit) _ShowInlinePreedit(pContext, context); } }
HRESULT COVTSF::_HandleCompositionInput(TfEditCookie ec, _In_ ITfContext *pContext, WCHAR wch) { ITfRange* pRangeComposition = nullptr; TF_SELECTION tfSelection; ULONG fetched = 0; BOOL isCovered = TRUE; CCompositionProcessorEngine* pCompositionProcessorEngine = nullptr; pCompositionProcessorEngine = _pCompositionProcessorEngine; if ((_pCandidateListUIPresenter != nullptr) && (_candidateMode != CANDIDATE_INCREMENTAL)) { _HandleCompositionFinalize(ec, pContext, FALSE); } // Start the new (std::nothrow) compositon if there is no composition. if (!_IsComposing()) { _StartComposition(pContext); } // first, test where a keystroke would go in the document if we did an insert if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched) != S_OK || fetched != 1) { return S_FALSE; } // is the insertion point covered by a composition? if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition))) { isCovered = _IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!isCovered) { goto Exit; } } // Add virtual key to composition processor engine pCompositionProcessorEngine->AddVirtualKey(wch); _HandleCompositionInputWorker(pCompositionProcessorEngine, ec, pContext); Exit: tfSelection.range->Release(); return S_OK; }
BOOL WeaselIME::ProcessKeyEvent(UINT vKey, KeyInfo kinfo, const LPBYTE lpbKeyState) { EZDBGONLYLOGGERPRINT("Process key event: vKey = 0x%x, kinfo = 0x%x, HIMC = 0x%x", vKey, UINT32(kinfo), m_hIMC); bool accepted = false; if (!m_client.Echo()) { m_client.Connect(launch_server); m_client.StartSession(); } weasel::KeyEvent ke; if (!ConvertKeyEvent(vKey, kinfo, lpbKeyState, ke)) { // unknown key event return FALSE; } accepted = m_client.ProcessKeyEvent(ke); // get commit string from server wstring commit; weasel::Status status; weasel::ResponseParser parser(&commit, NULL, &status); bool ok = m_client.GetResponseData(boost::ref(parser)); if (ok) { if (!commit.empty()) { _EndComposition(commit.c_str()); } else if (status.composing != m_composing) { if (m_composing) _EndComposition(NULL); else _StartComposition(); } } return (BOOL)accepted; }
HRESULT CTextService::_HandleKey(TfEditCookie ec, ITfContext *pContext, WPARAM wParam) { /* * FIXME: the following keys are not handled: * shift left VK_LSHIFT * shift right VK_RSHIFT * caps lock VK_CAPITAL * page up VK_PRIOR * page down VK_NEXT * ctrl num * shift space * numlock num VK_NUMLOCK */ if (('A' <= wParam && wParam <= 'Z')) { chewing_handle_Default(mChewingContext, wParam - 'A' + 'a'); } else if ('0' <= wParam && wParam <= '9') { chewing_handle_Default(mChewingContext, wParam); } else { switch(wParam) { case VK_OEM_COMMA: chewing_handle_Default(mChewingContext, ','); break; case VK_OEM_MINUS: chewing_handle_Default(mChewingContext, '-'); break; case VK_OEM_PERIOD: chewing_handle_Default(mChewingContext, '.'); break; case VK_OEM_1: chewing_handle_Default(mChewingContext, ';'); break; case VK_OEM_2: chewing_handle_Default(mChewingContext, '/'); break; case VK_OEM_3: chewing_handle_Default(mChewingContext, '`'); break; case VK_SPACE: chewing_handle_Space(mChewingContext); break; case VK_ESCAPE: chewing_handle_Esc(mChewingContext); break; case VK_RETURN: chewing_handle_Enter(mChewingContext); break; case VK_DELETE: chewing_handle_Del(mChewingContext); break; case VK_BACK: chewing_handle_Backspace(mChewingContext); break; case VK_UP: chewing_handle_Up(mChewingContext); break; case VK_DOWN: chewing_handle_Down(mChewingContext); case VK_LEFT: chewing_handle_Left(mChewingContext); break; case VK_RIGHT: chewing_handle_Right(mChewingContext); break; case VK_HOME: chewing_handle_Home(mChewingContext); break; case VK_END: chewing_handle_End(mChewingContext); break; default: return S_OK; } } // Remove old candidate list. We will create a new one if necessary. _pCandidateList->_EndCandidateList(); ChewingCandidates candidate(mChewingContext); if (!candidate.IsEmpty()) { _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeConverted); // // The document manager object is not cached. Get it from pContext. // ITfDocumentMgr *pDocumentMgr; if (pContext->GetDocumentMgr(&pDocumentMgr) == S_OK) { // // get the composition range. // ITfRange *pRange; if (_pComposition->GetRange(&pRange) == S_OK) { _pCandidateList->_StartCandidateList(_tfClientId, pDocumentMgr, pContext, ec, pRange, candidate); pRange->Release(); } pDocumentMgr->Release(); } return S_OK; } ChewingString commit(mChewingContext, CHEWING_STRING_COMMIT); if (!commit.IsEmpty()) { // FIXME: Need a better way to submit a string if (!_IsComposing()) _StartComposition(pContext); ULONG cFetched; BOOL fCovered; TF_SELECTION tfSelection; // FIXME: Why we need this here? // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // FIXME: Why we need this here? // is the insertion point covered by a composition? ITfRange *pRangeComposition; if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto End3; } } if (tfSelection.range->SetText(ec, 0, commit.GetString(), commit.GetLength()) != S_OK) goto End3; _TerminateComposition(ec, pContext); End3: // FIXME: RAII? tfSelection.range->Release(); } /* * Composition is mapped to preedit buffer + zuin buffer */ ChewingString preedit_zuin(mChewingContext, CHEWING_STRING_PREEDIT_ZUIN); if (preedit_zuin.IsEmpty()) { // Remove composition if (_IsComposing()) { ULONG cFetched; BOOL fCovered; TF_SELECTION tfSelection; // FIXME: Why we need this here? // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // FIXME: Why we need this here? // is the insertion point covered by a composition? ITfRange *pRangeComposition; if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto End; } } // Empties the composition tfSelection.range->SetText(ec, 0, L"", 0); _TerminateComposition(ec, pContext); End: // FIXME: RAII? tfSelection.range->Release(); } } else { if (!_IsComposing()) _StartComposition(pContext); ULONG cFetched; BOOL fCovered; TF_SELECTION tfSelection; // FIXME: Why we need this here? // first, test where a keystroke would go in the document if an insert is done if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; // FIXME: Why we need this here? // is the insertion point covered by a composition? ITfRange *pRangeComposition; if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fCovered = IsRangeCovered(ec, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fCovered) { goto End2; } } if (tfSelection.range->SetText(ec, 0, preedit_zuin.GetString(), preedit_zuin.GetLength()) != S_OK) goto End2; _SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeInput); End2: // FIXME: RAII? tfSelection.range->Release(); } return S_OK; }
HRESULT CTextService::_SetText(TfEditCookie ec, ITfContext *pContext, const std::wstring &text, LONG cchCursor, LONG cchOkuri, BOOL fixed) { TF_SELECTION tfSelection; ULONG cFetched = 0; LONG cch, cchRes; if(pContext == NULL && _pCandidateList != NULL) //辞書登録用 { _pCandidateList->_SetText(text, fixed, FALSE, FALSE); return S_OK; } if(!_IsComposing()) { if(!_StartComposition(pContext)) { return S_FALSE; } } if(pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK) { return S_FALSE; } if(cFetched != 1) { SafeRelease(&tfSelection.range); return S_FALSE; } ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { if(_IsRangeCovered(ec, tfSelection.range, pRange)) { pRange->SetText(ec, 0, text.c_str(), (LONG)text.size()); // shift from end to start. // shift over mathematical operators (U+2200-U+22FF) is rejected by OneNote. if(cchCursor == 0) { cchRes = (LONG)cursoridx - (LONG)kana.size(); if((complement && okuriidx != 0) || (!cx_showmodemark && okuriidx != 0 && cursoridx <= okuriidx && cursoridx < kana.size())) { cchRes += 1; } } else { cchRes = cchCursor - (LONG)text.size(); if(cchRes > 0) { cchRes = 0; } else if(cchRes < -(LONG)text.size()) { cchRes = -(LONG)text.size(); } } tfSelection.range->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); tfSelection.range->ShiftStartToRange(ec, pRange, TF_ANCHOR_END); tfSelection.range->ShiftStart(ec, cchRes, &cch, NULL); //decide cursor position tfSelection.range->Collapse(ec, TF_ANCHOR_START); pContext->SetSelection(ec, 1, &tfSelection); //composition attribute if(!fixed) { ITfRange *pRangeClone; if(pRange->Clone(&pRangeClone) == S_OK) { pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); if(cchCursor == 0 || !showentry) { if(inputkey) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputMark); if(cx_showmodemark) { pRangeClone->ShiftStart(ec, 1, &cch, NULL); } } if(!display_attribute_series[1] || !inputkey) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText); } if(cchOkuri != 0) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL); if(!display_attribute_series[2]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputOkuri); } if(hintmode && text.find_first_of(CHAR_SKK_HINT) != std::wstring::npos) { LONG hintpos = (LONG)text.find_first_of(CHAR_SKK_HINT); if(cchOkuri < hintpos) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, hintpos, &cch, NULL); _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText); } } } } else { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvMark); if(cx_showmodemark) { pRangeClone->ShiftStart(ec, 1, &cch, NULL); } if(!display_attribute_series[4]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvText); } if(cchOkuri != 0) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL); if(!display_attribute_series[5]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvOkuri); } } pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); pRangeClone->ShiftStartToRange(ec, tfSelection.range, TF_ANCHOR_END); if(!display_attribute_series[6]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvAnnot); } } SafeRelease(&pRangeClone); } } // for Excel's PHONETIC function if(fixed && !text.empty()) { ITfProperty *pProperty; if(pContext->GetProperty(GUID_PROP_READING, &pProperty) == S_OK) { VARIANT var; var.vt = VT_BSTR; std::wstring phone(kana); if(okuriidx == 0) { switch(inputmode) { case im_hiragana: case im_katakana: case im_katakana_ank: //接辞 if(!abbrevmode && kana.size() >= 2) { if(kana.front() == L'>') { phone = kana.substr(1); } else if(kana.back() == L'>') { phone = kana.substr(0, kana.size() - 1); } } break; default: break; } } else { if(kana.size() > (okuriidx + 1)) { phone = kana.substr(0, okuriidx) + kana.substr(okuriidx + 1); } else if(kana.size() >= okuriidx) { phone = kana.substr(0, okuriidx); } } if(!phone.empty()) { var.bstrVal = SysAllocString(phone.c_str()); pProperty->SetValue(ec, pRange, &var); SysFreeString(var.bstrVal); } SafeRelease(&pProperty); } } } SafeRelease(&pRange); } SafeRelease(&tfSelection.range); return S_OK; }
HRESULT CDIME::_HandleCandidateWorker(TfEditCookie ec, _In_ ITfContext *pContext) { debugPrint(L"CDIME::_HandleCandidateWorker() \n"); HRESULT hr = S_OK; CStringRange commitString, convertedString; CDIMEArray<CCandidateListItem> candidatePhraseList; CStringRange lastChar; CStringRange notify; if (nullptr == _pUIPresenter) { goto Exit; //should not happen } const WCHAR* pCandidateString = nullptr; DWORD_PTR candidateLen = 0; BOOL arrayUsingSPCode =FALSE; if (!_IsComposing()) _StartComposition(pContext); if (Global::imeMode == IME_MODE_ARRAY)// check if the _strokebuffer is array special code { candidateLen = _pCompositionProcessorEngine->CollectWordFromArraySpeicalCode(&pCandidateString); if(candidateLen) arrayUsingSPCode = TRUE; } candidateLen = 0; candidateLen = _pUIPresenter->_GetSelectedCandidateString(&pCandidateString); if (candidateLen == 0) { if(_candidateMode == CANDIDATE_WITH_NEXT_COMPOSITION || _candidateMode == CANDIDATE_PHRASE) { _HandleCancel(ec, pContext); goto Exit; } else { hr = S_FALSE; _HandleCancel(ec, pContext); DoBeep(BEEP_COMPOSITION_ERROR); //beep for no valid mapping found goto Exit; } } if (_pCompositionProcessorEngine->IsArrayShortCode() && candidateLen == 1 && *pCandidateString == 0x2394) // empty position in arry short code table. { hr = S_FALSE; if (Global::imeMode == IME_MODE_PHONETIC) DoBeep(BEEP_WARNING); else { if (CConfig::GetClearOnBeep()) _HandleCancel(ec, pContext); DoBeep(BEEP_COMPOSITION_ERROR); //beep for no valid mapping found } goto Exit; } StringCchCopy(_commitString, 1, L"\0"); StringCchCatN(_commitString, MAX_COMMIT_LENGTH, pCandidateString, candidateLen); commitString.Set(_commitString, candidateLen); //_commitString = commitString; PWCHAR pwch = new (std::nothrow) WCHAR[2]; // pCandidateString will be destroyed after _detelteCanddiateList was called. if(candidateLen > 1) { StringCchCopyN(pwch, 2, pCandidateString + candidateLen -1, 1); }else // cnadidateLen ==1 { StringCchCopyN(pwch, 2, pCandidateString, 1); } lastChar.Set(pwch, 1 ); //-----------------do reverse conversion notify. We should not show notify in UI-less mode, thus cancel reverse conversion notify in UILess Mode if (!_IsUILessMode()) { if (_pITfReverseConversion[Global::imeMode]) { _AsyncReverseConversion(pContext); //asynchronized the reverse conversion with editsession for better perfomance } //-----------------or complete real key code when input with wildcard else if (_isCandidateWithWildcard) { const WCHAR* pCandidateKeyCode = nullptr; DWORD_PTR keyCodeLen = _pUIPresenter->_GetSelectedCandidateKeyCode(&pCandidateKeyCode); StringCchCopy(_commitKeyCode, 1, L"\0"); StringCchCatN(_commitKeyCode, MAX_KEY_LENGTH, pCandidateKeyCode, keyCodeLen); CStringRange commitKeyCode, convertedKeyCode; _pCompositionProcessorEngine->GetReadingString(&convertedKeyCode, NULL, &commitKeyCode.Set(_commitKeyCode, wcslen(_commitKeyCode))); _pUIPresenter->ShowNotifyText(&convertedKeyCode); } } //-----------------do array spcial code notify. We should not show notify in UI-less mode, thus cancel forceSP mode in UILess Mode--- BOOL ArraySPFound = FALSE; if(Global::imeMode == IME_MODE_ARRAY && !_IsUILessMode() && !arrayUsingSPCode && (CConfig::GetArrayForceSP() || CConfig::GetArrayNotifySP())) { CStringRange specialCode; CStringRange notifyText; ArraySPFound = _pCompositionProcessorEngine->GetArraySpeicalCodeFromConvertedText(&commitString, &specialCode); if(specialCode.Get()) _pUIPresenter->ShowNotifyText(&specialCode); } convertedString = commitString; //----------------- do TC to SC covert if required---------------------------------------------------------------------------------- if(CConfig::GetDoHanConvert()) { _pCompositionProcessorEngine->GetSCFromTC(&commitString, &convertedString); } //----------------- commit the selected string ------------------------------------------------------------------------------------ if(Global::imeMode == IME_MODE_ARRAY && !_IsUILessMode() && !arrayUsingSPCode && CConfig::GetArrayForceSP() && ArraySPFound ) { _HandleCancel(ec, pContext); DoBeep(BEEP_WARNING); return hr; } else { hr = _AddComposingAndChar(ec, pContext, &convertedString); if (FAILED(hr)) return hr; // Do not send _endcandidatelist (or handleComplete) here to avoid cand dissapear in win8 metro _HandleComplete(ec,pContext); } //-----------------do accociated phrase (make phrase)-------------------------------------------------------------------------------- if (CConfig::GetMakePhrase()) { _pCompositionProcessorEngine->GetCandidateStringInConverted(lastChar, &candidatePhraseList); // We have a candidate list if candidatePhraseList.Cnt is not 0 // If we are showing reverse conversion, use UIPresenter if (candidatePhraseList.Count()) { CStringRange emptyComposition; if (!_IsComposing()) _StartComposition(pContext); //StartCandidateList require a valid selection from a valid pComposition to determine the location to show the candidate window _AddComposingAndChar(ec, pContext, &emptyComposition.Set(L" ",1)); _pUIPresenter->_ClearCandidateList(); _pUIPresenter->_SetCandidateTextColor(CConfig::GetPhraseColor(), CConfig::GetItemBGColor()); // Text color is green _pUIPresenter->_SetCandidateSelectedTextColor(CConfig::GetSelectedColor(), CConfig::GetSelectedBGColor()); _pUIPresenter->_SetCandidateNumberColor(CConfig::GetNumberColor(), CConfig::GetItemBGColor()); _pUIPresenter->_SetCandidateFillColor(CConfig::GetItemBGColor());//(HBRUSH)(COLOR_WINDOW+1)); // Background color is window _pUIPresenter->_SetCandidateText(&candidatePhraseList, _pCompositionProcessorEngine->GetCandidateListIndexRange(), TRUE, _pCompositionProcessorEngine->GetCandidateWindowWidth()); _pUIPresenter->_SetCandidateSelection(-1, FALSE); // set selected index to -1 if showing phrase candidates _candidateMode = CANDIDATE_PHRASE; _isCandidateWithWildcard = FALSE; } else { //cancel the composition if the phrase lookup return 0 results _HandleCancel(ec,pContext); } } else _DeleteCandidateList(TRUE, pContext); // endCanddiateUI if not doing associated phrase. Exit: return hr; }