Merge pull request #16435 from keymanapp/fix/windows/15333-simplify-keyboard-refresh

fix(windows): simplify keyboard refresh and make it more on-demand
This commit is contained in:
Marc Durdin 2026-09-01 16:10:39 +07:00 • committed by GitHub
commit 9b80c56810
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 218 additions and 170 deletions

View file

@ -67,6 +67,11 @@
#define KMC_LANGUAGEHOTKEY 20
//TOUCH #define KMC_CONTEXT 19 // 9.0.450.0
// Cross-architecture comms
#define KMC_REGISTER_HOST_WINDOW_X64 23
#define KMC_REGISTER_HOST_WINDOW_ARM64 24
#define RWM_KEYMAN_CONTROL "WM_KEYMAN_CONTROL"
#define RWM_KEYMAN_CONTROL_W L"WM_KEYMAN_CONTROL"
#define khLanguageSwitch 8

View file

@ -623,20 +623,23 @@ procedure TfrmMain.AppEventsMessage(var Msg: tagMSG;
var Handled: Boolean);
begin
inherited;
if (Msg.message = wm_keyman_refresh) and (Msg.WParam = KR_SETTINGS_CHANGED) then
if Msg.message = wm_keyman_refresh then
begin
// If we generated this refresh ourselves, ignore it
if (kmcom <> nil) and (Msg.lParam <> KeymanEngineControl.LastRefreshToken) then
if Msg.WParam = KR_SETTINGS_CHANGED then
begin
// The refresh event was generated by another process or thread
//
// We may receive the notification multiple times because it is broadcast
// to all top-level windows and we probably have a bunch of them.
// So, if we've already processed it, don't do so again.
if Msg.lParam <> LastRefreshToken then
// If we generated this refresh ourselves, ignore it
if (kmcom <> nil) and (Msg.lParam <> KeymanEngineControl.LastRefreshToken) then
begin
LastRefreshToken := Msg.lParam;
DoRefresh;
// The refresh event was generated by another process or thread
//
// We may receive the notification multiple times because it is broadcast
// to all top-level windows and we probably have a bunch of them.
// So, if we've already processed it, don't do so again.
if Msg.lParam <> LastRefreshToken then
begin
LastRefreshToken := Msg.lParam;
DoRefresh;
end;
end;
end;
end;

View file

@ -144,7 +144,7 @@ type
procedure editorKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
private
cefFonts: TframeCEFHost;
wm_keyman_control, wm_keyman_refresh: UINT;
wm_keyman_control: UINT;
FUpdating: Boolean;
FCheckFontsThread: TCheckFontsThread;
FCheckFontKeyboards: TCheckFontKeyboards;
@ -248,7 +248,6 @@ procedure TfrmTextEditor.TntFormCreate(Sender: TObject);
begin
inherited;
wm_keyman_control := RegisterWindowMessage('WM_KEYMAN_CONTROL');
wm_keyman_refresh := RegisterWindowMessage('WM_KEYMANREFRESH');
HelpTopic := 'context/text-editor';
Caption := MsgFromId(SKTextEditorCaption);
@ -724,7 +723,7 @@ end;
procedure TfrmTextEditor.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
if (Msg.message = wm_keyman_refresh) and (Msg.wParam = KR_REFRESH) then
if (Msg.message = wm_keyman_control) and (Msg.wParam = KMC_REFRESH) then
begin
StartCheckFontsThread;
end;

View file

