spiegel-keyman/windows/src/engine/keyman32/hotkeys.cpp
Marc Durdin ccc6498739 fix(windows): Keyman was crashing sporadically
Fixes #2147.

This potentially addresses the issues reported in #2147 where Keyman
would crash due to a race condition as a critical section was not
deleted before attempting to recreate it.

Some logging has been added for debugging these issues.

Also fixes memory leaks and another race on startup relating to loading
the taskbar icon.

There are still some known memory leaks because DLL_THREAD_DETACH is
not called for all threads before keyman32.dll is unloaded, so those
threads don't get the opportunity to clean themsselves up. However, the
key danger with the csGlobals critical section has been addressed.
2019-11-06 17:44:32 +11:00

143 lines
4.1 KiB
C++

/*
Name: hotkeys
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Create Date: 1 Aug 2006
Modified Date: 25 Oct 2016
Authors: mcdurdin
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
History: 01 Aug 2006 - mcdurdin - Initial version
11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
12 Mar 2010 - mcdurdin - I934 - x64 - Complete
03 Aug 2014 - mcdurdin - I4326 - V9.0 - Switch-off hotkey not working, then keyboard hotkey stopped working (win 8.1 jeremy) [High]
28 Aug 2014 - mcdurdin - I4390 - V9.0 - Free vs Pro
13 Oct 2014 - mcdurdin - I4451 - V9.0 - Language hotkeys are not working
14 Nov 2014 - mcdurdin - I4516 - V9.0 - Language hotkeys associated with non-primary keyboards do not trigger language change
27 Mar 2015 - mcdurdin - I4641 - V9.0 - Keyman can crash silently on exit due to null hotkeys being addressed
25 Oct 2016 - mcdurdin - I5136 - Remove additional product references from Keyman Engine
*/
// I5136
#include "pch.h"
#ifdef _WIN64
#error hotkeys.cpp is not required for win64.
#endif
Hotkeys *g_Hotkeys = NULL; // I4326
Hotkeys *Hotkeys::Instance() { // I4326
if(GetCurrentThreadId() != Globals::get_InitialisingThread()) {
return NULL; // Will bork on other threads given current usage :)
}
if(g_Hotkeys == NULL) {
g_Hotkeys = new Hotkeys;
g_Hotkeys->Load(); // I4390
}
return g_Hotkeys;
}
void Hotkeys::Unload() {
if (GetCurrentThreadId() != Globals::get_InitialisingThread()) {
OutputThreadDebugString("Unexpected: no other thread should be attempting to unload hotkeys");
return;
}
if (g_Hotkeys != NULL) {
delete g_Hotkeys;
g_Hotkeys = NULL;
}
}
void Hotkeys::Reload() { // I4326 // I4390
Hotkeys *hotkeys = Hotkeys::Instance(); // I4641
if(hotkeys == NULL) {
return;
}
hotkeys->Load(); // I4390
}
void Hotkeys::Load() { // I4390
SendDebugMessageFormat(0, sdmGlobal, 0, "Hotkeys::Load() enter");
m_nHotkeys = 0;
RegistryReadOnly reg(HKEY_CURRENT_USER);
/* Load interface hotkeys */
if(reg.OpenKeyReadOnly(REGSZ_KeymanHotkeys)) {
int n = 0;
char name[128];
while(reg.GetValueNames(name, 128, n++)) {
m_hotkeys[m_nHotkeys].HotkeyType = hktInterface;
m_hotkeys[m_nHotkeys].HotkeyValue = reg.ReadInteger(name);
m_hotkeys[m_nHotkeys].Target = atoi(name);
SendDebugMessageFormat(0, sdmGlobal, 0, "InterfaceHotkey[%d] = {HotkeyValue: %x, Target: %d}",
m_nHotkeys,
m_hotkeys[m_nHotkeys].HotkeyValue,
m_hotkeys[m_nHotkeys].Target);
if(++m_nHotkeys >= MAX_HOTKEYS) {
break;
}
}
}
reg.CloseKey();
if(m_nHotkeys >= MAX_HOTKEYS) {
return;
}
/* Load language hotkeys */ // I4451
if(reg.OpenKeyReadOnly(REGSZ_KeymanLanguageHotkeys)) {
int nkey = 0;
WCHAR valuename[128];
while(reg.GetValueNames(valuename, 128, nkey++))
{
m_hotkeys[m_nHotkeys].HotkeyType = hktLanguage;
m_hotkeys[m_nHotkeys].hkl = (HKL) wcstoul(valuename, NULL, 16); // I4516
if(m_hotkeys[m_nHotkeys].hkl == 0) {
// Will be a guid
if(!SUCCEEDED(CLSIDFromString(valuename, &m_hotkeys[m_nHotkeys].profileGUID))) {
continue;
}
}
WCHAR hkval[64];
reg.ReadString(valuename, hkval, 64);
m_hotkeys[m_nHotkeys].HotkeyValue = _wtoi(hkval);
SendDebugMessageFormat(0, sdmGlobal, 0, "LanguageHotkey[%d] = {HotkeyValue: %x, hkl: %x, profileGUID: %ws}", m_nHotkeys,
m_hotkeys[m_nHotkeys].HotkeyValue,
m_hotkeys[m_nHotkeys].hkl,
m_hotkeys[m_nHotkeys].hkl == 0 ? valuename : L"");
if(++m_nHotkeys >= MAX_HOTKEYS) {
break;
}
}
}
reg.CloseKey();
SendDebugMessageFormat(0, sdmGlobal, 0, "Hotkeys::Load() exit");
}
Hotkey *Hotkeys::GetHotkey(DWORD hotkey)
{
for(int i = 0; i < m_nHotkeys; i++)
if(m_hotkeys[i].HotkeyValue == hotkey)
return &m_hotkeys[i];
return NULL;
}