BOOL CSampleIME::_FindComposingRange(TfEditCookie ec, _In_ ITfContext *pContext, _In_ ITfRange *pSelection, _Outptr_result_maybenull_ ITfRange **ppRange)
{
    if (ppRange == nullptr)
    {
        return FALSE;
    }

    *ppRange = nullptr;

    // find GUID_PROP_COMPOSING
    ITfProperty* pPropComp = nullptr;
    IEnumTfRanges* enumComp = nullptr;

	/* GetProperty(GUID_PROP_COMPOSING, ...) -- nonzero if text is part of a composition */
    HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp);
    if (FAILED(hr) || pPropComp == nullptr)
    {
        return FALSE;
    }

	/* EnumRanges:
		Obtains an enumeration of ranges that contain unique values of the property GUID_PROP_COMPOSING within the given range */
    hr = pPropComp->EnumRanges(ec, &enumComp, pSelection);
    if (FAILED(hr) || enumComp == nullptr)
    {
        pPropComp->Release();
        return FALSE;
    }

    BOOL isCompExist = FALSE;
    VARIANT var;
    ULONG  fetched = 0;

    while (enumComp->Next(1, ppRange, &fetched) == S_OK && fetched == 1)
    {
        hr = pPropComp->GetValue(ec, *ppRange, &var);
        if (hr == S_OK)
        {
            if (var.vt == VT_I4 && var.lVal != 0)
            {
                isCompExist = TRUE;
                break;
            }
        }
        (*ppRange)->Release();
        *ppRange = nullptr;
    }

    pPropComp->Release();
    enumComp->Release();

    return isCompExist;
}
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 CTextService::_SetCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext, TfGuidAtom gaDisplayAttribute)
{
    ITfRange *pRangeComposition;
    ITfProperty *pDisplayAttributeProperty;
    HRESULT hr;

    // we need a range and the context it lives in
    if (_pComposition->GetRange(&pRangeComposition) != S_OK)
        return FALSE;

    hr = E_FAIL;

    // get our the display attribute property
    if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) == S_OK)
    {
        VARIANT var;
        // 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; 

        hr = pDisplayAttributeProperty->SetValue(ec, pRangeComposition, &var);

        pDisplayAttributeProperty->Release();
    }

    pRangeComposition->Release();
    return (hr == S_OK);
}
BOOL CSampleIME::_SetCompositionLanguage(TfEditCookie ec, _In_ ITfContext *pContext)
{
    HRESULT hr = S_OK;
    BOOL ret = TRUE;

    LANGID langidProfile = 0;
    GetLanguageProfile(&langidProfile);

    ITfRange* pRangeComposition = nullptr;
    ITfProperty* pLanguageProperty = nullptr;

    // we need a range and the context it lives in
    hr = _pComposition->GetRange(&pRangeComposition);
    if (FAILED(hr))
    {
        ret = FALSE;
        goto Exit;
    }

    // get our the language property
    hr = pContext->GetProperty(GUID_PROP_LANGID, &pLanguageProperty);
    if (FAILED(hr))
    {
        ret = FALSE;
        goto Exit;
    }

    VARIANT var;
    var.vt = VT_I4;   // we're going to set DWORD
    var.lVal = langidProfile; 

    hr = pLanguageProperty->SetValue(ec, pRangeComposition, &var);
    if (FAILED(hr))
    {
        ret = FALSE;
        goto Exit;
    }

    pLanguageProperty->Release();
    pRangeComposition->Release();

Exit:
    return ret;
}
void CTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext)
{
    ITfRange *pRangeComposition;
    ITfProperty *pDisplayAttributeProperty;

    // get the compositon range.
    if (_pComposition->GetRange(&pRangeComposition) != S_OK)
        return;

    // get our the display attribute property
    if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) == S_OK)
    {
        // clear the value over the range
        pDisplayAttributeProperty->Clear(ec, pRangeComposition);

        pDisplayAttributeProperty->Release();
    }

    pRangeComposition->Release();
}
STDAPI CStaticPropertyEditSession::DoEditSession(TfEditCookie ec)
{
    ITfProperty *pProperty;
    TF_SELECTION tfSelection;
    ULONG cFetched;

    if (_pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1)
        return S_FALSE;

    if (_pContext->GetProperty(c_guidPropStatic, &pProperty) == S_OK)
    {
        VARIANT var;
        var.vt = VT_BSTR; 
        var.bstrVal = SysAllocString(_sz);
        pProperty->SetValue(ec, tfSelection.range, &var);
        pProperty->Release();
    }

    tfSelection.range->Release();
    return S_OK;
}
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);
}
Example #8
0
BOOL CDIME::_SetCompositionLanguage(TfEditCookie ec, _In_ ITfContext *pContext)
{
	debugPrint(L"CDIME::_SetCompositionLanguage()");
    HRESULT hr = S_OK;
    BOOL ret = TRUE;

	if (pContext == nullptr || _pComposition == nullptr)
    {
		debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pContext or _pComposition");
		ret = FALSE;
        goto Exit;
    }

    ITfRange* pRangeComposition = nullptr;
    ITfProperty* pLanguageProperty = nullptr;

    // we need a range and the context it lives in
    hr = _pComposition->GetRange(&pRangeComposition);
    if (FAILED(hr) || pRangeComposition == nullptr)
    {
		if (FAILED(hr))
			debugPrint(L"CDIME::_SetCompositionLanguage() _pComposition->GetRange() failed");
		else
			debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pRangeComposition");

        ret = FALSE;
        goto Exit;
    }

    // get our the language property
    hr = pContext->GetProperty(GUID_PROP_LANGID, &pLanguageProperty);
    if (FAILED(hr) || pLanguageProperty == nullptr)
    {
		if (FAILED(hr))
			debugPrint(L"CDIME::_SetCompositionLanguage() pContext->GetProperty() failed hr = %x", hr);
		else
			debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pLanguageProperty");

        ret = FALSE;
        goto Exit;
    }

    VARIANT var;
    var.vt = VT_I4;   // we're going to set DWORD
    var.lVal = _langid; 

    hr = pLanguageProperty->SetValue(ec, pRangeComposition, &var);
    if (FAILED(hr) || pRangeComposition == nullptr)
    {
		if (FAILED(hr))
			debugPrint(L"CDIME::_SetCompositionLanguage() pLanguageProperty->SetValue() failed hr = %x", hr);
		else
			debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pRangeComposition ");

        ret = FALSE;
        goto Exit;
    }

    pLanguageProperty->Release();
    pRangeComposition->Release();

Exit:
    return ret;
}
Example #9
0
BOOL CDIME::_FindComposingRange(TfEditCookie ec, _In_ ITfContext *pContext, _In_ ITfRange *pSelection, _Outptr_result_maybenull_ ITfRange **ppRange)
{
	debugPrint(L"CDIME::_FindComposingRange()");

    if (pContext == nullptr || ppRange == nullptr)
    {
		debugPrint(L"CDIME::_FindComposingRange() failed with null pContext or pRange");
        return FALSE;
    }

    *ppRange = nullptr;

    // find GUID_PROP_COMPOSING
    ITfProperty* pPropComp = nullptr;
    IEnumTfRanges* enumComp = nullptr;

    HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp);
    if (FAILED(hr) || pPropComp == nullptr)
    {
		if (FAILED(hr))
			debugPrint(L"CDIME::_FindComposingRange()  pContext->GetProperty() failed");
		else
			debugPrint(L"CDIME::_FindComposingRange() failed with null pPropComp");
        return FALSE;
    }

    hr = pPropComp->EnumRanges(ec, &enumComp, pSelection);
    if (FAILED(hr) || enumComp == nullptr)
    {
		if (FAILED(hr))
			debugPrint(L"CDIME::_FindComposingRange()  pPropComp->EnumRanges failed");
		else
			debugPrint(L"CDIME::_FindComposingRange() failed with null enumComp");
        pPropComp->Release();
        return FALSE;
    }

    BOOL isCompExist = FALSE;
    VARIANT var;
    ULONG  fetched = 0;

    while (enumComp->Next(1, ppRange, &fetched) == S_OK && fetched == 1)
    {
		debugPrint(L"CDIME::_FindComposingRange() enumComp->Next() ");
        hr = pPropComp->GetValue(ec, *ppRange, &var);
        if (hr == S_OK)
        {
            if (var.vt == VT_I4 && var.lVal != 0)
            {
				WCHAR rangeText[4096];
				rangeText[0] = NULL;
				fetched = 0;
				hr = (*ppRange)->GetText(ec, 0, rangeText, 4096, &fetched);
				if (SUCCEEDED(hr))
				{
					if (lastReadingString.GetLength() > 0) // The last reading string is null when composing is just started and the range should be empty.
					{
						debugPrint(L"CDIME::_FindComposingRange() text in range = %s with %d character, last reading string = %s with %d characters",
							rangeText, fetched, lastReadingString.Get(), lastReadingString.GetLength());
						UINT cmpCount = (int)lastReadingString.GetLength();
						BOOL rangeMatchReadingString = FALSE;
						if (fetched > 0 && fetched > cmpCount)
						{
							LONG shifted = 0;
							// range contains other characters than last reading string, and these characters should be skipped with shifting the start anchor
							(*ppRange)->ShiftStart(ec, fetched - cmpCount, &shifted, NULL);
							debugPrint(L"CDIME::_FindComposingRange() shift start anchor with %d characters", shifted);
							rangeText[0] = NULL;
							hr = (*ppRange)->GetText(ec, 0, rangeText, 4096, &fetched);
							if (SUCCEEDED(hr))
								debugPrint(L"CDIME::_FindComposingRange() text in range with shited anchor = %s with %d character", rangeText, fetched);
						}
						// The range we are composing should always matched with the last reading string.
						rangeMatchReadingString = CompareString(GetLocale(), 0, rangeText, cmpCount, lastReadingString.Get(), cmpCount) == CSTR_EQUAL;
				
						if (rangeMatchReadingString)
						{
							isCompExist = TRUE;
							debugPrint(L"CDIME::_FindComposingRange() text in this range mathced with last reading string. isCompExist = TRUE");
							break;
						}
					}
					
				}
				else
				{
					debugPrint(L"CDIME::_FindComposingRange() cannot getText from range isCompExist = TRUE");
				}
            }
        }
		debugPrint(L"CDIME::_FindComposingRange() release *ppRange");
        if(*ppRange)
			(*ppRange)->Release();
        *ppRange = nullptr;
    }

    pPropComp->Release();
    enumComp->Release();

    return isCompExist;
}
void CTSFEditWnd::_Save(IStream *pStream)
{
    if(pStream)
    {
        HRESULT hr;
        
        //write the plain UNICODE text into the stream
        LPWSTR          pwsz;
        LONG            cch;
        ULONG           uWritten;
        LARGE_INTEGER   li;
        ULONG           uSize;

        //set the stream pointer to the start of the stream
        li.QuadPart = 0;
        pStream->Seek(li, STREAM_SEEK_SET, NULL);
        
        //get the text
        if(SUCCEEDED(_GetText(&pwsz, &cch)))
        {
            TF_PERSISTENT_PROPERTY_HEADER_ACP   PropHeader;

            //write the size, in BYTES, of the text
            uSize = cch * sizeof(WCHAR);
            hr = pStream->Write(&uSize, sizeof(ULONG), &uWritten);

            //write the text, including the NULL_terminator, into the stream
            hr = pStream->Write(pwsz, uSize, &uWritten);

            //free the memory allocated by _GetText
            GlobalFree(pwsz);

            //enumerate the properties in the context
            IEnumTfProperties   *pEnumProps;
            hr = m_pContext->EnumProperties(&pEnumProps);
            if(SUCCEEDED(hr))
            {
                ITfProperty *pProp;
                ULONG       uFetched;

                while(SUCCEEDED(pEnumProps->Next(1, &pProp, &uFetched)) && uFetched)
                {
                    //enumerate all the ranges that contain the property
                    IEnumTfRanges   *pEnumRanges;
                    hr = pProp->EnumRanges(m_EditCookie, &pEnumRanges, NULL);
                    if(SUCCEEDED(hr))
                    {
                        IStream *pTempStream;

                        //create a temporary stream to write the property data to
                        hr = CreateStreamOnHGlobal(NULL, TRUE, &pTempStream);
                        if(SUCCEEDED(hr))
                        {
                            ITfRange    *pRange;

                            while(SUCCEEDED(pEnumRanges->Next(1, &pRange, &uFetched)) && uFetched)
                            {
                                //reset the temporary stream's pointer
                                li.QuadPart = 0;
                                pTempStream->Seek(li, STREAM_SEEK_SET, NULL);
                                
                                //get the property header and data for the range
                                hr = m_pServices->Serialize(pProp, pRange, &PropHeader, pTempStream);

                                /*
                                Write the property header into the primary stream. 
                                The header also contains the size of the property 
                                data.
                                */
                                hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten);

                                //reset the temporary stream's pointer
                                li.QuadPart = 0;
                                pTempStream->Seek(li, STREAM_SEEK_SET, NULL);

                                //copy the property data from the temporary stream into the primary stream
                                ULARGE_INTEGER  uli;
                                uli.QuadPart = PropHeader.cb;

                                hr = pTempStream->CopyTo(pStream, uli, NULL, NULL);

                                pRange->Release();
                            }
                            
                            pTempStream->Release();
                        }
                        
                        pEnumRanges->Release();
                    }
                    
                    pProp->Release();
                }
                
                pEnumProps->Release();
            }

            //write a property header with zero size and guid into the stream as a terminator
            ZeroMemory(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP));
            hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten);
        }
    }
}
void CTSFEditWnd::_Load(IStream *pStream)
{
    if(NULL == pStream)
    {
        return;
    }

    //can't do this if someone has a lock
    if(_IsLocked(TS_LF_READ))
    {
        return;
    }

    _ClearText();

    HRESULT         hr;
    ULONG           uRead;
    LARGE_INTEGER   li;
    ULONG           uSize;

    //set the stream pointer to the start of the stream
    li.QuadPart = 0;
    pStream->Seek(li, STREAM_SEEK_SET, NULL);

    //get the size of the text, in BYTES. This is the first ULONG in the stream
    hr = pStream->Read(&uSize, sizeof(ULONG), &uRead);
    if(SUCCEEDED(hr) && (sizeof(ULONG) == uRead))
    {
        LPWSTR  pwsz;
        
        //allocate a buffer for the text plus one NULL character
        pwsz = (LPWSTR)GlobalAlloc(GPTR, uSize + sizeof(WCHAR));
        if(NULL != pwsz)
        {
            //get the plain UNICODE text from the stream
            hr = pStream->Read(pwsz, uSize, &uRead);
            if(SUCCEEDED(hr) && (uSize == uRead))
            {
                TF_PERSISTENT_PROPERTY_HEADER_ACP   PropHeader;
                
                //put the text into the edit control, but don't send a change notification
                BOOL    fOldNotify = m_fNotify;
                m_fNotify = FALSE;
                SetWindowTextW(m_hwndEdit, pwsz);
                m_fNotify = fOldNotify;

                /*
                Read each property header and property data from the stream. The 
                list of properties is terminated by a TF_PERSISTENT_PROPERTY_HEADER_ACP 
                structure with a cb member of zero.
                */
                hr = pStream->Read(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uRead);
                while(  SUCCEEDED(hr) && 
                        (sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP) == uRead) && 
                        (0 != PropHeader.cb))
                {
                    ITfProperty *pProp;

                    hr = m_pContext->GetProperty(PropHeader.guidType, &pProp);
                    if(SUCCEEDED(hr))
                    {
                        /*
                        Have TSF read the property data from the stream. This call 
                        will request a read lock, so make sure it can be granted 
                        or else this method will fail.
                        */
                        CTSFPersistentPropertyLoader *pLoader = new CTSFPersistentPropertyLoader(&PropHeader, pStream);
                        hr = m_pServices->Unserialize(pProp, &PropHeader, NULL, pLoader);

                        pProp->Release();
                    }

                    hr = pStream->Read(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uRead);
                }
            }
            
            GlobalFree(pwsz);
        }
    }
}