void CMarkTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec) { ITfRange *pRangeComposition; ITfContext *pContext; ITfProperty *pDisplayAttributeProperty; // we need a range and the context it lives in if (_pComposition->GetRange(&pRangeComposition) != S_OK) return; if (pRangeComposition->GetContext(&pContext) != S_OK) { pContext = NULL; goto Exit; } // get our the display attribute property if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) != S_OK) goto Exit; // clear the value over the range pDisplayAttributeProperty->Clear(ec, pRangeComposition); pDisplayAttributeProperty->Release(); Exit: pRangeComposition->Release(); SafeRelease(pContext); }
BOOL CMarkTextService::_SetCompositionDisplayAttributes(TfEditCookie ec) { ITfRange *pRangeComposition; ITfContext *pContext; ITfProperty *pDisplayAttributeProperty; VARIANT var; HRESULT hr; // we need a range and the context it lives in if (_pComposition->GetRange(&pRangeComposition) != S_OK) return FALSE; hr = E_FAIL; if (pRangeComposition->GetContext(&pContext) != S_OK) { pContext = NULL; goto Exit; } // get our the display attribute property if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) != S_OK) goto Exit; // set the value over the range // the application will use this guid atom to lookup the acutal rendering information var.vt = VT_I4; // we're going to set a TfGuidAtom var.lVal = _gaDisplayAttribute; // our cached guid atom for c_guidMarkDisplayAttribute hr = pDisplayAttributeProperty->SetValue(ec, pRangeComposition, &var); pDisplayAttributeProperty->Release(); Exit: pRangeComposition->Release(); SafeRelease(pContext); return (hr == S_OK); }
STDAPI CMarkTextService::OnEndEdit(ITfContext *pContext, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) { ITfRange *pRangeComposition; IEnumTfRanges *pEnumRanges; ITfRange *pRange; ITfContext *pCompositionContext; TF_SELECTION tfSelection; BOOL fResult; BOOL fCancelComposition; ULONG cFetched; if (_pComposition == NULL) return S_OK; // are we responsible for the edit? if (pContext->InWriteSession(_tfClientId, &fResult) == S_OK && fResult) return S_OK; // is this the context our composition lives in? if (_pComposition->GetRange(&pRangeComposition) != S_OK) return S_OK; if (pRangeComposition->GetContext(&pCompositionContext) != S_OK) goto Exit; fResult = IsEqualUnknown(pCompositionContext, pContext); pCompositionContext->Release(); if (!fResult) goto Exit; // different context fCancelComposition = FALSE; // we're composing in this context, cancel the composition if anything suspicious happened // did the selection move outside the composition? if (pEditRecord->GetSelectionStatus(&fResult) == S_OK && fResult) { if (pContext->GetSelection(ecReadOnly, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) == S_OK && cFetched == 1) { if (_pComposition->GetRange(&pRangeComposition) == S_OK) { fResult = IsRangeCovered(ecReadOnly, tfSelection.range, pRangeComposition); pRangeComposition->Release(); if (!fResult) { fCancelComposition = TRUE; } } tfSelection.range->Release(); } } if (fCancelComposition) goto CancelComposition; // did someone else edit the document text? if (pEditRecord->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT, NULL, 0, &pEnumRanges) == S_OK) { // is the enumerator empty? if (pEnumRanges->Next(1, &pRange, NULL) == S_OK) { pRange->Release(); fCancelComposition = TRUE; } pEnumRanges->Release(); } if (fCancelComposition) { CancelComposition: // we need a write edit session to cancel the composition _TerminateCompositionInContext(pContext); } Exit: pRangeComposition->Release(); return S_OK; }
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; }