mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-15 13:19:23 +00:00
Fixes #4965. When speech recognition is enabled, it sometimes activates after a Keyman keyboard is selected. This would cause Keyman to think it is being deactivated. We needed to check in `CKMTipTextService::OnActivated` that it was a keyboard-type TIP that was being activated, and only deactivate the Keyman hooks in that situation. This commit also adds a little logging helper function, and removes an unused variable `guidActiveProfile`.
293 lines
7.3 KiB
C++
293 lines
7.3 KiB
C++
/*
|
|
Name: kmtip
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 7 Sep 2009
|
|
|
|
Modified Date: 28 Mar 2016
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 07 Sep 2009 - mcdurdin - I2095 - TSF addin is not threadsafe
|
|
20 Nov 2012 - mcdurdin - I3582 - V9.0 - Remove language bar integration
|
|
20 Nov 2012 - mcdurdin - I3581 - V9.0 - KMTip needs to pass activated profile guid through to Keyman32 to switch keyboards
|
|
28 Nov 2012 - mcdurdin - I3590 - V9.0 - Initialise keystroke sink after we know which keyboard to activate
|
|
28 Nov 2012 - mcdurdin - I3588 - V9.0 - Use preserved keys in TSF to handle key combinations in Keyman
|
|
01 Jan 2013 - mcdurdin - I3714 - V9.0 - Applications hang when switching kmtip off if Keyman not running
|
|
01 May 2014 - mcdurdin - I4216 - V9.0 - Keyman TIP should use ITfTextInputProcessorEx
|
|
28 May 2014 - mcdurdin - I3706 - V9.0 - If kmtip CKMTipTextService::Activate fails, should we release pThreadMgr?
|
|
16 Jun 2014 - mcdurdin - I4274 - V9.0 - kmtip does not work if already active before KM starts
|
|
*/
|
|
//
|
|
// kmtip.cpp
|
|
//
|
|
// IUnknown, ITfTextInputProcessor implementation.
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "kmtip.h"
|
|
#include "registryw.h"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CreateInstance
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
/* static */
|
|
HRESULT CKMTipTextService::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
|
|
{
|
|
CKMTipTextService *pKMTip;
|
|
HRESULT hr;
|
|
|
|
if (ppvObj == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (NULL != pUnkOuter)
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
if ((pKMTip = new CKMTipTextService) == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
hr = pKMTip->QueryInterface(riid, ppvObj);
|
|
|
|
pKMTip->Release(); // caller still holds ref if hr == S_OK
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
__declspec(thread) CKMTipTextService *CKMTipTextService::ThreadThis;
|
|
|
|
CKMTipTextService::CKMTipTextService()
|
|
{
|
|
DllAddRef();
|
|
|
|
_pThreadMgr = NULL;
|
|
_tfClientId = TF_CLIENTID_NULL;
|
|
// I3582
|
|
_dwThreadMgrEventSinkCookie = TF_INVALID_COOKIE;
|
|
|
|
_keystrokeSinkInitialized = FALSE;
|
|
_dwActiveLanguageProfileNotifySinkCookie = 0;
|
|
_PreservedKeys = NULL;
|
|
_cPreservedKeyCount = 0;
|
|
_dwDeepIntegration = 0;
|
|
|
|
RegistryReadOnlyW reg(HKEY_CURRENT_USER);
|
|
_tryAndStartKeyman = reg.OpenKeyReadOnly(REGSZ_KeymanEngineDebug_CU) && reg.ValueExists(REGSZ_Flag_UseAutoStartTask) && reg.ReadInteger(REGSZ_Flag_UseAutoStartTask) != 0;
|
|
|
|
_cRef = 1;
|
|
ThreadThis = this;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CKMTipTextService::~CKMTipTextService()
|
|
{
|
|
ThreadThis = NULL;
|
|
DllRelease();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// QueryInterface
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CKMTipTextService::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
if (ppvObj == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_ITfTextInputProcessor))
|
|
{
|
|
*ppvObj = (ITfTextInputProcessor *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfThreadMgrEventSink))
|
|
{
|
|
*ppvObj = (ITfThreadMgrEventSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfActiveLanguageProfileNotifySink)) // I3581
|
|
{
|
|
*ppvObj = (ITfActiveLanguageProfileNotifySink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfThreadFocusSink))
|
|
{
|
|
*ppvObj = (ITfThreadFocusSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfTextEditSink))
|
|
{
|
|
*ppvObj = (ITfTextEditSink *)this;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfKeyEventSink))
|
|
{
|
|
*ppvObj = (ITfKeyEventSink *)this;
|
|
}
|
|
|
|
if (*ppvObj)
|
|
{
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AddRef
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI_(ULONG) CKMTipTextService::AddRef()
|
|
{
|
|
return ++_cRef;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Release
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI_(ULONG) CKMTipTextService::Release()
|
|
{
|
|
LONG cr = --_cRef;
|
|
|
|
assert(_cRef >= 0);
|
|
|
|
if (_cRef == 0)
|
|
{
|
|
Log(L"CKMTipTextService::Release --> deleting");
|
|
delete this;
|
|
}
|
|
|
|
return cr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Activate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CKMTipTextService::ActivateEx(ITfThreadMgr *ptim, TfClientId tid, DWORD dwFlags) { // I4216
|
|
LogEnter();
|
|
ITfDocumentMgr *pFocusDoc;
|
|
|
|
_cPreservedKeyCount = 0; // I3588 // I3714
|
|
_PreservedKeys = NULL; // I3588 // I3714
|
|
|
|
_pThreadMgr = ptim;
|
|
_pThreadMgr->AddRef();
|
|
|
|
_tfClientId = tid;
|
|
|
|
if(!_InitThreadMgrSink()) {
|
|
Log(L"Could not initialise thread manager sink");
|
|
goto ExitError;
|
|
}
|
|
|
|
if(!_InitKeyman()) {
|
|
Log(L"Could not initialise Keyman");
|
|
goto ExitError;
|
|
}
|
|
|
|
// start tracking the focus doc
|
|
if(_pThreadMgr->GetFocus(&pFocusDoc) == S_OK) {
|
|
// The system will call OnSetFocus only for focus events after Activate
|
|
// is called.
|
|
OnSetFocus(pFocusDoc, NULL);
|
|
pFocusDoc->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
ExitError:
|
|
Deactivate(); // cleanup any half-finished init // I3706
|
|
return E_FAIL;
|
|
}
|
|
|
|
STDAPI CKMTipTextService::Activate(ITfThreadMgr *pThreadMgr, TfClientId tfClientId)
|
|
{
|
|
LogEnter();
|
|
ITfDocumentMgr *pFocusDoc;
|
|
|
|
_cPreservedKeyCount = 0; // I3588 // I3714
|
|
_PreservedKeys = NULL; // I3588 // I3714
|
|
|
|
_pThreadMgr = pThreadMgr;
|
|
_pThreadMgr->AddRef();
|
|
|
|
_tfClientId = tfClientId;
|
|
|
|
if (!_InitThreadMgrSink())
|
|
{
|
|
Log(L"Could not initialise thread manager sink");
|
|
goto ExitError;
|
|
}
|
|
|
|
if(!_InitKeyman()) {
|
|
_TryAndStartKeyman();
|
|
Log(L"Could not initialise Keyman");
|
|
//goto ExitError;
|
|
}
|
|
|
|
// start tracking the focus doc
|
|
if (_pThreadMgr->GetFocus(&pFocusDoc) == S_OK)
|
|
{
|
|
// The system will call OnSetFocus only for focus events after Activate
|
|
// is called.
|
|
OnSetFocus(pFocusDoc, NULL);
|
|
pFocusDoc->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
ExitError:
|
|
Deactivate(); // cleanup any half-finished init // I3706
|
|
return E_FAIL;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Deactivate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CKMTipTextService::Deactivate()
|
|
{
|
|
LogEnter();
|
|
|
|
_UninitThreadMgrSink();
|
|
_UninitKeystrokeSink();
|
|
_UninitKeyman();
|
|
|
|
// we MUST release all refs to _pThreadMgr in Deactivate
|
|
SafeReleaseClear(_pThreadMgr);
|
|
|
|
_tfClientId = TF_CLIENTID_NULL;
|
|
|
|
return S_OK;
|
|
}
|