@ -1,18 +1,18 @@
(*
Name: kmint
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Documentation:
Description:
Create Date: 1 Aug 2006
Modified Date: 26 Jun 2012
Authors: mcdurdin
Related Files:
Dependencies:
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
Bugs:
Todo:
Notes:
History: 01 Aug 2006 - mcdurdin - Remove old Keyman 6 integration
01 Aug 2006 - mcdurdin - Look for pxx file in startup folder to determine product to start
05 Nov 2007 - mcdurdin - I937, I1128 - Repair COM object if it fails at startup
@ -43,7 +43,6 @@ function LoadKMCOM: Boolean;
const
KEYMAN_LAYOUT_CUSTOM = $000005FE;
KR_REFRESH = 2;
KR_SETTINGS_CHANGED = 3;
const
@ -136,7 +135,7 @@ begin
end;
procedure CoFreeUnusedLibrariesEx(dwUnloadDelay, dwReserved: DWORD); stdcall; external 'ole32.dll';
function LoadKMCOM: Boolean;
var
msg: string;

View file

@ -351,6 +351,7 @@ var
wm_keyman_globalswitch, wm_keyman_globalswitch_process, wm_keyman_control, wm_keyman_control_internal, wm_test_keyman_functioning: Cardinal;
FEnableCrashTest: Boolean = False;
wm_keyman_refresh: Cardinal;
const
KMC_StartProduct = 0;
@ -697,6 +698,10 @@ begin
end;
function TfrmKeyman7Main.AppMessage(var Message: TMessage): Boolean;
var
hwndTextEditor: THandle;
const
KR_PRE_REFRESH = 1;
begin
if Message.Msg = WM_ACTIVATEAPP then
begin
@ -728,6 +733,19 @@ begin
end;
Result := True;
end
else if Message.Msg = wm_keyman_refresh then
begin
if Message.WParam = KR_PRE_REFRESH then
begin
// The text editor needs a special prod for keyboard changes
hwndTextEditor := FindWindow('TfrmTextEditor', nil);
if hwndTextEditor <> 0 then
begin
PostMessage(hwndTextEditor, wm_keyman_control, KMC_REFRESH, 0);
end;
end;
Result := False;
end
else if Message.Msg = wm_keyman_control then
begin
Result := True;
@ -1241,13 +1259,13 @@ begin
// #12905: icon is otherwise invalid
TKeymanSentryClient.ReportHandledException(E, 'SetTrayIcon: Invalid icon for keyboard "'+kbd.ID+'"; icon filename "'+kbd.IconFilename+'"');
// Use the default app icon
rp.FTrayIcon.Icon.Assign(FTrayIcon);
rp.FTrayIcon.Icon.Assign(FTrayIcon);
end;
end
else
begin
// Use the default app icon
rp.FTrayIcon.Icon.Assign(FTrayIcon);
rp.FTrayIcon.Icon.Assign(FTrayIcon);
end;
if VisualKeyboardVisible then
@ -2119,6 +2137,7 @@ initialization
wm_keyman_globalswitch_process := RegisterWindowMessage('WM_KEYMAN_GLOBALSWITCH_PROCESS');
wm_keyman_control := RegisterWindowMessage('WM_KEYMAN_CONTROL');
wm_keyman_control_internal := RegisterWindowMessage('WM_KEYMAN_CONTROL_INTERNAL'); // I3933
wm_keyman_refresh := RegisterWindowMessage('WM_KEYMANREFRESH');
ChangeWindowMessageFilter(wm_keyman_control, MSGFLT_ADD);
ChangeWindowMessageFilter(wm_keyman_globalswitch, MSGFLT_ADD);

View file

@ -48,8 +48,7 @@ uses
MessageIdentifiers;
const
KR_REQUEST_REFRESH = 0; // Send this to any window, which will make Keyman post a KR_REFRESH to all top-level windows
KR_REFRESH = 2; // Finally this message get sent to all the other top-level windows in the system.
KR_REQUEST_REFRESH = 0; // Send this to any window, which will make Keyman post a KR_PRE_REFRESH to controllers, which will cause all threads to eventually refresh keyboards list
KR_SETTINGS_CHANGED = 3;
function KeymanCustomisation: IKeymanCustomisation;

View file

@ -68,6 +68,7 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPActivateKeyboard(GUID *profile)
PKEYMAN64THREADDATA _td = ThreadGlobals();
if(!_td) return FALSE;
RefreshThreadKeyboardsIfRequired();
RefreshToggleState();
if(profile != NULL) {

View file

@ -88,8 +88,15 @@ public:
static DWORD *ShiftState();
#ifndef _WIN64
static LONG *RefreshTag();
static LONG get_RefreshTag();
#ifndef _WIN64
static HWND get_hwndHostX64();
static HWND get_hwndHostARM64();
static HWND *hwndHostX64();
static HWND *hwndHostARM64();
#endif
static HHOOK get_hhookGetMessage();
@ -216,8 +223,7 @@ typedef struct tagKEYMAN64THREADDATA
BOOL CoreProcessEventRun; // True if core process event has been run
BOOL FInRefreshKeyboards;
BOOL RefreshRequired;
LONG RefreshTag_Thread; // TODO: we may be able to eliminate this with our delayed refresh pattern?
LONG RefreshTag_Thread;
/* Addin Globals */

View file

@ -95,6 +95,12 @@ BOOL isKeymanKeyboardActive = FALSE;
static DWORD dwTlsIndex = TLS_OUT_OF_INDEXES;
static CRITICAL_SECTION csGlobals;
// In order that every thread starts off needing a refresh, we set the starting
// refresh tag to 1, but the thread-level refresh tag will be 0 (initialized by
// `LocalAlloc(LPTR)`)
#define INITIAL_GLOBAL_REFRESH_TAG 1
#define INITIAL_THREAD_REFRESH_TAG 0
PKEYMAN64THREADDATA Globals_InitThread()
{
EnterCriticalSection(&csGlobals);
@ -269,9 +275,13 @@ static wchar_t
__declspec(align(8)) static UINT
f_vk_prefix = 0;
#ifndef _WIN64
__declspec(align(8)) static LONG
f_RefreshTag = 0;
f_RefreshTag = INITIAL_GLOBAL_REFRESH_TAG;
#ifndef _WIN64
__declspec(align(8)) static HWND
f_hwndHostX64 = 0,
f_hwndHostARM64 = 0;
#endif
static BOOL
@ -310,8 +320,15 @@ DWORD *Globals::InitialisingThread() { return &f_InitialisingThread; } // I43
DWORD *Globals::ShiftState() { return &f_ShiftState; }
#ifndef _WIN64
LONG *Globals::RefreshTag() { return &f_RefreshTag; }
LONG Globals::get_RefreshTag() { return f_RefreshTag; }
#ifndef _WIN64
HWND Globals::get_hwndHostX64() { return f_hwndHostX64; }
HWND *Globals::hwndHostX64() { return &f_hwndHostX64; }
HWND Globals::get_hwndHostARM64() { return f_hwndHostARM64; }
HWND *Globals::hwndHostARM64() { return &f_hwndHostARM64; }
#endif
HHOOK Globals::get_hhookCallWndProc() { return f_hhookCallWndProc; }
@ -436,8 +453,10 @@ BOOL Globals::ResetControllers() // I3092
f_FSingleThread = FALSE;
f_hwndIM = 0;
f_hwndIMAlways = 0;
f_RefreshTag = INITIAL_GLOBAL_REFRESH_TAG;
#ifndef _WIN64
f_RefreshTag = 0;
f_hwndHostX64 = NULL;
f_hwndHostARM64 = NULL;
#endif
Globals::Unlock();

View file

@ -106,6 +106,9 @@
HINSTANCE g_hInstance;
void RefreshKeyboards();
void LoadKeyboardSettings();
/*******************************************************************************************/
/* */
/* Keyman Initialisation */
@ -216,7 +219,7 @@ BOOL InitThread()
_td->FInitialising = TRUE; // Control re-entrancy, this is thread safe because the variable is per-thread
RefreshKeyboards(TRUE);
LoadKeyboardSettings();
_td->FInitialising = FALSE; // Control re-entrancy, this is thread safe because the variable is per-thread
@ -412,7 +415,9 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Initialise(HWND Handle, BOOL
UpdateActiveWindows();
*Globals::Keyman_Initialised() = TRUE;
RefreshKeyboards(TRUE); // I4786
// We initialize keyboards on the controller thread immediately
RefreshThreadKeyboardsIfRequired();
SendDebugMessageFormat("Keyman is now initialised");
@ -576,27 +581,15 @@ extern "C" DWORD _declspec(dllexport) WINAPI GetActiveKeymanID()
//
//---------------------------------------------------------------------------------------------------------
// This function prevents a refresh event from being processed more than once
// by a thread, for instance if a thread has multiple top-level windows
BOOL UpdateRefreshTag(LONG tag) // I1835 - Reduce chatter
{
void HandleRefresh(int code, LONG tag) {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if(!_td) return FALSE;
if(_td->RefreshTag_Thread != tag)
{
_td->RefreshTag_Thread = tag;
return TRUE;
}
return FALSE;
}
if(!_td) return;
void HandleRefresh(int code, LONG tag)
{
switch (code)
{
case KR_REQUEST_REFRESH:
// This is sent by Keyman COM API, ApplyToRunningKeymanEngine
SendDebugMessageFormat("#### Refresh Requested ####");
SendDebugMessageFormat("HandleRefresh(KR_REQUEST_REFRESH, %d); global refresh tag = %d; input thread refresh tag = %d", tag, Globals::get_RefreshTag(), _td->RefreshTag_Thread);
// We ask the master controller window to tell all instances
// of keyman32/keyman64 that a refresh is coming through
@ -608,41 +601,34 @@ void HandleRefresh(int code, LONG tag)
break;
case KR_PRE_REFRESH:
SendDebugMessageFormat("HandleRefresh(KR_PRE_REFRESH, %d); global refresh tag = %d; input thread refresh tag = %d", tag, Globals::get_RefreshTag(), _td->RefreshTag_Thread);
// The tag parameter will be zero for x86 controller, but will be the
// current tag for other architectures, coming from the x86 controller
if(Globals::get_InitialisingThread() != GetCurrentThreadId()) {
SendDebugMessageFormat("HandleRefresh: unexpected KR_PRE_REFRESH on a non-controller thread");
break;
}
#ifndef _WIN64
// We only need to broadcast the message from Win32; this avoids
// a double-broadcast which could happen if both keyman32 and keyman64
// receive the message, as they have independently managed RefreshTags
// This RefreshTag is only ever incremented here by the controller thread
// for x86 so this is a thread safe operation
*Globals::RefreshTag() = Globals::get_RefreshTag() + 1;
// This RefreshTag is only ever incremented here by the master controller
// so this is a thread safe operation
tag = ++(*Globals::RefreshTag());
if (UpdateRefreshTag(tag)) {
// The Keyman process gets the update first
RefreshKeyboards(FALSE);
PostMessage(HWND_BROADCAST, wm_keyman_refresh, KR_REFRESH, tag);
if(Globals::get_hwndHostX64() != NULL) {
PostMessage(Globals::get_hwndHostX64(), wm_keyman_refresh, KR_PRE_REFRESH, Globals::get_RefreshTag());
}
if(Globals::get_hwndHostARM64() != NULL) {
PostMessage(Globals::get_hwndHostARM64(), wm_keyman_refresh, KR_PRE_REFRESH, Globals::get_RefreshTag());
}
#else
*Globals::RefreshTag() = tag;
#endif
break;
case KR_REFRESH:
// All threads need to have their keyboard list
// refreshed after an update, but only once per
// refresh request
if (UpdateRefreshTag(tag)) {
#ifdef _WIN64
if (Globals::get_InitialisingThread() == GetCurrentThreadId()) {
// If this is the keyman.x64 or keymanarm64 thread, then we should
// go ahead and process the refresh immediately so
// that global settings are updated
RefreshKeyboards(FALSE);
}
else
#endif
// We'll update when we are called into action
ScheduleRefresh();
}
SendDebugMessageFormat("HandleRefresh: new tag = %d", Globals::get_RefreshTag());
RefreshThreadKeyboardsIfRequired();
break;
}
}
@ -695,6 +681,40 @@ void LoadBaseLayoutSettings() { // I4552 // I4583
delete reg;
}
/**
* If (per-architecture) global refresh tag differs from the current thread
* refresh tag, that indicates that a change has happened to the list of loaded
* keyboards, and we need to refresh the list now.
*/
void RefreshThreadKeyboardsIfRequired() {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (!_td) {
return;
}
SendDebugMessageFormat("RefreshThreadKeyboardsIfRequired(): global refresh tag = %d; input thread refresh tag = %d", Globals::get_RefreshTag(), _td->RefreshTag_Thread);
if (_td->RefreshTag_Thread != Globals::get_RefreshTag()) {
_td->RefreshTag_Thread = Globals::get_RefreshTag();
RefreshKeyboards();
}
}
/**
* Read the keyboard switch hotkeys, and base layout settings
*/
void LoadKeyboardSettings() {
#ifndef _WIN64
Hotkeys::Reload(); // I4326 // I4390
#endif
// Read global underlying keyboard flags
if(Globals::get_InitialisingThread() == GetCurrentThreadId()) {
LoadBaseLayoutSettings(); // I4583
}
}
// -----------------------------------------------------------------------------------------------
// - -
// - RefreshKeyboards: .... -
@ -743,32 +763,8 @@ void RefreshKeyboardProfiles(INTKEYBOARDINFO *kp, BOOL isTransient) {
}
}
void ScheduleRefresh() {
if (GetCurrentThreadId() == GetWindowThreadProcessId(GetForegroundWindow(), NULL)) {
RefreshKeyboards(FALSE);
}
else {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (!_td) {
return;
}
_td->RefreshRequired = TRUE;
}
}
void CheckScheduledRefresh() {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (!_td) {
return;
}
if (_td->RefreshRequired) {
RefreshKeyboards(FALSE);
_td->RefreshRequired = FALSE;
}
}
void RefreshKeyboards(BOOL Initialising)
{
void RefreshKeyboards() {
OutputThreadDebugString("RefreshKeyboards");
char sz[_MAX_FNAME];
char oldname[_MAX_FNAME];
@ -784,29 +780,17 @@ void RefreshKeyboards(BOOL Initialising)
oldname[0] = 0;
if(!Initialising)
{
if(_td->lpActiveKeyboard)
strcpy(oldname, _td->lpActiveKeyboard->Name);
if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard);
_td->lpActiveKeyboard = NULL;
_td->ActiveKeymanID = KEYMANID_NONKEYMAN;
if(_td->lpActiveKeyboard) {
strcpy(oldname, _td->lpActiveKeyboard->Name);
}
if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard);
_td->lpActiveKeyboard = NULL;
_td->ActiveKeymanID = KEYMANID_NONKEYMAN;
ReleaseKeyboards(TRUE);
/* Read the "keyboard off hotkey", simulate Alt+Gr, Hotkeys-Toggle flags */
#ifndef _WIN64
Hotkeys::Reload(); // I4326 // I4390
#endif
// Read global underlying keyboard flags
if(Globals::get_InitialisingThread() == GetCurrentThreadId()) {
LoadBaseLayoutSettings(); // I4583
}
LoadKeyboardSettings();
/* Read the keyboards */
@ -854,13 +838,13 @@ void RefreshKeyboards(BOOL Initialising)
}
delete reg; // I2714
if(!Initialising)
for(int i = 0; i < _td->nKeyboards; i++)
if(!_strcmpi(_td->lpKeyboards[i].Name, oldname))
{
SelectKeyboard(_td->lpKeyboards[i].KeymanID); // I3594
break;
}
for(int i = 0; i < _td->nKeyboards; i++) {
if(!_strcmpi(_td->lpKeyboards[i].Name, oldname))
{
SelectKeyboard(_td->lpKeyboards[i].KeymanID); // I3594
break;
}
}
_td->FInRefreshKeyboards = FALSE;

View file

@ -1156,7 +1156,7 @@
<ClInclude Include="KBD.H" />
<ClInclude Include="keyboardoptions.h" />
<ClInclude Include="keyman64.h" />
<ClInclude Include="keymancontrol.h" />
<ClInclude Include="..\..\..\include\keymancontrol.h" />
<ClInclude Include="keyman-debug-etw.h" />
<ClInclude Include="keyeventsenderthread.h" />
<ClInclude Include="keystate.h" />

View file

@ -210,7 +210,7 @@
<ClInclude Include="keyman64.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="keymancontrol.h">
<ClInclude Include="..\..\..\include\keymancontrol.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="keystate.h">

View file

@ -108,7 +108,6 @@
#define KR_REQUEST_REFRESH 0
#define KR_PRE_REFRESH 1
#define KR_REFRESH 2
#define KR_SETTINGS_CHANGED 3 // Broadcast when Keyman Configuration settings change
/* WM_KEY* message analysis */

View file

@ -207,12 +207,8 @@ void _OutputThreadDebugString(char* s);
/* Keyboard selection functions */
void HandleRefresh(int code, LONG tag);
void RefreshKeyboards(BOOL Initialising);
void CheckScheduledRefresh();
void ScheduleRefresh();
void RefreshThreadKeyboardsIfRequired();
void ReleaseKeyboards(BOOL Lock);
void CheckScheduledRefresh();
void ScheduleRefresh();
/* Glossary conversion functions */
@ -245,7 +241,7 @@ void keybd_shift(LPINPUT pInputs, int* n, BOOL isReset, LPBYTE const kbd);
#include "keystate.h"
#include "calldll.h"
#include "keymancontrol.h"
#include "..\..\..\include\keymancontrol.h"
#include "keyboardoptions.h"
#include "kmprocessactions.h"
#include "appcontext.h"

View file

@ -163,7 +163,7 @@ LRESULT _kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
case WM_KILLFOCUS:
{
CheckScheduledRefresh();
RefreshThreadKeyboardsIfRequired();
HWND hwnd = IsLanguageSwitchWindowVisible(); // I4326
if(hwnd != NULL && !Globals::IsControllerThread(GetCurrentThreadId())) SendToLanguageSwitchWindow(hwnd, VK_ESCAPE, 0); // I3025
@ -178,7 +178,7 @@ LRESULT _kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
}
break;
case WM_SETFOCUS:
CheckScheduledRefresh();
RefreshThreadKeyboardsIfRequired();
if (IsSysTrayWindow(cp->hwnd)) // I2443 - always do the focus change now? really unsure about this one
SendDebugMessageFormat("WM_SETFOCUS -- not hooking because IsSysTrayWindow");
else if (Globals::IsControllerThread(GetCurrentThreadId()))
@ -193,11 +193,11 @@ LRESULT _kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
case WM_ACTIVATE:
if(cp->wParam == WA_ACTIVE || cp->wParam == WA_CLICKACTIVE)
{
CheckScheduledRefresh();
RefreshThreadKeyboardsIfRequired();
}
break;
case WM_INPUTLANGCHANGE:
CheckScheduledRefresh();
RefreshThreadKeyboardsIfRequired();
SendDebugMessageFormat("WM_INPUTLANGCHANGE %x %x Hwnd=%x Parent=%x Focus=%x Active=%x", cp->wParam, cp->lParam, cp->hwnd, GetParent(cp->hwnd), GetFocus(), GetActiveWindow());
ReportActiveKeyboard(PC_UPDATE); // I4288

View file

@ -157,7 +157,7 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
BYTE scan = KEYMSG_LPARAM_SCAN(mp->lParam);
BYTE keyTransitionEvent = KEYMSG_FLAG_TRANSITION(mp->lParam);
CheckScheduledRefresh();
RefreshThreadKeyboardsIfRequired();
UpdateLastKeyCache(_td, mp->wParam, scan, keyTransitionEvent);
switch (mp->wParam) {
@ -393,20 +393,24 @@ void ProcessWMKeymanControlInternal(HWND hwnd, WPARAM wParam, LPARAM lParam)
void
ProcessWMKeymanControl(WPARAM wParam, LPARAM lParam) {
switch (wParam) {
case KMC_PROFILECHANGED:
{
if (!Globals::IsControllerThread(GetCurrentThreadId())) {
break;
}
WORD wAtom = HIWORD(lParam);
char atomStr[128];
if (GlobalGetAtomName(wAtom, atomStr, 128)) {
isKeymanKeyboardActive = strstr(atomStr, cs_clsidKMTipTextService) != nullptr;
}
break;
if (!Globals::IsControllerThread(GetCurrentThreadId())) {
return;
}
if (wParam == KMC_PROFILECHANGED) {
WORD wAtom = HIWORD(lParam);
char atomStr[128];
if (GlobalGetAtomName(wAtom, atomStr, 128)) {
isKeymanKeyboardActive = strstr(atomStr, cs_clsidKMTipTextService) != nullptr;
}
}
#ifndef _WIN64
else if(wParam == KMC_REGISTER_HOST_WINDOW_X64) {
*Globals::hwndHostX64() = (HWND) lParam;
} else if(wParam == KMC_REGISTER_HOST_WINDOW_ARM64) {
*Globals::hwndHostARM64() = (HWND) lParam;
}
#endif
}
/**

View file

@ -98,9 +98,7 @@ const PWSTR
szFail_UnknownError = L"Unknown error %d",
szFail_ErrorFormat = L"%s: %s (%d)",
szFail_ErrorFormat_OtherUnknown = L"%s: An unknown error occurred",
szWindowClass_x86_Wnd = L"TfrmKeyman7Main"; // Do not localize
szFail_ErrorFormat_OtherUnknown = L"%s: An unknown error occurred";
//const char *szGPA_ChangeWindowMessageFilter = "ChangeWindowMessageFilter"; // Do not localize
#define KEYMAN_SENTRY_LOGGER_DESKTOP_ENGINE_KEYMANHP KEYMAN_SENTRY_LOGGER_DESKTOP_ENGINE ARCH_LOG_FILE
@ -353,6 +351,15 @@ BOOL StartKeyman(HWND hWnd)
if(!Keyman_Initialise(hWnd, FALSE))
return Fail(hWnd, szError_FailedToInitialise);
// Tell the x86 controller our architecture's controller window handle which
// will process wm_keyman_refresh messages (in keyman##.dll)
UINT wm_keyman_control = RegisterWindowMessage(RWM_KEYMAN_CONTROL_W);
#if defined(_M_X64)
PostMessage(hwndController, wm_keyman_control, KMC_REGISTER_HOST_WINDOW_X64, (LPARAM) hWnd);
#elif defined(_M_ARM64)
PostMessage(hwndController, wm_keyman_control, KMC_REGISTER_HOST_WINDOW_ARM64, (LPARAM) hWnd);
#endif
KeymanStarted = TRUE;
return TRUE;

View file

@ -1,18 +1,18 @@
/*
Name: keymanhp
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Documentation:
Description:
Create Date: 11 Dec 2009
Modified Date: 11 Dec 2009
Authors: mcdurdin
Related Files:
Dependencies:
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
Bugs:
Todo:
Notes:
History: 11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
*/
#pragma once
@ -23,9 +23,9 @@
#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#endif
#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later.
#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE.
@ -35,3 +35,5 @@
#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
#include "..\..\..\include\keymancontrol.h"

View file

@ -280,6 +280,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="keymanhp.h" />
<ClInclude Include="..\..\..\include\keymancontrol.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>

View file

@ -32,6 +32,9 @@
<ClInclude Include="$(KEYMAN_ROOT)\common\windows\cpp\include\keymansentry.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\include\keymancontrol.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="keymanx64.rc">

View file

@ -63,6 +63,8 @@ const
WHR_INIT_FAILURE = 1; // 19.0 - hook failed to (re)install
WHR_UNINIT_FAILURE = 2; // 19.0 - hook failed to uninstall
KMC_REGISTER_HOST_WINDOW_X64 = 23;
KMC_REGISTER_HOST_WINDOW_ARM64 = 24;
PC_UPDATE = 0;
PC_UPDATE_LANGUAGESWITCH = 1;