First commit.
This commit is contained in:
commit
7b83802bb2
103 files changed
+19016
No files matched your search
+377
@@ -0,0 +1,377 @@
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
// PARTICULAR PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved
|
||||
|
||||
#include "Private.h"
|
||||
#include "Globals.h"
|
||||
#include "SampleIME.h"
|
||||
#include "CompositionProcessorEngine.h"
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// ITfCompositionSink::OnCompositionTerminated
|
||||
//
|
||||
// Callback for ITfCompositionSink. The system calls this method whenever
|
||||
// someone other than this service ends a composition.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _IsComposing
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
BOOL CSampleIME::_IsComposing()
|
||||
{
|
||||
return _pComposition != nullptr;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _SetComposition
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void CSampleIME::_SetComposition(_In_ ITfComposition *pComposition)
|
||||
{
|
||||
_pComposition = pComposition;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _AddComposingAndChar
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
HRESULT CSampleIME::_AddComposingAndChar(TfEditCookie ec, _In_ ITfContext *pContext, _In_ CStringRange *pstrAddString)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ULONG fetched = 0;
|
||||
TF_SELECTION tfSelection;
|
||||
|
||||
if (pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched) != S_OK || fetched == 0)
|
||||
return S_FALSE;
|
||||
|
||||
//
|
||||
// make range start to selection
|
||||
//
|
||||
ITfRange* pAheadSelection = nullptr;
|
||||
hr = pContext->GetStart(ec, &pAheadSelection);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pAheadSelection->ShiftEndToRange(ec, tfSelection.range, TF_ANCHOR_START);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ITfRange* pRange = nullptr;
|
||||
BOOL exist_composing = _FindComposingRange(ec, pContext, pAheadSelection, &pRange);
|
||||
|
||||
_SetInputString(ec, pContext, pRange, pstrAddString, exist_composing);
|
||||
|
||||
if (pRange)
|
||||
{
|
||||
pRange->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tfSelection.range->Release();
|
||||
|
||||
if (pAheadSelection)
|
||||
{
|
||||
pAheadSelection->Release();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _AddCharAndFinalize
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
HRESULT CSampleIME::_AddCharAndFinalize(TfEditCookie ec, _In_ ITfContext *pContext, _In_ CStringRange *pstrAddString)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
ULONG fetched = 0;
|
||||
TF_SELECTION tfSelection;
|
||||
|
||||
if ((hr = pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &fetched)) != S_OK || fetched != 1)
|
||||
return hr;
|
||||
|
||||
// we use SetText here instead of InsertTextAtSelection because we've already started a composition
|
||||
// we don't want to the app to adjust the insertion point inside our composition
|
||||
hr = tfSelection.range->SetText(ec, 0, pstrAddString->Get(), (LONG)pstrAddString->GetLength());
|
||||
if (hr == S_OK)
|
||||
{
|
||||
// update the selection, we'll make it an insertion point just past
|
||||
// the inserted text.
|
||||
tfSelection.range->Collapse(ec, TF_ANCHOR_END);
|
||||
pContext->SetSelection(ec, 1, &tfSelection);
|
||||
}
|
||||
|
||||
tfSelection.range->Release();
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _FindComposingRange
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp);
|
||||
if (FAILED(hr) || pPropComp == nullptr)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _SetInputString
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
HRESULT CSampleIME::_SetInputString(TfEditCookie ec, _In_ ITfContext *pContext, _Out_opt_ ITfRange *pRange, _In_ CStringRange *pstrAddString, BOOL exist_composing)
|
||||
{
|
||||
ITfRange* pRangeInsert = nullptr;
|
||||
if (!exist_composing)
|
||||
{
|
||||
_InsertAtSelection(ec, pContext, pstrAddString, &pRangeInsert);
|
||||
if (pRangeInsert == nullptr)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
pRange = pRangeInsert;
|
||||
}
|
||||
if (pRange != nullptr)
|
||||
{
|
||||
pRange->SetText(ec, 0, pstrAddString->Get(), (LONG)pstrAddString->GetLength());
|
||||
}
|
||||
|
||||
_SetCompositionLanguage(ec, pContext);
|
||||
|
||||
_SetCompositionDisplayAttributes(ec, pContext, _gaDisplayAttributeInput);
|
||||
|
||||
// update the selection, we'll make it an insertion point just past
|
||||
// the inserted text.
|
||||
ITfRange* pSelection = nullptr;
|
||||
TF_SELECTION sel;
|
||||
|
||||
if ((pRange != nullptr) && (pRange->Clone(&pSelection) == S_OK))
|
||||
{
|
||||
pSelection->Collapse(ec, TF_ANCHOR_END);
|
||||
|
||||
sel.range = pSelection;
|
||||
sel.style.ase = TF_AE_NONE;
|
||||
sel.style.fInterimChar = FALSE;
|
||||
pContext->SetSelection(ec, 1, &sel);
|
||||
pSelection->Release();
|
||||
}
|
||||
|
||||
if (pRangeInsert)
|
||||
{
|
||||
pRangeInsert->Release();
|
||||
}
|
||||
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _InsertAtSelection
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
HRESULT CSampleIME::_InsertAtSelection(TfEditCookie ec, _In_ ITfContext *pContext, _In_ CStringRange *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->Get(), (LONG)pstrAddString->GetLength(), &rangeInsert);
|
||||
|
||||
if ( FAILED(hr) || rangeInsert == nullptr)
|
||||
{
|
||||
rangeInsert = nullptr;
|
||||
pias->Release();
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
*ppCompRange = rangeInsert;
|
||||
pias->Release();
|
||||
hr = S_OK;
|
||||
|
||||
Exit:
|
||||
return hr;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _RemoveDummyCompositionForComposing
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
HRESULT CSampleIME::_RemoveDummyCompositionForComposing(TfEditCookie ec, _In_ ITfComposition *pComposition)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
ITfRange* pRange = nullptr;
|
||||
|
||||
if (pComposition)
|
||||
{
|
||||
hr = pComposition->GetRange(&pRange);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
pRange->SetText(ec, 0, nullptr, 0);
|
||||
pRange->Release();
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//+---------------------------------------------------------------------------
|
||||
//
|
||||
// _SetCompositionLanguage
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
BOOL CSampleIME::_SetCompositionLanguage(TfEditCookie ec, _In_ ITfContext *pContext)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
CCompositionProcessorEngine* pCompositionProcessorEngine = nullptr;
|
||||
pCompositionProcessorEngine = _pCompositionProcessorEngine;
|
||||
|
||||
LANGID langidProfile = 0;
|
||||
pCompositionProcessorEngine->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;
|
||||
}
|
||||
Reference in new issue
Block a user