Leaked source code of windows server 2003
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

//
// 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;
}