spiegel-keyman/windows/src/engine/keyman32/k32_globals.cpp
Marc Durdin 54642dc86d fix(windows): disable OutputDebugString from DllMain
Following investigation, it seems that OutputDebugString can trigger a
loader lock as it throws an exception which can be handled by a global
exception handler, which may try and load/unload DLLs or perform other
unsafe tasks (e.g. StackWalk). The safest solution is to remove the
debug string logging altogether from code paths that run from DllMain.

It would be nice to further simplify DllMain but that would be a
significant amount of additional work.
2025-11-13 14:47:39 +01:00

708 lines
22 KiB
C++

/*
Name: k32_globals
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Create Date: 1 Aug 2006
Modified Date: 6 Feb 2015
Authors: mcdurdin
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
History: 01 Aug 2006 - mcdurdin - Add hotkeys globals
14 Sep 2006 - mcdurdin - Add IsKeymanSystemWindow and UpdateActiveWindows functions
04 Dec 2006 - mcdurdin - Add PostProcessControllers and IsControllerProcess functions
16 May 2007 - mcdurdin - I819 - Test if Keyman is functioning - messages
05 Nov 2007 - mcdurdin - I1087 - Add language switching hotkeys for Desktop Pro
20 Jul 2008 - mcdurdin - I1412 - Keyman Engine starts multiple times in Tutorial
16 Jan 2009 - mcdurdin - I1552 - Check if controller windows are still valid before posting/sending messages (e.g. after Keyman exits abnormally)
16 Jan 2009 - mcdurdin - I1584 - SendMasterControllers now uses SendMessageTimeout
30 Jan 2009 - mcdurdin - I1835 - Improve refresh performance
09 Mar 2009 - mcdurdin - I1888 - Keyman Engine can crash with some multithreaded applications
11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888
11 Dec 2009 - mcdurdin - I1455 - Improve stability of keyboard switching, remove unneeded hooks
11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
11 Dec 2009 - mcdurdin - I934 - Add a flag for shutdown so we know when to remove hooks
11 Dec 2009 - mcdurdin - I823 - Use GetGUIThreadInfo
11 Dec 2009 - mcdurdin - I1455 - Move IsSysTrayWindow to k32_globals
12 Mar 2010 - mcdurdin - I934 - x64 - Complete
12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings
29 Mar 2010 - mcdurdin - I1089 - One keyboard - all apps
06 Apr 2010 - mcdurdin - I2271 - Select Keyboard tidy up
09 Apr 2010 - mcdurdin - I2292 - Keyman was not initialising for multi-thread apps already in memory
19 Apr 2010 - mcdurdin - I2297 - Use global cache to remember last active keyboard for all apps
04 May 2010 - mcdurdin - I2297 - Work on cross-process sharing of keyboard cache information
04 May 2010 - mcdurdin - I2352 - Debug logging not working reliably in some applications
04 May 2010 - mcdurdin - I2354 - Race conditions with controller windows
28 Jun 2010 - mcdurdin - I2443 - Don't test if system tray is a Keyman-system window (for system-wide language switching)
30 Nov 2010 - mcdurdin - I2543 - Support switching to TSF TIPs
31 Jan 2011 - mcdurdin - I2686 - Remove assertion in Globals_InitThread to prevent errors on thread/process termination
18 Feb 2011 - mcdurdin - I2722 - Fix crash with Adobe Reader and its inability to see Keyman's USER handles when in Sandbox
25 Mar 2011 - mcdurdin - I2814 - Global lock was not released in RegisterControllerWindow in failure cases
03 May 2011 - mcdurdin - I2866 - If Keyman tray icon is hidden, then Keyman does not switch focus back to active app
19 Aug 2011 - mcdurdin - I3040 - keyman32.dll can crash if advapi32.dll is not loaded when first called from a process
03 Oct 2011 - mcdurdin - I3092 - Keyman Engine does not restart nicely when shutdown uncleanly
02 Dec 2011 - mcdurdin - I3158 - Keyman Engine can crash other applications when multiple OEM products are started with a _tcscpy assertion
24 Jan 2012 - mcdurdin - I3143 - Report more useful information when Keyman fails to start
02 Feb 2012 - mcdurdin - I3183 - Report clearer error when failure to register controller window
04 Nov 2012 - mcdurdin - I3523 - V9.0 - Merge of I3143 - Report more useful information when Keyman fails to start
04 Nov 2012 - mcdurdin - I3524 - V9.0 - Merge of I3158 - Keyman Engine can crash other applications when multiple OEM products are started, with a _tcscpy assertion
04 Nov 2012 - mcdurdin - I3530 - V9.0 - Merge of I3183 - Report clearer error when failure to register controller window
28 Nov 2012 - mcdurdin - I3594 - V9.0 - Remove old SelectKeyboard code and related messages
24 Oct 2013 - mcdurdin - I3933 - V9.0 - Keyman tray icon menu is not showing installed keyboards
06 Mar 2014 - mcdurdin - I4124 - V9.0 - Language switch dialog is not working in v9
03 Aug 2014 - mcdurdin - I4326 - V9.0 - Switch-off hotkey not working, then keyboard hotkey stopped working (win 8.1 jeremy) [High]
25 Sep 2014 - mcdurdin - I4412 - V9.0 - Character Map needs to insert characters using SendInput
06 Feb 2015 - mcdurdin - I4583 - V9.0 - Remove altgr lookup test from keyman32 and put it into the registry
06 Feb 2015 - mcdurdin - I4552 - V9.0 - Add mnemonic recompile option to ignore deadkeys
*/
#include "pch.h"
#include "security.h"
/***************************************************************************/
/* */
/* Thread-local storage */
/* */
/***************************************************************************/
UINT
//TODO: consolidate these messages -- they are probably not all required now
wm_keyman = 0, // user message - ignore msg // I3594
wm_keyman_grabwindowproc = 0,
wm_keyman_refresh = 0,
wm_kmgetactivekeymanid = 0,
wm_keymanshift = 0,
wm_keyman_control = 0,
wm_keyman_control_internal = 0,
wm_keymanim_close = 0,
wm_keymanim_contextchanged = 0,
wm_test_keyman_functioning = 0;
//HWND hwndIM = 0, hwndIMOldFocus = 0;
BOOL
flag_ShouldSerializeInput = TRUE;
BOOL isKeymanKeyboardActive = FALSE;
static DWORD dwTlsIndex = TLS_OUT_OF_INDEXES;
static CRITICAL_SECTION csGlobals;
PKEYMAN64THREADDATA Globals_InitThread()
{
EnterCriticalSection(&csGlobals);
PKEYMAN64THREADDATA lpvData;
if(Globals::get_Keyman_Shutdown()) // I3092
{
// Thread or process is uninitialising, probably receiving a message to a window that is being destroyed
SetLastError(ERROR_KEYMAN_SHUTTING_DOWN); // I3143 // I3523
lpvData = NULL;
}
else if(dwTlsIndex == TLS_OUT_OF_INDEXES) // I2686
{
// Thread or process is uninitialising, probably receiving a message to a window that is being destroyed
SetLastError(ERROR_KEYMAN_TLS_OUT_OF_INDEXES); // I3143 // I3523
lpvData = NULL;
}
else
{
lpvData = (PKEYMAN64THREADDATA) LocalAlloc(LPTR, sizeof(KEYMAN64THREADDATA));
if(lpvData != NULL)
{
TlsSetValue(dwTlsIndex, lpvData);
lpvData->ActiveKeymanID = KEYMANID_NONKEYMAN;
lpvData->CurrentAddin = -1;
}
else SetLastError(ERROR_KEYMAN_MEMORY_ALLOCATION_FAILED); // I3143 // I3523
}
LeaveCriticalSection(&csGlobals);
ISerialKeyEventClient::Startup();
return lpvData;
}
void Globals_UninitThread()
{
// OutputThreadDebugString("Globals_UninitThread");
if (!Globals_ProcessInitialised()) {
// OutputThreadDebugString("Globals_UninitThread aborted without cleanup");
return;
}
ISerialKeyEventClient::Shutdown();
CloseThreadSharedBufferManager();
EnterCriticalSection(&csGlobals);
if(dwTlsIndex != TLS_OUT_OF_INDEXES)
{
LPVOID lpvData = TlsGetValue(dwTlsIndex);
if(lpvData != NULL)
{
LocalFree((HLOCAL) lpvData);
}
TlsSetValue(dwTlsIndex, NULL);
}
LeaveCriticalSection(&csGlobals);
}
BOOL Globals_InitProcess()
{
InitializeCriticalSection(&csGlobals);
EnterCriticalSection(&csGlobals);
if((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
{
LeaveCriticalSection(&csGlobals);
return FALSE;
}
Globals_InitThread();
LeaveCriticalSection(&csGlobals);
return TRUE;
}
void Globals_UninitProcess()
{
EnterCriticalSection(&csGlobals);
Globals_UninitThread();
TlsFree(dwTlsIndex);
dwTlsIndex = TLS_OUT_OF_INDEXES;
LeaveCriticalSection(&csGlobals);
DeleteCriticalSection(&csGlobals);
}
PKEYMAN64THREADDATA ThreadGlobals()
{
EnterCriticalSection(&csGlobals);
PKEYMAN64THREADDATA lpvData = NULL;
if(dwTlsIndex != TLS_OUT_OF_INDEXES)
{
lpvData = (PKEYMAN64THREADDATA) TlsGetValue(dwTlsIndex);
}
LeaveCriticalSection(&csGlobals);
return lpvData;
}
BOOL Globals_ProcessInitialised()
{
EnterCriticalSection(&csGlobals);
BOOL f = (dwTlsIndex != TLS_OUT_OF_INDEXES && TlsGetValue(dwTlsIndex) != NULL);
LeaveCriticalSection(&csGlobals);
return f;
}
/***************************************************************************/
/* */
/* System-wide storage */
/* */
/***************************************************************************/
#pragma data_seg(".SHARDATA")
static HHOOK
f_hhookGetMessage = NULL, // GETMESSAGE hook handle
f_hhookCallWndProc = NULL; // CALLWNDPROC hook handle
#ifndef _WIN64
static HHOOK
f_hhookLowLevelKeyboardProc = NULL; // I4124
#endif
static HWND
f_hLastActiveWnd = 0,
f_hLastFocusWnd = 0;
// of keyboard icon, etc.
static UINT
f_WindowsVersion = 0; // Windows Version
static BOOL
f_Keyman_Initialised = FALSE,
f_Keyman_Shutdown = FALSE;
static DWORD
f_FSingleThread = 0,
f_InitialisingThread = 0; // I4326
//static DWORD
// f_ActiveKeymanID = 0;
static HWND
f_hwndIM = 0;
static BOOL
f_hwndIMAlways = 0;
#define MAXCONTROLLERS 128
static HWND
f_MasterController = NULL;
static DWORD
f_ControllerThreads[MAXCONTROLLERS] = {0};
static int
f_MaxControllerThreads = 0;
static BOOL
f_SimulateAltGr = FALSE, // I4583
f_MnemonicDeadkeyConversionMode = FALSE; // I4583 // I4552
static char
f_BaseKeyboard[16] = ""; // I4583
static wchar_t
f_BaseKeyboardName[256] = L"", // I4583
f_BaseKeyboardNameAlt[64] = L""; // I4583
__declspec(align(8)) static UINT
f_vk_prefix = 0;
#ifndef _WIN64
__declspec(align(8)) static LONG
f_RefreshTag = 0;
#endif
static BOOL
f_debug_KeymanLog = FALSE,
f_debug_ToConsole = FALSE;
#pragma data_seg()
/***************************************************************************/
DWORD //static
f_ShiftState = 0;
HANDLE f_hLockMutex = 0;
HHOOK *Globals::hhookGetMessage() { return &f_hhookGetMessage; }
HHOOK *Globals::hhookCallWndProc() { return &f_hhookCallWndProc; }
#ifndef _WIN64
HHOOK *Globals::hhookLowLevelKeyboardProc() { return &f_hhookLowLevelKeyboardProc; } // I4124
#endif
HWND *Globals::hLastActiveWnd() { return &f_hLastActiveWnd; }
HWND *Globals::hLastFocusWnd() { return &f_hLastFocusWnd; }
HWND *Globals::hwndIM() { return &f_hwndIM; }
BOOL *Globals::hwndIMAlways() { return &f_hwndIMAlways; }
UINT *Globals::WindowsVersion() { return &f_WindowsVersion; }
BOOL *Globals::Keyman_Initialised() { return &f_Keyman_Initialised; }
BOOL *Globals::Keyman_Shutdown() { return &f_Keyman_Shutdown; }
DWORD *Globals::FSingleThread() { return &f_FSingleThread; }
DWORD *Globals::InitialisingThread() { return &f_InitialisingThread; } // I4326
//DWORD *Globals::ActiveKeymanID() { return &f_ActiveKeymanID; }
DWORD *Globals::ShiftState() { return &f_ShiftState; }
#ifndef _WIN64
LONG *Globals::RefreshTag() { return &f_RefreshTag; }
#endif
HHOOK Globals::get_hhookCallWndProc() { return f_hhookCallWndProc; }
HHOOK Globals::get_hhookGetMessage() { return f_hhookGetMessage; }
#ifndef _WIN64
HHOOK Globals::get_hhookLowLevelKeyboardProc() { return f_hhookLowLevelKeyboardProc; } // I4124
#endif
HWND Globals::get_hLastActiveWnd() { return f_hLastActiveWnd; }
HWND Globals::get_hLastFocusWnd() { return f_hLastFocusWnd; }
UINT Globals::get_WindowsVersion() { return f_WindowsVersion; }
BOOL Globals::get_Keyman_Initialised() { return f_Keyman_Initialised; }
BOOL Globals::get_Keyman_Shutdown() { return f_Keyman_Shutdown; }
DWORD Globals::get_FSingleThread() { return f_FSingleThread; }
DWORD Globals::get_InitialisingThread() { return f_InitialisingThread; } // I4326
//DWORD Globals::get_ActiveKeymanID() { return f_ActiveKeymanID; }
DWORD Globals::get_ShiftState() { return f_ShiftState; }
char *Globals::get_BaseKeyboard() { return f_BaseKeyboard; } // I4583
BOOL Globals::get_SimulateAltGr() { return f_SimulateAltGr; } // I4583
wchar_t *Globals::get_BaseKeyboardName() { return f_BaseKeyboardName; } // I4583
wchar_t *Globals::get_BaseKeyboardNameAlt() { return f_BaseKeyboardNameAlt; } // I4583
UINT Globals::get_vk_prefix() { return f_vk_prefix; }
void Globals::set_vk_prefix(UINT value) { f_vk_prefix = value; }
BOOL Globals::get_MnemonicDeadkeyConversionMode() { return f_MnemonicDeadkeyConversionMode; } // I4583 // I4552
BOOL Globals::get_debug_KeymanLog() { return f_debug_KeymanLog; }
BOOL Globals::get_debug_ToConsole() { return f_debug_ToConsole; }
void Globals::SetBaseKeyboardName(wchar_t *baseKeyboardName, wchar_t *baseKeyboardNameAlt) { // I4583
wcscpy_s(f_BaseKeyboardName, baseKeyboardName);
wcscpy_s(f_BaseKeyboardNameAlt, baseKeyboardNameAlt);
}
void Globals::SetBaseKeyboardFlags(char *baseKeyboard, BOOL simulateAltGr, BOOL mnemonicDeadkeyConversionMode) { // I4583 // I4552
SendDebugEntry();
SendDebugMessageFormat("baseKeyboard='%s', simulateAltGr=%d, mnemonicDeadkeyConversionMode=%d",
baseKeyboard, simulateAltGr, mnemonicDeadkeyConversionMode);
strcpy_s(f_BaseKeyboard, baseKeyboard);
f_SimulateAltGr = simulateAltGr;
f_MnemonicDeadkeyConversionMode = mnemonicDeadkeyConversionMode;
SendDebugExit();
}
/**
Loads settings that are globally applied at application startup. These cannot
be changed until Keyman is restarted.
*/
BOOL Globals::InitSettings() {
SendDebugEntry();
f_vk_prefix = _VK_PREFIX_DEFAULT;
RegistryReadOnly reg(HKEY_LOCAL_MACHINE);
if (reg.OpenKeyReadOnly(REGSZ_KeymanLM) &&
reg.ValueExists(REGSZ_ZapVirtualKeyCode)) {
f_vk_prefix = reg.ReadInteger(REGSZ_ZapVirtualKeyCode);
reg.CloseKey();
SendDebugMessageFormat("vk_prefix set in '" REGSZ_ZapVirtualKeyCode "' to %x" , f_vk_prefix);
}
SendDebugExit();
return TRUE;
}
BOOL Globals::Lock()
{
if(f_hLockMutex == 0)
{
f_hLockMutex = CreateMutex(NULL, FALSE, "Tavultesoft_KeymanEngine_GlobalLock");
if(f_hLockMutex == 0) return FALSE;
}
if(WaitForSingleObject(f_hLockMutex, 1000) == WAIT_OBJECT_0) return TRUE; // I3183 // I3530
SetLastError(ERROR_TIMEOUT); // I3183 // I3530
return FALSE; // I3183 // I3530
}
BOOL Globals::InitHandles() // I3040
{
if(f_hLockMutex == 0)
f_hLockMutex = CreateMutex(NULL, FALSE, "Tavultesoft_KeymanEngine_GlobalLock");
if(f_hLockMutex == 0) return FALSE;
SetObjectToLowIntegrity(f_hLockMutex);
GrantPermissionToAllApplicationPackages(f_hLockMutex, MUTEX_ALL_ACCESS);
return TRUE;
}
BOOL Globals::Unlock()
{
return ReleaseMutex(f_hLockMutex);
}
BOOL Globals::ResetControllers() // I3092
{
SendDebugEntry();
if(!Globals::Lock()) {
SendDebugExit();
return FALSE;
}
f_MasterController = NULL;
f_MaxControllerThreads = 0;
f_hhookCallWndProc = NULL;
f_hhookGetMessage = NULL;
#ifndef _WIN64
f_hhookLowLevelKeyboardProc = NULL; // I4124
#endif
f_hLastActiveWnd = 0;
f_hLastFocusWnd = 0;
f_WindowsVersion = 0;
f_Keyman_Shutdown = FALSE;
f_Keyman_Initialised = FALSE;
f_FSingleThread = FALSE;
f_hwndIM = 0;
f_hwndIMAlways = 0;
#ifndef _WIN64
f_RefreshTag = 0;
#endif
Globals::Unlock();
SendDebugExit();
return TRUE;
}
BOOL Globals::CheckControllers()
{
return TRUE; // I2722
}
BOOL Globals::IsControllerWindow(HWND hwnd)
{
if(!Lock()) return FALSE;
CheckControllers();
DWORD tid = GetWindowThreadProcessId(hwnd, NULL);
for(int i = 0; i < f_MaxControllerThreads; i++)
if(tid == f_ControllerThreads[i])
{
Unlock();
return TRUE;
}
Unlock();
return FALSE;
}
BOOL Globals::IsControllerThread(DWORD tid)
{
if(!Lock()) return FALSE;
CheckControllers();
for(int i = 0; i < f_MaxControllerThreads; i++)
{
if(f_ControllerThreads[i] == tid)
{
Unlock();
return TRUE;
}
}
Unlock();
return FALSE;
}
void Globals::PostMasterController(UINT msg, WPARAM wParam, LPARAM lParam)
{
if(!Lock()) return;
SendDebugEntry();
CheckControllers();
if(f_MasterController == NULL)
{
SendDebugMessageFormat("no controllers [%x : %x, %x]", msg, wParam, lParam);
Unlock();
SendDebugExit();
return;
}
if(ShouldDebug())
{
char buf[64];
GetClassName(f_MasterController, buf, 64);
buf[63] = 0;
SendDebugMessageFormat("%s [%x : %x, %x]", buf, msg, wParam, lParam);
}
if(!PostMessage(f_MasterController, msg, wParam, lParam)) {
DebugLastError("PostMessage");
}
Unlock();
SendDebugExit();
}
LRESULT Globals::SendMasterController(UINT msg, WPARAM wParam, LPARAM lParam)
{
if(!Lock()) return 0;
SendDebugEntry();
CheckControllers();
if(f_MasterController == NULL)
{
Unlock();
SendDebugMessageFormat("no controllers [%x : %x, %x]", msg, wParam, lParam);
SendDebugExit();
return 0;
}
HWND hwnd = f_MasterController;
Unlock();
if(ShouldDebug())
{
char buf[64];
GetClassName(hwnd, buf, 64);
buf[63] = 0;
SendDebugMessageFormat("%s [%x : %x, %x]", buf, msg, wParam, lParam);
}
// Window may be taken out of list between Lock and Unlock but let's not worry about this
SetLastError(ERROR_SUCCESS);
DWORD_PTR dwResult = 0;
if(!SendMessageTimeout(hwnd, msg, wParam, lParam, SMTO_BLOCK, 100, &dwResult)) {
DebugLastError("SendMessageTimeout");
} else {
SendDebugMessageFormat("returned %x", dwResult);
}
SendDebugExit();
return dwResult;
}
extern "C" void _declspec(dllexport) WINAPI Keyman_PostControllers(UINT msg, WPARAM wParam, LPARAM lParam)
{
// no-op (removed as part of #5060)
UNREFERENCED_PARAMETER(msg);
UNREFERENCED_PARAMETER(wParam);
UNREFERENCED_PARAMETER(lParam);
}
extern "C" void _declspec(dllexport) WINAPI Keyman_PostMasterController(UINT msg, WPARAM wParam, LPARAM lParam)
{
Globals::PostMasterController(msg, wParam, lParam);
}
extern "C" LRESULT _declspec(dllexport) WINAPI Keyman_SendMasterController(UINT msg, WPARAM wParam, LPARAM lParam)
{
return Globals::SendMasterController(msg, wParam, lParam);
}
extern "C" BOOL _declspec(dllexport) WINAPI Keyman_RegisterControllerWindow(HWND hwnd)
{
// no-op (removed as part of #5060)
UNREFERENCED_PARAMETER(hwnd);
return TRUE;
}
extern "C" BOOL _declspec(dllexport) WINAPI Keyman_RegisterControllerThread(DWORD tid)
{
if(!Globals::Lock())
{
// last error set by Globals::Lock
return FALSE;
}
if(f_MaxControllerThreads == MAXCONTROLLERS)
{
Globals::Unlock(); // I2814
SetLastError(ERROR_KEYMAN_TOO_MANY_CONTROLLERS); // I3183 // I3530
return FALSE;
}
if(Globals::IsControllerThread(tid))
{
Globals::Unlock(); // I2814
return TRUE;
}
f_ControllerThreads[f_MaxControllerThreads++] = tid;
Globals::Unlock();
return TRUE;
}
extern "C" BOOL _declspec(dllexport) WINAPI Keyman_RegisterMasterController(HWND hwnd)
{
if (!Globals::Lock())
{
// last error set by Globals::Lock
return FALSE;
}
f_MasterController = hwnd;
Globals::Unlock();
return TRUE;
}
extern "C" BOOL _declspec(dllexport) WINAPI Keyman_UnregisterControllerWindow(HWND hwnd)
{
// no-op (removed as part of #5060)
UNREFERENCED_PARAMETER(hwnd);
return TRUE;
}
extern "C" BOOL _declspec(dllexport) WINAPI Keyman_UnregisterControllerThread(DWORD tid)
{
if(!Globals::Lock()) return FALSE;
for(int i = 0; i < f_MaxControllerThreads; i++)
if(f_ControllerThreads[i] == tid)
{
for(int j = i+1; j < f_MaxControllerThreads; j++) f_ControllerThreads[j-1] = f_ControllerThreads[j];
f_MaxControllerThreads--;
Globals::Unlock();
return TRUE;
}
Globals::Unlock();
return FALSE;
}
extern "C" BOOL _declspec(dllexport) WINAPI Keyman_UnregisterMasterController()
{
if (!Globals::Lock()) return FALSE;
f_MasterController = NULL;
Globals::Unlock();
return TRUE;
}
BOOL IsKeymanSystemWindow(HWND hwnd)
{
if(hwnd == 0 || IsSysTrayWindow(hwnd)) return TRUE; // I2866
return Globals::IsControllerWindow(hwnd);
}
BOOL IsTooltipWindow(HWND hwnd)
{
char buf[64];
if(!GetClassName(hwnd, buf, 64)) return FALSE;
return !_strcmpi(buf, "tooltips_class32");
}
void UpdateActiveWindows()
{
GUITHREADINFO gti;
gti.cbSize = sizeof(GUITHREADINFO);
GetGUIThreadInfo(0, &gti);
if(IsKeymanSystemWindow(gti.hwndActive) || IsKeymanSystemWindow(gti.hwndFocus)) return;
if(IsTooltipWindow(gti.hwndActive) || IsTooltipWindow(gti.hwndFocus)) return;
*Globals::hLastActiveWnd() = gti.hwndActive;
*Globals::hLastFocusWnd() = gti.hwndFocus;
Globals::PostMasterController(wm_keyman_control, KMC_SETFOCUSINFO, 0);
}
BOOL IsSysTrayWindow(HWND hwnd)
{
char buf[64];
GetClassName(hwnd, buf, 63);
return(!strcmp(buf, "SysTabControl32") ||
!strcmp(buf, "TrayNotifyWnd") ||
!strcmp(buf, "Shell_TrayWnd") ||
!strcmp(buf, "NotifyIconOverflowWindow")); // I2866
}
BOOL Reg_GetDebugFlag(LPSTR pszFlagRegistrySetting, BOOL bDefault) {
RegistryReadOnly r(HKEY_CURRENT_USER);
if (r.OpenKeyReadOnly(REGSZ_Keyman_Debug)) {
if (r.ValueExists(pszFlagRegistrySetting)) {
return !!r.ReadInteger(pszFlagRegistrySetting);
}
}
return bDefault;
}
void Globals::LoadDebugSettings() {
RegistryReadOnly reg(HKEY_CURRENT_USER);
if (reg.OpenKeyReadOnly(REGSZ_KeymanCU)) {
f_debug_KeymanLog = reg.ValueExists(REGSZ_Debug) && reg.ReadInteger(REGSZ_Debug);
f_debug_ToConsole = reg.ValueExists(REGSZ_DebugToConsole) && reg.ReadInteger(REGSZ_DebugToConsole); // I3951
}
else {
f_debug_KeymanLog = FALSE;
f_debug_ToConsole = FALSE; // I3951
}
}
void WINAPI SetCustomPostKeyCallback(CUSTOMPOSTKEYCALLBACKPROC proc) {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (!_td) return;
_td->CustomPostKeyCallback = proc;
}