STDAPI WeaselTSF::DoEditSession(TfEditCookie ec) { ITfInsertAtSelection *pInsertAtSelection; ITfRange *pRange; TF_SELECTION tfSelection; if (_pEditSessionContext->QueryInterface(IID_ITfInsertAtSelection, (LPVOID *) &pInsertAtSelection) != S_OK) return E_FAIL; /* insert the text */ if (pInsertAtSelection->InsertTextAtSelection(ec, 0, _pEditSessionText, _cEditSessionText, &pRange) != S_OK) { pInsertAtSelection->Release(); return E_FAIL; } /* update the selection to an insertion point just past the inserted text. */ pRange->Collapse(ec, TF_ANCHOR_END); tfSelection.range = pRange; tfSelection.style.ase = TF_AE_NONE; tfSelection.style.fInterimChar = FALSE; _pEditSessionContext->SetSelection(ec, 1, &tfSelection); pRange->Release(); pInsertAtSelection->Release(); return S_OK; }
// callback from edit session for starting composition HRESULT TextService::doStartCompositionEditSession(TfEditCookie cookie, StartCompositionEditSession* session) { ITfContext* context = session->context(); ITfContextComposition* contextComposition; if(context->QueryInterface(IID_ITfContextComposition, (void**)&contextComposition) == S_OK) { // get current insertion point in the current context ITfRange* range = NULL; ITfInsertAtSelection* insertAtSelection; if(context->QueryInterface(IID_ITfInsertAtSelection, (void **)&insertAtSelection) == S_OK) { // get current selection range & insertion position (query only, did not insert any text) insertAtSelection->InsertTextAtSelection(cookie, TF_IAS_QUERYONLY, NULL, 0, &range); insertAtSelection->Release(); } if(range) { if(contextComposition->StartComposition(cookie, range, (ITfCompositionSink*)this, &composition_) == S_OK) { // according to the TSF sample provided by M$, we need to reset current // selection here. (maybe the range is altered by StartComposition()? // So mysterious. TSF is absolutely overly-engineered! TF_SELECTION selection; selection.range = range; selection.style.ase = TF_AE_NONE; selection.style.fInterimChar = FALSE; context->SetSelection(cookie, 1, &selection); // we did not release composition_ object. we store it for use later } range->Release(); } contextComposition->Release(); } return S_OK; }
void InsertTextAtSelection(TfEditCookie ec, ITfContext *pContext, const WCHAR *pchText, ULONG cchText) { ITfInsertAtSelection *pInsertAtSelection; ITfRange *pRange; TF_SELECTION tfSelection; // we need a special interface to insert text at the selection if (pContext->QueryInterface(IID_ITfInsertAtSelection, (void **)&pInsertAtSelection) != S_OK) return; // insert the text if (pInsertAtSelection->InsertTextAtSelection(ec, 0, pchText, cchText, &pRange) != S_OK) goto Exit; // update the selection, we'll make it an insertion point just past // the inserted text. pRange->Collapse(ec, TF_ANCHOR_END); tfSelection.range = pRange; tfSelection.style.ase = TF_AE_NONE; tfSelection.style.fInterimChar = FALSE; pContext->SetSelection(ec, 1, &tfSelection); pRange->Release(); Exit: pInsertAtSelection->Release(); }
STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) { ITfInsertAtSelection *pInsertAtSelection = NULL; ITfRange *pRangeInsert = NULL; ITfContextComposition *pContextComposition = NULL; ITfComposition *pComposition = NULL; HRESULT hr = E_FAIL; // we need a special interface to insert text at the selection if (_pContext->QueryInterface(IID_ITfInsertAtSelection, (void **)&pInsertAtSelection) != S_OK) { goto Exit; } // insert the text if (pInsertAtSelection->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, NULL, 0, &pRangeInsert) != S_OK) { goto Exit; } // get an interface on the context we can use to deal with compositions if (_pContext->QueryInterface(IID_ITfContextComposition, (void **)&pContextComposition) != S_OK) { goto Exit; } // start the new composition if ((pContextComposition->StartComposition(ec, pRangeInsert, _pTextService, &pComposition) == S_OK) && (pComposition != NULL)) { // Store the pointer of this new composition object in the instance // of the CTextService class. So this instance of the CTextService // class can know now it is in the composition stage. _pTextService->_SetComposition(pComposition); // // set selection to the adjusted range // TF_SELECTION tfSelection; tfSelection.range = pRangeInsert; tfSelection.style.ase = TF_AE_NONE; tfSelection.style.fInterimChar = FALSE; _pContext->SetSelection(ec, 1, &tfSelection); } Exit: if (pContextComposition != NULL) pContextComposition->Release(); if (pRangeInsert != NULL) pRangeInsert->Release(); if (pInsertAtSelection != NULL) pInsertAtSelection->Release(); return S_OK; }
STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) { ITfInsertAtSelection* pInsertAtSelection = nullptr; ITfRange* pRangeInsert = nullptr; ITfContextComposition* pContextComposition = nullptr; ITfComposition* pComposition = nullptr; if (FAILED(_pContext->QueryInterface(IID_ITfInsertAtSelection, (void **)&pInsertAtSelection))) { goto Exit; } if (FAILED(pInsertAtSelection->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, NULL, 0, &pRangeInsert))) { goto Exit; } if (FAILED(_pContext->QueryInterface(IID_ITfContextComposition, (void **)&pContextComposition))) { goto Exit; } if (SUCCEEDED(pContextComposition->StartComposition(ec, pRangeInsert, _pTextService, &pComposition)) && (nullptr != pComposition)) { _pTextService->_SetComposition(pComposition); // set selection to the adjusted range TF_SELECTION tfSelection; tfSelection.range = pRangeInsert; tfSelection.style.ase = TF_AE_NONE; tfSelection.style.fInterimChar = FALSE; _pContext->SetSelection(ec, 1, &tfSelection); _pTextService->_SaveCompositionContext(_pContext); } Exit: if (nullptr != pContextComposition) { pContextComposition->Release(); } if (nullptr != pRangeInsert) { pRangeInsert->Release(); } if (nullptr != pInsertAtSelection) { pInsertAtSelection->Release(); } return S_OK; }
STDAPI CStartCompositionEditSession::DoEditSession(TfEditCookie ec) { HRESULT hr = E_FAIL; ITfInsertAtSelection *pInsertAtSelection = NULL; ITfRange *pRangeComposition = NULL; if (_pContext->QueryInterface(IID_ITfInsertAtSelection, (LPVOID *) &pInsertAtSelection) != S_OK) goto Exit; if (pInsertAtSelection->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, NULL, 0, &pRangeComposition) != S_OK) goto Exit; ITfContextComposition *pContextComposition = NULL; ITfComposition *pComposition = NULL; if (_pContext->QueryInterface(IID_ITfContextComposition, (LPVOID *) &pContextComposition) != S_OK) goto Exit; if ((pContextComposition->StartComposition(ec, pRangeComposition, _pTextService, &pComposition) == S_OK) && (pComposition != NULL)) { _pTextService->_SetComposition(pComposition); /* set selection */ /* WORKAROUND: * CUAS does not provide a correct GetTextExt() position unless the composition is filled with characters. * So we insert a dummy space character here. * This is the same workaround used by Microsoft Pinyin IME (New Experience). */ if (_fCUASWorkaroundEnabled) { pRangeComposition->SetText(ec, TF_ST_CORRECTION, L" ", 1); pRangeComposition->Collapse(ec, TF_ANCHOR_START); } TF_SELECTION tfSelection; tfSelection.range = pRangeComposition; tfSelection.style.ase = TF_AE_NONE; tfSelection.style.fInterimChar = FALSE; _pContext->SetSelection(ec, 1, &tfSelection); } Exit: if (pContextComposition != NULL) pContextComposition->Release(); if (pRangeComposition != NULL) pRangeComposition->Release(); if (pInsertAtSelection != NULL) pInsertAtSelection->Release(); return hr; }
HRESULT CDIME::_InsertAtSelection(TfEditCookie ec, _In_ ITfContext *pContext, _In_ CStringRange *pstrAddString, _Outptr_ ITfRange **ppCompRange) { debugPrint(L"CDIME::_InsertAtSelection()"); ITfRange* rangeInsert = nullptr; ITfInsertAtSelection* pias = nullptr; HRESULT hr = S_OK; if (ppCompRange == nullptr || pContext == nullptr || pstrAddString == nullptr) { debugPrint(L"CDIME::_InsertAtSelection() failed with null ppCompRange or pContext or pstrAddstring"); hr = E_INVALIDARG; goto Exit; } *ppCompRange = nullptr; hr = pContext->QueryInterface(IID_ITfInsertAtSelection, (void **)&pias); if (FAILED(hr) || pias == nullptr) { debugPrint(L"CDIME::_InsertAtSelection() failed with null pias or QueryInterface failed"); goto Exit; } hr = pias->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, pstrAddString->Get(), (LONG)pstrAddString->GetLength(), &rangeInsert); if ( FAILED(hr) || rangeInsert == nullptr) { debugPrint(L"CDIME::_InsertAtSelection() InsertTextAtSelection failed"); rangeInsert = nullptr; pias->Release(); goto Exit; } WCHAR rangeText[256]; rangeText[0] = NULL; ULONG fetched = 0; hr = rangeInsert->GetText(ec, 0, rangeText, 256, &fetched); if (SUCCEEDED(hr) && rangeText) debugPrint(L"CDIME::_InsertAtSelection() text in range = %s", rangeText); *ppCompRange = rangeInsert; pias->Release(); hr = S_OK; Exit: return hr; }
STDAPI CGetTextExtentEditSession::DoEditSession(TfEditCookie ec) { ITfInsertAtSelection *pInsertAtSelection = NULL; ITfRange *pRangeComposition = NULL; RECT rc; BOOL fClipped; if ((_pContext->QueryInterface(IID_ITfInsertAtSelection, (LPVOID *) &pInsertAtSelection)) != S_OK) goto Exit; if ((pInsertAtSelection->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, NULL, 0, &pRangeComposition)) != S_OK) goto Exit; if ((_pContextView->GetTextExt(ec, pRangeComposition, &rc, &fClipped)) == S_OK) _pTextService->_SetCompositionPosition(rc); Exit: if (pRangeComposition != NULL) pRangeComposition->Release(); if (pInsertAtSelection != NULL) pInsertAtSelection->Release(); return S_OK; }
HRESULT CSampleIME::_InsertAtSelection(TfEditCookie ec, _In_ ITfContext *pContext, _In_ const std::wstring &pstrAddString, _Outptr_ ITfRange **ppCompRange) { ITfRange* rangeInsert = nullptr; ITfInsertAtSelection* pias = nullptr; HRESULT hr = S_OK; if (ppCompRange == nullptr) { hr = E_INVALIDARG; goto Exit; } *ppCompRange = nullptr; hr = pContext->QueryInterface(IID_ITfInsertAtSelection, (void **)&pias); if (FAILED(hr)) { goto Exit; } hr = pias->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, pstrAddString.c_str(), pstrAddString.length(), &rangeInsert); if ( FAILED(hr) || rangeInsert == nullptr) { rangeInsert = nullptr; pias->Release(); goto Exit; } *ppCompRange = rangeInsert; pias->Release(); hr = S_OK; Exit: return hr; }
STDAPI CCompositionEditSession::DoEditSession(TfEditCookie ec) { ITfInsertAtSelection *pInsertAtSelection; ITfContextComposition *pContextComposition; ITfComposition *pComposition; ITfRange *pRangeComposition; ITfRange *pRangeInsert; ITfContext *pCompositionContext; HRESULT hr; BOOL fEqualContexts; // get an interface on the context we can use to deal with compositions if (_pContext->QueryInterface(IID_ITfContextComposition, (void **)&pContextComposition) != S_OK) return E_FAIL; hr = E_FAIL; pInsertAtSelection = NULL; if (_pMark->_IsComposing()) { // we have a composition, let's terminate it // it's possible our current composition is in another context...let's find out fEqualContexts = TRUE; if (_pMark->_GetComposition()->GetRange(&pRangeComposition) == S_OK) { if (pRangeComposition->GetContext(&pCompositionContext) == S_OK) { fEqualContexts = IsEqualUnknown(pCompositionContext, _pContext); if (!fEqualContexts) { // need an edit session in the composition context _pMark->_TerminateCompositionInContext(pCompositionContext); } pCompositionContext->Release(); } pRangeComposition->Release(); } // if the composition is in pContext, we already have an edit cookie if (fEqualContexts) { _pMark->_TerminateComposition(ec); } } else { // let's start a new composition over the current selection // this is totally contrived, a real text service would have // some meaningful logic to trigger this // first, test where a keystroke would go in the document if we did an insert // we need a special interface to insert text at the selection if (_pContext->QueryInterface(IID_ITfInsertAtSelection, (void **)&pInsertAtSelection) != S_OK) { pInsertAtSelection = NULL; goto Exit; } if (pInsertAtSelection->InsertTextAtSelection(ec, TF_IAS_QUERYONLY, NULL, 0, &pRangeInsert) != S_OK) goto Exit; // start the composition if (pContextComposition->StartComposition(ec, pRangeInsert, _pMark, &pComposition) != S_OK) { pComposition = NULL; } pRangeInsert->Release(); // _pComposition may be NULL even if StartComposition return S_OK, this mean the application // rejected the composition if (pComposition != NULL) { _pMark->_SetComposition(pComposition); // underline the composition text to give the user some feedback UI _pMark->_SetCompositionDisplayAttributes(ec); } } // if we make it here, we've succeeded hr = S_OK; Exit: SafeRelease(pInsertAtSelection); pContextComposition->Release(); return hr; }