mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 19:02:32 +00:00
540 lines
12 KiB
C++
540 lines
12 KiB
C++
![]() |
/*
|
||
|
* PROJECT: ReactOS msctfime.ime
|
||
|
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||
|
* PURPOSE: The sinks of msctfime.ime
|
||
|
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
|
||
|
*/
|
||
|
|
||
|
#include "msctfime.h"
|
||
|
|
||
|
WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
|
||
|
|
||
|
/// @implemented
|
||
|
CCompartmentEventSink::CCompartmentEventSink(FN_EVENTSINK fnEventSink, LPVOID pUserData)
|
||
|
: m_array()
|
||
|
, m_cRefs(1)
|
||
|
, m_fnEventSink(fnEventSink)
|
||
|
, m_pUserData(pUserData)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
CCompartmentEventSink::~CCompartmentEventSink()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP CCompartmentEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfCompartmentEventSink))
|
||
|
{
|
||
|
*ppvObj = this;
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
*ppvObj = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CCompartmentEventSink::AddRef()
|
||
|
{
|
||
|
return ::InterlockedIncrement(&m_cRefs);
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CCompartmentEventSink::Release()
|
||
|
{
|
||
|
if (::InterlockedDecrement(&m_cRefs) == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
return m_cRefs;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP CCompartmentEventSink::OnChange(REFGUID rguid)
|
||
|
{
|
||
|
return m_fnEventSink(m_pUserData, rguid);
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
HRESULT
|
||
|
CCompartmentEventSink::_Advise(IUnknown *pUnknown, REFGUID rguid, BOOL bThread)
|
||
|
{
|
||
|
CESMAP *pCesMap = m_array.Append(1);
|
||
|
if (!pCesMap)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
ITfSource *pSource = NULL;
|
||
|
|
||
|
HRESULT hr = GetCompartment(pUnknown, rguid, &pCesMap->m_pComp, bThread);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void **)&pSource);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
hr = pSource->AdviseSink(IID_ITfCompartmentEventSink, this, &pCesMap->m_dwCookie);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
if (pCesMap->m_pComp)
|
||
|
{
|
||
|
pCesMap->m_pComp->Release();
|
||
|
pCesMap->m_pComp = NULL;
|
||
|
}
|
||
|
m_array.Remove(m_array.size() - 1, 1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pSource)
|
||
|
pSource->Release();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
HRESULT CCompartmentEventSink::_Unadvise()
|
||
|
{
|
||
|
CESMAP *pCesMap = m_array.data();
|
||
|
size_t cItems = m_array.size();
|
||
|
if (!cItems)
|
||
|
return S_OK;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
ITfSource *pSource = NULL;
|
||
|
HRESULT hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void **)&pSource);
|
||
|
if (SUCCEEDED(hr))
|
||
|
pSource->UnadviseSink(pCesMap->m_dwCookie);
|
||
|
|
||
|
if (pCesMap->m_pComp)
|
||
|
{
|
||
|
pCesMap->m_pComp->Release();
|
||
|
pCesMap->m_pComp = NULL;
|
||
|
}
|
||
|
|
||
|
if (pSource)
|
||
|
pSource->Release();
|
||
|
|
||
|
++pCesMap;
|
||
|
--cItems;
|
||
|
} while (cItems);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************/
|
||
|
|
||
|
/// @implemented
|
||
|
CTextEventSink::CTextEventSink(FN_ENDEDIT fnEndEdit, LPVOID pCallbackPV)
|
||
|
{
|
||
|
m_cRefs = 1;
|
||
|
m_pUnknown = NULL;
|
||
|
m_dwEditSinkCookie = (DWORD)-1;
|
||
|
m_dwLayoutSinkCookie = (DWORD)-1;
|
||
|
m_fnLayoutChange = NULL;
|
||
|
m_fnEndEdit = fnEndEdit;
|
||
|
m_pCallbackPV = pCallbackPV;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
CTextEventSink::~CTextEventSink()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP CTextEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfTextEditSink))
|
||
|
{
|
||
|
*ppvObj = this;
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
if (IsEqualIID(riid, IID_ITfTextLayoutSink))
|
||
|
{
|
||
|
*ppvObj = static_cast<ITfTextLayoutSink*>(this);
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CTextEventSink::AddRef()
|
||
|
{
|
||
|
return ::InterlockedIncrement(&m_cRefs);
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CTextEventSink::Release()
|
||
|
{
|
||
|
if (::InterlockedDecrement(&m_cRefs) == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
return m_cRefs;
|
||
|
}
|
||
|
|
||
|
struct TEXT_EVENT_SINK_END_EDIT
|
||
|
{
|
||
|
TfEditCookie m_ecReadOnly;
|
||
|
ITfEditRecord *m_pEditRecord;
|
||
|
ITfContext *m_pContext;
|
||
|
};
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP CTextEventSink::OnEndEdit(
|
||
|
ITfContext *pic,
|
||
|
TfEditCookie ecReadOnly,
|
||
|
ITfEditRecord *pEditRecord)
|
||
|
{
|
||
|
TEXT_EVENT_SINK_END_EDIT Data = { ecReadOnly, pEditRecord, pic };
|
||
|
return m_fnEndEdit(1, m_pCallbackPV, (LPVOID)&Data);
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP CTextEventSink::OnLayoutChange(
|
||
|
ITfContext *pContext,
|
||
|
TfLayoutCode lcode,
|
||
|
ITfContextView *pContextView)
|
||
|
{
|
||
|
switch (lcode)
|
||
|
{
|
||
|
case TF_LC_CREATE:
|
||
|
return m_fnLayoutChange(3, m_fnEndEdit, pContextView);
|
||
|
case TF_LC_CHANGE:
|
||
|
return m_fnLayoutChange(2, m_fnEndEdit, pContextView);
|
||
|
case TF_LC_DESTROY:
|
||
|
return m_fnLayoutChange(4, m_fnEndEdit, pContextView);
|
||
|
default:
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
HRESULT CTextEventSink::_Advise(IUnknown *pUnknown, UINT uFlags)
|
||
|
{
|
||
|
m_pUnknown = NULL;
|
||
|
m_uFlags = uFlags;
|
||
|
|
||
|
ITfSource *pSource = NULL;
|
||
|
HRESULT hr = pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
ITfTextEditSink *pSink = static_cast<ITfTextEditSink*>(this);
|
||
|
if (uFlags & 1)
|
||
|
hr = pSource->AdviseSink(IID_ITfTextEditSink, pSink, &m_dwEditSinkCookie);
|
||
|
if (SUCCEEDED(hr) && (uFlags & 2))
|
||
|
hr = pSource->AdviseSink(IID_ITfTextLayoutSink, pSink, &m_dwLayoutSinkCookie);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
m_pUnknown = pUnknown;
|
||
|
pUnknown->AddRef();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pSource->UnadviseSink(m_dwEditSinkCookie);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pSource)
|
||
|
pSource->Release();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
HRESULT CTextEventSink::_Unadvise()
|
||
|
{
|
||
|
if (!m_pUnknown)
|
||
|
return E_FAIL;
|
||
|
|
||
|
ITfSource *pSource = NULL;
|
||
|
HRESULT hr = m_pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (m_uFlags & 1)
|
||
|
hr = pSource->UnadviseSink(m_dwEditSinkCookie);
|
||
|
if (m_uFlags & 2)
|
||
|
hr = pSource->UnadviseSink(m_dwLayoutSinkCookie);
|
||
|
|
||
|
pSource->Release();
|
||
|
}
|
||
|
|
||
|
m_pUnknown->Release();
|
||
|
m_pUnknown = NULL;
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************/
|
||
|
|
||
|
/// @implemented
|
||
|
CThreadMgrEventSink::CThreadMgrEventSink(
|
||
|
_In_ FN_INITDOCMGR fnInit,
|
||
|
_In_ FN_PUSHPOP fnPushPop,
|
||
|
_Inout_ LPVOID pvCallbackPV)
|
||
|
{
|
||
|
m_fnInit = fnInit;
|
||
|
m_fnPushPop = fnPushPop;
|
||
|
m_pCallbackPV = pvCallbackPV;
|
||
|
m_cRefs = 1;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP CThreadMgrEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfThreadMgrEventSink))
|
||
|
{
|
||
|
*ppvObj = this;
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
*ppvObj = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CThreadMgrEventSink::AddRef()
|
||
|
{
|
||
|
return ::InterlockedIncrement(&m_cRefs);
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CThreadMgrEventSink::Release()
|
||
|
{
|
||
|
if (::InterlockedDecrement(&m_cRefs) == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
return m_cRefs;
|
||
|
}
|
||
|
|
||
|
INT CALLBACK
|
||
|
CThreadMgrEventSink::DIMCallback(
|
||
|
UINT nCode,
|
||
|
ITfDocumentMgr *pDocMgr1,
|
||
|
ITfDocumentMgr *pDocMgr2,
|
||
|
LPVOID pUserData)
|
||
|
{
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CThreadMgrEventSink::OnInitDocumentMgr(ITfDocumentMgr *pdim)
|
||
|
{
|
||
|
if (!m_fnInit)
|
||
|
return S_OK;
|
||
|
return m_fnInit(0, pdim, NULL, m_pCallbackPV);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CThreadMgrEventSink::OnUninitDocumentMgr(ITfDocumentMgr *pdim)
|
||
|
{
|
||
|
if (!m_fnInit)
|
||
|
return S_OK;
|
||
|
return m_fnInit(1, pdim, NULL, m_pCallbackPV);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CThreadMgrEventSink::OnSetFocus(ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus)
|
||
|
{
|
||
|
if (!m_fnInit)
|
||
|
return S_OK;
|
||
|
return m_fnInit(2, pdimFocus, pdimPrevFocus, m_pCallbackPV);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CThreadMgrEventSink::OnPushContext(ITfContext *pic)
|
||
|
{
|
||
|
if (!m_fnPushPop)
|
||
|
return S_OK;
|
||
|
return m_fnPushPop(3, pic, m_pCallbackPV);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CThreadMgrEventSink::OnPopContext(ITfContext *pic)
|
||
|
{
|
||
|
if (!m_fnPushPop)
|
||
|
return S_OK;
|
||
|
return m_fnPushPop(4, pic, m_pCallbackPV);
|
||
|
}
|
||
|
|
||
|
void CThreadMgrEventSink::SetCallbackPV(_Inout_ LPVOID pv)
|
||
|
{
|
||
|
if (!m_pCallbackPV)
|
||
|
m_pCallbackPV = pv;
|
||
|
}
|
||
|
|
||
|
HRESULT CThreadMgrEventSink::_Advise(ITfThreadMgr *pThreadMgr)
|
||
|
{
|
||
|
m_pThreadMgr = NULL;
|
||
|
|
||
|
HRESULT hr = E_FAIL;
|
||
|
ITfSource *pSource = NULL;
|
||
|
if (pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK &&
|
||
|
pSource->AdviseSink(IID_ITfThreadMgrEventSink, this, &m_dwCookie) == S_OK)
|
||
|
{
|
||
|
m_pThreadMgr = pThreadMgr;
|
||
|
pThreadMgr->AddRef();
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
if (pSource)
|
||
|
pSource->Release();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CThreadMgrEventSink::_Unadvise()
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
ITfSource *pSource = NULL;
|
||
|
|
||
|
if (m_pThreadMgr)
|
||
|
{
|
||
|
if (m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK &&
|
||
|
pSource->UnadviseSink(m_dwCookie) == S_OK)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
if (pSource)
|
||
|
pSource->Release();
|
||
|
}
|
||
|
|
||
|
if (m_pThreadMgr)
|
||
|
{
|
||
|
m_pThreadMgr->Release();
|
||
|
m_pThreadMgr = NULL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************/
|
||
|
|
||
|
/// @implemented
|
||
|
CActiveLanguageProfileNotifySink::CActiveLanguageProfileNotifySink(
|
||
|
_In_ FN_COMPARE fnCompare,
|
||
|
_Inout_opt_ void *pUserData)
|
||
|
{
|
||
|
m_dwConnection = (DWORD)-1;
|
||
|
m_fnCompare = fnCompare;
|
||
|
m_cRefs = 1;
|
||
|
m_pUserData = pUserData;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
CActiveLanguageProfileNotifySink::~CActiveLanguageProfileNotifySink()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP CActiveLanguageProfileNotifySink::QueryInterface(REFIID riid, LPVOID* ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfActiveLanguageProfileNotifySink))
|
||
|
{
|
||
|
*ppvObj = this;
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
*ppvObj = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::AddRef()
|
||
|
{
|
||
|
return ::InterlockedIncrement(&m_cRefs);
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::Release()
|
||
|
{
|
||
|
if (::InterlockedDecrement(&m_cRefs) == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
return m_cRefs;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
STDMETHODIMP
|
||
|
CActiveLanguageProfileNotifySink::OnActivated(
|
||
|
REFCLSID clsid,
|
||
|
REFGUID guidProfile,
|
||
|
BOOL fActivated)
|
||
|
{
|
||
|
if (!m_fnCompare)
|
||
|
return 0;
|
||
|
|
||
|
return m_fnCompare(clsid, guidProfile, fActivated, m_pUserData);
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
HRESULT
|
||
|
CActiveLanguageProfileNotifySink::_Advise(
|
||
|
ITfThreadMgr *pThreadMgr)
|
||
|
{
|
||
|
m_pThreadMgr = NULL;
|
||
|
|
||
|
ITfSource *pSource = NULL;
|
||
|
HRESULT hr = pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource);
|
||
|
if (FAILED(hr))
|
||
|
return E_FAIL;
|
||
|
|
||
|
hr = pSource->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, this, &m_dwConnection);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
m_pThreadMgr = pThreadMgr;
|
||
|
pThreadMgr->AddRef();
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
if (pSource)
|
||
|
pSource->Release();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/// @implemented
|
||
|
HRESULT
|
||
|
CActiveLanguageProfileNotifySink::_Unadvise()
|
||
|
{
|
||
|
if (!m_pThreadMgr)
|
||
|
return E_FAIL;
|
||
|
|
||
|
ITfSource *pSource = NULL;
|
||
|
HRESULT hr = m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pSource->UnadviseSink(m_dwConnection);
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
if (pSource)
|
||
|
pSource->Release();
|
||
|
|
||
|
if (m_pThreadMgr)
|
||
|
{
|
||
|
m_pThreadMgr->Release();
|
||
|
m_pThreadMgr = NULL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|