You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
682 lines
18 KiB
682 lines
18 KiB
//
|
|
// ksmgr.cpp
|
|
//
|
|
|
|
#include "private.h"
|
|
#include "dim.h"
|
|
#include "tim.h"
|
|
#include "ic.h"
|
|
#include "computil.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CAsyncProcessKeyQueueItem
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CAsyncProcessKeyQueueItem : public CAsyncQueueItem
|
|
{
|
|
public:
|
|
CAsyncProcessKeyQueueItem(WPARAM wParam, LPARAM lParam, DWORD dwFlags, BOOL *pfEaten) : CAsyncQueueItem(dwFlags & TIM_AKH_SYNC ? TRUE : FALSE)
|
|
{
|
|
_wParam = wParam;
|
|
_lParam = lParam;
|
|
if ((dwFlags & TIM_AKH_SYNC) && pfEaten)
|
|
_pfEaten = pfEaten;
|
|
else
|
|
{
|
|
if (pfEaten)
|
|
*pfEaten = TRUE;
|
|
|
|
_pfEaten = &_fEaten;
|
|
}
|
|
|
|
_dwFlags = dwFlags;
|
|
}
|
|
|
|
HRESULT DoDispatch(CInputContext *pic)
|
|
{
|
|
CThreadInputMgr *ptim = CThreadInputMgr::_GetThis();
|
|
if (!ptim)
|
|
{
|
|
Assert(0);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (HIWORD(_lParam) & KF_UP)
|
|
{
|
|
ptim->TestKeyUp(_wParam, _lParam, _pfEaten);
|
|
if (*_pfEaten && !(_dwFlags & TIM_AKH_TESTONLY))
|
|
ptim->KeyUp(_wParam, _lParam, _pfEaten);
|
|
}
|
|
else
|
|
{
|
|
ptim->TestKeyDown(_wParam, _lParam, _pfEaten);
|
|
if (*_pfEaten && !(_dwFlags & TIM_AKH_TESTONLY))
|
|
ptim->KeyDown(_wParam, _lParam, _pfEaten);
|
|
}
|
|
|
|
//
|
|
// We needs to simulate keydown message because
|
|
// we might return *pfEaten = TRUE;
|
|
// When it is async,
|
|
// When it was not eaten by keystroke mgr.
|
|
// When it has TIM_AKH_SIMULATEKEYMSG
|
|
//
|
|
if (!(_dwFlags & TIM_AKH_SYNC) &&
|
|
!*_pfEaten &&
|
|
(_dwFlags & TIM_AKH_SIMULATEKEYMSGS))
|
|
{
|
|
UINT uMsg = WM_KEYDOWN;
|
|
|
|
// key up msg?
|
|
if (HIWORD(_lParam) & KF_UP)
|
|
uMsg++;
|
|
|
|
// sys key msg?
|
|
if (HIWORD(_lParam) & (KF_MENUMODE | KF_ALTDOWN))
|
|
uMsg |= 0x04;
|
|
|
|
PostMessage(GetFocus(), uMsg, _wParam, _lParam);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
private:
|
|
WPARAM _wParam;
|
|
LPARAM _lParam;
|
|
BOOL *_pfEaten;
|
|
BOOL _fEaten;
|
|
BOOL _dwFlags;
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _AsyncKeyHandler
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CThreadInputMgr::_AsyncKeyHandler(WPARAM wParam, LPARAM lParam, DWORD dwFlags, BOOL *pfEaten)
|
|
{
|
|
CAsyncProcessKeyQueueItem *pAsyncProcessKeyQueueItem;
|
|
BOOL bRet;
|
|
HRESULT hr;
|
|
|
|
if (!_pFocusDocInputMgr)
|
|
return FALSE;
|
|
|
|
if (_pFocusDocInputMgr->_GetCurrentStack() < 0)
|
|
return FALSE;
|
|
|
|
//
|
|
// Issue:
|
|
//
|
|
// We don't know which IC in the focus DIM will handle the hotkey yet.
|
|
// because the selection is changed by the application so we need to get ec
|
|
// to update the current selection pos. We do call GetSelection
|
|
// inside the root IC's lock. So it might be failed if hotkey's target
|
|
// is TOP IC.
|
|
//
|
|
CInputContext *pic = _pFocusDocInputMgr->_GetIC(0);
|
|
|
|
pAsyncProcessKeyQueueItem = new CAsyncProcessKeyQueueItem(wParam, lParam, dwFlags, pfEaten);
|
|
if (!pAsyncProcessKeyQueueItem)
|
|
return FALSE;
|
|
|
|
hr = S_OK;
|
|
|
|
bRet = TRUE;
|
|
if ((pic->_QueueItem(pAsyncProcessKeyQueueItem->GetItem(), FALSE, &hr) != S_OK) || FAILED(hr))
|
|
{
|
|
Assert(0);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
pAsyncProcessKeyQueueItem->_Release();
|
|
return bRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AdviseSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::AdviseKeyEventSink(TfClientId tid, ITfKeyEventSink *pSink, BOOL fForeground)
|
|
{
|
|
CTip *ctip;
|
|
|
|
if (!_GetCTipfromGUIDATOM(tid, &ctip))
|
|
return E_INVALIDARG;
|
|
|
|
if (ctip->_pKeyEventSink != NULL)
|
|
return CONNECT_E_ADVISELIMIT;
|
|
|
|
ctip->_pKeyEventSink = pSink;
|
|
ctip->_pKeyEventSink->AddRef();
|
|
ctip->_fForegroundKeyEventSink = fForeground;
|
|
|
|
//
|
|
// overwrite the foreground tip.
|
|
//
|
|
if (fForeground)
|
|
_SetForeground(tid);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UnadviseSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::UnadviseKeyEventSink(TfClientId tid)
|
|
{
|
|
CTip *ctip;
|
|
|
|
if (!_GetCTipfromGUIDATOM(tid, &ctip))
|
|
return E_INVALIDARG;
|
|
|
|
if (ctip->_pKeyEventSink == NULL)
|
|
return CONNECT_E_NOCONNECTION;
|
|
|
|
SafeReleaseClear(ctip->_pKeyEventSink);
|
|
|
|
if (_tidForeground == tid)
|
|
{
|
|
_SetForeground(TF_INVALID_GUIDATOM);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetForeground
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetForeground(CLSID *pclsid)
|
|
{
|
|
if (!pclsid)
|
|
return E_INVALIDARG;
|
|
|
|
*pclsid = GUID_NULL;
|
|
|
|
if (_tidForeground == TF_INVALID_GUIDATOM)
|
|
return S_FALSE;
|
|
|
|
return MyGetGUID(_tidForeground, pclsid);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetForeground
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_SetForeground(TfClientId tid)
|
|
{
|
|
HRESULT hr;
|
|
CTip *ctip;
|
|
CTip *ctipForeground;
|
|
|
|
ctip = NULL;
|
|
|
|
if (tid != TF_INVALID_GUIDATOM)
|
|
{
|
|
_GetCTipfromGUIDATOM(tid, &ctip);
|
|
}
|
|
|
|
if (ctip)
|
|
{
|
|
if (ctip->_pKeyEventSink == NULL || !ctip->_fForegroundKeyEventSink)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
if (_tidForeground != TF_INVALID_GUIDATOM)
|
|
{
|
|
if (_tidForeground == tid)
|
|
goto Exit;
|
|
|
|
_GetCTipfromGUIDATOM(_tidForeground, &ctipForeground);
|
|
Assert(ctipForeground != NULL);
|
|
|
|
if (ctipForeground->_pKeyEventSink != NULL) // might be NULL if we got here from ITfKeyEventMgr::Unadvise
|
|
{
|
|
ctipForeground->_pKeyEventSink->OnSetFocus(FALSE);
|
|
}
|
|
|
|
_tidForeground = 0;
|
|
}
|
|
|
|
if (ctip != NULL)
|
|
{
|
|
if (ctip->_pKeyEventSink == NULL || !ctip->_fForegroundKeyEventSink)
|
|
{
|
|
// highly unlikely, but the tip Unadvise'd when we called OnSetFocus(FALSE) on the old foreground tip
|
|
hr = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
_tidForeground = tid;
|
|
|
|
ctip->_pKeyEventSink->OnSetFocus(TRUE);
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TestKeyDown
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::TestKeyDown(WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Perf_StartStroke(PERF_STROKE_TESTDOWN);
|
|
|
|
hr = _KeyStroke(KS_DOWN_TEST, wParam, lParam, pfEaten, TRUE, 0);
|
|
|
|
Perf_EndStroke(PERF_STROKE_TESTDOWN);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// KeyDown
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::KeyDown(WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Perf_IncCounter(PERF_KEYDOWN_COUNT);
|
|
Perf_StartStroke(PERF_STROKE_DOWN);
|
|
|
|
hr = _KeyStroke(KS_DOWN, wParam, lParam, pfEaten, TRUE, 0);
|
|
|
|
Perf_EndStroke(PERF_STROKE_DOWN);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TestKeyUp
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::TestKeyUp(WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Perf_StartStroke(PERF_STROKE_TESTUP);
|
|
|
|
hr = _KeyStroke(KS_UP_TEST, wParam, lParam, pfEaten, TRUE, 0);
|
|
|
|
Perf_EndStroke(PERF_STROKE_TESTUP);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// KeyUp
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::KeyUp(WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Perf_StartStroke(PERF_STROKE_UP);
|
|
|
|
hr = _KeyStroke(KS_UP, wParam, lParam, pfEaten, TRUE, 0);
|
|
|
|
Perf_EndStroke(PERF_STROKE_UP);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// KeyDownUpEx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::KeyDownUpEx(WPARAM wParam, LPARAM lParam, DWORD dwFlags, BOOL *pfEaten)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (HIWORD(lParam) & KF_UP)
|
|
{
|
|
if (dwFlags & TF_KEY_TEST)
|
|
{
|
|
Perf_StartStroke(PERF_STROKE_TESTUP);
|
|
hr = _KeyStroke(KS_UP_TEST, wParam, lParam, pfEaten, TRUE, dwFlags);
|
|
Perf_EndStroke(PERF_STROKE_TESTUP);
|
|
}
|
|
else
|
|
{
|
|
Perf_StartStroke(PERF_STROKE_UP);
|
|
hr = _KeyStroke(KS_UP, wParam, lParam, pfEaten, TRUE, dwFlags);
|
|
Perf_EndStroke(PERF_STROKE_UP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dwFlags & TF_KEY_TEST)
|
|
{
|
|
Perf_StartStroke(PERF_STROKE_TESTDOWN);
|
|
hr = _KeyStroke(KS_DOWN_TEST, wParam, lParam, pfEaten, TRUE, dwFlags);
|
|
Perf_EndStroke(PERF_STROKE_TESTDOWN);
|
|
}
|
|
else
|
|
{
|
|
Perf_IncCounter(PERF_KEYDOWN_COUNT);
|
|
Perf_StartStroke(PERF_STROKE_DOWN);
|
|
hr = _KeyStroke(KS_DOWN, wParam, lParam, pfEaten, TRUE, dwFlags);
|
|
Perf_EndStroke(PERF_STROKE_DOWN);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// KeyStroke
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_KeyStroke(KSEnum ksenum, WPARAM wParam, LPARAM lParam, BOOL *pfEaten, BOOL fSync, DWORD dwFlags)
|
|
{
|
|
CInputContext *pic;
|
|
int iStack;
|
|
HRESULT hr;
|
|
ITfDocumentMgr *pdim;
|
|
int i;
|
|
|
|
if (pfEaten == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
hr = S_OK;
|
|
*pfEaten = FALSE;
|
|
|
|
if (_pFocusDocInputMgr == NULL) // no focus ic?
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
pdim = _GetFocusDocInputMgr();
|
|
|
|
if (!(dwFlags & TF_KEY_INTERNAL))
|
|
{
|
|
if (!(dwFlags & TF_KEY_MSCTFIME) && (pdim && _IsMsctfimeDim(pdim)))
|
|
{
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (_CheckPreservedKey(ksenum, wParam, lParam, fSync))
|
|
{
|
|
*pfEaten = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
iStack = _pFocusDocInputMgr->_GetCurrentStack();
|
|
|
|
if (iStack < 0)
|
|
goto Exit;
|
|
|
|
while (iStack >= 0)
|
|
{
|
|
pic = _pFocusDocInputMgr->_GetIC(iStack);
|
|
|
|
pic->_UpdateKeyEventFilter();
|
|
|
|
// try left/right side of the selection.
|
|
for (i=LEFT_FILTERTIP; i<=RIGHT_FILTERTIP; i++)
|
|
{
|
|
hr = _CallKeyEventSinkNotForeground(pic->_gaKeyEventFilterTIP[i],
|
|
pic, ksenum, wParam, lParam, pfEaten);
|
|
|
|
if (hr == S_OK && *pfEaten)
|
|
goto Exit;
|
|
|
|
// _CallKeyEventSinkNotForeground returns "error" codes on valid input
|
|
// this just means, keep going
|
|
hr = S_OK; // keep trying other sinks if there's an error
|
|
*pfEaten = FALSE;
|
|
|
|
if (_pFocusDocInputMgr->_GetCurrentStack() < iStack)
|
|
goto NextIC;
|
|
}
|
|
|
|
// try foreground tip.
|
|
if (_tidForeground != TF_INVALID_GUIDATOM)
|
|
{
|
|
hr = _CallKeyEventSink(_tidForeground,
|
|
pic, ksenum, wParam, lParam, pfEaten);
|
|
|
|
if (hr == S_OK && *pfEaten)
|
|
break;
|
|
|
|
hr = S_OK; // keep trying other sinks if there's an error
|
|
*pfEaten = FALSE;
|
|
|
|
if (_pFocusDocInputMgr == NULL)
|
|
{
|
|
// this can happen if the app is buggy and switches the focus
|
|
// inside a SetText or whatever call (perhaps to bring up an
|
|
// error dialog, etc.).
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if (_pFocusDocInputMgr->_GetCurrentStack() < iStack)
|
|
goto NextIC;
|
|
}
|
|
|
|
if (pic->_pICKbdSink)
|
|
{
|
|
switch (ksenum)
|
|
{
|
|
case KS_DOWN:
|
|
hr = pic->_pICKbdSink->OnKeyDown(wParam, lParam, pfEaten);
|
|
break;
|
|
case KS_UP:
|
|
hr = pic->_pICKbdSink->OnKeyUp(wParam, lParam, pfEaten);
|
|
break;
|
|
case KS_DOWN_TEST:
|
|
hr = pic->_pICKbdSink->OnTestKeyDown(wParam, lParam, pfEaten);
|
|
break;
|
|
case KS_UP_TEST:
|
|
hr = pic->_pICKbdSink->OnTestKeyUp(wParam, lParam, pfEaten);
|
|
break;
|
|
}
|
|
|
|
if (hr == S_OK && *pfEaten)
|
|
break;
|
|
|
|
hr = S_OK; // keep trying other sinks if there's an error
|
|
*pfEaten = FALSE;
|
|
}
|
|
|
|
NextIC:
|
|
iStack--;
|
|
if (_pFocusDocInputMgr->_GetCurrentStack() < iStack)
|
|
{
|
|
iStack = _pFocusDocInputMgr->_GetCurrentStack();
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CallKeyEventSinkNotForeground
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT CThreadInputMgr::_CallKeyEventSinkNotForeground(TfClientId tid, CInputContext *pic, KSEnum ksenum, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
CTip *ctip;
|
|
|
|
if (tid == _tidForeground)
|
|
return E_INVALIDARG;
|
|
|
|
if (!_GetCTipfromGUIDATOM(tid, &ctip))
|
|
return E_INVALIDARG;
|
|
|
|
if (ctip->_fForegroundKeyEventSink ||
|
|
ctip->_pKeyEventSink == NULL)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return _CallKeyEventSink(tid, pic, ksenum, wParam, lParam, pfEaten);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CallKeyEventSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
HRESULT CThreadInputMgr::_CallKeyEventSink(TfClientId tid, CInputContext *pic, KSEnum ksenum, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
ITfKeyEventSink *pSink;
|
|
CTip *ctip;
|
|
HRESULT hr;
|
|
|
|
if (!_GetCTipfromGUIDATOM(tid, &ctip))
|
|
return E_INVALIDARG;
|
|
|
|
if (!(pSink = ctip->_pKeyEventSink))
|
|
return S_FALSE;
|
|
|
|
switch (ksenum)
|
|
{
|
|
case KS_DOWN:
|
|
hr = pSink->OnKeyDown(pic, wParam, lParam, pfEaten);
|
|
break;
|
|
case KS_DOWN_TEST:
|
|
hr = pSink->OnTestKeyDown(pic, wParam, lParam, pfEaten);
|
|
break;
|
|
case KS_UP:
|
|
hr = pSink->OnKeyUp(pic, wParam, lParam, pfEaten);
|
|
break;
|
|
case KS_UP_TEST:
|
|
hr = pSink->OnTestKeyUp(pic, wParam, lParam, pfEaten);
|
|
break;
|
|
default:
|
|
Assert(0);
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CheckPreservedKey
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CThreadInputMgr::_CheckPreservedKey(KSEnum ksenum, WPARAM wParam, LPARAM lParam, BOOL fSync)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
switch (ksenum)
|
|
{
|
|
case KS_DOWN:
|
|
if (!(lParam & 0x80000000))
|
|
bRet = _ProcessHotKey(wParam, lParam, TSH_NONSYSHOTKEY, FALSE, fSync);
|
|
break;
|
|
case KS_DOWN_TEST:
|
|
if (!(lParam & 0x80000000))
|
|
bRet = _ProcessHotKey(wParam, lParam, TSH_NONSYSHOTKEY, TRUE, fSync);
|
|
break;
|
|
case KS_UP:
|
|
if (lParam & 0x80000000)
|
|
bRet = _ProcessHotKey(wParam, lParam, TSH_NONSYSHOTKEY, FALSE, fSync);
|
|
break;
|
|
case KS_UP_TEST:
|
|
if (lParam & 0x80000000)
|
|
bRet = _ProcessHotKey(wParam, lParam, TSH_NONSYSHOTKEY, TRUE, fSync);
|
|
break;
|
|
default:
|
|
Assert(0);
|
|
break;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _NotifyKeyTraceEventSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CThreadInputMgr::_NotifyKeyTraceEventSink(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CStructArray<GENERICSINK> *rgKeyTraceEventSinks;
|
|
int i;
|
|
|
|
rgKeyTraceEventSinks = _GetKeyTraceEventSinks();
|
|
|
|
for (i=0; i<rgKeyTraceEventSinks->Count(); i++)
|
|
{
|
|
if (lParam & 0x80000000)
|
|
((ITfKeyTraceEventSink *)rgKeyTraceEventSinks->GetPtr(i)->pSink)->OnKeyTraceUp(wParam, lParam);
|
|
else
|
|
((ITfKeyTraceEventSink *)rgKeyTraceEventSinks->GetPtr(i)->pSink)->OnKeyTraceDown(wParam, lParam);
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _IsMsctfimeDim
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CThreadInputMgr::_IsMsctfimeDim(ITfDocumentMgr *pdim)
|
|
{
|
|
// Get GUID_COMPARTMENT_CTFIME_DIMFLAGS from ..\msctfime\globals.cpp
|
|
const GUID GUID_COMPARTMENT_CTFIME_DIMFLAGS = {0xa94c5fd2, 0xc471, 0x4031, {0x95, 0x46, 0x70, 0x9c, 0x17, 0x30, 0x0c, 0xb9}};
|
|
|
|
HRESULT hr;
|
|
DWORD dwFlags;
|
|
|
|
hr = GetCompartmentDWORD(pdim, GUID_COMPARTMENT_CTFIME_DIMFLAGS,
|
|
&dwFlags, FALSE);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Check COMPDIMFLAG_OWNEDDIM(0x0001).
|
|
return (dwFlags & 0x0001) ? TRUE : FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|