You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
684 lines
21 KiB
684 lines
21 KiB
/*++
|
|
|
|
Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
txtevcb.cpp
|
|
|
|
Abstract:
|
|
|
|
This file implements the CTextEventSinkCallBack Class.
|
|
|
|
Author:
|
|
|
|
Revision History:
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
|
|
#include "private.h"
|
|
#include "txtevcb.h"
|
|
#include "ime.h"
|
|
#include "editses.h"
|
|
#include "context.h"
|
|
#include "profile.h"
|
|
|
|
|
|
// from ctf\sapilayr\globals.cpp
|
|
const GUID GUID_ATTR_SAPI_GREENBAR = {
|
|
0xc3a9e2e8,
|
|
0x738c,
|
|
0x48e0,
|
|
{0xac, 0xc8, 0x43, 0xee, 0xfa, 0xbf, 0x83, 0xc8}
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::_IsSapiFeedbackUIPresent
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CTextEventSinkCallBack::_IsSapiFeedbackUIPresent(
|
|
Interface_Attach<ITfContext>& ic,
|
|
TESENDEDIT *ee
|
|
)
|
|
{
|
|
EnumPropertyArgs args;
|
|
|
|
args.comp_guid = GUID_ATTR_SAPI_GREENBAR;
|
|
if (FAILED(ic->GetProperty(GUID_PROP_ATTRIBUTE, args.Property)))
|
|
return FALSE;
|
|
|
|
Interface<IEnumTfRanges> EnumReadOnlyProperty;
|
|
if (FAILED(args.Property->EnumRanges(ee->ecReadOnly, EnumReadOnlyProperty, NULL)))
|
|
return FALSE;
|
|
|
|
args.ec = ee->ecReadOnly;
|
|
args.pLibTLS = m_pLibTLS;
|
|
|
|
CEnumrateInterface<IEnumTfRanges,
|
|
ITfRange,
|
|
EnumPropertyArgs> Enumrate(EnumReadOnlyProperty,
|
|
EnumPropertyCallback,
|
|
&args); // Argument of callback func.
|
|
ENUM_RET ret_prop_attribute = Enumrate.DoEnumrate();
|
|
if (ret_prop_attribute == ENUM_FIND)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::_IsComposingPresent
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CTextEventSinkCallBack::_IsComposingPresent(
|
|
Interface_Attach<ITfContext>& ic,
|
|
TESENDEDIT *ee
|
|
)
|
|
{
|
|
/*
|
|
* This is automatic detection code of the Hangul + alphanumeric input
|
|
* If detected a Hangul + alphanumeric, then we finalized all text.
|
|
*/
|
|
|
|
EnumTrackPropertyArgs args;
|
|
|
|
const GUID *guids[] = {&GUID_PROP_COMPOSING,
|
|
&GUID_PROP_MSIMTF_PREPARE_RECONVERT};
|
|
const int guid_size = sizeof(guids) / sizeof(GUID*);
|
|
|
|
args.guids = (GUID**)guids;
|
|
args.num_guids = guid_size;
|
|
|
|
if (FAILED(ic->TrackProperties(guids, args.num_guids, // system property
|
|
NULL, 0, // application property
|
|
args.Property)))
|
|
return FALSE;
|
|
|
|
//
|
|
// get the text range that does not include read only area for
|
|
// reconversion.
|
|
//
|
|
Interface<ITfRange> rangeAllText;
|
|
LONG cch;
|
|
if (FAILED(ImmIfEditSessionCallBack::GetAllTextRange(ee->ecReadOnly,
|
|
ic,
|
|
&rangeAllText,
|
|
&cch)))
|
|
return FALSE;
|
|
|
|
|
|
Interface<IEnumTfRanges> EnumReadOnlyProperty;
|
|
if (FAILED(args.Property->EnumRanges(ee->ecReadOnly, EnumReadOnlyProperty, rangeAllText)))
|
|
return FALSE;
|
|
|
|
|
|
args.ec = ee->ecReadOnly;
|
|
args.pLibTLS = m_pLibTLS;
|
|
|
|
CEnumrateInterface<IEnumTfRanges,
|
|
ITfRange,
|
|
EnumTrackPropertyArgs> Enumrate(EnumReadOnlyProperty,
|
|
EnumTrackPropertyCallback,
|
|
&args); // Argument of callback func.
|
|
ENUM_RET ret_prop_composing = Enumrate.DoEnumrate();
|
|
if (ret_prop_composing == ENUM_FIND)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::_IsInterim
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CTextEventSinkCallBack::_IsInterim(
|
|
Interface_Attach<ITfContext>& ic,
|
|
TESENDEDIT *ee
|
|
)
|
|
{
|
|
Interface_TFSELECTION sel;
|
|
ULONG cFetched;
|
|
|
|
if (ic->GetSelection(ee->ecReadOnly, TF_DEFAULT_SELECTION, 1, sel, &cFetched) != S_OK)
|
|
return FALSE;
|
|
|
|
if (sel->style.fInterimChar) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::_IsCompositionChanged
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CTextEventSinkCallBack::_IsCompositionChanged(
|
|
Interface_Attach<ITfContext>& ic,
|
|
TESENDEDIT *ee
|
|
)
|
|
{
|
|
ENUM_RET enumret;
|
|
|
|
BOOL fChanged;
|
|
if (SUCCEEDED(ee->pEditRecord->GetSelectionStatus(&fChanged)))
|
|
{
|
|
if (fChanged)
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Find GUID_PROP_MSIMTF_TRACKCOMPOSITION property.
|
|
//
|
|
EnumFindFirstTrackCompRangeArgs argsFindFirstTrackCompRange;
|
|
Interface<ITfProperty> PropertyTrackComposition;
|
|
if (FAILED(ic->GetProperty(GUID_PROP_MSIMTF_TRACKCOMPOSITION,
|
|
argsFindFirstTrackCompRange.Property)))
|
|
return FALSE;
|
|
|
|
|
|
|
|
Interface<IEnumTfRanges> EnumFindFirstTrackCompRange;
|
|
if (FAILED(argsFindFirstTrackCompRange.Property->EnumRanges(ee->ecReadOnly,
|
|
EnumFindFirstTrackCompRange,
|
|
NULL)))
|
|
return FALSE;
|
|
|
|
argsFindFirstTrackCompRange.ec = ee->ecReadOnly;
|
|
|
|
CEnumrateInterface<IEnumTfRanges,
|
|
ITfRange,
|
|
EnumFindFirstTrackCompRangeArgs> EnumrateFindFirstTrackCompRange(
|
|
EnumFindFirstTrackCompRange,
|
|
EnumFindFirstTrackCompRangeCallback,
|
|
&argsFindFirstTrackCompRange);
|
|
|
|
enumret = EnumrateFindFirstTrackCompRange.DoEnumrate();
|
|
|
|
//
|
|
// if there is no track composition property,
|
|
// the composition has been changed since we put it.
|
|
//
|
|
if (enumret != ENUM_FIND)
|
|
return TRUE;
|
|
|
|
Interface<ITfRange> rangeTrackComposition;
|
|
if (FAILED(argsFindFirstTrackCompRange.Range->Clone(rangeTrackComposition)))
|
|
return FALSE;
|
|
|
|
//
|
|
// get the text range that does not include read only area for
|
|
// reconversion.
|
|
//
|
|
Interface<ITfRange> rangeAllText;
|
|
LONG cch;
|
|
if (FAILED(ImmIfEditSessionCallBack::GetAllTextRange(ee->ecReadOnly,
|
|
ic,
|
|
&rangeAllText,
|
|
&cch)))
|
|
return FALSE;
|
|
|
|
LONG lResult;
|
|
if (FAILED(rangeTrackComposition->CompareStart(ee->ecReadOnly,
|
|
rangeAllText,
|
|
TF_ANCHOR_START,
|
|
&lResult)))
|
|
return FALSE;
|
|
|
|
//
|
|
// if the start position of the track composition range is not
|
|
// the beggining of IC,
|
|
// the composition has been changed since we put it.
|
|
//
|
|
if (lResult != 0)
|
|
return TRUE;
|
|
|
|
if (FAILED(rangeTrackComposition->CompareEnd(ee->ecReadOnly,
|
|
rangeAllText,
|
|
TF_ANCHOR_END,
|
|
&lResult)))
|
|
return FALSE;
|
|
|
|
//
|
|
// if the start position of the track composition range is not
|
|
// the beggining of IC,
|
|
// the composition has been changed since we put it.
|
|
//
|
|
if (lResult != 0)
|
|
return TRUE;
|
|
|
|
|
|
//
|
|
// If we find the changes in these property, we need to update hIMC.
|
|
//
|
|
const GUID *guids[] = {&GUID_PROP_COMPOSING,
|
|
&GUID_PROP_ATTRIBUTE,
|
|
&GUID_PROP_READING,
|
|
&GUID_PROP_MSIMTF_PREPARE_RECONVERT};
|
|
const int guid_size = sizeof(guids) / sizeof(GUID*);
|
|
|
|
Interface<IEnumTfRanges> EnumPropertyChanged;
|
|
|
|
if (FAILED(ee->pEditRecord->GetTextAndPropertyUpdates(TF_GTP_INCL_TEXT,
|
|
guids, guid_size,
|
|
EnumPropertyChanged)))
|
|
return FALSE;
|
|
|
|
EnumPropertyChangedCallbackArgs args;
|
|
args.ec = ee->ecReadOnly;
|
|
CEnumrateInterface<IEnumTfRanges,
|
|
ITfRange,
|
|
EnumPropertyChangedCallbackArgs> Enumrate(EnumPropertyChanged,
|
|
EnumPropertyChangedCallback,
|
|
&args);
|
|
enumret = Enumrate.DoEnumrate();
|
|
|
|
if (enumret == ENUM_FIND)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::TextEventSinkCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// static
|
|
HRESULT
|
|
CTextEventSinkCallBack::TextEventSinkCallback(
|
|
UINT uCode,
|
|
void *pv,
|
|
void *pvData
|
|
)
|
|
{
|
|
DebugMsg(TF_FUNC, TEXT("TextEventSinkCallback"));
|
|
|
|
ASSERT(uCode == ICF_TEXTDELTA); // the pvData cast only works in this case
|
|
if (uCode != ICF_TEXTDELTA)
|
|
return S_OK;
|
|
|
|
CTextEventSinkCallBack* _this = (CTextEventSinkCallBack*)pv;
|
|
ASSERT(_this);
|
|
|
|
TESENDEDIT* ee = (TESENDEDIT*)pvData;
|
|
ASSERT(ee);
|
|
|
|
HRESULT hr;
|
|
|
|
IMCLock imc(_this->m_hIMC);
|
|
if (FAILED(hr = imc.GetResult()))
|
|
return hr;
|
|
|
|
IMCCLock<CTFIMECONTEXT> imc_ctfime(imc->hCtfImeContext);
|
|
if (FAILED(hr=imc_ctfime.GetResult()))
|
|
return hr;
|
|
|
|
CicInputContext* _pCicContext = imc_ctfime->m_pCicContext;
|
|
if (_pCicContext == NULL)
|
|
return E_FAIL;
|
|
|
|
ASSERT(_pCicContext != NULL);
|
|
|
|
#ifdef UNSELECTCHECK
|
|
if (!_pAImeContext->m_fSelected)
|
|
return S_OK;
|
|
#endif UNSELECTCHECK
|
|
|
|
Interface_Attach<ITfContext> ic(_pCicContext->GetInputContext());
|
|
|
|
|
|
|
|
/*
|
|
* We have composition text.
|
|
*/
|
|
|
|
TLS* ptls = TLS::GetTLS();
|
|
if (ptls == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
BOOL fInReconvertEditSession;
|
|
|
|
fInReconvertEditSession = _pCicContext->m_fInReconvertEditSession.IsSetFlag();
|
|
|
|
|
|
if (!_this->_IsCompositionChanged(ic, ee))
|
|
return S_OK;
|
|
|
|
BOOL fComp;
|
|
BOOL fSapiFeedback;
|
|
|
|
// need to check speech feedback UI.
|
|
fSapiFeedback = _this->_IsSapiFeedbackUIPresent(ic, ee);
|
|
|
|
fComp = _this->_IsComposingPresent(ic, ee);
|
|
|
|
LANGID langid;
|
|
CicProfile* _pProfile = ptls->GetCicProfile();
|
|
|
|
if (_pProfile == NULL)
|
|
{
|
|
DebugMsg(TF_ERROR, TEXT("CTextEventSinkCallBack::TextEventSinkCallback. _pProfile==NULL."));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
_pProfile->GetLangId(&langid);
|
|
|
|
switch (PRIMARYLANGID(langid))
|
|
{
|
|
case LANG_KOREAN:
|
|
//
|
|
// We will finalize Korean composition string immediately if it
|
|
// doesn't set the interim definition. For example, Korean
|
|
// Handwriting TIP case.
|
|
//
|
|
// Bug#482983 - Notepad doesn't support the level 2 composition
|
|
// window for Korean.
|
|
//
|
|
// And we should not do this during HanjaReConversion.
|
|
//
|
|
if (fComp && _pCicContext->m_fHanjaReConversion.IsResetFlag())
|
|
{
|
|
if (!(_this->_IsInterim(ic, ee)))
|
|
{
|
|
//
|
|
// Reset fComp to false to complete the current composition
|
|
// string.
|
|
//
|
|
fComp = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LANG_JAPANESE:
|
|
case LANG_CHINESE:
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// #500698
|
|
//
|
|
// Reset fComp to false to complete the current composition
|
|
// string.
|
|
//
|
|
if (!ptls->NonEACompositionEnabled())
|
|
{
|
|
fComp = FALSE;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Update composition and generate WM_IME_COMPOSITION
|
|
//
|
|
// if there is SAPI green bar.
|
|
// - there is only hIMC composition if there is Speech Green bar.
|
|
//
|
|
// if Reconversion just started.
|
|
// - because some tip may not change the text yet.
|
|
// then there is no composition range yet.
|
|
//
|
|
// if now clearing DocFeed buffer.
|
|
// - because the change happens in read-only text
|
|
// nothing in hIMC changes.
|
|
//
|
|
if (fComp || fSapiFeedback || fInReconvertEditSession ||
|
|
_pCicContext->m_fInClearDocFeedEditSession.IsSetFlag())
|
|
{
|
|
//
|
|
// Retreive text delta from GUID_PROP_COMPOSING
|
|
//
|
|
const GUID *guids[] = {&GUID_PROP_COMPOSING};
|
|
const int guid_size = sizeof(guids) / sizeof(GUID*);
|
|
|
|
Interface<IEnumTfRanges> EnumPropertyUpdate;
|
|
hr = ee->pEditRecord->GetTextAndPropertyUpdates(0, // dwFlags
|
|
guids, guid_size,
|
|
EnumPropertyUpdate);
|
|
if (SUCCEEDED(hr)) {
|
|
EnumPropertyUpdateArgs args(ic.GetPtr(), _this->m_tid, imc, _this->m_pLibTLS);
|
|
|
|
if (FAILED(hr=ic->GetProperty(GUID_PROP_COMPOSING, args.Property)))
|
|
return hr;
|
|
|
|
args.ec = ee->ecReadOnly;
|
|
args.dwDeltaStart = 0;
|
|
|
|
CEnumrateInterface<IEnumTfRanges,
|
|
ITfRange,
|
|
EnumPropertyUpdateArgs> Enumrate(EnumPropertyUpdate,
|
|
EnumPropertyUpdateCallback,
|
|
&args); // Argument of callback func.
|
|
ENUM_RET ret_prop_update = Enumrate.DoEnumrate();
|
|
if (ret_prop_update == ENUM_FIND) {
|
|
//
|
|
// Remove GUID_PROP_MSIMTF_PREPARE_RECONVERT property.
|
|
//
|
|
_this->EscbRemoveProperty(imc, &GUID_PROP_MSIMTF_PREPARE_RECONVERT);
|
|
|
|
//
|
|
// Update composition string with delta start position
|
|
//
|
|
return _this->EscbUpdateCompositionString(imc, args.dwDeltaStart);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update composition string
|
|
//
|
|
return _this->EscbUpdateCompositionString(imc);
|
|
}
|
|
else {
|
|
//
|
|
// Clear DocFeed range's text store.
|
|
// Find GUID_PROP_MSIMTF_READONLY property and SetText(NULL).
|
|
//
|
|
// ImmIfIME::ClearDocFeedBuffer() essential function for all ESCB_RECONVERTSTRING's edit
|
|
// session except only ImmIfIME::SetupDocFeedString() since this is provided for keyboard
|
|
// TIP's DocFeeding.
|
|
//
|
|
_this->EscbClearDocFeedBuffer(imc, *_pCicContext, FALSE); // No TF_ES_SYNC
|
|
//
|
|
// Composition complete.
|
|
//
|
|
return _this->EscbCompComplete(imc, FALSE); // No TF_ES_SYNC
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::EnumPropertyCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// static
|
|
ENUM_RET
|
|
CTextEventSinkCallBack::EnumPropertyCallback(
|
|
ITfRange* pRange,
|
|
EnumPropertyArgs *pargs
|
|
)
|
|
{
|
|
ENUM_RET ret = ENUM_CONTINUE;
|
|
VARIANT var;
|
|
QuickVariantInit(&var);
|
|
|
|
HRESULT hr = pargs->Property->GetValue(pargs->ec, pRange, &var);
|
|
if (SUCCEEDED(hr)) {
|
|
if (IsEqualIID(pargs->comp_guid, GUID_NULL)) {
|
|
if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0))
|
|
ret = ENUM_FIND;
|
|
}
|
|
else if (V_VT(&var) == VT_I4) {
|
|
TfGuidAtom guid = V_I4(&var);
|
|
if (IsEqualTFGUIDATOM(pargs->pLibTLS, guid, pargs->comp_guid))
|
|
ret = ENUM_FIND;
|
|
}
|
|
}
|
|
|
|
VariantClear(&var);
|
|
return ret;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::EnumTrackPropertyCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// static
|
|
ENUM_RET
|
|
CTextEventSinkCallBack::EnumTrackPropertyCallback(
|
|
ITfRange* pRange,
|
|
EnumTrackPropertyArgs *pargs
|
|
)
|
|
{
|
|
ENUM_RET ret = ENUM_CONTINUE;
|
|
VARIANT var;
|
|
QuickVariantInit(&var);
|
|
|
|
HRESULT hr = pargs->Property->GetValue(pargs->ec, pRange, &var);
|
|
if (SUCCEEDED(hr)) {
|
|
Interface<IEnumTfPropertyValue> EnumPropVal;
|
|
hr = var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, EnumPropVal);
|
|
if (SUCCEEDED(hr)) {
|
|
TF_PROPERTYVAL tfPropertyVal;
|
|
|
|
while (EnumPropVal->Next(1, &tfPropertyVal, NULL) == S_OK) {
|
|
for (int i=0; i < pargs->num_guids; i++) {
|
|
if (IsEqualGUID(tfPropertyVal.guidId, *pargs->guids[i])) {
|
|
if ((V_VT(&tfPropertyVal.varValue) == VT_I4 && V_I4(&tfPropertyVal.varValue) != 0)) {
|
|
ret = ENUM_FIND;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VariantClear(&tfPropertyVal.varValue);
|
|
|
|
if (ret == ENUM_FIND)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VariantClear(&var);
|
|
return ret;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::EnumPropertyUpdateCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// static
|
|
ENUM_RET
|
|
CTextEventSinkCallBack::EnumPropertyUpdateCallback(
|
|
ITfRange* update_range,
|
|
EnumPropertyUpdateArgs *pargs
|
|
)
|
|
{
|
|
ENUM_RET ret = ENUM_CONTINUE;
|
|
VARIANT var;
|
|
QuickVariantInit(&var);
|
|
|
|
HRESULT hr = pargs->Property->GetValue(pargs->ec, update_range, &var);
|
|
if (SUCCEEDED(hr)) {
|
|
if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0)) {
|
|
|
|
Interface_Creator<ImmIfEditSession> _pEditSession(
|
|
new ImmIfEditSession(ESCB_GET_ALL_TEXT_RANGE,
|
|
pargs->imc,
|
|
pargs->tid,
|
|
pargs->ic.GetPtr(),
|
|
pargs->pLibTLS)
|
|
);
|
|
if (_pEditSession.Valid()) {
|
|
|
|
Interface<ITfRange> full_range;
|
|
|
|
if (SUCCEEDED(_pEditSession->RequestEditSession(TF_ES_READ | TF_ES_SYNC,
|
|
&full_range))) {
|
|
|
|
if (SUCCEEDED(full_range->ShiftEndToRange(pargs->ec, update_range, TF_ANCHOR_START))) {
|
|
Interface<ITfRangeACP> unupdate_range;
|
|
if (SUCCEEDED(full_range->QueryInterface(IID_ITfRangeACP, unupdate_range))) {
|
|
LONG acpStart;
|
|
LONG cch;
|
|
if (SUCCEEDED(unupdate_range->GetExtent(&acpStart, &cch))) {
|
|
pargs->dwDeltaStart = cch;
|
|
ret = ENUM_FIND;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VariantClear(&var);
|
|
return ret;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::EnumPropertyChangedCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// static
|
|
ENUM_RET
|
|
CTextEventSinkCallBack::EnumPropertyChangedCallback(
|
|
ITfRange* update_range,
|
|
EnumPropertyChangedCallbackArgs *pargs
|
|
)
|
|
{
|
|
BOOL empty;
|
|
if (update_range->IsEmpty(pargs->ec, &empty) == S_OK && empty)
|
|
return ENUM_CONTINUE;
|
|
|
|
return ENUM_FIND;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CTextEventSinkCallBack::EnumPropertyChangedCallback
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// static
|
|
ENUM_RET
|
|
CTextEventSinkCallBack::EnumFindFirstTrackCompRangeCallback(
|
|
ITfRange* update_range,
|
|
EnumFindFirstTrackCompRangeArgs *pargs
|
|
)
|
|
{
|
|
ENUM_RET ret = ENUM_CONTINUE;
|
|
VARIANT var;
|
|
QuickVariantInit(&var);
|
|
|
|
HRESULT hr = pargs->Property->GetValue(pargs->ec, update_range, &var);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if ((V_VT(&var) == VT_I4 && V_I4(&var) != 0))
|
|
{
|
|
update_range->Clone(pargs->Range);
|
|
ret = ENUM_FIND;
|
|
}
|
|
}
|
|
VariantClear(&var);
|
|
return ret;
|
|
}
|