/* * @doc INTERNAL * * @module CUIM.CPP -- Cicero Implementation * * Most everything to do with Cicero handling. * * Original Author: * Hon Wah Chan * * History: * 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