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