windows-nt/Source/XPSP1/NT/windows/richedit/re41/cuim.cpp
2020-09-26 16:20:57 +08:00

4595 lines
91 KiB
C++

/*
* @doc INTERNAL
*
* @module CUIM.CPP -- Cicero Implementation
*
* Most everything to do with Cicero handling.
*
* Original Author: <nl>
* Hon Wah Chan
*
* History: <nl>
* 11/16/1999 honwch
*
* Copyright (c) 1995-2001, Microsoft Corporation. All rights reserved.
*/
#include "_common.h"
#ifndef NOFEPROCESSING
#ifndef NOPRIVATEMESSAGE
#include "_MSREMSG.H"
#endif
#include "_array.h"
#include "msctf.h"
#include "textstor.h"
#include "ctffunc.h"
#include "msctf_g.c"
#include "msctf_i.c"
#include "textstor_i.c"
#include "ctffunc_i.c"
#include "msctfp.h"
#include "msctfp_g.c"
#include "textserv.h"
#include "_cmsgflt.h"
#include "_ime.h"
#include "_cuim.h"
const IID IID_ITfContextRenderingMarkup = {
0xa305b1c0,
0xc776,
0x4523,
{0xbd, 0xa0, 0x7c, 0x5a, 0x2e, 0x0f, 0xef, 0x10}
};
const IID IID_ITfEnableService = {
0x3035d250,
0x43b4,
0x4253,
{0x81, 0xe6, 0xea, 0x87, 0xfd, 0x3e, 0xed, 0x43}
};
const IID IID_IServiceProvider = {
0x6d5140c1,
0x7436,
0x11ce,
{0x80, 0x34, 0x00, 0xaa, 0x00, 0x60, 0x09, 0xfa}
};
// {35D46968-01FF-4cd8-A379-9A87C9CC789F}
const GUID CLSID_MSFTEDIT = {
0x35d46968,
0x01ff,
0x4cd8,
{0xa3,0x79,0x9a,0x87, 0xc9,0xcc,0x78,0x9f}
};
#define CONNECT_E_NOCONNECTION MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x0200) // from OLECTL.H
#undef DEFINE_GUID
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
const GUID name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#include "dcattrs.h"
const TS_ATTRID *_arTSAttridSupported[] =
{
&DCATTRID_Font_FaceName, // iattrFacename
&DCATTRID_Font_SizePts, // iattrSize
&DCATTRID_Font_Style_Color, // iattrColor
&DCATTRID_Font_Style_Bold, // iattrBold
&DCATTRID_Font_Style_Italic, // iattrItalic
&DCATTRID_Font_Style_Underline, // iattrUnderline
&DCATTRID_Font_Style_Subscript, // iattrSubscript
&DCATTRID_Font_Style_Superscript, // iattrSuperscript
&DCATTRID_Text_RightToLeft, // iattrRTL
&DCATTRID_Text_VerticalWriting, // iattrVertical
&GUID_PROP_MODEBIAS, // iattrBias
&DCATTRID_Text_Orientation, // iattrTxtOrient
};
enum IATTR_INDEX
{
iattrFacename = 0,
iattrSize,
iattrColor,
iattrBold,
iattrItalic,
iattrUnderline,
iattrSubscript,
iattrSuperscript,
iattrRTL,
iattrVertical,
iattrBias,
iattrTxtOrient,
MAX_ATTR_SUPPORT
};
/* GUID_NULL */
const GUID GUID_NULL = {
0x00000000,
0x0000,
0x0000,
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
const GUID GUID_DCSERVICE_DATAOBJECT = {
0x6086fbb5,
0xe225,
0x46ce,
{0xa7, 0x70, 0xc1, 0xbb, 0xd3, 0xe0, 0x5d, 0x7b}
};
const GUID GUID_DCSERVICE_ACCESSIBLE = {
0xf9786200,
0xa5bf,
0x4a0f,
{0x8c, 0x24, 0xfb, 0x16, 0xf5, 0xd1, 0xaa, 0xbb}
};
const GUID GUID_DCSERVICE_ACTIVEX = {
0xea937a50,
0xc9a6,
0x4b7d,
{0x89, 0x4a, 0x49, 0xd9, 0x9b, 0x78, 0x48, 0x34}
};
// This array need to match the definition for EM_SETCTFMODEBIAS
const GUID *_arModeBiasSupported[] =
{
&GUID_MODEBIAS_NONE,
&GUID_MODEBIAS_FILENAME,
&GUID_MODEBIAS_NAME,
&GUID_MODEBIAS_READING,
&GUID_MODEBIAS_DATETIME,
&GUID_MODEBIAS_CONVERSATION,
&GUID_MODEBIAS_NUMERIC,
&GUID_MODEBIAS_HIRAGANA,
&GUID_MODEBIAS_KATAKANA,
&GUID_MODEBIAS_HANGUL,
&GUID_MODEBIAS_HALFWIDTHKATAKANA,
&GUID_MODEBIAS_FULLWIDTHALPHANUMERIC,
&GUID_MODEBIAS_HALFWIDTHALPHANUMERIC,
};
/*
* CUIM::CUIM ()
*
* @mfunc
*
*
* @rdesc
*
*
*/
CUIM::CUIM(CTextMsgFilter *pTextMsgFilter)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::CUIM");
_crefs = 1;
_pTextMsgFilter = pTextMsgFilter;
};
/*
* CUIM::~CUIM ()
*
* @mfunc
*
*
* @rdesc
*
*
*/
CUIM::~CUIM()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::~CUIM");
Uninit();
}
/*
* STDMETHODIMP CUIM::QueryInterface (riid, ppv)
*
* @mfunc
* IUnknown QueryInterface support
*
* @rdesc
* NOERROR if interface supported
*
*/
STDMETHODIMP CUIM::QueryInterface (REFIID riid, void ** ppv)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::QueryInterface");
if( IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_ITextStoreACP) )
*ppv = (ITextStoreACP *)this;
else if(IsEqualIID(riid, IID_ITfContextOwnerCompositionSink) )
*ppv = (ITfContextOwnerCompositionSink *)this;
else if (IsEqualIID(riid, IID_ITfMouseTrackerACP))
*ppv = (ITfMouseTrackerACP *)this;
else if (IsEqualIID(riid, IID_ITfEnableService))
*ppv = (ITfEnableService *)this;
else if (IsEqualIID(riid, IID_IServiceProvider))
*ppv = (IServiceProvider *)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
/*
* STDMETHODIMP_(ULONG) CUIM::AddRef
*
* @mfunc
* IUnknown AddRef support
*
* @rdesc
* Reference count
*/
STDMETHODIMP_(ULONG) CUIM::AddRef()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::AddRef");
return ++_crefs;
}
/*
* STDMETHODIMP_(ULONG) CUIM::Release()
*
* @mfunc
* IUnknown Release support - delete object when reference count is 0
*
* @rdesc
* Reference count
*/
STDMETHODIMP_(ULONG) CUIM::Release()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::Release");
_crefs--;
if( _crefs == 0 )
{
delete this;
return 0;
}
return _crefs;
}
/*
* STDMETHODIMP CUIM::AdviseSink()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::AdviseSink(
REFIID riid,
IUnknown *punk,
DWORD dwMask)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::AdviseSink");
HRESULT hr = E_FAIL;
if (_fShutDown)
return E_UNEXPECTED;
Assert(_ptss == NULL);
if(IsEqualIID(riid, IID_ITextStoreACPSink))
hr = punk->QueryInterface(riid, (void **)&_ptss);
return hr == S_OK ? S_OK : E_UNEXPECTED;
}
/*
* STDMETHODIMP CUIM::UnadviseSink()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::UnadviseSink(IUnknown *punk)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::UnadviseSink");
Assert(_ptss == punk); // we're dealing with cicero, this should always hold
_ptss->Release();
_ptss = NULL;
return S_OK;
}
/*
* STDMETHODIMP CUIM::RequestLock()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::RequestLock(
DWORD dwLockFlags,
HRESULT *phrSession)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::RequestLock");
if (!phrSession)
return E_POINTER;
if (_fShutDown)
{
*phrSession = TS_E_SYNCHRONOUS;
return S_OK;
}
Assert(_ptss);
if (_cCallMgrLevels && !_fAllowUIMLock || // Check if we are ready to grant locks
_fReadLockOn || _fWriteLockOn) // We don't allow re-entrance either.
{
// No lock allow
if (dwLockFlags & TS_LF_SYNC)
*phrSession = TS_E_SYNCHRONOUS;
else
{
if (dwLockFlags & TS_LF_READ)
_fReadLockPending = 1;
if ((dwLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE)
_fWriteLockPending = 1;
*phrSession = TS_S_ASYNC;
}
return S_OK;
}
IUnknown *pIUnknown = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->GetCallManager(&pIUnknown);
if ((dwLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE)
{
_fReadLockPending = 0;
_fWriteLockPending = 0;
_fReadLockOn = 1;
_fWriteLockOn = 1;
}
else if ((dwLockFlags & TS_LF_READ) == TS_LF_READ)
{
_fReadLockPending = 0;
_fReadLockOn = 1;
}
if (_fWriteLockOn)
{
if (W32->IsFECodePage(_pTextMsgFilter->_uKeyBoardCodePage))
_pTextMsgFilter->_pTextDoc->IMEInProgress(tomTrue);
EnterCriticalSection(&g_CriticalSection);
}
*phrSession = _ptss->OnLockGranted(dwLockFlags);
if (_fWriteLockOn)
{
// Check if any text has been added
if (_parITfEnumRange && _parITfEnumRange->Count())
{
int idx;
int idxMax = _parITfEnumRange->Count();
for (idx = 0 ; idx < idxMax; idx++)
{
IEnumTfRanges **ppEnumRange = (IEnumTfRanges **)(_parITfEnumRange->Elem(idx));
if (ppEnumRange && *ppEnumRange)
{
HandleFocusRange(*ppEnumRange);
(*ppEnumRange)->Release();
}
}
_parITfEnumRange->Clear(AF_KEEPMEM);
}
}
if (_fEndTyping)
OnUIMTypingDone();
if (_fWriteLockOn)
{
_pTextMsgFilter->_pTextDoc->IMEInProgress(tomFalse);
LeaveCriticalSection(&g_CriticalSection);
}
_fEndTyping = 0;
_fWriteLockOn = 0;
_fReadLockOn = 0;
_fHoldCTFSelChangeNotify = 1;
if (pIUnknown)
hResult = _pTextMsgFilter->_pTextDoc->ReleaseCallManager(pIUnknown);
_fHoldCTFSelChangeNotify = 0;
return S_OK;
}
/*
* STDMETHODIMP CUIM::GetStatus()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetStatus(
TS_STATUS *pdcs)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetStatus");
if (_fShutDown)
return S_OK;
if (pdcs)
{
LRESULT lresult = 0;
pdcs->dwStaticFlags = (TS_SS_REGIONS | TS_SS_NOHIDDENTEXT);
if ( S_OK == _pTextMsgFilter->_pTextService->TxSendMessage(
EM_GETDOCFLAGS, GDF_ALL, 0, &lresult))
{
if (lresult & GDF_READONLY)
pdcs->dwDynamicFlags = TS_SD_READONLY;
// Don't want to support overtyping in Cicero yet.
// if (lresult & GDF_OVERTYPE)
// dcs.dwDynamicFlags = TS_SD_OVERTYPE;
}
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::QueryInsert()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::QueryInsert(
LONG acpTestStart,
LONG acpTestEnd,
ULONG cch,
LONG *pacpResultStart,
LONG *pacpResultEnd)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::QueryInsert");
HRESULT hResult;
ITextRange *pTextRange = NULL;
*pacpResultStart = -1;
*pacpResultEnd = -1;
if (_fShutDown)
return S_OK;
hResult = _pTextMsgFilter->_pTextDoc->Range(acpTestStart, acpTestEnd, &pTextRange);
if (hResult != S_OK)
return TS_E_READONLY;
Assert(pTextRange);
if(pTextRange->CanEdit(NULL) == S_FALSE)
{
hResult = TS_E_READONLY;
goto EXIT; // Cannot edit text
}
*pacpResultStart = acpTestStart;
*pacpResultEnd = acpTestEnd;
hResult = S_OK;
EXIT:
pTextRange->Release();
return hResult;
}
/*
* STDMETHODIMP CUIM::GetSelection()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetSelection(
ULONG ulIndex,
ULONG ulCount,
TS_SELECTION_ACP *pSelection,
ULONG *pcFetched)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetSelection");
HRESULT hResult;
ITextSelection *pTextSel = NULL;
if (!pSelection || !pcFetched)
return E_POINTER;
if (!_fReadLockOn)
return TS_E_NOLOCK;
*pcFetched = 0;
if (_fShutDown)
return TS_E_NOSELECTION;
if (ulIndex == TS_DEFAULT_SELECTION)
ulIndex = 0;
else if (ulIndex > 1)
return E_INVALIDARG; // We donnot have discontiguous selection.
if (_fInterimChar)
{
pSelection[0].acpStart = _acpInterimStart;
pSelection[0].acpEnd = _acpInterimEnd;
pSelection[0].style.ase = (TsActiveSelEnd) _ase;
pSelection[0].style.fInterimChar = TRUE;
*pcFetched = 1;
return S_OK;
}
hResult = _pTextMsgFilter->_pTextDoc->GetSelectionEx(&pTextSel);
if (pTextSel)
{
long cpMin = 0, cpMax = 0;
long lFlags = 0;
hResult = pTextSel->GetStart(&cpMin);
hResult = pTextSel->GetEnd(&cpMax);
hResult = pTextSel->GetFlags(&lFlags);
pSelection[0].acpStart = cpMin;
pSelection[0].acpEnd = cpMax;
pSelection[0].style.ase = (lFlags & tomSelStartActive) ? TS_AE_START : TS_AE_END;
pSelection[0].style.fInterimChar = FALSE;
*pcFetched = 1;
pTextSel->Release();
return S_OK;
}
return TS_E_NOSELECTION;
}
/*
* STDMETHODIMP CUIM::SetSelection()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::SetSelection(
ULONG ulCount,
const TS_SELECTION_ACP *pSelection)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::SetSelection");
HRESULT hResult;
ITextRange *pTextRange = NULL;
if (!pSelection)
return E_POINTER;
if (ulCount <= 0)
return E_INVALIDARG;
if (!_fWriteLockOn)
return TS_E_NOLOCK;
if (_fShutDown)
return S_OK;
if (pSelection->style.fInterimChar)
{
_pTextMsgFilter->_pTextDoc->SetCaretType(tomKoreanBlockCaret); // Set Block caret mode
_acpInterimStart = pSelection[0].acpStart;
_acpInterimEnd = pSelection[0].acpEnd;
_fInterimChar = 1;
_ase = pSelection[0].style.ase;
}
else
{
if (_fInterimChar)
{
_fInterimChar = 0;
_pTextMsgFilter->_pTextDoc->SetCaretType(tomNormalCaret); // Reset Block caret mode
}
hResult = _pTextMsgFilter->_pTextDoc->Range(pSelection[0].acpStart, pSelection[0].acpEnd, &pTextRange);
if (pTextRange)
{
long lCount;
_pTextMsgFilter->_pTextDoc->Freeze(&lCount); // Turn off display
pTextRange->Select();
pTextRange->Release();
_pTextMsgFilter->_pTextDoc->Unfreeze(&lCount); // Turn on display
}
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::GetText()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetText(
LONG acpStart,
LONG acpEnd,
WCHAR *pchPlain,
ULONG cchPlainReq,
ULONG *pcchPlainOut,
TS_RUNINFO *prgRunInfo,
ULONG ulRunInfoReq,
ULONG *pulRunInfoOut,
LONG *pacpNext)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetText");
if (!_fReadLockOn)
return TS_E_NOLOCK;
if (pchPlain == NULL && cchPlainReq != 0 ||
prgRunInfo == NULL && ulRunInfoReq != 0)
return E_INVALIDARG;
BOOL fDoRunInfo = ulRunInfoReq > 0;
LONG acpMaxText = 0;
BOOL fEOP = FALSE;
GetStoryLength(&acpMaxText);
if (acpStart < 0 || acpStart > acpMaxText)
return TS_E_INVALIDPOS;
if (acpEnd < 0)
acpEnd = acpMaxText;
else if (acpEnd < acpStart)
return TS_E_INVALIDPOS;
if (pcchPlainOut)
*pcchPlainOut = 0;
if (pulRunInfoOut)
*pulRunInfoOut = 0;
if (pacpNext)
*pacpNext = acpStart;
if (_fShutDown)
return S_OK;
LRESULT lresult = 0;
if ( S_OK == _pTextMsgFilter->_pTextService->TxSendMessage(
EM_GETDOCFLAGS, GDF_ALL, 0, &lresult))
{
if ((lresult & GDF_RICHTEXT) && acpEnd == acpMaxText)
fEOP = TRUE;
}
if (cchPlainReq || ulRunInfoReq)
{
HRESULT hResult;
ITextRange *pTextRange = NULL;
long fHiddenTextInRange = tomFalse;
BOOL fCopyData = FALSE;
long *pHiddenTxtBlk = NULL;
long cHiddenTxtBlk = 0;
if (cchPlainReq && acpEnd > (long)cchPlainReq + acpStart)
acpEnd = cchPlainReq + acpStart;
hResult = _pTextMsgFilter->_pTextDoc->Range(acpStart, acpEnd, &pTextRange);
if (pTextRange)
{
BSTR bstr = NULL;
long cpMin, cpMax;
ULONG cch;
pTextRange->GetStart(&cpMin);
pTextRange->GetEnd(&cpMax);
if (fDoRunInfo)
{
ITextFont *pFont = NULL;
hResult = pTextRange->GetFont(&pFont);
if (pFont)
{
pFont->GetHidden(&fHiddenTextInRange);
pFont->Release();
if (fHiddenTextInRange == tomUndefined) // Some hidden text inside range
BuildHiddenTxtBlks(cpMin, cpMax, &pHiddenTxtBlk, cHiddenTxtBlk);
}
}
hResult = pTextRange->GetText(&bstr);
if (bstr)
{
cch = cpMax - cpMin;
if (cchPlainReq)
{
if (cchPlainReq > cch)
cchPlainReq = cch;
fCopyData = TRUE;
}
else
cchPlainReq = cch;
// Convert character into special Cicero char.
long cpCurrentStart = cpMin;
long cpCurrent = cpMin;
long idx = 0;
ULONG cRunInfo = 0;
BOOL fRunInfoNotEnough = FALSE;
long cpNextHiddenText = tomForward;
if (fDoRunInfo && pHiddenTxtBlk)
cpNextHiddenText = pHiddenTxtBlk[0];
if (fHiddenTextInRange != tomTrue)
{
WCHAR *pText = (WCHAR *)bstr;
while (cpCurrent < cpMax)
{
if (cpCurrent == cpNextHiddenText)
{
// setup run info for current good text
if (cpCurrent != cpCurrentStart)
{
if (cRunInfo >= ulRunInfoReq)
{
fRunInfoNotEnough = TRUE;
break;
}
prgRunInfo[cRunInfo].uCount = cpCurrent - cpCurrentStart;
prgRunInfo[cRunInfo].type = TS_RT_PLAIN;
cRunInfo++;
}
long cchHiddenText = pHiddenTxtBlk[idx+1];
// setup run info for hidden text block
if (cRunInfo >= ulRunInfoReq)
{
fRunInfoNotEnough = TRUE;
break;
}
prgRunInfo[cRunInfo].uCount = cchHiddenText;
prgRunInfo[cRunInfo].type = TS_RT_OPAQUE;
cRunInfo++;
idx += 2;
if (idx < cHiddenTxtBlk)
cpNextHiddenText = pHiddenTxtBlk[idx];
else
cpNextHiddenText = tomForward;
cpCurrent += cchHiddenText;
pText += cchHiddenText;
cpCurrentStart = cpCurrent;
}
else
{
switch (*pText)
{
case WCH_EMBEDDING:
*pText = TS_CHAR_EMBEDDED;
break;
case STARTFIELD:
case ENDFIELD:
*pText = TS_CHAR_REGION;
if (cpCurrent + 1 < cpMax)
{
pText++;
cpCurrent++;
Assert(*pText == 0x000d);
*pText = TS_CHAR_REGION;
}
break;
}
cpCurrent++;
// Convert EOP into TS_CHAR_REGION
if (fEOP && cpCurrent == acpMaxText && *pText == CR)
*pText = TS_CHAR_REGION;
pText++;
}
}
}
if (fDoRunInfo)
{
// setup run info for last chunk of good text
if (cpCurrent != cpCurrentStart && cRunInfo < ulRunInfoReq)
{
prgRunInfo[cRunInfo].uCount = cpCurrent - cpCurrentStart;
prgRunInfo[cRunInfo].type = TS_RT_PLAIN;
cRunInfo++;
}
if (pulRunInfoOut)
*pulRunInfoOut = cRunInfo ? cRunInfo : 1;
// All the text belong to the same run
if (cRunInfo == 0)
{
prgRunInfo[0].uCount = cchPlainReq;
prgRunInfo[0].type = (fHiddenTextInRange == tomTrue) ? TS_RT_OPAQUE : TS_RT_PLAIN;
}
}
if (fRunInfoNotEnough)
{
// Runinfo too small. need to add cch from all valid runs
TS_RUNINFO *prgRunInfoData = prgRunInfo;
ULONG idx;
cchPlainReq = 0;
for (idx=0; idx < cRunInfo; idx++)
{
cchPlainReq += prgRunInfoData->uCount;
prgRunInfoData++;
}
}
if (fCopyData)
// fill in the buffer
memcpy(pchPlain, (LPSTR)bstr, cchPlainReq * sizeof(WCHAR));
if (pcchPlainOut)
*pcchPlainOut = cchPlainReq;
if (pacpNext)
*pacpNext = cpMin + cchPlainReq;
SysFreeString(bstr);
}
pTextRange->Release();
FreePv(pHiddenTxtBlk);
}
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::SetText()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::SetText(
DWORD dwFlags,
LONG acpStart,
LONG acpEnd,
const WCHAR *pchText,
ULONG cch,
TS_TEXTCHANGE *pChange)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::SetText");
return InsertData(dwFlags, acpStart, acpEnd, pchText, cch, NULL, pChange);
}
/*
* STDMETHODIMP CUIM::InsertData()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::InsertData(
DWORD dwFlags,
LONG acpStart,
LONG acpEnd,
const WCHAR *pchText,
ULONG cch,
IDataObject *pDataObject,
TS_TEXTCHANGE *pChange)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::InsertData");
HRESULT hResult = S_OK;
ITextRange *pTextRange = NULL;
BOOL fInsertObject = pDataObject != NULL;
if (!_fWriteLockOn)
return TS_E_NOLOCK;
if (_fShutDown)
return S_OK;
hResult = _pTextMsgFilter->_pTextDoc->Range(acpStart, acpEnd, &pTextRange);
if (pTextRange)
{
BSTR bstr = NULL;
if(pTextRange->CanEdit(NULL) == S_FALSE)
{
pTextRange->Release();
return TS_E_READONLY; // Cannot edit text
}
LONG cchExced = 0;
BOOL fDelSelection = FALSE;
if ((LONG)cch > (acpEnd - acpStart) &&
_pTextMsgFilter->_pTextDoc->CheckTextLimit((LONG)cch - (acpEnd-acpStart), &cchExced) == NOERROR &&
cchExced > 0)
{
// We reach text limit, beep and exit
_pTextMsgFilter->_pTextDoc->SysBeep();
pTextRange->Release();
return E_FAIL;
}
if (!fInsertObject)
{
bstr = SysAllocStringLen(pchText, cch);
if (!bstr)
{
pTextRange->Release();
return E_OUTOFMEMORY;
}
}
if (!_fAnyWriteOperation)
{
// Start the UIM typing
ITextFont *pCurrentFont = NULL;
BOOL fRestFont = TRUE;
_fAnyWriteOperation = 1;
hResult = pTextRange->GetStart(&_cpMin);
// Hold notification if needed
if (!(_pTextMsgFilter->_fIMEAlwaysNotify))
_pTextMsgFilter->_pTextDoc->SetNotificationMode(tomFalse);
if (!_bstrComposition)
{
if (fRestFont && _pTextFont)
{
_pTextFont->Release();
_pTextFont = NULL;
}
if (acpStart != acpEnd)
{
if (_pTextFont == NULL)
{
ITextRange *pRange = NULL;
// Get font at cpStart+1
hResult = _pTextMsgFilter->_pTextDoc->Range(acpStart, acpStart+1, &pRange);
if (pRange)
{
hResult = pRange->GetFont(&pCurrentFont);
if (pCurrentFont)
{
hResult = pCurrentFont->GetDuplicate(&_pTextFont);
pCurrentFont->Release();
pCurrentFont = NULL;
}
pRange->Release();
}
}
// if any current selection, turn on Undo to delete it....
_pTextMsgFilter->_pTextDoc->Undo(tomResume, NULL);
pTextRange->SetText(NULL);
_pTextMsgFilter->_pTextDoc->Undo(tomSuspend, NULL);
fDelSelection = TRUE;
}
else
{
ITextSelection *pTextSel = NULL;
hResult = _pTextMsgFilter->_pTextDoc->GetSelectionEx(&pTextSel);
if (pTextSel)
{
long cpMin = 0;
hResult = pTextSel->GetStart(&cpMin);
if (hResult == S_OK && cpMin == acpStart)
hResult = pTextSel->GetFont(&pCurrentFont);
if (!pCurrentFont)
hResult = pTextRange->GetFont(&pCurrentFont);
if (pCurrentFont)
{
hResult = pCurrentFont->GetDuplicate(&_pTextFont);
pCurrentFont->Release();
pCurrentFont = NULL;
}
pTextSel->Release();
}
}
}
Assert (_pTextFont);
if (_pTextFont)
{
long cpMin;
pTextRange->GetStart(&cpMin);
_pTextMsgFilter->_uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
CIme::CheckKeyboardFontMatching(cpMin, _pTextMsgFilter, _pTextFont);
}
}
if (fInsertObject)
{
LRESULT lresult;
CHARRANGE charRange = {acpStart, acpEnd};
if (fDelSelection)
charRange.cpMost = acpStart;
hResult = _pTextMsgFilter->_pTextService->TxSendMessage(EM_INSERTOBJ, (WPARAM)&charRange,
(LPARAM)pDataObject, &lresult);
if (hResult == NOERROR && pChange)
{
pChange->acpStart = acpStart;
pChange->acpOldEnd = acpEnd;
pChange->acpNewEnd = acpStart+1;
}
}
else
{
long lCount;
long cpMin, cpMax;
_pTextMsgFilter->_pTextDoc->Freeze(&lCount); // Turn off display
hResult = pTextRange->SetText(bstr);
_pTextMsgFilter->_pTextDoc->Unfreeze(&lCount); // Turn on display
pTextRange->GetStart(&cpMin);
pTextRange->GetEnd(&cpMax);
if (_pTextFont)
pTextRange->SetFont(_pTextFont);
POINT ptBottomPos;
if (_pTextMsgFilter->_uKeyBoardCodePage == CP_KOREAN)
{
if (pTextRange->GetPoint( tomEnd+TA_BOTTOM+TA_LEFT,
&(ptBottomPos.x), &(ptBottomPos.y) ) != NOERROR)
pTextRange->ScrollIntoView(tomEnd);
}
SysFreeString(bstr);
// out params
pChange->acpStart = cpMin;
pChange->acpOldEnd = acpEnd;
pChange->acpNewEnd = cpMax;
hResult = S_OK;
}
pTextRange->Release();
}
return hResult;
}
/*
* STDMETHODIMP CUIM::GetFormattedText()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetFormattedText(
LONG acpStart,
LONG acpEnd,
IDataObject **ppDataObject)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetFormattedText");
return E_NOTIMPL;
}
/*
* STDMETHODIMP CUIM::GetEmbedded()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetEmbedded(
LONG acpPos,
REFGUID rguidService,
REFIID riid,
IUnknown **ppunk)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetEmbedded");
WORD wServiceRequested = 0;
if (!_fReadLockOn)
return TS_E_NOLOCK;
if (!ppunk)
return E_INVALIDARG;
if (IsEqualIID(rguidService, GUID_DCSERVICE_ACTIVEX))
wServiceRequested = 1;
else if (IsEqualIID(rguidService, GUID_DCSERVICE_DATAOBJECT))
wServiceRequested = 2;
else
return E_INVALIDARG;
ITextRange *pTextRange = NULL;
IUnknown *pIUnk = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->Range(acpPos, acpPos+1, &pTextRange);
if (SUCCEEDED(hResult) && pTextRange)
{
hResult = pTextRange->GetEmbeddedObject(&pIUnk);
if (SUCCEEDED(hResult) && pIUnk)
hResult = pIUnk->QueryInterface(wServiceRequested == 1 ? riid : IID_IDataObject,
(LPVOID FAR *)ppunk);
else
hResult = E_FAIL;
if (pIUnk)
pIUnk->Release();
pTextRange->Release();
}
return hResult;
}
/*
* STDMETHODIMP CUIM::InsertEmbedded()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::InsertEmbedded(
DWORD dwFlags,
LONG acpStart,
LONG acpEnd,
IDataObject *pDataObject,
TS_TEXTCHANGE *pChange)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::InsertEmbedded");
if (!pDataObject)
return E_INVALIDARG;
if (_pTextMsgFilter->_fAllowEmbedded == 0)
return TS_E_FORMAT; // Client doesn't want insert embedded
return InsertData(dwFlags, acpStart, acpEnd, NULL, 1, pDataObject, pChange);
}
/*
* STDMETHODIMP CUIM::RequestSupportedAttrs()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::RequestSupportedAttrs(
DWORD dwFlags,
ULONG cFilterAttrs,
const TS_ATTRID *paFilterAttrs)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::RequestSupportedAttrs");
if (_fShutDown)
return E_NOTIMPL;
return GetAttrs(0, cFilterAttrs, paFilterAttrs, TRUE);
}
/*
* STDMETHODIMP CUIM::RequestAttrsAtPosition()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::RequestAttrsAtPosition(
LONG acpPos,
ULONG cFilterAttrs,
const TS_ATTRID *paFilterAttrs,
DWORD dwFlags)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::RequestAttrsAtPosition");
if (_fShutDown)
return E_NOTIMPL;
return GetAttrs(acpPos, cFilterAttrs, paFilterAttrs, FALSE);
}
/*
* STDMETHODIMP CUIM::RequestAttrsTransitioningAtPosition()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::RequestAttrsTransitioningAtPosition(
LONG acpPos,
ULONG cFilterAttrs,
const TS_ATTRID *paFilterAttrs,
DWORD dwFlags)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::RequestAttrsTransitioningAtPosition");
return E_NOTIMPL;
}
/*
* STDMETHODIMP CUIM::FindNextAttrTransition()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::FindNextAttrTransition(
LONG acpStart,
LONG acpHalt,
ULONG cFilterAttrs,
const TS_ATTRID *paFilterAttrs,
DWORD dwFlags,
LONG *pacpNext,
BOOL *pfFound,
LONG *plFoundOffset)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::FindNextAttrTransition");
return E_NOTIMPL;
}
/*
* STDMETHODIMP CUIM::RetrieveRequestedAttrs()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::RetrieveRequestedAttrs(
ULONG ulCount,
TS_ATTRVAL *paAttrVals,
ULONG *pcFetched)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::RetrieveRequestedAttrs");
if (!pcFetched)
return E_INVALIDARG;
if (_fShutDown)
return E_NOTIMPL;
*pcFetched = 0;
if (_parAttrsVal && _uAttrsValCurrent < _uAttrsValTotal)
{
ULONG cFetched = min(ulCount, _uAttrsValTotal - _uAttrsValCurrent);
if (cFetched)
{
memcpy(paAttrVals, &_parAttrsVal[_uAttrsValCurrent], cFetched * sizeof(TS_ATTRVAL));
memset(&_parAttrsVal[_uAttrsValCurrent], 0, cFetched * sizeof(TS_ATTRVAL));
_uAttrsValCurrent += cFetched;
*pcFetched = cFetched;
// If everything is fetched, clean up
if (_uAttrsValCurrent == _uAttrsValTotal)
InitAttrVarArray();
}
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::GetEndACP()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetEndACP(LONG *pacp)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetEndACP");
if (!_fReadLockOn)
return TS_E_NOLOCK;
if (!pacp)
return E_INVALIDARG;
if (_fShutDown)
return E_NOTIMPL;
return GetStoryLength(pacp);
}
/*
* STDMETHODIMP CUIM::GetActiveView()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetActiveView(TsViewCookie *pvcView)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetActiveView");
if (!pvcView)
return E_INVALIDARG;
*pvcView = 0;
return S_OK;
}
/*
* STDMETHODIMP CUIM::GetACPFromPoint()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetACPFromPoint(
TsViewCookie vcView,
const POINT *pt,
DWORD dwFlags,
LONG *pacp)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetACPFromPoint");
if (!pt || !pacp)
return E_POINTER;
if (_fShutDown)
return E_NOTIMPL;
ITextRange *pTextRange = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->RangeFromPoint(pt->x, pt->y, &pTextRange);
if (hResult == S_OK && pTextRange)
hResult = pTextRange->GetStart(pacp);
if (pTextRange)
pTextRange->Release();
return hResult;
}
/*
* STDMETHODIMP CUIM::GetTextExt()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetTextExt(
TsViewCookie vcView,
LONG acpStart,
LONG acpEnd,
RECT *prc,
BOOL *pfClipped)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetTextExt");
if (!prc)
return E_POINTER;
if (_fShutDown)
return E_NOTIMPL;
if (pfClipped)
*pfClipped = TRUE;
ITextRange *pTextRange = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->Range(acpStart, acpEnd, &pTextRange);
if (hResult == S_OK && pTextRange)
{
BOOL fClipped = FALSE;
POINT ptStart, ptEnd;
hResult = pTextRange->GetPoint( tomStart+TA_TOP+TA_LEFT,
&(ptStart.x), &(ptStart.y) );
if (hResult != S_OK)
{
hResult = pTextRange->GetPoint( tomStart+TA_TOP+TA_LEFT+tomAllowOffClient,
&(ptStart.x), &(ptStart.y) );
fClipped = TRUE;
}
if (hResult == S_OK)
{
hResult = pTextRange->GetPoint( acpStart == acpEnd ? tomStart+TA_BOTTOM+TA_LEFT :
tomEnd+TA_BOTTOM+TA_LEFT,
&(ptEnd.x), &(ptEnd.y) );
if (hResult != S_OK)
{
hResult = pTextRange->GetPoint( acpStart == acpEnd ? tomStart+TA_BOTTOM+TA_LEFT+tomAllowOffClient :
tomEnd+TA_BOTTOM+TA_LEFT+tomAllowOffClient,
&(ptEnd.x), &(ptEnd.y) );
fClipped = TRUE;
}
if (hResult == S_OK)
{
prc->left = ptStart.x;
prc->top = ptStart.y;
prc->right = ptEnd.x;
prc->bottom = ptEnd.y;
if (pfClipped)
*pfClipped = fClipped;
}
}
}
if (pTextRange)
pTextRange->Release();
return hResult;
}
/*
* STDMETHODIMP CUIM::GetScreenExt()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetScreenExt(
TsViewCookie vcView,
RECT *prc)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetScreenExt");
if (!prc)
return E_POINTER;
return _pTextMsgFilter->_pTextDoc->GetClientRect(tomIncludeInset,
&(prc->left), &(prc->top), &(prc->right), &(prc->bottom));
}
/*
* STDMETHODIMP CUIM::GetWnd()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::GetWnd(
TsViewCookie vcView,
HWND *phwnd)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetWnd");
if (!phwnd)
return E_INVALIDARG;
if (_fShutDown)
return E_NOTIMPL;
*phwnd = _pTextMsgFilter->_hwnd;
if (!*phwnd) // Windowless mode...
{
long hWnd;
if (_pTextMsgFilter->_pTextDoc->GetWindow(&hWnd) != S_OK || !hWnd)
return E_NOTIMPL;
*phwnd = (HWND)(DWORD_PTR)hWnd;
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::QueryInsertEmbedded()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::QueryInsertEmbedded(
const GUID *pguidService,
const FORMATETC *pFormatEtc,
BOOL *pfInsertable)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::QueryInsertEmbedded");
if (!pfInsertable)
return E_INVALIDARG;
// Check setting if client wants to support embedded
*pfInsertable = _pTextMsgFilter->_fAllowEmbedded ? TRUE : FALSE;
return S_OK;
}
/*
* STDMETHODIMP CUIM::InsertTextAtSelection()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::InsertTextAtSelection(
DWORD dwFlags,
const WCHAR *pchText,
ULONG cch,
LONG *pacpStart,
LONG *pacpEnd,
TS_TEXTCHANGE *pChange)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::InsertTextAtSelection");
TS_SELECTION_ACP acpSelection;
ULONG cFetched;
LONG acpResultStart;
LONG acpResultEnd;
HRESULT hr;
if (_fShutDown)
return E_NOTIMPL;
if ((dwFlags & TS_IAS_QUERYONLY) || !(dwFlags & TS_IAS_NOQUERY))
{
if (!pacpStart || !pacpEnd)
return E_POINTER;
}
hr = GetSelection(TS_DEFAULT_SELECTION, 1, &acpSelection, &cFetched);
if (hr != S_OK)
return hr;
hr = QueryInsert(acpSelection.acpStart, acpSelection.acpEnd, cch,
&acpResultStart, &acpResultEnd);
if (hr != S_OK)
return hr;
if (dwFlags & TS_IAS_QUERYONLY)
{
// Query only, return data
*pacpStart = acpResultStart;
*pacpEnd = acpResultEnd;
return S_OK;
}
if (!_fUIMTyping)
{
// special case where no OnStartComposition before this call
_fInsertTextAtSel = 1;
_pTextMsgFilter->_pTextDoc->Undo(tomSuspend, NULL); // turn off undo
}
hr = SetText(0, acpResultStart, acpResultEnd, pchText, cch, pChange);
if (hr != S_OK)
{
if (!_fUIMTyping)
{
// SetText fail, reset state before exit
_fInsertTextAtSel = 0;
_pTextMsgFilter->_pTextDoc->Undo(tomResume, NULL); // turn on undo
}
return hr;
}
if (!(dwFlags & TS_IAS_NOQUERY) && pChange)
{
*pacpStart = pChange->acpStart;
*pacpEnd = pChange->acpNewEnd;
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::InsertEmbeddedAtSelection()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::InsertEmbeddedAtSelection(
DWORD dwFlags,
IDataObject *pDataObject,
LONG *pacpStart,
LONG *pacpEnd,
TS_TEXTCHANGE *pChange)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::InsertEmbeddedAtSelection");
return E_NOTIMPL;
}
/*
* void CUIM::OnPreReplaceRange()
*
* @mfunc
*
*
* @rdesc
*
*/
void CUIM::OnPreReplaceRange(
LONG cp, //@parm cp where ReplaceRange starts ("cpMin")
LONG cchDel, //@parm Count of chars after cp that are deleted
LONG cchNew, //@parm Count of chars inserted after cp
LONG cpFormatMin, //@parm cpMin for a formatting change
LONG cpFormatMax, //@parm cpMost for a formatting change
NOTIFY_DATA *pNotifyData) //@parm special data to indicate changes
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::OnPreReplaceRange");
return;
};
/*
* void CUIM::OnPostReplaceRange()
*
* @mfunc
*
*
* @rdesc
*
*/
void CUIM::OnPostReplaceRange(
LONG cp, //@parm cp where ReplaceRange starts ("cpMin")
LONG cchDel, //@parm Count of chars after cp that are deleted
LONG cchNew, //@parm Count of chars inserted after cp
LONG cpFormatMin, //@parm cpMin for a formatting change
LONG cpFormatMax, //@parm cpMost for a formatting change
NOTIFY_DATA *pNotifyData) //@parm special data to indicate changes
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::OnPostReplaceRange");
if (_fShutDown)
return;
if (cp != CONVERT_TO_PLAIN && cp != CP_INFINITE && _ptss && !_fWriteLockOn)
{
// Forward change notification to UIM
TS_TEXTCHANGE tsTxtChange;
tsTxtChange.acpStart = cp;
if (cchDel == cchNew)
{
// text modified
tsTxtChange.acpNewEnd =
tsTxtChange.acpOldEnd = cp + cchDel;
_ptss->OnTextChange(0, &tsTxtChange);
}
else
{
if (cchDel)
{
// text deleted
tsTxtChange.acpNewEnd = cp;
tsTxtChange.acpOldEnd = cp + cchDel;
_ptss->OnTextChange(0, &tsTxtChange);
}
if (cchNew)
{
// text added
tsTxtChange.acpOldEnd = cp;
tsTxtChange.acpNewEnd = cp + cchNew;
_ptss->OnTextChange(0, &tsTxtChange);
}
}
}
return;
};
/*
* void CUIM::Zombie()
*
* @mfunc
*
*
* @rdesc
*
*/
void CUIM::Zombie()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::Zombie");
return;
};
/*
* STDMETHODIMP CUIM::OnStartComposition()
*
* @mfunc
*
*
* @rdesc
*
*/
STDAPI CUIM::OnStartComposition(
ITfCompositionView *pComposition,
BOOL *pfOk)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::OnStartComposition");
if (_fUIMTyping)
*pfOk = FALSE;
else
{
BOOL fInsertTextCalled = _fInsertTextAtSel;
BOOL fRetainFont = _fEndTyping;
*pfOk = TRUE;
_fUIMTyping = 1;
_fAnyWriteOperation = _fAnyWriteOperation && (_fEndTyping || fInsertTextCalled);
_fEndTyping = 0;
_fInsertTextAtSel = 0;
if (!fInsertTextCalled)
_pTextMsgFilter->_pTextDoc->Undo(tomSuspend, NULL); // turn off undo
_cchComposition = 0;
_acpFocusRange = tomForward;
_cchFocusRange = 0;
CleanUpComposition();
if (!fInsertTextCalled && pComposition)
{
HRESULT hr;
ITfRange *pRangeNew = NULL;
hr = pComposition->GetRange(&pRangeNew);
if (pRangeNew)
{
LONG acpStart;
LONG cchStart;
GetExtentAcpPrange(pRangeNew, acpStart, cchStart);
pRangeNew->Release();
if (cchStart > 0)
{
// Save the original text
ITextRange *pTextRange = NULL;
ITextFont *pCurrentFont = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->Range(acpStart, acpStart+cchStart, &pTextRange);
if (!fRetainFont && _pTextFont)
{
_pTextFont->Release();
_pTextFont = NULL;
}
if (pTextRange)
{
if (fRetainFont && _acpPreFocusRangeLast <= acpStart
&& (acpStart + cchStart) <= (_acpPreFocusRangeLast + _cchFocusRangeLast))
{
// Cont'u from previous composition
_acpFocusRange = _acpPreFocusRangeLast;
_cchFocusRange = _cchFocusRangeLast;
}
else
{
hResult = pTextRange->GetText(&_bstrComposition);
Assert(!_pObjects);
_cObjects = BuildObject(pTextRange, _bstrComposition, &_pObjects, 0);
_acpBstrStart = acpStart;
_cchComposition = cchStart;
GetEndACP(&_cpEnd);
}
if (!_pTextFont)
{
hResult = pTextRange->Collapse(tomTrue);
hResult = pTextRange->Move(1, tomCharacter, NULL);
hResult = pTextRange->GetFont(&pCurrentFont);
if (pCurrentFont)
{
hResult = pCurrentFont->GetDuplicate(&_pTextFont);
pCurrentFont->Release();
if (_pTextFont)
{
long cpMin;
pTextRange->GetStart(&cpMin);
_pTextMsgFilter->_uKeyBoardCodePage = GetKeyboardCodePage(0x0FFFFFFFF);
CIme::CheckKeyboardFontMatching(cpMin, _pTextMsgFilter, _pTextFont);
}
}
}
pTextRange->Release();
}
}
}
}
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::OnUpdateComposition()
*
* @mfunc
*
*
* @rdesc
*
*/
STDAPI CUIM::OnUpdateComposition(
ITfCompositionView *pComposition,
ITfRange *pRangeNew)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::OnUpdateComposition");
LONG acpStart;
LONG cchStart;
if (pRangeNew)
{
GetExtentAcpPrange(pRangeNew, acpStart, cchStart);
if (_bstrComposition)
{
long cpEnd;
GetEndACP(&cpEnd);
long cpCurrentCompEnd = _acpBstrStart + _cchComposition + cpEnd - _cpEnd;
long cchExtendAfter = acpStart + cchStart - cpCurrentCompEnd;
if (_acpBstrStart > acpStart)
{
LONG cchExtendBefore = _acpBstrStart - acpStart;
ITextRange *pTextRange = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->Range(acpStart,
acpStart+cchExtendBefore, &pTextRange);
if (pTextRange)
{
BSTR bstrExtendBefore = NULL;
hResult = pTextRange->GetText(&bstrExtendBefore);
if (bstrExtendBefore)
{
BSTR bstrNew = SysAllocStringLen(NULL, _cchComposition+cchExtendBefore+1);
if (bstrNew)
{
WCHAR *pNewText = (WCHAR *)bstrNew;
WCHAR *pText = (WCHAR *)bstrExtendBefore;
memcpy(pNewText, pText, cchExtendBefore * sizeof(WCHAR));
pNewText += cchExtendBefore;
pText = (WCHAR *)_bstrComposition;
memcpy(pNewText, pText, _cchComposition * sizeof(WCHAR));
*(pNewText+_cchComposition) = L'\0';
SysFreeString(_bstrComposition);
_bstrComposition = bstrNew;
_cchComposition += cchExtendBefore;
_acpBstrStart = acpStart;
}
SysFreeString(bstrExtendBefore);
}
pTextRange->Release();
}
}
if (cchExtendAfter > 0)
{
// Extend beyond current composition, append new text to the original text
ITextRange *pTextRange = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->Range(cpCurrentCompEnd,
cpCurrentCompEnd+cchExtendAfter, &pTextRange);
if (pTextRange)
{
BSTR bstrExtend = NULL;
hResult = pTextRange->GetText(&bstrExtend);
if (bstrExtend)
{
BSTR bstrNew = SysAllocStringLen(NULL, _cchComposition+cchExtendAfter+1);
if (bstrNew)
{
WCHAR *pNewText = (WCHAR *)bstrNew;
WCHAR *pText = (WCHAR *)_bstrComposition;
memcpy(pNewText, pText, _cchComposition * sizeof(WCHAR));
pNewText += _cchComposition;
pText = (WCHAR *)bstrExtend;
memcpy(pNewText, pText, cchExtendAfter * sizeof(WCHAR));
*(pNewText+cchExtendAfter) = L'\0';
SysFreeString(_bstrComposition);
_bstrComposition = bstrNew;
_cchComposition += cchExtendAfter;
}
SysFreeString(bstrExtend);
}
pTextRange->Release();
}
}
}
}
if (pComposition)
{
HRESULT hr;
ITfRange *pRangeComp = NULL;
hr = pComposition->GetRange(&pRangeComp);
if (pRangeComp)
{
GetExtentAcpPrange(pRangeComp, _acpFocusRange, _cchFocusRange);
pRangeComp->Release();
}
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::OnEndComposition()
*
* @mfunc
*
*
* @rdesc
*
*/
STDAPI CUIM::OnEndComposition(
ITfCompositionView *pComposition)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::OnEndComposition");
_fUIMTyping = 0;
_fEndTyping = 1;
_acpPreFocusRangeLast = _acpFocusRange;
_cchFocusRangeLast = _cchFocusRange;
_acpFocusRange = tomForward;
_cchFocusRange = 0;
return S_OK;
}
/*
* STDMETHODIMP CUIM::AdviseMouseSink()
*
* @mfunc
* Setup Mouse Sink to handle mouse operation
*
* @rdesc
* S_OK is mouse trap is added to link list
* CONNECT_E_NOCONNECTION is not added.
*/
STDAPI CUIM::AdviseMouseSink(
ITfRangeACP *pRangeACP,
ITfMouseSink *pSinkInput,
DWORD *pdwCookie)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::AdviseMouseSink");
if (_fShutDown)
return CONNECT_E_NOCONNECTION;
if (!pRangeACP || !pSinkInput || !pdwCookie)
return E_POINTER;
CTFMOUSETRAP *pSinkNew = NULL;
LONG cpMouseStart, cchMosueComp;
ITfMouseSink *pSinkMouseInput = NULL;
if (FAILED(pSinkInput->QueryInterface(IID_ITfMouseSink, (void **)&pSinkMouseInput)))
return E_FAIL;
if (GetExtentAcpPrange(pRangeACP, cpMouseStart, cchMosueComp))
{
if (!_pSinkList) // No first link
{
_pSinkList = new CTFMOUSETRAP;
pSinkNew = _pSinkList;
}
else
{
if (!(_pSinkList->pMouseSink)) // The first link is empty
pSinkNew = _pSinkList;
else
{
pSinkNew = new CTFMOUSETRAP;
if (pSinkNew) // Add new trap to the bottom of list
{
CTFMOUSETRAP *pSink = _pSinkList;
while (pSink->pNext) // Find the bottom of list
pSink = pSink->pNext;
pSink->pNext = pSinkNew;
}
}
}
if (pSinkNew)
{
pSinkNew->dwCookie = *pdwCookie = (DWORD)(DWORD_PTR)pSinkMouseInput;
pSinkNew->cpMouseStart = cpMouseStart;
pSinkNew->cchMosueComp = cchMosueComp;
pSinkNew->pMouseSink = pSinkMouseInput;
_fMosueSink = 1;
return S_OK;
}
}
if (pSinkMouseInput)
pSinkMouseInput->Release();
return CONNECT_E_NOCONNECTION;
}
/*
* STDMETHODIMP CUIM::UnadviseMouseSink()
*
* @mfunc
* Remove Mouse Sink
*
* @rdesc
*
*/
STDAPI CUIM::UnadviseMouseSink(
DWORD dwCookie)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::UnadviseMouseSink");
if (_fShutDown)
return CONNECT_E_NOCONNECTION;
if (_fMosueSink == 0)
return CONNECT_E_NOCONNECTION;
Assert(_pSinkList);
CTFMOUSETRAP *pSink = _pSinkList;
CTFMOUSETRAP *pSinkParent = NULL;
while (pSink->dwCookie != dwCookie) // Find the cookie
{
pSinkParent = pSink;
pSink = pSink->pNext;
if (!pSink) // Reach list bottom?
return CONNECT_E_NOCONNECTION; // cookie not found
}
Assert(pSink->pMouseSink);
if (pSink->pMouseSink)
pSink->pMouseSink->Release();
if (pSink == _pSinkList) // Match the first link?
{
if (pSink->pNext)
_pSinkList = pSink->pNext;
else
{
_fMosueSink = 0; // No more mouse trap left
memset(_pSinkList, 0, sizeof(CTFMOUSETRAP));
}
}
else
{ // Match link other than the first link
Assert(pSinkParent);
pSinkParent->pNext = pSink->pNext;
delete pSink;
}
return S_OK;
}
/*
* STDMETHODIMP CUIM::Init()
*
* @mfunc
*
*
* @rdesc
*
*/
STDMETHODIMP CUIM::Init()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::Init");
HRESULT hResult;
// Init some CUIM data
_cCallMgrLevels = 1;
_fAllowUIMLock = 1;
hResult = _pTextMsgFilter->_pTim->CreateDocumentMgr(&_pdim);
if (FAILED(hResult))
goto ExitError;
hResult = _pdim->CreateContext(_pTextMsgFilter->_tid, 0, (ITextStoreACP *)this, &_pic, &_editCookie);
if (FAILED(hResult))
goto ExitError;
hResult = _pdim->Push(_pic);
if (FAILED(hResult))
goto ExitError;
// Get the interface for rendering markup
if (_pic->QueryInterface(IID_ITfContextRenderingMarkup, (void **)&_pContextRenderingMarkup) != S_OK)
_pContextRenderingMarkup = NULL;
_pDAM = NULL;
_pCategoryMgr = NULL;
hResult = CoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ITfDisplayAttributeMgr, (void**)&(_pDAM));
hResult = CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ITfCategoryMgr, (void**)&_pCategoryMgr);
_pTextEditSink = new CTextEditSink(EndEditCallback, this);
if (_pTextEditSink)
{
if (FAILED(_pTextEditSink->_Advise(_pic)))
{
delete _pTextEditSink;
_pTextEditSink = NULL;
}
}
LRESULT lresult;
_pTextMsgFilter->_pTextService->TxSendMessage(EM_SETUPNOTIFY, 1, (LPARAM)(ITxNotify *)this, &lresult);
_fAllowUIMLock = 0;
return S_OK;
ExitError:
Uninit();
return hResult;
}
/*
* void CUIM::Uninit()
*
* @mfunc
*
*
* @rdesc
*
*/
void CUIM::Uninit()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::Uninit");
if (_pTextFont)
{
_pTextFont->Release();
_pTextFont = NULL;
}
if (_parITfEnumRange)
{
int idx = _parITfEnumRange->Count();
for ( ; idx > 0; idx--)
{
IEnumTfRanges **ppEnumRange = (IEnumTfRanges **)(_parITfEnumRange->Elem(idx-1));
if (ppEnumRange && *ppEnumRange)
(*ppEnumRange)->Release();
}
_parITfEnumRange->Clear(AF_DELETEMEM);
delete _parITfEnumRange;
_parITfEnumRange = NULL;
}
if (_parAttrsVal)
{
InitAttrVarArray(FALSE);
FreePv (_parAttrsVal);
_parAttrsVal = NULL;
}
if (_pSinkList)
{
CTFMOUSETRAP *pSink = _pSinkList;
_pSinkList = NULL;
// Delete the Mouse sinks list
while (1)
{
CTFMOUSETRAP *pNext = pSink->pNext;
if(pSink->pMouseSink)
pSink->pMouseSink->Release();
delete pSink;
if (!pNext) // Any more?
break; // Done.
pSink = pNext;
}
}
if (_pContextRenderingMarkup)
{
_pContextRenderingMarkup->Release();
_pContextRenderingMarkup = NULL;
}
if (_pDAM)
{
_pDAM->Release();
_pDAM = NULL;
}
if (_pCategoryMgr)
{
_pCategoryMgr->Release();
_pCategoryMgr = NULL;
}
if (_pTextEditSink)
{
_pTextEditSink->_Unadvise();
delete _pTextEditSink;
_pTextEditSink = NULL;
}
if (_pdim && _pic)
_pdim->Pop(TF_POPF_ALL);
if (_pic)
{
_pic->Release();
_pic = NULL;
}
if (_pdim)
{
_pdim->Release();
_pdim = NULL;
}
if (_pacrUl)
{
_pacrUl->Clear(AF_DELETEMEM);
delete _pacrUl;
_pacrUl = NULL;
}
}
/*
* void CreateUIM()
*
* @mfunc
*
*
* @rdesc
*
*/
BOOL CreateUIM(CTextMsgFilter *pTextMsgFilter)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CreateUIM");
BOOL fCreateUIM = FALSE;
HRESULT hResult = CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER,
IID_ITfThreadMgr, (void**)&(pTextMsgFilter->_pTim));
if (hResult == S_OK)
{
// ready to start interacting
if (pTextMsgFilter->_pTim->Activate(&(pTextMsgFilter->_tid)) == S_OK)
{
pTextMsgFilter->_pCUIM = new CUIM(pTextMsgFilter);
if (pTextMsgFilter->_pCUIM)
{
hResult = pTextMsgFilter->_pCUIM->Init();
if (hResult == S_OK)
fCreateUIM = TRUE;
else
{
delete pTextMsgFilter->_pCUIM;
pTextMsgFilter->_pCUIM = NULL;
}
}
}
if (!fCreateUIM)
{
pTextMsgFilter->_pTim->Release();
pTextMsgFilter->_pTim = NULL;
}
else if (GetFocus() == pTextMsgFilter->_hwnd)
pTextMsgFilter->_pCUIM->OnSetFocus();
}
return fCreateUIM;
}
/*
* BOOL CUIM::GetExtentAcpPrange()
*
* @mfunc
*
*
* @rdesc
*
*/
BOOL CUIM::GetExtentAcpPrange(
ITfRange *ITfRangeIn,
long &cpFirst,
long &cpLim)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetExtentAcpPrange");
ITfRangeACP *prangeACP = NULL;
if (SUCCEEDED(ITfRangeIn->QueryInterface(IID_ITfRangeACP, (void **)&prangeACP)))
{
prangeACP->GetExtent(&cpFirst, &cpLim);
prangeACP->Release();
return TRUE;
}
return FALSE;
}
/*
* HRESULT CUIM::EndEditCallback()
*
* @mfunc
*
*
* @rdesc
*
*/
HRESULT CUIM::EndEditCallback(ITfEditRecord *pEditRecord, void *pv)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::EndEditCallback");
HRESULT hr;
CUIM *_this = (CUIM *)pv;
IEnumTfRanges *pEnumRanges;
const GUID *rgGUID[1];
if (!(_this->_fWriteLockOn))
{
_this->HandleTempDispAttr(pEditRecord);
return S_OK;
}
// Get lid changes
rgGUID[0] = &GUID_PROP_LANGID;
hr = pEditRecord->GetTextAndPropertyUpdates(0, (const GUID**)rgGUID, 1, &pEnumRanges);
if (SUCCEEDED(hr))
{
_this->HandleLangID (pEnumRanges);
pEnumRanges->Release();
}
// Get attribute changes
rgGUID[0] = &GUID_PROP_ATTRIBUTE;
hr = pEditRecord->GetTextAndPropertyUpdates(0, (const GUID**)rgGUID, 1, &pEnumRanges);
if (SUCCEEDED(hr))
{
_this->HandlePropAttrib (pEnumRanges);
pEnumRanges->Release();
}
rgGUID[0] = &GUID_PROP_COMPOSING;
hr = pEditRecord->GetTextAndPropertyUpdates(0, (const GUID**)rgGUID, 1, &pEnumRanges);
if (SUCCEEDED(hr))
{
// Save the TextDelta to be process after the lock is off
if (!(_this->_parITfEnumRange))
_this->_parITfEnumRange = new CITfEnumRange();
if (_this->_parITfEnumRange)
{
LONG idxItem;
IEnumTfRanges **ppItem;
ppItem = _this->_parITfEnumRange->Add(1, &idxItem);
if (ppItem)
*ppItem = pEnumRanges;
else
pEnumRanges->Release(); // Add fail, forget it
}
}
return S_OK;
}
/*
* void CUIM::HandleDispAttr(*pITfRangeProp, var, cp, cch)
*
* @mfunc
*
*
* @rdesc
*
*/
void CUIM::HandleDispAttr(
ITfRange *pITfRangeProp,
VARIANT &var,
long acpStartRange,
long cch)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::HandleDispAttr");
HRESULT hResult = TRUE;
if (pITfRangeProp)
hResult = GetExtentAcpPrange(pITfRangeProp, acpStartRange, cch);
if (hResult && cch > 0)
{
ITextRange *pTextRange = NULL;
hResult = _pTextMsgFilter->_pTextDoc->Range(acpStartRange, acpStartRange+cch, &pTextRange);
if (pTextRange)
{
ITextFont *pFont = NULL;
if (_pTextFont)
_pTextFont->GetDuplicate(&pFont);
if (pFont)
{
if (var.vt == VT_I4)
{
GUID guid;
ITfDisplayAttributeInfo *pDAI = NULL;
TF_DISPLAYATTRIBUTE da;
if (_pCategoryMgr->GetGUID(var.ulVal, &guid) == S_OK &&
SUCCEEDED(_pDAM->GetDisplayAttributeInfo(guid, &pDAI, NULL)))
{
COLORREF cr;
long lUnderline;
long idx = 0;
Assert(pDAI);
pDAI->GetAttributeInfo(&da);
if (GetUIMAttributeColor(&da.crText, &cr))
pFont->SetForeColor(cr);
if (GetUIMAttributeColor(&da.crBk, &cr))
pFont->SetBackColor(cr);
lUnderline = GetUIMUnderline(da, idx, cr);
if (lUnderline != tomNone)
{
if (idx)
{
hResult = _pTextMsgFilter->_pTextDoc->SetEffectColor(idx, cr);
if (hResult == S_OK)
lUnderline += (idx << 8);
}
pFont->SetUnderline(lUnderline);
}
}
if (pDAI)
pDAI->Release();
}
pTextRange->SetFont(pFont);
pFont->Release();
}
pTextRange->Release();
}
}
}
/*
* HRESULT CUIM::HandlePropAttrib(ITfEnumTextDeltas *pEnumTextDeltas)
*
* @mfunc
*
*
* @rdesc
*
*/
HRESULT CUIM::HandlePropAttrib(IEnumTfRanges *pEnumRanges)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::HandlePropAttrib");
ITfRange *pITfRange = NULL;
if (!_pDAM || !_pCategoryMgr || _fInterimChar)
return S_OK;
ITfProperty *pProp = NULL;
HRESULT hResult = _pic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp);
if (SUCCEEDED(hResult))
{
long lCount;
TS_SELECTION_ACP acpSelection;
ULONG cFetched;
GetSelection(0, 0, &acpSelection, &cFetched);
_pTextMsgFilter->_pTextDoc->Freeze(&lCount); // Turn off display
while (pEnumRanges->Next(1, &pITfRange, NULL) == S_OK)
{
BOOL fAnyPropRange = FALSE;
IEnumTfRanges *pEnumPropRange = NULL;
long acpRangeStart, ccpRangeStart;
VARIANT var;
GetExtentAcpPrange(pITfRange, acpRangeStart, ccpRangeStart);
// Create a property Enum for ranges within pITfRange
if (pProp->EnumRanges(_editCookie, &pEnumPropRange, pITfRange) == S_OK)
{
ITfRange *pITfRangeProp = NULL;
while (pEnumPropRange->Next(1, &pITfRangeProp, NULL) == S_OK)
{
VariantInit(&var);
if (!fAnyPropRange)
{
long acpCurrentRange, ccpCurrent;
if (GetExtentAcpPrange(pITfRangeProp, acpCurrentRange, ccpCurrent))
{
if (acpCurrentRange > acpRangeStart)
HandleDispAttr(NULL, var, acpRangeStart, acpCurrentRange - acpRangeStart);
}
fAnyPropRange = TRUE;
}
pProp->GetValue(_editCookie, pITfRangeProp, &var);
HandleDispAttr(pITfRangeProp, var);
VariantClear(&var);
pITfRangeProp->Release();
}
pEnumPropRange->Release();
}
if (!fAnyPropRange)
{
// Whole string doesn't contain any disp. attribute.
VariantInit(&var);
HandleDispAttr(pITfRange, var);
}
pITfRange->Release();
}
pProp->Release();
// Only want to scroll back if its not a selection
if (acpSelection.acpStart == acpSelection.acpEnd)
{
ITextRange *pTextRange;
hResult = _pTextMsgFilter->_pTextDoc->Range(acpSelection.acpStart, acpSelection.acpEnd, &pTextRange);
if (pTextRange)
{
pTextRange->Select();
pTextRange->Release();
}
}
_pTextMsgFilter->_pTextDoc->Unfreeze(&lCount); // Turn on display
}
return S_OK;
}
/*
* void CUIM::GetUIMUnderline()
*
* @mfunc
*
*
* @rdesc
*
*/
long CUIM::GetUIMUnderline(
TF_DISPLAYATTRIBUTE &da,
long &idx,
COLORREF &cr)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetUIMUnderline");
long lStyle = tomNone;
idx = 0;
if (da.lsStyle != TF_LS_NONE)
{
switch(da.lsStyle)
{
// case TFLS_SOLID:
default:
lStyle = da.fBoldLine ? tomThick : tomSingle;
break;
case TF_LS_DOT:
case TF_LS_DASH: // Dash line should show as dotted line
lStyle = tomDotted;
break;
case TF_LS_SQUIGGLE:
lStyle = tomWave;
break;
}
if (GetUIMAttributeColor(&da.crLine, &cr))
{
if (!_pacrUl) // Create the array if it is not there
_pacrUl = new CUlColorArray();
if (_pacrUl)
{
LONG idxMax = _pacrUl->Count();
LONG idxItem;
COLORREF *pCr;
// Check if this item is in the array
for (idxItem=0; idxItem < idxMax; idxItem++)
{
pCr = _pacrUl->Elem(idxItem);
Assert(pCr);
if (*pCr == cr)
idx = idxItem + 1; // found it
}
if (!idx)
{
// Add it to array
pCr = _pacrUl->Add(1, &idxItem);
if (pCr)
{
*pCr = cr;
idx = idxItem + 1; // return new idx
}
}
}
}
}
return lStyle;
}
/*
* void CUIM::HandleFinalString(ITfRange *pPropRange, long acpStartRange, long cch)
* @mfunc
*
*
* @rdesc
*
*/
void CUIM::HandleFinalString(
ITfRange *pPropRange,
long acpStartRange,
long cch,
BOOL fEndComposition)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::HandleFinalString");
HRESULT hResult = TRUE;
if (pPropRange)
hResult = GetExtentAcpPrange(pPropRange, acpStartRange, cch);
if (hResult == TRUE && cch)
{
if (_bstrComposition && !fEndComposition)
return;
ITextRange *pTextRange = NULL;
ITextSelection *pTextSel = NULL;
long cpSelMin = 0, cpSelMax = 0;
BOOL fTextSel = FALSE;
// Need to maintain current selection
hResult = _pTextMsgFilter->_pTextDoc->GetSelectionEx(&pTextSel);
if (pTextSel)
{
hResult = pTextSel->GetStart(&cpSelMin);
hResult = pTextSel->GetEnd(&cpSelMax);
pTextSel->Release();
fTextSel = TRUE;
}
if (_bstrComposition)
{
long cpEnd;
GetEndACP(&cpEnd);
cch = _cchComposition + cpEnd - _cpEnd;
acpStartRange = _acpBstrStart;
}
hResult = _pTextMsgFilter->_pTextDoc->Range(acpStartRange, acpStartRange+cch, &pTextRange);
if (pTextRange)
{
long cEmbeddedObjects = 0;
BSTR bstr = NULL;
if (cch)
hResult = pTextRange->GetText(&bstr);
if (SUCCEEDED(hResult) && (bstr || cch == 0))
{
long lCount;
BSTR bstrTemp = NULL;
if (!_fAnyWriteOperation) // No new string
goto IGNORE_STRING; // no need to insert
if (_bstrComposition)
{
if (bstr)
{
WCHAR *pStr1 = _bstrComposition;
WCHAR *pStr2 = bstr;
while (*pStr1 != 0 && *pStr1 == *pStr2)
{
pStr1++;
pStr2++;
}
if (*pStr1 == *pStr2) // Same data, no need to insert
{
if (acpStartRange == cpSelMin)
{
pTextRange->Collapse(tomFalse);
pTextRange->Select();
}
goto IGNORE_STRING;
}
}
bstrTemp = _bstrComposition;
}
// Build embed object data if necessary
EMBEDOBJECT arEmbeddObjects[5];
EMBEDOBJECT *pEmbeddObjects = arEmbeddObjects;
if (bstr)
cEmbeddedObjects =
BuildObject(pTextRange, bstr, &pEmbeddObjects, ARRAY_SIZE(arEmbeddObjects));
_pTextMsgFilter->_pTextDoc->Freeze(&lCount); // Turn off display
// We want the final text to be in the undo stack.
// So, we first delete the final string.
// Resume undo and add the final string back. Yuk!
if (bstrTemp && _cObjects)
{
long cpMin;
long cchBstr = SysStringLen(bstrTemp);
pTextRange->GetStart(&cpMin);
InsertTextandObject(pTextRange, bstrTemp, _pObjects, _cObjects);
pTextRange->SetRange(cpMin, cpMin+cchBstr);
}
else
pTextRange->SetText(bstrTemp);
if (_pTextFont)
pTextRange->SetFont(_pTextFont);
_pTextMsgFilter->_pTextDoc->Undo(tomResume, NULL);
_pTextMsgFilter->_pTextDoc->SetNotificationMode(tomTrue);
if (cEmbeddedObjects == 0)
pTextRange->SetText(bstr);
else
{
InsertTextandObject(pTextRange, bstr, pEmbeddObjects, cEmbeddedObjects);
CleanUpObjects(cEmbeddedObjects, pEmbeddObjects);
if (pEmbeddObjects != arEmbeddObjects)
delete pEmbeddObjects;
}
_pTextMsgFilter->_pTextDoc->Undo(tomSuspend, NULL);
// Hold notification if needed
if (!(_pTextMsgFilter->_fIMEAlwaysNotify))
_pTextMsgFilter->_pTextDoc->SetNotificationMode(tomFalse);
if (fTextSel)
{
ITextRange *pSelRange = NULL;
// restore previous selection.
hResult = _pTextMsgFilter->_pTextDoc->Range(cpSelMin, cpSelMax, &pSelRange);
if (pSelRange)
{
pSelRange->Select();
pSelRange->Release();
}
}
else
{
pTextRange->Collapse(tomFalse);
pTextRange->Select();
}
_pTextMsgFilter->_pTextDoc->Unfreeze(&lCount); // Turn on display
}
IGNORE_STRING:
if (bstr)
SysFreeString(bstr);
pTextRange->Release();
}
}
}
/*
* HRESULT CUIM::HandleFocusRange(IEnumTfRanges *pEnumRanges)
* @mfunc
*
*
* @rdesc
*
*/
HRESULT CUIM::HandleFocusRange(IEnumTfRanges *pEnumRanges)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::HandleFocusRange");
ITfProperty *pProp = NULL;
ITfRange *pITfRange;
HRESULT hResult = _pic->GetProperty(GUID_PROP_COMPOSING, &pProp);
BOOL fAnyPendingFocusRange = FALSE;
if (SUCCEEDED(hResult))
{
// Enumerate all the changes
pEnumRanges->Reset();
while (pEnumRanges->Next(1, &pITfRange, NULL) == S_OK)
{
BOOL fAnyPropRange = FALSE;
IEnumTfRanges *pEnumPropRange = NULL;
long acpStartRange, ccp;
GetExtentAcpPrange(pITfRange, acpStartRange, ccp);
// Create a property Enum for ranges within pITfRange
if (pProp->EnumRanges(_editCookie, &pEnumPropRange, pITfRange) == S_OK)
{
ITfRange *pPropRange = NULL;
// Try to get a value for the property
while (pEnumPropRange->Next(1, &pPropRange, NULL) == S_OK)
{
VARIANT var;
VariantInit(&var);
if (!fAnyPropRange)
{
long acpCurrentRange, ccpCurrent;
GetExtentAcpPrange(pPropRange, acpCurrentRange, ccpCurrent);
if (acpCurrentRange > acpStartRange)
{
// We have a final string before the new string.
HandleFinalString(NULL, acpStartRange, acpCurrentRange - acpStartRange);
}
fAnyPropRange = TRUE;
}
hResult = pProp->GetValue(_editCookie, pPropRange, &var);
if (SUCCEEDED(hResult) && var.vt == VT_I4 && var.ulVal == 0)
hResult = E_FAIL; // Just as good as not finding the range
else
fAnyPendingFocusRange = TRUE;
VariantClear(&var);
if (hResult != S_OK)
HandleFinalString(pPropRange);
pPropRange->Release();
}
pEnumPropRange->Release();
}
if (!fAnyPropRange) // Any focus range?
HandleFinalString(pITfRange); // No --> the whole string is final string
if (_fEndTyping && _bstrComposition && _acpBstrStart != tomForward)
HandleFinalString(NULL, _acpBstrStart, _cchComposition, TRUE);
pITfRange->Release();
}
pProp->Release();
}
return S_OK;
}
/*
* HRESULT CUIM::HandleLangID(IEnumTfRanges *pEnumRanges)
*
* @mfunc
*
*
* @rdesc
*
*/
HRESULT CUIM::HandleLangID(IEnumTfRanges *pEnumRanges)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::HandleLangID");
ITfProperty *pProp = NULL;
ITfRange *pITfRange;
HRESULT hResult;
LCID lcid;
// TODO:
// if _pTextFont is NULL, setup _pTextFont to handle the langID.
if (!_pTextFont)
return S_OK;
hResult = _pic->GetProperty(GUID_PROP_LANGID, &pProp);
if (SUCCEEDED(hResult))
{
// Enumerate all the changes
pEnumRanges->Reset();
while (pEnumRanges->Next(1, &pITfRange, NULL) == S_OK)
{
IEnumTfRanges *pEnumPropRange = NULL;
// Create a property Enum for ranges within pITfRange
if (pProp->EnumRanges(_editCookie, &pEnumPropRange, pITfRange) == S_OK)
{
ITfRange *pPropRange = NULL;
if (pEnumPropRange->Next(1, &pPropRange, NULL) == S_OK)
{
VARIANT var;
VariantInit(&var);
hResult = pProp->GetValue(_editCookie, pITfRange, &var);
if (SUCCEEDED(hResult) && var.vt == VT_I4)
{
lcid = (LCID)var.ulVal;
UINT cpgProp = CodePageFromCharRep(CharRepFromLID(lcid));
ITextFont *pTextFont=NULL;
_pTextFont->GetDuplicate(&pTextFont);
if (pTextFont)
{
HRESULT hResult;
LONG acpStart, cchStart;
ITextRange *pTextRange;
UINT cpgTemp = _pTextMsgFilter->_uKeyBoardCodePage;
GetExtentAcpPrange(pITfRange, acpStart, cchStart);
if (cchStart)
{
_pTextMsgFilter->_uKeyBoardCodePage = cpgProp;
CIme::CheckKeyboardFontMatching(acpStart, _pTextMsgFilter, pTextFont);
_pTextMsgFilter->_uKeyBoardCodePage = cpgTemp;
hResult = _pTextMsgFilter->_pTextDoc->Range(acpStart, acpStart+cchStart, &pTextRange);
if (pTextRange)
{
pTextRange->SetFont(pTextFont);
pTextRange->Release();
}
}
pTextFont->Release();
}
}
VariantClear(&var);
pPropRange->Release();
}
pEnumPropRange->Release();
}
pITfRange->Release();
}
pProp->Release();
}
return S_OK;
}
/*
* HRESULT CUIM::OnSetFocus(BOOL fEnable)
*
* @mfunc
*
*
*/
void CUIM::OnSetFocus(BOOL fEnable)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::OnSetFocus");
_pTextMsgFilter->_pTim->SetFocus(fEnable ? _pdim : NULL);
}
/*
* HRESULT CUIM::CompleteUIMText()
*
* @mfunc
*
*
*/
void CUIM::CompleteUIMText()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::CompleteUIMText");
HRESULT hResult;
ITfContextOwnerCompositionServices *pCompositionServices;
_fAllowUIMLock = 1;
Assert(_pic);
if (_pic->QueryInterface(IID_ITfContextOwnerCompositionServices, (void **)&pCompositionServices) == S_OK)
{
// passing in NULL means "all compositions"
hResult = pCompositionServices->TerminateComposition(NULL);
pCompositionServices->Release();
}
_fAllowUIMLock = 0;
}
/*
* BOOL CUIM::GetUIMAttributeColor()
*
* @mfunc
* Helper routine to get UIM color
*
* @rdesc
* TRUE if we setup input pcr with the UIM color
*
*/
BOOL CUIM::GetUIMAttributeColor(TF_DA_COLOR *pdac, COLORREF *pcr)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetUIMAttributeColor");
BOOL fRetCode = FALSE;
switch (pdac->type)
{
//case TFCT_NONE:
// return FALSE;
case TF_CT_SYSCOLOR:
*pcr = GetSysColor(pdac->nIndex);
fRetCode = TRUE;
break;
case TF_CT_COLORREF:
*pcr = pdac->cr;
fRetCode = TRUE;
break;
}
return fRetCode;
}
/*
* void CUIM::OnUIMTypingDone()
*
* @mfunc
* Helper routine to cleanup after UIM Typing is done
*
*/
void CUIM::OnUIMTypingDone()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::OnUIMTypingDone");
if (_pTextFont)
{
_pTextFont->Release();
_pTextFont = NULL;
}
CleanUpComposition();
// Reset Korean block caret if needed
if (_fInterimChar)
{
_fInterimChar = 0;
_pTextMsgFilter->_pTextDoc->SetCaretType(tomNormalCaret); // Reset Block caret mode
}
_fAnyWriteOperation = 0;
_pTextMsgFilter->_pTextDoc->Undo(tomResume, NULL);
_pTextMsgFilter->_pTextDoc->SetNotificationMode(tomTrue);
if (_pacrUl)
_pacrUl->Clear(AF_DELETEMEM);
};
/*
* BOOL CUIM::GetGUIDATOMFromGUID()
*
* @mfunc
* Helper routine to get GUIDATOM from UIM
*
*/
BOOL CUIM::GetGUIDATOMFromGUID(
REFGUID rguid,
TfGuidAtom *pguidatom)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetGUIDATOMFromGUID");
if (_pCategoryMgr && _pCategoryMgr->RegisterGUID(rguid, pguidatom) == S_OK)
return TRUE;
return FALSE;
}
/*
* BOOL CUIM::GetAttrs()
*
* @mfunc
* Helper routine to get Attr
*
*/
HRESULT CUIM::GetAttrs(
LONG acpPos,
ULONG cFilterAttrs,
const TS_ATTRID *paFilterAttrs,
BOOL fGetDefault)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetAttrs");
HRESULT hResult;
ITextFont *pTextFont = NULL;
ITextPara *pTextPara = NULL;
int idx;
BOOL fRequestedAll = FALSE;
int idxAttr;
TS_ATTRVAL *pAttrVal;
ITextRange *pTextRange = NULL;
if (cFilterAttrs == 0)
{
fRequestedAll = TRUE;
cFilterAttrs = MAX_ATTR_SUPPORT;
}
InitAttrVarArray();
if (!_parAttrsVal)
return E_OUTOFMEMORY;
if (fGetDefault)
{
// Get document defaults font and para
hResult = _pTextMsgFilter->_pTextDoc->GetDocumentFont(&pTextFont);
if (FAILED(hResult))
goto EXIT;
hResult = _pTextMsgFilter->_pTextDoc->GetDocumentPara(&pTextPara);
if (FAILED(hResult))
goto EXIT;
}
else
{
hResult = _pTextMsgFilter->_pTextDoc->Range(acpPos, acpPos, &pTextRange);
if (FAILED(hResult))
goto EXIT;
hResult = pTextRange->GetFont(&pTextFont);
hResult = pTextRange->GetPara(&pTextPara);
}
pAttrVal = _parAttrsVal;
for (idx = 0; idx < (int)cFilterAttrs; idx++, paFilterAttrs++)
{
if (fRequestedAll)
idxAttr = idx;
else
idxAttr = FindGUID(*paFilterAttrs);
if (idxAttr >= 0)
{
if (PackAttrData(idxAttr, pTextFont, pTextPara, pAttrVal))
{
_uAttrsValTotal++;
pAttrVal++;
if (_uAttrsValTotal == MAX_ATTR_SUPPORT)
break;
}
}
}
hResult = S_OK;
EXIT:
if (pTextFont)
pTextFont->Release();
if (pTextPara)
pTextPara->Release();
if (pTextRange)
pTextRange->Release();
return hResult;
}
/*
* int CUIM::FindGUID
*
* @mfunc
* Helper routine to check if we supported the requested Attribute GUID
*
*/
int CUIM::FindGUID(REFGUID guid)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::FindGUID");
ULONG i;
for (i=0; i < MAX_ATTR_SUPPORT; i++)
{
if (IsEqualIID(*(_arTSAttridSupported[i]), guid))
return i;
}
// not found
return -1;
}
/*
* int CUIM::PackAttrData
*
* @mfunc
* Helper routine to fill in data for the given Attrib index
*
*/
BOOL CUIM::PackAttrData(
LONG idx,
ITextFont *pITextFont,
ITextPara *pITextPara,
TS_ATTRVAL *pAttrVal)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::PackAttrData");
long lValue;
float x;
BSTR bstrName;
HRESULT hResult;
const GUID *pGUID;
TfGuidAtom guidatom;
if (idx < 0 || idx >= MAX_ATTR_SUPPORT)
return FALSE;
if (!pITextFont && idx <= iattrSuperscript)
return FALSE;
if (!pITextPara && idx == iattrRTL)
return FALSE;
pAttrVal->varValue.vt = VT_BOOL;
memcpy(&pAttrVal->idAttr, _arTSAttridSupported[idx], sizeof(TS_ATTRID));
switch(idx)
{
case iattrFacename:
hResult = pITextFont->GetName(&bstrName);
pAttrVal->varValue.vt = VT_BSTR;
pAttrVal->varValue.bstrVal = bstrName;
break;
case iattrSize:
x = 0.0;
hResult = pITextFont->GetSize(&x);
lValue = (long)x;
pAttrVal->varValue.vt = VT_I4;
pAttrVal->varValue.lVal = x;
break;
case iattrColor:
hResult = pITextFont->GetForeColor(&lValue);
pAttrVal->varValue.vt = VT_I4;
pAttrVal->varValue.lVal = lValue; // TODO: check for tomAutocolor
break;
case iattrBold:
hResult = pITextFont->GetBold(&lValue);
pAttrVal->varValue.boolVal = lValue == tomTrue ? tomTrue : VARIANT_FALSE;
break;
case iattrItalic:
hResult = pITextFont->GetItalic(&lValue);
pAttrVal->varValue.boolVal = lValue == tomTrue ? tomTrue : VARIANT_FALSE;
break;
case iattrUnderline:
hResult = pITextFont->GetUnderline(&lValue);
pAttrVal->varValue.boolVal = lValue == tomNone ? VARIANT_FALSE : tomTrue;
break;
case iattrSubscript:
hResult = pITextFont->GetSubscript(&lValue);
pAttrVal->varValue.boolVal = lValue == tomTrue ? tomTrue : VARIANT_FALSE;
break;
case iattrSuperscript:
hResult = pITextFont->GetSuperscript(&lValue);
pAttrVal->varValue.boolVal = lValue == tomTrue ? tomTrue : VARIANT_FALSE;
break;
case iattrRTL:
{
LRESULT lres = 0;
_pTextMsgFilter->_pTextService->TxSendMessage(
EM_GETPARATXTFLOW, 0, (LPARAM)pITextPara, &lres);
pAttrVal->varValue.boolVal = lres ? tomTrue : VARIANT_FALSE;
}
break;
case iattrVertical:
BOOL fAtFont;
_pTextMsgFilter->_pTextDoc->GetFEFlags(&lValue);
fAtFont = lValue & tomUseAtFont;
lValue &= tomTextFlowMask;
pAttrVal->varValue.boolVal = (fAtFont && lValue == tomTextFlowSW) ? tomTrue : VARIANT_FALSE;
break;
case iattrBias:
pGUID = &GUID_MODEBIAS_NONE;
if (IN_RANGE(CTFMODEBIAS_DEFAULT, _pTextMsgFilter->_wUIMModeBias, CTFMODEBIAS_HALFWIDTHALPHANUMERIC))
pGUID = _arModeBiasSupported[_pTextMsgFilter->_wUIMModeBias];
if (!GetGUIDATOMFromGUID(*pGUID, &guidatom))
guidatom = TF_INVALID_GUIDATOM;
pAttrVal->varValue.vt = VT_I4;
pAttrVal->varValue.lVal = guidatom;
break;
case iattrTxtOrient:
// Get Text flow and setup the text rotation
_pTextMsgFilter->_pTextDoc->GetFEFlags(&lValue);
lValue &= tomTextFlowMask;
pAttrVal->varValue.vt = VT_I4;
pAttrVal->varValue.lVal = 0;
if (lValue == tomTextFlowSW)
pAttrVal->varValue.lVal = 2700;
else if (lValue == tomTextFlowNE)
pAttrVal->varValue.lVal = 900;
break;
}
return TRUE;
}
/*
* STDMETHODIMP CUIM::GetStoryLength
*
* @mfunc
* Helper routine to check the attribute filters
*
*/
STDMETHODIMP CUIM::GetStoryLength(LONG *pacp)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetStoryLength");
ITextRange *pTextRange = NULL;
HRESULT hResult = _pTextMsgFilter->_pTextDoc->Range(0, 0, &pTextRange);
if (hResult == S_OK && pTextRange)
{
long Count;
hResult = pTextRange->GetStoryLength(&Count);
if (hResult == S_OK)
*pacp = Count;
pTextRange->Release();
}
return hResult;
}
/*
* void CUIM::InitAttrVarArray
*
* @mfunc
* Helper routine to setup AttrVar Array
*
*/
void CUIM::InitAttrVarArray(BOOL fAllocData)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::InitAttrVarArray");
if (_parAttrsVal)
{
USHORT uIdx;
TS_ATTRVAL *pAttrVal = _parAttrsVal;
for (uIdx = 0; uIdx < _uAttrsValTotal; uIdx++, pAttrVal++)
VariantClear(&(pAttrVal->varValue));
memset(_parAttrsVal, 0, _uAttrsValTotal * sizeof(TS_ATTRVAL));
}
else if (fAllocData)
{
_parAttrsVal= (TS_ATTRVAL *)PvAlloc(sizeof(TS_ATTRVAL) * MAX_ATTR_SUPPORT, GMEM_ZEROINIT);
Assert(_parAttrsVal);
}
_uAttrsValCurrent = 0;
_uAttrsValTotal = 0;
}
/*
* HRESULT CUIM::MouseCheck(UINT *pmsg, WPARAM *pwparam, LPARAM *plparam, LRESULT *plres)
*
* @mfunc
* Perform UIM mouse check
*
* @rdesc
* int S_OK if handled
* S_FALSE Don't handle and should be ignored
*
*/
HRESULT CUIM::MouseCheck(
UINT *pmsg,
WPARAM *pwparam,
LPARAM *plparam,
LRESULT *plres)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::MouseCheck");
BOOL fRetCode = FALSE;
if (_fShutDown)
return S_FALSE;
if (_fMosueSink)
{
BOOL fTerminateIME;
long cpCusor = -1;
CTFMOUSETRAP *pSinkList = _pSinkList;
Assert(_pSinkList);
_fAllowUIMLock = 1;
// Get thru the list until one of the traps has handled the message
while(fRetCode == FALSE && pSinkList)
{
if (cpCusor == -1 || pSinkList->cpMouseStart < cpCusor &&
cpCusor <= pSinkList->cpMouseStart + pSinkList->cchMosueComp) // Within composition range?
{
fRetCode = _pTextMsgFilter->MouseOperation(*pmsg, pSinkList->cpMouseStart,
pSinkList->cchMosueComp, *pwparam, &(pSinkList->wParamBefore), &fTerminateIME,
NULL, &cpCusor, pSinkList->pMouseSink);
}
pSinkList = pSinkList->pNext;
}
_fAllowUIMLock = 0;
if ( !fRetCode && IsUIMTyping() && WM_MOUSEMOVE != *pmsg )
_pTextMsgFilter->CompleteUIMTyping(CIme::TERMINATE_NORMAL);
}
return fRetCode ? S_OK : S_FALSE;
}
/*
* HRESULT CUIM::Reconverse
*
* @mfunc
* Perform UIM reconversion
*
* @rdesc
* int S_OK if handled
* S_FALSE Don't handle and should be ignored
* -1 Don't handle and try IME reconverse
*
*/
int CUIM::Reconverse()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::Reconverse");
HRESULT hResult;
ITfRange *pITfRange = NULL;
ITfFnReconversion *pITfReconverse = NULL;
ITfFunctionProvider *pITfFctProvider = NULL;
TF_SELECTION TFSel = {0};
ULONG cSel;
int retCode = -1;
int fConvertible = FALSE;
if (_fUIMTyping)
return S_FALSE;
_fAllowUIMLock = 1;
_fHoldCTFSelChangeNotify = 1;
hResult = _pTextMsgFilter->_pTim->GetFunctionProvider(GUID_SYSTEM_FUNCTIONPROVIDER, &pITfFctProvider);
if (SUCCEEDED(hResult))
{
hResult = pITfFctProvider->GetFunction(GUID_NULL, IID_ITfFnReconversion, (IUnknown **)&pITfReconverse);
pITfFctProvider->Release();
if (SUCCEEDED(hResult))
{
int fCurrentLock = _fReadLockOn;
if (!fCurrentLock)
_fReadLockOn = 1; // Setup internal read lock
hResult = _pic->GetSelection(_editCookie, 0, 1, &TFSel, &cSel);
if (!fCurrentLock)
_fReadLockOn = 0; // Clear internal read lock
if (hResult == S_OK && cSel == 1)
{
if (pITfReconverse->QueryRange(TFSel.range, &pITfRange, &fConvertible) == S_OK && fConvertible)
{
pITfReconverse->Reconvert(pITfRange);
retCode = S_OK;
}
}
}
}
if (TFSel.range)
TFSel.range->Release();
if (pITfRange)
pITfRange->Release();
if (pITfReconverse)
pITfReconverse->Release();
_fAllowUIMLock = 0;
return retCode;
}
/*
* HRESULT CUIM::FindHiddenText
*
* @mfunc
* Find Hidden text and return the end of the range
*
* @rdesc
*
*/
HRESULT CUIM::FindHiddenText(
long cp,
long cpEnd,
long &cpRange)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::FindHiddenText");
HRESULT hResult;
long unitMoved;
ITextRange *pTextRange = NULL;
cpRange = cp;
if (cpRange >= cpEnd)
return S_OK;
hResult = _pTextMsgFilter->_pTextDoc->Range(cpRange, cpRange, &pTextRange);
if (!SUCCEEDED(hResult))
return hResult;
hResult = pTextRange->EndOf(tomHidden, tomExtend, &unitMoved);
if (SUCCEEDED(hResult))
{
Assert(unitMoved);
cpRange = 0;
hResult = pTextRange->GetEnd(&cpRange);
Assert(cpRange);
}
pTextRange->Release();
return hResult;
}
/*
* HRESULT CUIM::FindUnhiddenText
*
* @mfunc
* Find Unhidden text and return the end of the range
*
* @rdesc
*
*/
HRESULT CUIM::FindUnhiddenText(
long cp,
long cpEnd,
long &cpRange)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::FindUnhiddenText");
HRESULT hResult;
long unitMoved;
ITextRange *pTextRange = NULL;
ITextFont *pTextFont = NULL;
long fHidden;
cpRange = cp;
if (cpRange >= cpEnd)
return S_OK;
hResult = _pTextMsgFilter->_pTextDoc->Range(cpRange, cpRange, &pTextRange);
if (!SUCCEEDED(hResult))
return hResult;
Assert(pTextRange);
while (cpRange < cpEnd)
{
hResult = pTextRange->MoveEnd(tomCharacter, 1, &unitMoved);
if (!SUCCEEDED(hResult))
break;
if (!unitMoved)
{
hResult = E_FAIL;
break;
}
hResult = pTextRange->GetFont(&pTextFont);
if (!SUCCEEDED(hResult))
break;
Assert(pTextFont);
pTextFont->GetHidden(&fHidden);
pTextFont->Release();
if (fHidden)
break;
hResult = pTextRange->EndOf(tomCharFormat, tomMove, &unitMoved);
if (!SUCCEEDED(hResult))
break;
if (unitMoved > 0)
{
cpRange = 0;
hResult = pTextRange->GetEnd(&cpRange);
if (!SUCCEEDED(hResult))
break;
Assert(cpRange);
}
else
cpRange = cpEnd;
}
pTextRange->Release();
return hResult;
}
/*
* void CUIM::BuildHiddenTxtBlks
*
* @mfunc
* Build hidden text blocks
*
*
*/
void CUIM::BuildHiddenTxtBlks(
long &cpMin,
long &cpMax,
long **ppHiddenTxtBlk,
long &cHiddenTxtBlk)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::BuildHiddenTxtBlks");
long cHiddenTxtBlkAlloc = 0;
long *pHiddenTxtBlk;
long cpCurrent = cpMin;
long cpNext;
HRESULT hResult;
cHiddenTxtBlkAlloc = 20;
pHiddenTxtBlk = (long *)PvAlloc(cHiddenTxtBlkAlloc * sizeof(long), GMEM_ZEROINIT);
if (pHiddenTxtBlk)
{
pHiddenTxtBlk[0] = tomForward;
while (cpCurrent < cpMax)
{
hResult = FindUnhiddenText(cpCurrent, cpMax, cpNext);
if (!SUCCEEDED(hResult))
break;
if (cpNext >= cpMax)
break;
hResult = FindHiddenText(cpNext, cpMax, cpCurrent);
if (!SUCCEEDED(hResult))
break;
Assert(cpCurrent > cpNext);
// Save the hidden text block cp and length
pHiddenTxtBlk[cHiddenTxtBlk] = cpNext;
cpCurrent = min(cpCurrent, cpMax);
pHiddenTxtBlk[cHiddenTxtBlk+1] = cpCurrent - cpNext;
cHiddenTxtBlk += 2;
if (cHiddenTxtBlk >= cHiddenTxtBlkAlloc)
{
cHiddenTxtBlkAlloc += 20;
pHiddenTxtBlk = (long *)PvReAlloc(pHiddenTxtBlk, cHiddenTxtBlkAlloc * sizeof(long));
if (!pHiddenTxtBlk)
break;
}
}
}
*ppHiddenTxtBlk = pHiddenTxtBlk;
}
/*
* BOOL CUIM::CTFOpenStatus
*
* @mfunc
* Get/Set current CTF open status
*
* @rdesc
* For GetOpenStatus
* return 1 is Open, 0 if Close or fail
*
* For SetOpenStatus
* return TRUE is set status without problem, FALSE if fail
*
*/
BOOL CUIM::CTFOpenStatus(
BOOL fGetOpenStatus,
BOOL fOpen)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::CTFOpenStatus");
HRESULT hr;
VARIANT var;
BOOL fRet = FALSE;
ITfCompartment *pComp = NULL;
ITfCompartmentMgr *pCompMgr = NULL;
hr = _pTextMsgFilter->_pTim->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompMgr);
if (SUCCEEDED(hr))
{
Assert(pCompMgr);
hr = pCompMgr->GetCompartment(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, &pComp);
if (SUCCEEDED(hr))
{
Assert(pComp);
VariantInit(&var);
if (fGetOpenStatus)
{
if (pComp->GetValue(&var) == S_OK)
{
Assert(var.vt == VT_I4);
fRet = var.lVal ? TRUE : FALSE ;
}
}
else
{
var.vt = VT_I4;
var.lVal = fOpen;
hr = pComp->SetValue(_pTextMsgFilter->_tid, &var);
fRet = SUCCEEDED(hr);
}
VariantClear(&var);
}
}
if (pComp)
pComp->Release();
if (pCompMgr)
pCompMgr->Release();
return fRet;
}
/*
* BOOL CUIM::BuildObject
*
* @mfunc
* Build an array of embedded objects
*
* @rdesc
* return Number of objects in the array returned in pEmbeddObjects
*
*/
int CUIM::BuildObject(
ITextRange *pTextRange,
BSTR bstr,
EMBEDOBJECT **ppEmbeddObjects,
int cSize)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::BuildObject");
long cpMin;
HRESULT hResult = pTextRange->GetStart(&cpMin);
WCHAR *pText = (WCHAR *)bstr;
EMBEDOBJECT *pEmbeddObjStart = *ppEmbeddObjects;
EMBEDOBJECT *pEmbeddObj = *ppEmbeddObjects;
BOOL fAllocateBuffer = FALSE;
long cObjects = 0;
long cchBstr = SysStringLen(bstr);
if (hResult == S_OK)
{
for(long i = 0; i < cchBstr; i++, pText++)
{
if (*pText == WCH_EMBEDDING)
{
// Get IDataObject
HRESULT hr;
IDataObject *pIDataObj = NULL;
BOOL fReadLockOld = _fReadLockOn;
_fReadLockOn = TRUE;
hr = GetEmbedded(cpMin+i, GUID_DCSERVICE_DATAOBJECT, IID_IDataObject, (IUnknown **)&pIDataObj);
_fReadLockOn = fReadLockOld;
// Store it in the memory
if (cObjects < cSize)
{
pEmbeddObj->cpOffset = i;
pEmbeddObj->pIDataObj = pIDataObj;
pEmbeddObj++;
cObjects++;
}
else
{
long cNewSize = cSize + 5;
EMBEDOBJECT *pEmbeddObjTemp;
if (fAllocateBuffer)
{
pEmbeddObjTemp = (EMBEDOBJECT *)PvReAlloc(pEmbeddObjStart, sizeof(EMBEDOBJECT) * cNewSize);
if (pEmbeddObjTemp)
{
pEmbeddObjStart = pEmbeddObjTemp;
pEmbeddObj = pEmbeddObjStart + cSize;
cSize = cNewSize;
pEmbeddObj->cpOffset = i;
pEmbeddObj->pIDataObj = pIDataObj;
pEmbeddObj++;
cObjects++;
}
else
{
// Cleanup here
pIDataObj->Release();
break;
}
}
else
{
fAllocateBuffer = TRUE;
pEmbeddObjTemp = (EMBEDOBJECT *)PvAlloc(sizeof(EMBEDOBJECT) * cNewSize, GMEM_ZEROINIT);
if (pEmbeddObjTemp)
{
if (cSize)
{
// Copy previous data to new buffer
memcpy(pEmbeddObjTemp, pEmbeddObjStart, sizeof(EMBEDOBJECT) * cSize);
}
pEmbeddObjStart = pEmbeddObjTemp;
pEmbeddObj = pEmbeddObjStart + cSize;
cSize = cNewSize;
pEmbeddObj->cpOffset = i;
pEmbeddObj->pIDataObj = pIDataObj;
pEmbeddObj++;
cObjects++;
}
else
{
// Cleanup here
pIDataObj->Release();
break;
}
}
}
}
}
}
*ppEmbeddObjects = pEmbeddObjStart;
return cObjects;
}
/*
* BOOL CUIM::InsertTextandObject
*
* @mfunc
* Insert text and embedded objects
*
*/
void CUIM::InsertTextandObject(
ITextRange *pTextRange,
BSTR bstr,
EMBEDOBJECT *pEmbeddObjects,
long cEmbeddedObjects)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::InsertTextandObject");
WCHAR *pText = (WCHAR *)bstr;
WCHAR *pTextStart = pText;
long cObjects = 0;
long cchBstr = SysStringLen(bstr);
HRESULT hr;
for(long i = 0; i < cchBstr; i++, pText++)
{
if (*pText == WCH_EMBEDDING)
{
// Insert Text if necessary
if (pTextStart != pText)
{
BSTR bstr = SysAllocStringLen(pTextStart, pText-pTextStart);
if (bstr)
{
hr = pTextRange->SetText(bstr);
SysFreeString(bstr);
pTextRange->Collapse(tomFalse);
}
}
if (cObjects < cEmbeddedObjects)
{
LRESULT lresult;
long cpMin = 0, cpMax = 0;
HRESULT hResult = pTextRange->GetStart(&cpMin);
hResult = pTextRange->GetEnd(&cpMax);
CHARRANGE charRange = {cpMin, cpMax};
hr = _pTextMsgFilter->_pTextService->TxSendMessage(EM_INSERTOBJ, (WPARAM)&charRange,
(LPARAM)(pEmbeddObjects->pIDataObj), &lresult);
hr = pTextRange->Move(tomCharacter, 1, NULL); // move over the embedded char
cObjects++;
pEmbeddObjects++;
}
// Setup for next string after the embedded object
pTextStart = pText + 1;
}
}
// Insert last Text if necessary
if (pTextStart != pText)
{
BSTR bstr = SysAllocStringLen(pTextStart, pText-pTextStart);
if (bstr)
{
hr = pTextRange->SetText(bstr);
SysFreeString(bstr);
}
}
}
/*
* BOOL CUIM::CleanUpObjects
*
* @mfunc
* Free the objects
*
*/
void CUIM::CleanUpObjects(
long cObjects,
EMBEDOBJECT *pObjects)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::CleanUpObjects");
for (long i = 0; i < cObjects; i++, pObjects++)
{
if (pObjects->pIDataObj)
pObjects->pIDataObj->Release();
}
}
/*
* void CUIM::CleanUpComposition
*
* @mfunc
* Free the composition string and objects list
*
*/
void CUIM::CleanUpComposition()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::CleanUpComposition");
if (_bstrComposition)
{
SysFreeString (_bstrComposition);
_bstrComposition = NULL;
}
_acpBstrStart = tomForward;
if (_cObjects)
{
CleanUpObjects(_cObjects, _pObjects);
delete _pObjects;
_cObjects = 0;
_pObjects = NULL;
}
}
/*
* BOOL CUIM::HandleTempDispAttr
*
* @mfunc
* This routine handle temp. display attribute that are set
* outside CTF composition. It is using ITfContextRenderingMarkup
* to get the range and display data.
*
*/
void CUIM::HandleTempDispAttr(
ITfEditRecord *pEditRecord)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::HandleTempDispAttr");
if (_pContextRenderingMarkup)
{
HRESULT hr;
const GUID *rgGUID[1];
IEnumTfRanges *pEnumRanges = NULL;
// Get attribute changes
rgGUID[0] = &GUID_PROP_ATTRIBUTE;
hr = pEditRecord->GetTextAndPropertyUpdates(0, (const GUID**)rgGUID, 1, &pEnumRanges);
if (SUCCEEDED(hr))
{
ITfRange *pITfRange = NULL;
while (pEnumRanges->Next(1, &pITfRange, NULL) == S_OK)
{
IEnumTfRenderingMarkup *pEnumMarkup;
TF_RENDERINGMARKUP tfRenderingMarkup;
long acpStartRange, cch;
if (_pContextRenderingMarkup->GetRenderingMarkup(_editCookie, TF_GRM_INCLUDE_PROPERTY, pITfRange, &pEnumMarkup) == S_OK)
{
while (pEnumMarkup->Next(1, &tfRenderingMarkup, NULL) == S_OK)
{
HRESULT hResult;
hResult = GetExtentAcpPrange(tfRenderingMarkup.pRange, acpStartRange, cch);
if (hResult && cch > 0)
{
ITextRange *pTextRange = NULL;
hResult = _pTextMsgFilter->_pTextDoc->Range(acpStartRange, acpStartRange+cch, &pTextRange);
if (pTextRange)
{
ITextFont *pFont = NULL;
hResult = pTextRange->GetFont(&pFont);
if (pFont)
{
long lStyle;
COLORREF cr;
_pTextMsgFilter->_pTextDoc->Undo(tomSuspend, NULL);
TF_DISPLAYATTRIBUTE da = tfRenderingMarkup.tfDisplayAttr;
pFont->Reset(tomApplyTmp);
switch (da.lsStyle)
{
// case TFLS_SOLID:
default:
lStyle = da.fBoldLine ? tomThick : tomSingle;
break;
case TF_LS_DOT:
case TF_LS_DASH: // Dash line should show as dotted line
lStyle = tomDotted;
break;
case TF_LS_SQUIGGLE:
lStyle = tomWave;
break;
case TF_LS_NONE:
lStyle = tomNone;
break;
}
if (lStyle != tomNone)
{
pFont->SetUnderline(lStyle);
if (GetUIMAttributeColor(&da.crLine, &cr))
pFont->SetUnderline(cr | 0x0FF000000);
}
if (GetUIMAttributeColor(&da.crText, &cr))
pFont->SetForeColor(cr);
if (GetUIMAttributeColor(&da.crBk, &cr))
pFont->SetBackColor(cr);
pFont->Reset(tomApplyNow);
pFont->Release();
_pTextMsgFilter->_pTextDoc->Undo(tomResume, NULL);
}
pTextRange->Release();
}
}
}
pEnumMarkup->Release();
}
pITfRange->Release();
}
}
if (pEnumRanges)
pEnumRanges->Release();
}
}
/*
* STDAPI CUIM::QueryService(REFGUID guidService, REFIID riid, void **ppv)
*
* @mfunc
* Handle ITfEnableService::QueryService. Cicero/tip call this interface to obtain
* IID_ITfEnableService i/f
*
* @rdesc
* S_OK if service supported
*
*/
STDAPI CUIM::QueryService(
REFGUID guidService,
REFIID riid,
void **ppv)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::QueryService");
if (ppv == NULL)
return E_INVALIDARG;
*ppv = NULL;
// we support just one service
if (!IsEqualGUID(guidService, GUID_SERVICE_TEXTSTORE))
return E_NOINTERFACE;
if (IsEqualIID(riid, IID_IServiceProvider))
{
*ppv = (IServiceProvider *)this;
}
else if (IsEqualIID(riid, IID_ITfEnableService))
{
*ppv = (ITfEnableService *)this;
}
if (*ppv == NULL)
return E_NOINTERFACE;
AddRef();
return S_OK;
}
/*
* STDAPI CUIM::IsEnabled(REFGUID rguidServiceCategory, CLSID clsidService, IUnknown *punkService, BOOL *pfOkToRun)
*
* @mfunc
* Handle ITfEnableService::QueryService. Cicero/tip call this interface to check
* if we support the service
*
* @rdesc
* S_OK if service supported
*
*/
STDAPI CUIM::IsEnabled(
REFGUID rguidServiceCategory,
CLSID clsidService,
IUnknown *punkService,
BOOL *pfOkToRun)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::IsEnabled");
if (pfOkToRun == NULL)
return E_INVALIDARG;
// default is disallow
*pfOkToRun = FALSE;
// clsidService identifies the particular tip, but we don't use it here
// punkService is a custom interface, probably for config, but we don't use it here yet
if (IsEqualGUID(rguidServiceCategory, GUID_TFCAT_TIP_SMARTTAG))
{
*pfOkToRun = _pTextMsgFilter->_fAllowSmartTag ? TRUE : FALSE;
}
else if (IsEqualGUID(rguidServiceCategory, GUID_TFCAT_TIP_PROOFING))
{
*pfOkToRun = _pTextMsgFilter->_fAllowProofing ? TRUE : FALSE;;
}
return S_OK;
}
/*
* STDAPI CUIM::GetId(GUID *pguidId)
*
* @mfunc
* get the RE clid
*
* @rdesc
* S_OK
*
*/
STDAPI CUIM::GetId(
GUID *pguidId)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::GetId");
if (pguidId == NULL)
return E_INVALIDARG;
*pguidId = CLSID_MSFTEDIT;
return S_OK;
}
/*
* void CUIM::NotifyService()
*
* @mfunc
* Notify Cicero about change in services.
*
*
*/
void CUIM::NotifyService()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CUIM::NotifyService");
ITfCompartmentMgr *pCompartmentMgr;
ITfCompartment *pCompartment;
VARIANT varValue;
if (_pic->QueryInterface(IID_ITfCompartmentMgr, (void **)&pCompartmentMgr) != S_OK)
return;
// give any waiting tips a heads up we've changed our state
if (pCompartmentMgr->GetCompartment(GUID_COMPARTMENT_ENABLESTATE, &pCompartment) == S_OK)
{
varValue.vt = VT_I4;
varValue.lVal = 1; // arbitrary value, we just want to generate a change event
pCompartment->SetValue(_pTextMsgFilter->_tid, &varValue);
pCompartment->Release();
}
pCompartmentMgr->Release();
}
/*
* STDAPI CTextEditSink::QueryInterface
*
* @mfunc
* IUnknown QueryInterface support
*
* @rdesc
* NOERROR if interface supported
*
*/
STDAPI CTextEditSink::QueryInterface(REFIID riid, void **ppvObj)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextEditSink::QueryInterface");
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_ITfTextEditSink))
{
*ppvObj = (CTextEditSink *)this;
}
if (*ppvObj)
{
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
/*
* STDMETHODIMP_(ULONG) CTextEditSink::AddRef
*
* @mfunc
* IUnknown AddRef support
*
* @rdesc
* Reference count
*/
STDAPI_(ULONG) CTextEditSink::AddRef()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextEditSink::AddRef");
return ++_cRef;
}
/*
* STDMETHODIMP_(ULONG) CTextEditSink::Release()
*
* @mfunc
* IUnknown Release support - delete object when reference count is 0
*
* @rdesc
* Reference count
*/
STDAPI_(ULONG) CTextEditSink::Release()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextEditSink::Release");
long cr;
cr = --_cRef;
Assert(cr >= 0);
if (cr == 0)
{
delete this;
}
return cr;
}
/*
* CTextEditSink::CTextEditSink()
*
* @mfunc
*
* ctor
*
*/
CTextEditSink::CTextEditSink(PTESCALLBACK pfnCallback, void *pv)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextEditSink::CTextEditSink");
_cRef = 1;
_dwCookie = 0x0FFFFFFFF;
_pfnCallback = pfnCallback;
_pv = pv;
}
/*
* STDAPI CTextEditSink::OnEndEdit()
*
* @mfunc
*
*
* @rdesc
*
*/
STDAPI CTextEditSink::OnEndEdit(
ITfContext *pic,
TfEditCookie ecReadOnly,
ITfEditRecord *pEditRecord)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextEditSink::OnEndEdit");
return _pfnCallback(pEditRecord, _pv);
}
/*
* HRESULT CTextEditSink::_Advise
*
* @mfunc
*
*
* @rdesc
*
*/
HRESULT CTextEditSink::_Advise(ITfContext *pic)
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextEditSink::_Advise");
HRESULT hr;
ITfSource *source = NULL;
_pic = NULL;
hr = E_FAIL;
if (FAILED(pic->QueryInterface(IID_ITfSource, (void **)&source)))
return E_FAIL;
if (FAILED(source->AdviseSink(IID_ITfTextEditSink, this, &_dwCookie)))
goto Exit;
_pic = pic;
_pic->AddRef();
hr = S_OK;
Exit:
source->Release();
return hr;
}
/*
* HRESULT CTextEditSink::_Unadvise
*
* @mfunc
*
*
* @rdesc
*
*/
HRESULT CTextEditSink::_Unadvise()
{
TRACEBEGIN(TRCSUBSYSFE, TRCSCOPEINTERN, "CTextEditSink::_Unadvise");
HRESULT hr;
ITfSource *source = NULL;
hr = E_FAIL;
if (_pic == NULL)
return E_FAIL;
if (FAILED(_pic->QueryInterface(IID_ITfSource, (void **)&source)))
return E_FAIL;
if (FAILED(source->UnadviseSink(_dwCookie)))
goto Exit;
hr = S_OK;
Exit:
source->Release();
_pic->Release();
_pic = NULL;
return hr;
}
#endif // NOFEPROCESSING