/* 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); } }
STDAPI CDIME::OnCompositionTerminated(TfEditCookie ecWrite, _In_ ITfComposition *pComposition) { debugPrint(L"CDIME::OnCompositionTerminated()"); HRESULT hr = S_OK; ITfContext* pContext = _pContext; // Clear dummy composition _RemoveDummyCompositionForComposing(ecWrite, pComposition); // Clear display attribute and end composition, _EndComposition will release composition for us if (pContext) { pContext->AddRef(); } _EndComposition(pContext); _DeleteCandidateList(TRUE, pContext); if (pContext) { pContext->Release(); pContext = nullptr; } return hr; }
STDAPI CTextService::OnEndEdit(ITfContext *pContext, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) { BOOL fSelectionChanged; IEnumTfRanges *pEnumTextChanges; ITfRange *pRange; // // did the selection change? // The selection change includes the movement of caret as well. // The caret position is represent as the empty selection range when // there is no selection. // if (pEditRecord->GetSelectionStatus(&fSelectionChanged) == S_OK && fSelectionChanged) { // If the selection is moved to out side of the current composition, // we terminate the composition. This TextService supports only one // composition in one context object. if (_IsComposing()) { TF_SELECTION tfSelection; ULONG cFetched; if (pContext->GetSelection(ecReadOnly, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) == S_OK && cFetched == 1) { ITfRange *pRangeComposition; // is the insertion point covered by a composition? if (_pComposition->GetRange(&pRangeComposition) == S_OK) { if (!IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition)) { _EndComposition(pContext); } pRangeComposition->Release(); } } } } // text modification? if (pEditRecord->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, &pEnumTextChanges) == S_OK) { if (pEnumTextChanges->Next(1, &pRange, NULL) == S_OK) { // // pRange is the updated range. // pRange->Release(); } pEnumTextChanges->Release(); } return S_OK; }
HRESULT COVTSF::_HandleCompositionFinalize(TfEditCookie ec, _In_ ITfContext *pContext, BOOL isCandidateList) { HRESULT hr = S_OK; if (isCandidateList && _pCandidateListUIPresenter) { // Finalize selected candidate string from CCandidateListUIPresenter DWORD_PTR candidateLen = 0; const WCHAR *pCandidateString = nullptr; candidateLen = _pCandidateListUIPresenter->_GetSelectedCandidateString(&pCandidateString); CStringRange candidateString; candidateString.Set(pCandidateString, candidateLen); if (candidateLen) { // Finalize character hr = _AddCharAndFinalize(ec, pContext, &candidateString); if (FAILED(hr)) { return hr; } } } else { // Finalize current text store strings if (_IsComposing()) { ULONG fetched = 0; TF_SELECTION tfSelection; if (FAILED(pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) || fetched != 1) { return S_FALSE; } ITfRange* pRangeComposition = nullptr; if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition))) { if (_IsRangeCovered(ec, tfSelection.range, pRangeComposition)) { _EndComposition(pContext); } pRangeComposition->Release(); } tfSelection.range->Release(); } } _HandleCancel(ec, pContext); 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; }
void CDIME::OnKeyboardClosed() { debugPrint(L"CDIME::OnKeyboardClosed()\n"); // switching to English (native) mode delete the phrase candidate window before exting. _isChinese = FALSE; if(_IsComposing()) { _EndComposition(_pContext); } _DeleteCandidateList(TRUE,_pContext); }
void CDIME::OnSwitchedToHalfShape() { debugPrint(L"CDIME::OnSwitchedToHalfShape()\n"); _isFullShape = FALSE; if(_IsComposing()) { _EndComposition(_pContext); } _DeleteCandidateList(TRUE,_pContext); if (CConfig::GetDoubleSingleByteMode() != DOUBLE_SINGLE_BYTE_SHIFT_SPACE) CConfig::SetDoubleSingleByteMode(DOUBLE_SINGLE_BYTE_ALWAYS_SINGLE); }
STDAPI CSampleIME::OnEndEdit(__RPC__in_opt ITfContext *pContext, TfEditCookie ecReadOnly, __RPC__in_opt ITfEditRecord *pEditRecord) { BOOL isSelectionChanged; // // did the selection change? // The selection change includes the movement of caret as well. // The caret position is represent as the empty selection range when // there is no selection. // if (pEditRecord == nullptr) { return E_INVALIDARG; } if (SUCCEEDED(pEditRecord->GetSelectionStatus(&isSelectionChanged)) && isSelectionChanged) { // If the selection is moved to out side of the current composition, // we terminate the composition. This TextService supports only one // composition in one context object. if (_IsComposing()) { TF_SELECTION tfSelection; ULONG fetched = 0; if (pContext == nullptr) { return E_INVALIDARG; } if (FAILED(pContext->GetSelection(ecReadOnly, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) || fetched != 1) { return S_FALSE; } ITfRange* pRangeComposition = nullptr; if (SUCCEEDED(_pComposition->GetRange(&pRangeComposition))) { if (!_IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition)) { _EndComposition(pContext); } pRangeComposition->Release(); } tfSelection.range->Release(); } } return S_OK; }
STDAPI CTextService::OnEndEdit(ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) { if(_IsComposing() && pic != nullptr) { ITfRange *pRange = nullptr; if(SUCCEEDED(_pComposition->GetRange(&pRange)) && (pRange != nullptr)) { // clear when auto completion BOOL fEmpty = FALSE; if(SUCCEEDED(pRange->IsEmpty(ecReadOnly, &fEmpty)) && fEmpty) { if(!roman.empty() || !kana.empty()) { _ResetStatus(); _EndComposition(pic); } } // reposition candidate window if(_pCandidateList != nullptr) { ITfContextView *pContextView = nullptr; if(SUCCEEDED(pic->GetActiveView(&pContextView)) && (pContextView != nullptr)) { RECT rc = {}; BOOL fClipped; if(SUCCEEDED(pContextView->GetTextExt(ecReadOnly, pRange, &rc, &fClipped))) { _pCandidateList->_Move(&rc, ecReadOnly, pic); } SafeRelease(&pContextView); } } SafeRelease(&pRange); } } return S_OK; }
STDAPI CSampleIME::OnCompositionTerminated(TfEditCookie ecWrite, _In_ ITfComposition *pComposition) { // Clear dummy composition _RemoveDummyCompositionForComposing(ecWrite, pComposition); // Clear display attribute and end composition, _EndComposition will release composition for us ITfContext* pContext = _pContext; if (pContext) { pContext->AddRef(); } _EndComposition(_pContext); _DeleteCandidateList(FALSE, pContext); if (pContext) { pContext->Release(); pContext = nullptr; } return S_OK; }