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.
288 lines
8.0 KiB
288 lines
8.0 KiB
//
|
|
// keys.cpp
|
|
//
|
|
// ITfKeyEventSink implementation.
|
|
//
|
|
|
|
#include "globals.h"
|
|
#include "case.h"
|
|
#include "editsess.h"
|
|
|
|
class CKeystrokeEditSession : public CEditSessionBase
|
|
{
|
|
public:
|
|
CKeystrokeEditSession(ITfContext *pContext, WPARAM wParam) : CEditSessionBase(pContext)
|
|
{
|
|
_wParam = wParam;
|
|
}
|
|
|
|
// ITfEditSession
|
|
STDMETHODIMP DoEditSession(TfEditCookie ec);
|
|
|
|
private:
|
|
WPARAM _wParam;
|
|
};
|
|
|
|
|
|
/* 5d6d1b1e-64f2-47cd-9fe1-4e032c2dae77 */
|
|
static const GUID GUID_PRESERVEDKEY_FLIPCASE = { 0x5d6d1b1e, 0x64f2, 0x47cd, {0x9f, 0xe1, 0x4e, 0x03, 0x2c, 0x2d, 0xae, 0x77} };
|
|
// arbitrary hotkey: ctl-f
|
|
static const TF_PRESERVEDKEY c_FlipCaseKey = { 'F', TF_MOD_CONTROL };
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsKeyEaten
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
inline BOOL IsKeyEaten(BOOL fFlipKeys, WPARAM wParam)
|
|
{
|
|
// we're only interested in VK_A - VK_Z, when the "Flip Keys" menu option
|
|
// is on
|
|
return fFlipKeys && (wParam >= 'A') && (wParam <= 'Z');
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _Menu_FlipKeys
|
|
//
|
|
// Advise or unadvise a keystroke sink.
|
|
//----------------------------------------------------------------------------
|
|
|
|
/* static */
|
|
void CCaseTextService::_Menu_FlipKeys(CCaseTextService *_this)
|
|
{
|
|
_this->_fFlipKeys = !_this->_fFlipKeys;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _InitKeystrokeSink
|
|
//
|
|
// Advise a keystroke sink.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCaseTextService::_InitKeystrokeSink()
|
|
{
|
|
ITfKeystrokeMgr *pKeystrokeMgr;
|
|
HRESULT hr;
|
|
|
|
if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK)
|
|
return FALSE;
|
|
|
|
hr = pKeystrokeMgr->AdviseKeyEventSink(_tfClientId, (ITfKeyEventSink *)this, TRUE);
|
|
|
|
pKeystrokeMgr->Release();
|
|
|
|
return (hr == S_OK);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _UninitKeystrokeSink
|
|
//
|
|
// Unadvise a keystroke sink. Assumes we have advised one already.
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCaseTextService::_UninitKeystrokeSink()
|
|
{
|
|
ITfKeystrokeMgr *pKeystrokeMgr;
|
|
|
|
if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK)
|
|
return;
|
|
|
|
pKeystrokeMgr->UnadviseKeyEventSink(_tfClientId);
|
|
|
|
pKeystrokeMgr->Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _InitPreservedKey
|
|
//
|
|
// Register a hot key.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCaseTextService::_InitPreservedKey()
|
|
{
|
|
ITfKeystrokeMgr *pKeystrokeMgr;
|
|
HRESULT hr;
|
|
|
|
if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK)
|
|
return FALSE;
|
|
|
|
hr = pKeystrokeMgr->PreserveKey(_tfClientId, GUID_PRESERVEDKEY_FLIPCASE,
|
|
&c_FlipCaseKey, L"Toggle Case",
|
|
wcslen(L"Toggle Case"));
|
|
|
|
pKeystrokeMgr->Release();
|
|
|
|
return (hr == S_OK);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _UninitPreservedKey
|
|
//
|
|
// Uninit a hot key.
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCaseTextService::_UninitPreservedKey()
|
|
{
|
|
ITfKeystrokeMgr *pKeystrokeMgr;
|
|
|
|
if (_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr, (void **)&pKeystrokeMgr) != S_OK)
|
|
return;
|
|
|
|
pKeystrokeMgr->UnpreserveKey(GUID_PRESERVEDKEY_FLIPCASE, &c_FlipCaseKey);
|
|
|
|
pKeystrokeMgr->Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnSetFocus
|
|
//
|
|
// Called by the system whenever this service gets the keystroke device focus.
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CCaseTextService::OnSetFocus(BOOL fForeground)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnTestKeyDown
|
|
//
|
|
// Called by the system to query this service wants a potential keystroke.
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CCaseTextService::OnTestKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
*pfEaten = IsKeyEaten(_fFlipKeys, wParam);
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnKeyDown
|
|
//
|
|
// Called by the system to offer this service a keystroke. If *pfEaten == TRUE
|
|
// on exit, the application will not handle the keystroke.
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CCaseTextService::OnKeyDown(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
CKeystrokeEditSession *pEditSession;
|
|
HRESULT hr = S_OK;
|
|
|
|
*pfEaten = IsKeyEaten(_fFlipKeys, wParam);
|
|
|
|
if (*pfEaten)
|
|
{
|
|
// we'll insert a char ourselves in place of this keystroke
|
|
if ((pEditSession = new CKeystrokeEditSession(pContext, wParam)) == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
// we need a lock to do our work
|
|
// nb: this method is one of the few places where it is legal to use
|
|
// the TF_ES_SYNC flag
|
|
if (pContext->RequestEditSession(_tfClientId, pEditSession, TF_ES_SYNC | TF_ES_READWRITE, &hr) != S_OK)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
pEditSession->Release();
|
|
}
|
|
|
|
Exit:
|
|
if (hr != S_OK)
|
|
{
|
|
*pfEaten = FALSE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// DoEditSession
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CKeystrokeEditSession::DoEditSession(TfEditCookie ec)
|
|
{
|
|
WCHAR wc;
|
|
|
|
// we want to toggle the english case of the keystroke
|
|
// nb: this is quick-and-dirty code, not intended to demonstrate the
|
|
// correct way to flip capitalization!
|
|
|
|
if (GetKeyState(VK_SHIFT) & 0x8000)
|
|
{
|
|
// shift-key, make it lowercase
|
|
wc = (WCHAR)(_wParam | 32);
|
|
}
|
|
else
|
|
{
|
|
// else make it capital
|
|
wc = (WCHAR)_wParam;
|
|
}
|
|
|
|
InsertTextAtSelection(ec, _pContext, &wc, 1);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnTestKeyUp
|
|
//
|
|
// Called by the system to query this service wants a potential keystroke.
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CCaseTextService::OnTestKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
*pfEaten = IsKeyEaten(_fFlipKeys, wParam);
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnKeyUp
|
|
//
|
|
// Called by the system to offer this service a keystroke. If *pfEaten == TRUE
|
|
// on exit, the application will not handle the keystroke.
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CCaseTextService::OnKeyUp(ITfContext *pContext, WPARAM wParam, LPARAM lParam, BOOL *pfEaten)
|
|
{
|
|
*pfEaten = IsKeyEaten(_fFlipKeys, wParam);
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// OnPreservedKey
|
|
//
|
|
// Called when a hotkey (registered by us, or by the system) is typed.
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CCaseTextService::OnPreservedKey(ITfContext *pContext, REFGUID rguid, BOOL *pfEaten)
|
|
{
|
|
if (IsEqualGUID(rguid, GUID_PRESERVEDKEY_FLIPCASE))
|
|
{
|
|
_Menu_FlipDoc(this);
|
|
*pfEaten = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pfEaten = FALSE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|