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.
2210 lines
54 KiB
2210 lines
54 KiB
//
|
|
// tim.cpp
|
|
//
|
|
|
|
#include "private.h"
|
|
#include "lmcons.h" // for UNLEN
|
|
#include "tim.h"
|
|
#include "dim.h"
|
|
#include "range.h"
|
|
#include "imelist.h"
|
|
#include "nuimgr.h"
|
|
#include "assembly.h"
|
|
#include "acp2anch.h"
|
|
#include "sink.h"
|
|
#include "ic.h"
|
|
#include "funcprv.h"
|
|
#include "enumfnpr.h"
|
|
#include "enumdim.h"
|
|
#include "profiles.h"
|
|
#include "marshal.h"
|
|
#include "timlist.h"
|
|
#include "nuihkl.h"
|
|
#include "immxutil.h"
|
|
#include "dam.h"
|
|
#include "hotkey.h"
|
|
#include "sddl.h"
|
|
|
|
extern void UninitBackgroundThread(); // bthread.cpp
|
|
extern "C" HRESULT WINAPI TF_GetGlobalCompartment(ITfCompartmentMgr **ppCompMgr);
|
|
|
|
const IID *CThreadInputMgr::_c_rgConnectionIIDs[TIM_NUM_CONNECTIONPTS] =
|
|
{
|
|
&IID_ITfDisplayAttributeNotifySink,
|
|
&IID_ITfActiveLanguageProfileNotifySink,
|
|
&IID_ITfThreadFocusSink,
|
|
&IID_ITfPreservedKeyNotifySink,
|
|
&IID_ITfThreadMgrEventSink,
|
|
&IID_ITfKeyTraceEventSink,
|
|
};
|
|
|
|
BOOL OnForegroundChanged(HWND hwndFocus);
|
|
|
|
DBG_ID_INSTANCE(CEnumDocumentInputMgrs);
|
|
|
|
#ifndef _WIN64
|
|
static const TCHAR c_szCicLoadMutex[] = TEXT("CtfmonInstMutex");
|
|
#else
|
|
static const TCHAR c_szCicLoadMutex[] = TEXT("CtfmonInstMutex.IA64");
|
|
#endif
|
|
|
|
static BOOL s_fOnlyTranslationRunning = FALSE;
|
|
|
|
TCHAR g_szUserUnique[MAX_PATH];
|
|
TCHAR g_szUserSidString[MAX_PATH];
|
|
BOOL g_fUserSidString = FALSE;
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitUniqueString
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
char *GetUserSIDString()
|
|
{
|
|
HANDLE hToken = NULL;
|
|
char *pszStringSid = NULL;
|
|
|
|
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
|
|
|
|
if (hToken)
|
|
{
|
|
DWORD dwReturnLength = 0;
|
|
void *pvUserBuffer = NULL;
|
|
|
|
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwReturnLength);
|
|
|
|
pvUserBuffer = cicMemAllocClear(dwReturnLength);
|
|
if (pvUserBuffer &&
|
|
GetTokenInformation(hToken,
|
|
TokenUser,
|
|
pvUserBuffer,
|
|
dwReturnLength,
|
|
&dwReturnLength))
|
|
{
|
|
if (!ConvertSidToStringSid(((TOKEN_USER*)(pvUserBuffer))->User.Sid,
|
|
&pszStringSid))
|
|
{
|
|
if (pszStringSid)
|
|
LocalFree(pszStringSid);
|
|
|
|
pszStringSid = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if (pvUserBuffer)
|
|
{
|
|
cicMemFree(pvUserBuffer);
|
|
}
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return pszStringSid;
|
|
}
|
|
|
|
BOOL InitUserSidString()
|
|
{
|
|
if (g_fUserSidString)
|
|
return TRUE;
|
|
|
|
char *pStringSid = GetUserSIDString();
|
|
if (pStringSid)
|
|
{
|
|
StringCchCopy(g_szUserSidString, ARRAYSIZE(g_szUserSidString), pStringSid);
|
|
g_fUserSidString = TRUE;
|
|
LocalFree(pStringSid);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitUniqueString
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL InitUniqueString()
|
|
{
|
|
TCHAR ach[MAX_PATH];
|
|
DWORD dwLength;
|
|
HDESK hdesk;
|
|
|
|
g_szUserUnique[0] = TEXT('\0');
|
|
|
|
hdesk = GetThreadDesktop(GetCurrentThreadId());
|
|
|
|
if (hdesk &&
|
|
GetUserObjectInformation(hdesk, UOI_NAME, ach, sizeof(ach) /* byte count */, &dwLength))
|
|
{
|
|
StringCchCat(g_szUserUnique, ARRAYSIZE(g_szUserUnique), ach);
|
|
}
|
|
|
|
DWORD dwLen = ARRAYSIZE(ach);
|
|
if (InitUserSidString())
|
|
{
|
|
StringCchCat(g_szUserUnique, ARRAYSIZE(g_szUserUnique), g_szUserSidString);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetDesktopUniqueName
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void GetDesktopUniqueName(const TCHAR *pszPrefix, TCHAR *pch, ULONG cchPch)
|
|
{
|
|
StringCchCopy(pch, cchPch, pszPrefix);
|
|
StringCchCat(pch, cchPch, g_szUserUnique);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TF_IsCtfmonRunning
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
extern "C" BOOL WINAPI TF_IsCtfmonRunning()
|
|
{
|
|
TCHAR ach[MAX_PATH];
|
|
HANDLE hInstanceMutex;
|
|
|
|
//
|
|
// get mutex name.
|
|
//
|
|
GetDesktopUniqueName(c_szCicLoadMutex, ach, ARRAYSIZE(ach));
|
|
|
|
|
|
hInstanceMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, ach);
|
|
|
|
if (hInstanceMutex != NULL)
|
|
{
|
|
// ctfmon.exe is already running, don't do any more work
|
|
CloseHandle(hInstanceMutex);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ExecuteLoader
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
const char c_szCtfmonExe[] = "ctfmon.exe";
|
|
const char c_szCtfmonExeN[] = "ctfmon.exe -n";
|
|
|
|
void ExecuteLoader(void)
|
|
{
|
|
if (TF_IsCtfmonRunning())
|
|
return;
|
|
|
|
FullPathExec(c_szCtfmonExe,
|
|
s_fOnlyTranslationRunning ? c_szCtfmonExeN : c_szCtfmonExe,
|
|
SW_SHOWMINNOACTIVE,
|
|
FALSE);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// TF_CreateCicLoadMutex
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
extern "C" HANDLE WINAPI TF_CreateCicLoadMutex(BOOL *pfWinLogon)
|
|
{
|
|
*pfWinLogon = FALSE;
|
|
|
|
if (IsOnNT())
|
|
{
|
|
//
|
|
// This checking is for logged on user or not. So we can blcok running
|
|
// ctfmon.exe process from non-authorized user.
|
|
//
|
|
if (!IsInteractiveUserLogon())
|
|
{
|
|
g_SharedMemory.Close();
|
|
#ifdef WINLOGON_LANGBAR
|
|
g_SharedMemory.Start();
|
|
#else
|
|
return NULL;
|
|
#endif WINLOGON_LANGBAR
|
|
}
|
|
}
|
|
|
|
HANDLE hmutex;
|
|
TCHAR ach[MAX_PATH];
|
|
|
|
//
|
|
// get mutex name after calling SetThreadDesktop.
|
|
//
|
|
GetDesktopUniqueName(c_szCicLoadMutex, ach, ARRAYSIZE(ach));
|
|
|
|
#ifdef __DEBUG
|
|
{
|
|
char szBuf[MAX_PATH];
|
|
wsprintf(szBuf, "TF_CreateCicLoadMutex in %s\r\n", ach);
|
|
OutputDebugString(szBuf);
|
|
}
|
|
#endif
|
|
|
|
CCicSecAttr sa;
|
|
hmutex = CreateMutex(sa, FALSE, ach);
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
//
|
|
// another cicload process is already running
|
|
//
|
|
CloseHandle(hmutex);
|
|
hmutex = NULL;
|
|
}
|
|
|
|
return hmutex;
|
|
}
|
|
|
|
DBG_ID_INSTANCE(CThreadInputMgr);
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CThreadInputMgr::CThreadInputMgr()
|
|
:CCompartmentMgr(g_gaApp, COMPTYPE_TIM)
|
|
{
|
|
Dbg_MemSetThisNameID(TEXT("CThreadInputMgr"));
|
|
|
|
Assert(_GetThis() == NULL);
|
|
_SetThis(this); // save a pointer to this in TLS
|
|
|
|
_fAddedProcessAtom = FALSE;
|
|
_SetProcessAtom();
|
|
|
|
Assert(_fActiveView == FALSE);
|
|
Assert(_pSysHookSink == NULL);
|
|
Assert(_fFirstSetFocusAfterActivated == FALSE);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CThreadInputMgr::~CThreadInputMgr()
|
|
{
|
|
ATOM atom;
|
|
|
|
Assert(_tidForeground == TF_INVALID_GUIDATOM);
|
|
Assert(_tidPrevForeground == TF_INVALID_GUIDATOM);
|
|
|
|
Assert(_rgTip.Count() == 0);
|
|
|
|
Assert(_pPendingCleanupContext == NULL);
|
|
Assert(_pSysHookSink == NULL);
|
|
|
|
SafeReleaseClear(_pSysFuncPrv);
|
|
SafeReleaseClear(_pAppFuncProvider);
|
|
|
|
// remove ref to this in TLS
|
|
_SetThis(NULL);
|
|
|
|
// Release the per-process atom
|
|
if (_fAddedProcessAtom &&
|
|
(atom = FindAtom(TF_PROCESS_ATOM)))
|
|
{
|
|
DeleteAtom(atom);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CreateInstance
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
/* static */
|
|
BOOL CThreadInputMgr::VerifyCreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
|
|
{
|
|
// Look up disabling Text Services status from the registry.
|
|
// If it is disabled, return fail not to support Text Services.
|
|
if (IsDisabledTextServices())
|
|
return FALSE;
|
|
|
|
if (NoTipsInstalled(&s_fOnlyTranslationRunning))
|
|
return FALSE;
|
|
|
|
//
|
|
// Check up the interactive user logon
|
|
//
|
|
if (!IsInteractiveUserLogon())
|
|
return FALSE;
|
|
|
|
//
|
|
// #609356
|
|
//
|
|
// we don't want to start Cicero on SMSCliToknAcct& account.
|
|
//
|
|
char szUserName[UNLEN + 1];
|
|
DWORD dwUserNameLen = UNLEN;
|
|
if (GetUserName(szUserName, &dwUserNameLen) && dwUserNameLen)
|
|
{
|
|
if (!lstrcmp(szUserName, "SMSCliToknAcct&"))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetProcessAtom
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CThreadInputMgr::_SetProcessAtom()
|
|
{
|
|
if (_fAddedProcessAtom)
|
|
return;
|
|
|
|
// AddRef the per-process atom
|
|
if (FindAtom(TF_ENABLE_PROCESS_ATOM))
|
|
{
|
|
AddAtom(TF_PROCESS_ATOM);
|
|
_fAddedProcessAtom = TRUE;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _StaticInit_OnActivate
|
|
//
|
|
// Init all our process global members. Called from Activate.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CThreadInputMgr::_StaticInit_OnActivate()
|
|
{
|
|
|
|
CicEnterCriticalSection(g_cs);
|
|
|
|
// register two special guid atoms
|
|
MyRegisterGUID(GUID_APPLICATION, &g_gaApp);
|
|
MyRegisterGUID(GUID_SYSTEM, &g_gaSystem);
|
|
|
|
CicLeaveCriticalSection(g_cs);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Activate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::Activate(TfClientId *ptid)
|
|
{
|
|
return ActivateEx(ptid, 0);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ActivateEx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::ActivateEx(TfClientId *ptid, DWORD dwFlags)
|
|
{
|
|
CDisplayAttributeMgr *pDisplayAttrMgr;
|
|
CAssemblyList *pAsmList = NULL;
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
|
|
if (ptid == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ptid = TF_INVALID_GUIDATOM;
|
|
|
|
if (_fInDeactivate)
|
|
{
|
|
Assert(0); // woah, we're inside Deactivate higher up the stack...
|
|
return E_UNEXPECTED;
|
|
}
|
|
_fInActivate = TRUE;
|
|
|
|
//
|
|
// Windows #476099
|
|
//
|
|
// Under CUAS, TIM could be created before Word set TF_ENABLE_PROCESS_ATIM,
|
|
// so we need to check the atom whenever Activate() is called.
|
|
//
|
|
_SetProcessAtom();
|
|
|
|
if (_iActivateRefCount++ > 0)
|
|
goto Exit;
|
|
|
|
Assert(_iActivateRefCount == 1);
|
|
|
|
ExecuteLoader();
|
|
|
|
CtfImmSetCiceroStartInThread(TRUE);
|
|
|
|
if (EnsureTIMList(psfn))
|
|
g_timlist.SetFlags(psfn->dwThreadId, TLF_TIMACTIVE | TLF_GCOMPACTIVE);
|
|
|
|
// g_gcomplist.Init();
|
|
|
|
_StaticInit_OnActivate();
|
|
|
|
// dink with active accessibility
|
|
if (GetSharedMemory()->cMSAARef >= 0) // don't worry about mutex since this is just for perf
|
|
{
|
|
_InitMSAA();
|
|
}
|
|
|
|
// make sure lbaritems are updated
|
|
TF_CreateLangBarItemMgr(&_plbim);
|
|
|
|
//
|
|
// we call _Init here to make sure Reconversion and DeviceType items
|
|
// are added. LangBarItemMgr could be created before TIM is created.
|
|
// Then the LangBarItemMgr does not have Reconversion or DeviceTye items.
|
|
//
|
|
if (psfn && psfn->plbim)
|
|
psfn->plbim->_Init();
|
|
|
|
if (psfn)
|
|
{
|
|
//
|
|
// perf: need to find a way to delay allocation.
|
|
//
|
|
pAsmList = EnsureAssemblyList(psfn);
|
|
}
|
|
|
|
//
|
|
// warm up the tips
|
|
//
|
|
|
|
if (!pAsmList || !pAsmList->Count())
|
|
goto Exit;
|
|
|
|
// keep a ref on the display attr mgr while tips are activated
|
|
Assert(_fReleaseDisplayAttrMgr == FALSE);
|
|
if (CDisplayAttributeMgr::CreateInstance(NULL, IID_CDisplayAttributeMgr, (void **)&pDisplayAttrMgr) == S_OK)
|
|
{
|
|
_fReleaseDisplayAttrMgr = TRUE;
|
|
}
|
|
|
|
if (!(dwFlags & TF_TMAE_NOACTIVATETIP))
|
|
{
|
|
//
|
|
// get first (default) assembly.
|
|
//
|
|
CAssembly *pAsm;
|
|
pAsm = pAsmList->FindAssemblyByLangId(GetCurrentAssemblyLangId(psfn));
|
|
if (pAsm)
|
|
ActivateAssembly(pAsm->GetLangId(), ACTASM_ONTIMACTIVE);
|
|
}
|
|
|
|
if (GetSharedMemory()->dwFocusThread == GetCurrentThreadId())
|
|
{
|
|
_OnThreadFocus(TRUE);
|
|
}
|
|
|
|
InitDefaultHotkeys();
|
|
_fFirstSetFocusAfterActivated = TRUE;
|
|
|
|
Exit:
|
|
_fInActivate = FALSE;
|
|
|
|
*ptid = g_gaApp;
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Deactivate
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::Deactivate()
|
|
{
|
|
SYSTHREAD *psfn;
|
|
int i;
|
|
int nCnt;
|
|
HRESULT hr;
|
|
CLEANUPCONTEXT cc;
|
|
|
|
if (_fInActivate)
|
|
{
|
|
Assert(0); // woah, we're inside Activate higher up the stack...
|
|
return E_UNEXPECTED;
|
|
}
|
|
_fInDeactivate = TRUE;
|
|
|
|
hr = S_OK;
|
|
|
|
_iActivateRefCount--;
|
|
|
|
if (_iActivateRefCount > 0)
|
|
goto Exit;
|
|
|
|
if (_iActivateRefCount < 0)
|
|
{
|
|
Assert(0); // someone is under-refing us
|
|
_iActivateRefCount = 0;
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
CtfImmSetCiceroStartInThread(FALSE);
|
|
|
|
UninitDefaultHotkeys();
|
|
|
|
psfn = GetSYSTHREAD();
|
|
|
|
_SetFocus(NULL, TRUE);
|
|
|
|
if (_fActiveUI)
|
|
{
|
|
_OnThreadFocus(FALSE);
|
|
}
|
|
_tidPrevForeground = TF_INVALID_GUIDATOM;
|
|
|
|
_iActivateRefCount = 0; // must do this after calling _OnThreadFocus(FALSE) or the call will be ignored
|
|
|
|
//
|
|
// #489905
|
|
//
|
|
// we can not call sink anymore after DLL_PROCESS_DETACH.
|
|
//
|
|
if (DllShutdownInProgress())
|
|
goto Exit;
|
|
|
|
// cleanup all the ics
|
|
cc.fSync = TRUE;
|
|
cc.pCatId = NULL;
|
|
cc.langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
|
cc.pfnPostCleanup = NULL;
|
|
cc.lPrivate = 0;
|
|
|
|
_CleanupContexts(&cc);
|
|
|
|
|
|
// deactivate everyone
|
|
for (i=0; i<_rgTip.Count(); i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
|
|
if (ptip->_pTip != NULL)
|
|
{
|
|
_DeactivateTip(ptip);
|
|
}
|
|
}
|
|
// wipe out the array after calling everyone
|
|
for (i=0; i<_rgTip.Count(); i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
|
|
ptip->CleanUp();
|
|
delete ptip;
|
|
}
|
|
_rgTip.Clear();
|
|
|
|
if (_pAAAdaptor != NULL)
|
|
{
|
|
_UninitMSAA();
|
|
}
|
|
|
|
if (psfn != NULL &&
|
|
psfn->plbim &&
|
|
psfn->plbim->_GetLBarItemDeviceTypeArray() &&
|
|
(nCnt = psfn->plbim->_GetLBarItemDeviceTypeArray()->Count()))
|
|
{
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
CLBarItemDeviceType *plbiDT;
|
|
plbiDT = psfn->plbim->_GetLBarItemDeviceTypeArray()->Get(i);
|
|
if (plbiDT)
|
|
plbiDT->Uninit();
|
|
}
|
|
}
|
|
|
|
// g_gcomplist.Uninit();
|
|
g_timlist.ClearFlags(GetCurrentThreadId(), TLF_TIMACTIVE);
|
|
|
|
if (_fReleaseDisplayAttrMgr && psfn->pdam != NULL)
|
|
{
|
|
psfn->pdam->Release();
|
|
}
|
|
_fReleaseDisplayAttrMgr = FALSE;
|
|
|
|
Perf_DumpStats();
|
|
|
|
Exit:
|
|
_fInDeactivate = FALSE;
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetActiveInputProcessors
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_GetActiveInputProcessors(ULONG ulCount, CLSID *pclsid, ULONG *pulCount)
|
|
{
|
|
ULONG i;
|
|
ULONG ulCopy;
|
|
ULONG ulCnt;
|
|
HRESULT hr;
|
|
|
|
if (!pulCount)
|
|
return E_INVALIDARG;
|
|
|
|
ulCnt = _rgTip.Count();
|
|
if (!pclsid)
|
|
{
|
|
ulCopy = 0;
|
|
for (i = 0; i < ulCnt; i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
if (ptip->_fActivated)
|
|
ulCopy++;
|
|
}
|
|
*pulCount = ulCopy;
|
|
return S_OK;
|
|
}
|
|
|
|
ulCopy = min((int)ulCount, _rgTip.Count());
|
|
*pulCount = ulCopy;
|
|
|
|
hr = S_OK;
|
|
|
|
for (i = 0; i < ulCnt; i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
|
|
if (ulCopy && ptip->_fActivated)
|
|
{
|
|
if (FAILED(hr = MyGetGUID(ptip->_guidatom, pclsid)))
|
|
break;
|
|
|
|
pclsid++;
|
|
ulCopy--;
|
|
}
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsActivateInputProcessor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_IsActiveInputProcessor(REFCLSID clsid)
|
|
{
|
|
TfGuidAtom guidatom;
|
|
|
|
if (FAILED(MyRegisterGUID(clsid, &guidatom)))
|
|
return E_FAIL;
|
|
|
|
return _IsActiveInputProcessorByATOM(guidatom);
|
|
}
|
|
|
|
HRESULT CThreadInputMgr::_IsActiveInputProcessorByATOM(TfGuidAtom guidatom)
|
|
{
|
|
ULONG i;
|
|
ULONG ulCnt;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
ulCnt = _rgTip.Count();
|
|
for (i = 0; i < ulCnt; i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
|
|
if (ptip->_guidatom == guidatom)
|
|
{
|
|
hr = ptip->_fActivated ? S_OK : S_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ActivateInputProcessor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::ActivateInputProcessor(REFCLSID clsid, REFGUID guidProfile, HKL hklSubstitute, BOOL fActivate)
|
|
{
|
|
CTip *ptip;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (fActivate)
|
|
{
|
|
if (_ActivateTip(clsid, hklSubstitute, &ptip) == S_OK)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TfGuidAtom guidatom;
|
|
|
|
if (FAILED(MyRegisterGUID(clsid, &guidatom)))
|
|
return E_FAIL;
|
|
|
|
if (_GetCTipfromGUIDATOM(guidatom, &ptip))
|
|
{
|
|
hr = _DeactivateTip(ptip);
|
|
}
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
NotifyActivateInputProcessor(clsid, guidProfile, fActivate);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// NotifyActivateInputProcessor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::NotifyActivateInputProcessor(REFCLSID clsid, REFGUID guidProfile, BOOL fActivate)
|
|
{
|
|
if (DllShutdownInProgress())
|
|
return S_OK;
|
|
|
|
CStructArray<GENERICSINK> *rgActiveTIPNotifySinks;
|
|
int i;
|
|
|
|
// Notify this to ITfActiveLanguageProfileNotifySink
|
|
rgActiveTIPNotifySinks = _GetActiveTIPNotifySinks();
|
|
|
|
for (i=0; i<rgActiveTIPNotifySinks->Count(); i++)
|
|
{
|
|
((ITfActiveLanguageProfileNotifySink *)rgActiveTIPNotifySinks->GetPtr(i)->pSink)->OnActivated(clsid, guidProfile, fActivate);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetSubstituteIMEModule
|
|
//
|
|
// Win98's imm.dll load and free IME module whenever hKL is changed. But
|
|
// Cicero changes hKL frequently even during IME is showing it's on
|
|
// dialog boxies.
|
|
// It is bad to free IME module then. So we keep IME's module ref count
|
|
// in CTip.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CThreadInputMgr::_GetSubstituteIMEModule(CTip *ptip, HKL hklSubstitute)
|
|
{
|
|
char szIMEFile[MAX_PATH];
|
|
|
|
//
|
|
// In NT, system keep the module of IME. So we don't have to cache it.
|
|
//
|
|
if (IsOnNT())
|
|
return;
|
|
|
|
if (!IsIMEHKL(hklSubstitute))
|
|
return;
|
|
|
|
if (ptip->_hInstSubstituteHKL)
|
|
return;
|
|
|
|
if (ImmGetIMEFileNameA(hklSubstitute, szIMEFile, ARRAYSIZE(szIMEFile)))
|
|
{
|
|
ptip->_hInstSubstituteHKL = LoadSystemLibrary(szIMEFile);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ActivateTip
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_ActivateTip(REFCLSID clsid, HKL hklSubstitute, CTip **pptip)
|
|
{
|
|
ITfTextInputProcessor *pitip;
|
|
CTip *ptip = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
TfGuidAtom guidatom;
|
|
int i;
|
|
int nCnt;
|
|
BOOL fCoInitCountCkipMode;
|
|
|
|
if (FAILED(MyRegisterGUID(clsid, &guidatom)))
|
|
return E_FAIL;
|
|
|
|
nCnt = _rgTip.Count();
|
|
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
ptip = _rgTip.Get(i);
|
|
|
|
if (ptip->_guidatom == guidatom)
|
|
{
|
|
Assert(ptip->_pTip);
|
|
if (!ptip->_fActivated)
|
|
{
|
|
ptip->_fActivated = TRUE;
|
|
|
|
fCoInitCountCkipMode = CtfImmEnterCoInitCountSkipMode();
|
|
ptip->_pTip->Activate(this, guidatom);
|
|
if (fCoInitCountCkipMode)
|
|
CtfImmLeaveCoInitCountSkipMode();
|
|
|
|
hr = S_OK;
|
|
goto Exit;
|
|
}
|
|
hr = S_FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(CoCreateInstance(clsid,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_ITfTextInputProcessor,
|
|
(void**)&pitip)))
|
|
{
|
|
CTip **pptipBuf;
|
|
if ((ptip = new CTip) == NULL)
|
|
{
|
|
pitip->Release();
|
|
goto Exit;
|
|
}
|
|
|
|
pptipBuf = _rgTip.Append(1);
|
|
if (!pptipBuf)
|
|
{
|
|
delete ptip;
|
|
pitip->Release();
|
|
goto Exit;
|
|
}
|
|
|
|
*pptipBuf = ptip;
|
|
|
|
ptip->_pTip = pitip;
|
|
|
|
ptip->_guidatom = guidatom;
|
|
ptip->_fActivated = TRUE;
|
|
|
|
//
|
|
// add refcound of IME file module of klSubstitute.
|
|
//
|
|
_GetSubstituteIMEModule(ptip, hklSubstitute);
|
|
|
|
// and activate its ui
|
|
fCoInitCountCkipMode = CtfImmEnterCoInitCountSkipMode();
|
|
ptip->_pTip->Activate(this, guidatom);
|
|
if (fCoInitCountCkipMode)
|
|
CtfImmLeaveCoInitCountSkipMode();
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
Exit:
|
|
//
|
|
// Stress 613240
|
|
//
|
|
// clsid {f25e9f57-2fc8-4eb3-a41a-cce5f08541e6} Tablet PC handwriting
|
|
// TIP somehow has this problem. During tip->Activate(), tim seems to
|
|
// be deactivated. So now _rgTip is empty.
|
|
//
|
|
if (!_rgTip.Count())
|
|
{
|
|
ptip = NULL;
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (pptip)
|
|
*pptip = ptip;
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
// hook up any display attribute collections for this tip
|
|
CDisplayAttributeMgr::_AdviseMarkupCollection(ptip->_pTip, guidatom);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// DeactivateTip
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_DeactivateTip(CTip *ptip)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
//
|
|
// #622929
|
|
//
|
|
// Hack for UninitThread on shutting down.
|
|
//
|
|
SYSTHREAD *psfn = FindSYSTHREAD();
|
|
if (psfn && psfn->fUninitThreadOnShuttingDown)
|
|
{
|
|
Assert(0);
|
|
return S_OK;
|
|
}
|
|
|
|
Assert(ptip->_pTip);
|
|
if (ptip->_fActivated)
|
|
{
|
|
BOOL fCoInitCountCkipMode;
|
|
|
|
if (ptip->_guidatom == _tidForeground)
|
|
{
|
|
_SetForeground(TF_INVALID_GUIDATOM);
|
|
}
|
|
|
|
if (ptip->_guidatom == _tidPrevForeground)
|
|
{
|
|
_tidPrevForeground = TF_INVALID_GUIDATOM;
|
|
}
|
|
|
|
ptip->_fActivated = FALSE;
|
|
|
|
if (psfn)
|
|
psfn->fDeactivatingTIP = TRUE;
|
|
|
|
fCoInitCountCkipMode = CtfImmEnterCoInitCountSkipMode();
|
|
ptip->_pTip->Deactivate();
|
|
if (fCoInitCountCkipMode)
|
|
CtfImmLeaveCoInitCountSkipMode();
|
|
|
|
if (psfn)
|
|
psfn->fDeactivatingTIP = FALSE;
|
|
|
|
hr = S_OK;
|
|
|
|
// unhook any display attribute collections for this tip
|
|
CDisplayAttributeMgr::_UnadviseMarkupCollection(ptip->_guidatom);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// _OnThreadFocus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_OnThreadFocus(BOOL fActivate)
|
|
{
|
|
int i;
|
|
ITfThreadFocusSink *pUIFocusSink;
|
|
|
|
if (_iActivateRefCount == 0)
|
|
return S_OK; // thread has not been Activate'd
|
|
|
|
if (_fActiveUI == fActivate)
|
|
return S_OK; // already in a matching state
|
|
|
|
_fActiveUI = fActivate;
|
|
|
|
if (!fActivate)
|
|
{
|
|
if (_tidForeground != TF_INVALID_GUIDATOM)
|
|
{
|
|
_tidPrevForeground = _tidForeground;
|
|
_tidForeground = TF_INVALID_GUIDATOM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_tidPrevForeground != TF_INVALID_GUIDATOM)
|
|
{
|
|
_tidForeground = _tidPrevForeground;
|
|
_tidPrevForeground = TF_INVALID_GUIDATOM;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<_GetUIFocusSinks()->Count(); i++)
|
|
{
|
|
pUIFocusSink = (ITfThreadFocusSink *)_GetUIFocusSinks()->GetPtr(i)->pSink;
|
|
_try {
|
|
if (fActivate)
|
|
{
|
|
pUIFocusSink->OnSetThreadFocus();
|
|
}
|
|
else
|
|
{
|
|
pUIFocusSink->OnKillThreadFocus();
|
|
}
|
|
}
|
|
_except(1) {
|
|
Assert(0);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CreateDocumentMgr
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::CreateDocumentMgr(ITfDocumentMgr **ppdim)
|
|
{
|
|
CDocumentInputManager *dim;
|
|
CDocumentInputManager **ppSlot;
|
|
|
|
if (ppdim == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppdim = NULL;
|
|
|
|
dim = new CDocumentInputManager;
|
|
if (dim == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
ppSlot = _rgdim.Append(1);
|
|
|
|
if (ppSlot == NULL)
|
|
{
|
|
dim->Release();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*ppSlot = dim;
|
|
*ppdim = dim;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _CheckNewActiveView
|
|
//
|
|
// Returns TRUE if the old and new value don't match, and there is both an old and new value.
|
|
// FALSE otherwise.
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CThreadInputMgr::_CheckNewActiveView(CDocumentInputManager *pdim)
|
|
{
|
|
CInputContext *pic;
|
|
TsViewCookie vcActiveViewOld;
|
|
BOOL fActiveViewOld;
|
|
|
|
fActiveViewOld = _fActiveView;
|
|
_fActiveView = FALSE;
|
|
|
|
if (pdim == NULL)
|
|
return FALSE;
|
|
|
|
vcActiveViewOld = _vcActiveView;
|
|
|
|
if (pic = pdim->_GetTopIC())
|
|
{
|
|
if (pic->_GetTSI()->GetActiveView(&_vcActiveView) != S_OK)
|
|
{
|
|
Assert(0); // how did GetActiveView fail?
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// empty dim so set null active view.
|
|
//
|
|
_vcActiveView = TS_VCOOKIE_NUL;
|
|
}
|
|
|
|
_fActiveView = TRUE;
|
|
|
|
return (fActiveViewOld && _vcActiveView != vcActiveViewOld);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _SetFocus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HRESULT CThreadInputMgr::_SetFocus(CDocumentInputManager *pdim, BOOL fInternal)
|
|
{
|
|
int iStack;
|
|
BOOL fDoLayoutNotify;
|
|
BOOL fNewActiveView;
|
|
BOOL fDIMFocusChanged;
|
|
CDocumentInputManager *pPrevFocusDIM;
|
|
SYSTHREAD *psfn = GetSYSTHREAD();
|
|
BOOL fFirstSetFocusAfterActivated;
|
|
BOOL fShutdownInProgress = DllShutdownInProgress();
|
|
|
|
fNewActiveView = _CheckNewActiveView(pdim);
|
|
fDoLayoutNotify = FALSE;
|
|
|
|
fFirstSetFocusAfterActivated = _fFirstSetFocusAfterActivated;
|
|
_fFirstSetFocusAfterActivated = FALSE;
|
|
|
|
_fInternalFocusedDim = fInternal;
|
|
|
|
//
|
|
// stop pending focus change.
|
|
//
|
|
|
|
if (psfn != NULL )
|
|
psfn->hwndBeingFocused = NULL;
|
|
|
|
if (pdim == _pFocusDocInputMgr)
|
|
{
|
|
if (pdim == NULL)
|
|
{
|
|
//
|
|
// we were ready to be acitvated Cicero. But the first setfocus
|
|
// was not Cicero enabled after Activate call....
|
|
//
|
|
// if we or msctfime are in thread detach, we don't
|
|
// have to set assembly back.
|
|
//
|
|
if (psfn &&
|
|
fFirstSetFocusAfterActivated &&
|
|
!psfn->fCUASDllDetachInOtherOrMe)
|
|
SetFocusDIMForAssembly(FALSE);
|
|
|
|
return S_OK; // nothing happened (no view change)
|
|
}
|
|
|
|
// did the default view change?
|
|
if (!fNewActiveView)
|
|
return S_OK; // nothing happened (no view change)
|
|
|
|
fDoLayoutNotify = TRUE;
|
|
}
|
|
|
|
pPrevFocusDIM = _pFocusDocInputMgr;;
|
|
_pFocusDocInputMgr = NULL;
|
|
|
|
if (pdim != NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
{
|
|
BOOL fFound = FALSE;
|
|
int i = 0;
|
|
int nCnt = _rgdim.Count();
|
|
CDocumentInputManager **ppdim = _rgdim.GetPtr(0);
|
|
while (i < nCnt)
|
|
{
|
|
if (*ppdim == pdim)
|
|
{
|
|
fFound = TRUE;
|
|
}
|
|
i++;
|
|
ppdim++;
|
|
}
|
|
if (!fFound)
|
|
{
|
|
Assert(0);
|
|
}
|
|
}
|
|
#endif
|
|
_pFocusDocInputMgr = pdim;
|
|
_pFocusDocInputMgr->AddRef();
|
|
}
|
|
|
|
if ((!pPrevFocusDIM && _pFocusDocInputMgr) ||
|
|
(pPrevFocusDIM && !_pFocusDocInputMgr))
|
|
{
|
|
fDIMFocusChanged = TRUE;
|
|
|
|
//
|
|
// we will call SetFocusDIMForAssembly() and it will makes
|
|
// ThreadItmChange. So we don't need to handle OnUpdate call.
|
|
//
|
|
if (psfn && psfn->plbim)
|
|
psfn->plbim->StopHandlingOnUpdate();
|
|
}
|
|
else
|
|
{
|
|
fDIMFocusChanged = FALSE;
|
|
}
|
|
|
|
//
|
|
// we skip notification in Shutdown
|
|
//
|
|
if (!fShutdownInProgress)
|
|
{
|
|
_MSAA_OnSetFocus(pdim);
|
|
_NotifyCallbacks(TIM_SETFOCUS, pdim, pPrevFocusDIM);
|
|
}
|
|
|
|
SafeReleaseClear(pPrevFocusDIM);
|
|
|
|
//
|
|
// we skip notification in Shutdown
|
|
//
|
|
if (fShutdownInProgress)
|
|
goto Exit;
|
|
|
|
if (fDoLayoutNotify)
|
|
{
|
|
// kick a layout chg notification for the benefit
|
|
// of tips just tracking the active view
|
|
iStack = _pFocusDocInputMgr->_GetCurrentStack();
|
|
if (iStack >= 0)
|
|
{
|
|
_pFocusDocInputMgr->_GetIC(iStack)->OnLayoutChange(TS_LC_CHANGE, _vcActiveView);
|
|
}
|
|
|
|
}
|
|
|
|
if (fDIMFocusChanged)
|
|
{
|
|
//
|
|
// if we or msctfime are in thread detach, we don't
|
|
// have to set assembly back.
|
|
//
|
|
if (psfn && !psfn->fCUASDllDetachInOtherOrMe)
|
|
SetFocusDIMForAssembly(_pFocusDocInputMgr ? TRUE : FALSE);
|
|
}
|
|
else
|
|
{
|
|
if (psfn && psfn->plbim && psfn->plbim->_GetLBarItemReconv())
|
|
psfn->plbim->_GetLBarItemReconv()->ShowOrHide(TRUE);
|
|
}
|
|
|
|
//
|
|
// we now start handling ITfLangBarMge::OnUpdate()
|
|
//
|
|
if (psfn && psfn->plbim)
|
|
psfn->plbim->StartHandlingOnUpdate();
|
|
|
|
Exit:
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetAssoc
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CDocumentInputManager *CThreadInputMgr::_GetAssoc(HWND hWnd)
|
|
{
|
|
CDocumentInputManager *dim;
|
|
|
|
dim = _dimwndMap._Find(hWnd);
|
|
|
|
return dim;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetAssoced
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
HWND CThreadInputMgr::_GetAssoced(CDocumentInputManager *pdim)
|
|
{
|
|
HWND hwnd = NULL;
|
|
|
|
if (!pdim)
|
|
return NULL;
|
|
|
|
if (_dimwndMap._FindKey(pdim, &hwnd))
|
|
return hwnd;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetGUIDATOMfromITfIME
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CThreadInputMgr::_GetGUIDATOMfromITfIME(ITfTextInputProcessor *pTip, TfGuidAtom *pguidatom)
|
|
{
|
|
int i;
|
|
int nCnt = _rgTip.Count();
|
|
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
if (ptip->_pTip == pTip)
|
|
{
|
|
*pguidatom = ptip->_guidatom;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetITfIMEfromCLSID
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CThreadInputMgr::_GetITfIMEfromGUIDATOM(TfGuidAtom guidatom, ITfTextInputProcessor **ppTip)
|
|
{
|
|
int i;
|
|
int nCnt = _rgTip.Count();
|
|
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
if (ptip->_guidatom == guidatom)
|
|
{
|
|
*ppTip = ptip->_pTip;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetCTipfromCLSID
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CThreadInputMgr::_GetCTipfromGUIDATOM(TfGuidAtom guidatom, CTip **pptip)
|
|
{
|
|
int i;
|
|
int nCnt = _rgTip.Count();
|
|
|
|
for (i = 0; i < nCnt; i++)
|
|
{
|
|
CTip *ptip = _rgTip.Get(i);
|
|
if (ptip->_guidatom == guidatom)
|
|
{
|
|
*pptip = ptip;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _NotifyCallbacks
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CThreadInputMgr::_NotifyCallbacks(TimNotify notify, CDocumentInputManager *dim, void *pv)
|
|
{
|
|
int i;
|
|
|
|
//
|
|
// #489905
|
|
//
|
|
// we can not call sink anymore after DLL_PROCESS_DETACH.
|
|
//
|
|
if (DllShutdownInProgress())
|
|
return;
|
|
|
|
CStructArray<GENERICSINK> *_rgSink = _GetThreadMgrEventSink();
|
|
|
|
i = 0;
|
|
while(i < _rgSink->Count())
|
|
{
|
|
int nCnt = _rgSink->Count();
|
|
ITfThreadMgrEventSink *pSink = (ITfThreadMgrEventSink *)_rgSink->GetPtr(i)->pSink;
|
|
|
|
switch (notify)
|
|
{
|
|
case TIM_INITDIM:
|
|
pSink->OnInitDocumentMgr(dim);
|
|
break;
|
|
|
|
case TIM_UNINITDIM:
|
|
pSink->OnUninitDocumentMgr(dim);
|
|
break;
|
|
|
|
case TIM_SETFOCUS:
|
|
pSink->OnSetFocus(dim, (ITfDocumentMgr *)pv);
|
|
break;
|
|
|
|
case TIM_INITIC:
|
|
pSink->OnPushContext((ITfContext *)pv);
|
|
break;
|
|
|
|
case TIM_UNINITIC:
|
|
pSink->OnPopContext((ITfContext *)pv);
|
|
break;
|
|
}
|
|
|
|
if (i >= _rgSink->Count())
|
|
break;
|
|
|
|
if (nCnt == _rgSink->Count())
|
|
i++;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UpdateDispAttr
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CThreadInputMgr::UpdateDispAttr()
|
|
{
|
|
CStructArray<GENERICSINK> *rgDispAttrNotifySinks;
|
|
int i;
|
|
|
|
rgDispAttrNotifySinks = _GetDispAttrNotifySinks();
|
|
|
|
for (i=0; i<rgDispAttrNotifySinks->Count(); i++)
|
|
{
|
|
((ITfDisplayAttributeNotifySink *)rgDispAttrNotifySinks->GetPtr(i)->pSink)->OnUpdateInfo();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitSystemFunctionProvider
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CThreadInputMgr::InitSystemFunctionProvider()
|
|
{
|
|
if (_pSysFuncPrv)
|
|
return;
|
|
//
|
|
// register system function provider.
|
|
//
|
|
_pSysFuncPrv = new CFunctionProvider();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// InitSystemFunctionProvider
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CFunctionProvider *CThreadInputMgr::GetSystemFunctionProvider()
|
|
{
|
|
InitSystemFunctionProvider();
|
|
if (_pSysFuncPrv)
|
|
_pSysFuncPrv->AddRef();
|
|
|
|
return _pSysFuncPrv;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetFunctionProvider
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetFunctionProvider(REFCLSID clsidTIP, ITfFunctionProvider **ppv)
|
|
{
|
|
TfGuidAtom guidatom;
|
|
HRESULT hr = TF_E_NOPROVIDER;
|
|
CTip *ctip;
|
|
|
|
if (ppv == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppv = NULL;
|
|
|
|
//
|
|
// create system function provider, if it is not create yet.
|
|
//
|
|
if (IsEqualGUID(clsidTIP, GUID_SYSTEM_FUNCTIONPROVIDER))
|
|
{
|
|
*ppv = GetSystemFunctionProvider();
|
|
hr = (*ppv) ? S_OK : E_FAIL;
|
|
goto Exit;
|
|
}
|
|
else if (IsEqualGUID(clsidTIP, GUID_APP_FUNCTIONPROVIDER))
|
|
{
|
|
if (_pAppFuncProvider == NULL)
|
|
goto Exit;
|
|
|
|
*ppv = _pAppFuncProvider;
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(MyRegisterGUID(clsidTIP, &guidatom)))
|
|
goto Exit;
|
|
if (!_GetCTipfromGUIDATOM(guidatom, &ctip))
|
|
goto Exit;
|
|
|
|
if (ctip->_pFuncProvider == NULL)
|
|
goto Exit;
|
|
|
|
*ppv = ctip->_pFuncProvider;
|
|
}
|
|
|
|
(*ppv)->AddRef();
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// EnumFunctionProviders
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::EnumFunctionProviders(IEnumTfFunctionProviders **ppEnum)
|
|
{
|
|
CEnumFunctionProviders *pEnum;
|
|
|
|
if (!ppEnum)
|
|
return E_INVALIDARG;
|
|
|
|
*ppEnum = NULL;
|
|
//
|
|
// create system function provider, if it is not create yet.
|
|
//
|
|
InitSystemFunctionProvider();
|
|
|
|
pEnum = new CEnumFunctionProviders();
|
|
if (!pEnum)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (!pEnum->_Init(this))
|
|
{
|
|
pEnum->Release();
|
|
return E_FAIL;
|
|
}
|
|
*ppEnum = pEnum;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AdviseSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::AdviseSink(REFIID refiid, IUnknown *punk, DWORD *pdwCookie)
|
|
{
|
|
return GenericAdviseSink(refiid, punk, _c_rgConnectionIIDs, _rgSinks, TIM_NUM_CONNECTIONPTS, pdwCookie);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UnadviseSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::UnadviseSink(DWORD dwCookie)
|
|
{
|
|
return GenericUnadviseSink(_rgSinks, TIM_NUM_CONNECTIONPTS, dwCookie);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AdviseSingleSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::AdviseSingleSink(TfClientId tid, REFIID riid, IUnknown *punk)
|
|
{
|
|
CTip *ctip;
|
|
|
|
if (punk == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
if (tid == g_gaApp)
|
|
{
|
|
if (IsEqualIID(riid, IID_ITfFunctionProvider))
|
|
{
|
|
if (_pAppFuncProvider)
|
|
return CONNECT_E_ADVISELIMIT;
|
|
|
|
if (punk->QueryInterface(IID_ITfFunctionProvider, (void **)&_pAppFuncProvider) != S_OK)
|
|
return E_NOINTERFACE;
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (!_GetCTipfromGUIDATOM(tid, &ctip))
|
|
return E_INVALIDARG;
|
|
|
|
if (IsEqualIID(riid, IID_ITfFunctionProvider))
|
|
{
|
|
if (ctip->_pFuncProvider != NULL)
|
|
return CONNECT_E_ADVISELIMIT;
|
|
|
|
if (punk->QueryInterface(IID_ITfFunctionProvider, (void **)&ctip->_pFuncProvider) != S_OK)
|
|
return E_NOINTERFACE;
|
|
|
|
return S_OK;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfCleanupContextDurationSink))
|
|
{
|
|
if (ctip->_pCleanupDurationSink != NULL)
|
|
return CONNECT_E_ADVISELIMIT;
|
|
|
|
if (punk->QueryInterface(IID_ITfCleanupContextDurationSink, (void **)&ctip->_pCleanupDurationSink) != S_OK)
|
|
return E_NOINTERFACE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return CONNECT_E_CANNOTCONNECT;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UnadviseSingleSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::UnadviseSingleSink(TfClientId tid, REFIID riid)
|
|
{
|
|
CTip *ctip;
|
|
|
|
if (tid == g_gaApp)
|
|
{
|
|
if (IsEqualIID(riid, IID_ITfFunctionProvider))
|
|
{
|
|
if (_pAppFuncProvider == NULL)
|
|
return CONNECT_E_NOCONNECTION;
|
|
|
|
SafeReleaseClear(_pAppFuncProvider);
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (!_GetCTipfromGUIDATOM(tid, &ctip))
|
|
return E_INVALIDARG;
|
|
|
|
if (IsEqualIID(riid, IID_ITfFunctionProvider))
|
|
{
|
|
if (ctip->_pFuncProvider == NULL)
|
|
return CONNECT_E_NOCONNECTION;
|
|
|
|
SafeReleaseClear(ctip->_pFuncProvider);
|
|
|
|
return S_OK;
|
|
}
|
|
else if (IsEqualIID(riid, IID_ITfCleanupContextDurationSink))
|
|
{
|
|
if (ctip->_pCleanupDurationSink == NULL)
|
|
return CONNECT_E_NOCONNECTION;
|
|
|
|
SafeReleaseClear(ctip->_pCleanupDurationSink);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return CONNECT_E_NOCONNECTION;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// EnumItems
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::EnumItems(IEnumTfLangBarItems **ppEnum)
|
|
{
|
|
if (ppEnum == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppEnum = NULL;
|
|
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->EnumItems(ppEnum);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetItem
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetItem(REFGUID rguid, ITfLangBarItem **ppItem)
|
|
{
|
|
if (ppItem == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppItem = NULL;
|
|
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->GetItem(rguid, ppItem);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AddItem
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::AddItem(ITfLangBarItem *punk)
|
|
{
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->AddItem(punk);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// RemoveItem
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::RemoveItem(ITfLangBarItem *punk)
|
|
{
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->RemoveItem(punk);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AdviseItemSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::AdviseItemSink(ITfLangBarItemSink *punk, DWORD *pdwCookie, REFGUID rguid)
|
|
{
|
|
if (pdwCookie == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*pdwCookie = 0;
|
|
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->AdviseItemSink(punk, pdwCookie, rguid);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UnadviseItemSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::UnadviseItemSink(DWORD dwCookie)
|
|
{
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->UnadviseItemSink(dwCookie);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetItemFloatingRect
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetItemFloatingRect(DWORD dwThreadId, REFGUID rguid, RECT *prc)
|
|
{
|
|
if (prc == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
memset(prc, 0, sizeof(*prc));
|
|
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->GetItemFloatingRect(dwThreadId, rguid, prc);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetItemsStatus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetItemsStatus(ULONG ulCount, const GUID *prgguid, DWORD *pdwStatus)
|
|
{
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->GetItemsStatus(ulCount, prgguid, pdwStatus);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetItemNum
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetItemNum(ULONG *pulCount)
|
|
{
|
|
if (pulCount == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*pulCount = 0;
|
|
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->GetItemNum(pulCount);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetItems
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetItems(ULONG ulCount, ITfLangBarItem **ppItem, TF_LANGBARITEMINFO *pInfo, DWORD *pdwStatus, ULONG *pcFetched)
|
|
{
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->GetItems(ulCount, ppItem, pInfo, pdwStatus, pcFetched);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AdviseItemsSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CThreadInputMgr::AdviseItemsSink(ULONG ulCount, ITfLangBarItemSink **ppunk, const GUID *pguidItem, DWORD *pdwCookie)
|
|
{
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->AdviseItemsSink(ulCount, ppunk, pguidItem, pdwCookie);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// UnadviseItemsSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CThreadInputMgr::UnadviseItemsSink(ULONG ulCount, DWORD *pdwCookie)
|
|
{
|
|
if (_plbim == NULL)
|
|
return E_FAIL;
|
|
|
|
return _plbim->UnadviseItemsSink(ulCount, pdwCookie);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// EnumDocumentInputMgrs
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::EnumDocumentMgrs(IEnumTfDocumentMgrs **ppEnum)
|
|
{
|
|
CEnumDocumentInputMgrs *pEnum;
|
|
|
|
if (!ppEnum)
|
|
return E_INVALIDARG;
|
|
|
|
if ((pEnum = new CEnumDocumentInputMgrs()) == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (!pEnum->_Init(this))
|
|
{
|
|
pEnum->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
*ppEnum = pEnum;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetFocus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetFocus(ITfDocumentMgr **ppdimFocus)
|
|
{
|
|
if (ppdimFocus == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppdimFocus = _pFocusDocInputMgr;
|
|
|
|
if (*ppdimFocus)
|
|
{
|
|
(*ppdimFocus)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetFocus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::SetFocus(ITfDocumentMgr *pdimFocus)
|
|
{
|
|
CDocumentInputManager *dim = NULL;
|
|
HRESULT hr;
|
|
|
|
if (pdimFocus && (dim = GetCDocumentInputMgr(pdimFocus)) == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
// pdimFocus may be NULL, which means clear the focus
|
|
// (_tim->_SetFocus will check for this)
|
|
hr = _SetFocus(dim, FALSE);
|
|
|
|
SafeRelease(dim);
|
|
|
|
//
|
|
// #602692
|
|
//
|
|
// The richedit calls SetFocus(dim) when it gets WM_SETFOCUS.
|
|
// But user32!SetFocus() of this WM_SETFOCUS could be made by
|
|
// AcitivateWindow() of another user32!SetFocus() call.
|
|
// If this happens, CBTHook() has been called and we won't get
|
|
// another notification when pq->hwndFocus is changed.
|
|
//
|
|
// So we can not call OnForegroundChanges() right now and need to wait
|
|
// until pq->hwndFocus() set. So we can trust user32!GetFocus().
|
|
//
|
|
PostThreadMessage(GetCurrentThreadId(),
|
|
g_msgPrivate,
|
|
TFPRIV_ONSETWINDOWFOCUS,
|
|
(LPARAM)-2);
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// AssociateFocus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::AssociateFocus(HWND hwnd, ITfDocumentMgr *pdimNew, ITfDocumentMgr **ppdimPrev)
|
|
{
|
|
CDocumentInputManager *dim;
|
|
CDocumentInputManager *dimNew;
|
|
SYSTHREAD *psfn;
|
|
|
|
if (ppdimPrev == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppdimPrev = NULL;
|
|
|
|
if (!IsWindow(hwnd))
|
|
return E_INVALIDARG;
|
|
|
|
if (pdimNew == NULL)
|
|
{
|
|
dimNew = NULL;
|
|
}
|
|
else if ((dimNew = GetCDocumentInputMgr(pdimNew)) == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
// get the old association and remove it from our list
|
|
dim = _GetAssoc(hwnd);
|
|
|
|
if (dim != NULL)
|
|
{
|
|
_dimwndMap._Remove(hwnd);
|
|
}
|
|
|
|
*ppdimPrev = dim;
|
|
if (*ppdimPrev)
|
|
(*ppdimPrev)->AddRef();
|
|
|
|
// setup the new assoc
|
|
// nb: we don't AddRef the dim, since we assume caller will clear before releasing it
|
|
if (dimNew != NULL)
|
|
{
|
|
_dimwndMap._Set(hwnd, dimNew);
|
|
}
|
|
|
|
//
|
|
// if some window is being focused, we will have another _SetFocus().
|
|
// Then we don't have to call _SetFocus() now.
|
|
//
|
|
psfn = GetSYSTHREAD();
|
|
if (psfn && !psfn->hwndBeingFocused && (hwnd == ::GetFocus()))
|
|
_SetFocus(dimNew, TRUE);
|
|
|
|
SafeRelease(dimNew);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// IsThreadFocus
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::IsThreadFocus(BOOL *pfUIFocus)
|
|
{
|
|
if (pfUIFocus == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*pfUIFocus = _fActiveUI;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetAssociated
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetAssociated(HWND hWnd, ITfDocumentMgr **ppdim)
|
|
{
|
|
//
|
|
// we may need to have a more complex logic here.
|
|
// Some application does not call AssociateFocus and it may
|
|
// handle the dim focus by it self. The we need to walk all TSI and
|
|
// find the window is associated to an IC.
|
|
//
|
|
*ppdim = _GetAssoc(hWnd);
|
|
if (*ppdim)
|
|
(*ppdim)->AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// SetSysHookSink
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::SetSysHookSink(ITfSysHookSink *pSink)
|
|
{
|
|
// nb: this is a private, internal interface method
|
|
// so we break COM rules and DON'T AddRef pSink (to avoid a circular ref)
|
|
// we'll get a call later with pSink == NULL to clear it out
|
|
// the pointer is contained in the life of the aimm layer tip,
|
|
// which is responsible for NULLing it out before unloading
|
|
_pSysHookSink = pSink;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// RequestPostponedLock
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::RequestPostponedLock(ITfContext *pic)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
CInputContext *pcic = GetCInputContext(pic);
|
|
if (!pcic)
|
|
goto Exit;
|
|
|
|
if (pcic->_fLockHeld)
|
|
pcic->_EmptyLockQueue(pcic->_dwlt, FALSE);
|
|
else
|
|
{
|
|
SYSTHREAD *psfn;
|
|
if (psfn = GetSYSTHREAD())
|
|
{
|
|
CInputContext::_PostponeLockRequestCallback(psfn, pcic);
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
SafeRelease(pcic);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetGlobalCompartment
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetGlobalCompartment(ITfCompartmentMgr **ppCompMgr)
|
|
{
|
|
return TF_GetGlobalCompartment(ppCompMgr);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// GetClientId
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::GetClientId(REFCLSID rclsid, TfClientId *ptid)
|
|
{
|
|
TfGuidAtom guidatom;
|
|
if (!ptid)
|
|
return E_INVALIDARG;
|
|
|
|
*ptid = TF_INVALID_GUIDATOM;
|
|
|
|
if (FAILED(MyRegisterGUID(rclsid, &guidatom)))
|
|
return E_FAIL;
|
|
|
|
*ptid = guidatom;
|
|
return S_OK;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// CallImm32Hotkeyhandler
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDAPI CThreadInputMgr::CallImm32HotkeyHanlder(WPARAM wParam, LPARAM lParam, BOOL *pbHandled)
|
|
{
|
|
if (!pbHandled)
|
|
return E_INVALIDARG;
|
|
|
|
*pbHandled = CheckImm32HotKey(wParam, lParam);
|
|
|
|
return S_OK;
|
|
}
|