diff --git a/windows/src/engine/keyman32/keymancontrol.h b/windows/include/keymancontrol.h
similarity index 94%
rename from windows/src/engine/keyman32/keymancontrol.h
rename to windows/include/keymancontrol.h
index b25d0ceebf..a83749234a 100644
--- a/windows/src/engine/keyman32/keymancontrol.h
+++ b/windows/include/keymancontrol.h
@@ -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
diff --git a/windows/src/desktop/kmshell/main/UfrmMain.pas b/windows/src/desktop/kmshell/main/UfrmMain.pas
index e367a795ae..a8fdfe9845 100644
--- a/windows/src/desktop/kmshell/main/UfrmMain.pas
+++ b/windows/src/desktop/kmshell/main/UfrmMain.pas
@@ -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;
diff --git a/windows/src/desktop/kmshell/startup/help/UfrmTextEditor.pas b/windows/src/desktop/kmshell/startup/help/UfrmTextEditor.pas
index d67143e8ee..f0f46cfc6d 100644
--- a/windows/src/desktop/kmshell/startup/help/UfrmTextEditor.pas
+++ b/windows/src/desktop/kmshell/startup/help/UfrmTextEditor.pas
@@ -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;
diff --git a/windows/src/desktop/kmshell/util/kmint.pas b/windows/src/desktop/kmshell/util/kmint.pas
index 334e0b0409..c63abdbc6c 100644
--- a/windows/src/desktop/kmshell/util/kmint.pas
+++ b/windows/src/desktop/kmshell/util/kmint.pas
@@ -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;
diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas
index 4b51f337c1..fd5c24fcf2 100644
--- a/windows/src/engine/keyman/UfrmKeyman7Main.pas
+++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas
@@ -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);
diff --git a/windows/src/engine/keyman/kmint.pas b/windows/src/engine/keyman/kmint.pas
index 76170998d0..6d1f937d18 100644
--- a/windows/src/engine/keyman/kmint.pas
+++ b/windows/src/engine/keyman/kmint.pas
@@ -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;
diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp
index be657e4a12..b1b0345556 100644
--- a/windows/src/engine/keyman32/appint/aiTIP.cpp
+++ b/windows/src/engine/keyman32/appint/aiTIP.cpp
@@ -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) {
diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h
index 9db8044394..02b799f1ed 100644
--- a/windows/src/engine/keyman32/globals.h
+++ b/windows/src/engine/keyman32/globals.h
@@ -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 */
diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp
index 807b246466..19d2b0a12e 100644
--- a/windows/src/engine/keyman32/k32_globals.cpp
+++ b/windows/src/engine/keyman32/k32_globals.cpp
@@ -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();
diff --git a/windows/src/engine/keyman32/keyman32.cpp b/windows/src/engine/keyman32/keyman32.cpp
index 312865c61f..c60f674bf5 100644
--- a/windows/src/engine/keyman32/keyman32.cpp
+++ b/windows/src/engine/keyman32/keyman32.cpp
@@ -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;
diff --git a/windows/src/engine/keyman32/keyman32.vcxproj b/windows/src/engine/keyman32/keyman32.vcxproj
index 5d246b7bbe..dd5643290e 100644
--- a/windows/src/engine/keyman32/keyman32.vcxproj
+++ b/windows/src/engine/keyman32/keyman32.vcxproj
@@ -1156,7 +1156,7 @@
-
+
diff --git a/windows/src/engine/keyman32/keyman32.vcxproj.filters b/windows/src/engine/keyman32/keyman32.vcxproj.filters
index c5b38a60d1..a812f04249 100644
--- a/windows/src/engine/keyman32/keyman32.vcxproj.filters
+++ b/windows/src/engine/keyman32/keyman32.vcxproj.filters
@@ -210,7 +210,7 @@
Header Files
-
+
Header Files
diff --git a/windows/src/engine/keyman32/keyman64.h b/windows/src/engine/keyman32/keyman64.h
index eb199722c7..c062c73cb6 100644
--- a/windows/src/engine/keyman32/keyman64.h
+++ b/windows/src/engine/keyman32/keyman64.h
@@ -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 */
diff --git a/windows/src/engine/keyman32/keymanengine.h b/windows/src/engine/keyman32/keymanengine.h
index 15bf2f1b59..6c769951e5 100644
--- a/windows/src/engine/keyman32/keymanengine.h
+++ b/windows/src/engine/keyman32/keymanengine.h
@@ -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"
diff --git a/windows/src/engine/keyman32/kmhook_callwndproc.cpp b/windows/src/engine/keyman32/kmhook_callwndproc.cpp
index eedb06bc0b..38d1fd3909 100644
--- a/windows/src/engine/keyman32/kmhook_callwndproc.cpp
+++ b/windows/src/engine/keyman32/kmhook_callwndproc.cpp
@@ -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
diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp
index f000c2661e..cef36c382a 100644
--- a/windows/src/engine/keyman32/kmhook_getmessage.cpp
+++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp
@@ -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
}
/**
diff --git a/windows/src/engine/keymanhp/keymanhp.cpp b/windows/src/engine/keymanhp/keymanhp.cpp
index 81d386c000..483bbfa701 100644
--- a/windows/src/engine/keymanhp/keymanhp.cpp
+++ b/windows/src/engine/keymanhp/keymanhp.cpp
@@ -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;
diff --git a/windows/src/engine/keymanhp/keymanhp.h b/windows/src/engine/keymanhp/keymanhp.h
index 28a1f391d5..823a16ad45 100644
--- a/windows/src/engine/keymanhp/keymanhp.h
+++ b/windows/src/engine/keymanhp/keymanhp.h
@@ -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
#include
#include
+
+#include "..\..\..\include\keymancontrol.h"
\ No newline at end of file
diff --git a/windows/src/engine/keymanhp/keymanhp.vcxproj b/windows/src/engine/keymanhp/keymanhp.vcxproj
index 3aedb14b70..37e63c2707 100644
--- a/windows/src/engine/keymanhp/keymanhp.vcxproj
+++ b/windows/src/engine/keymanhp/keymanhp.vcxproj
@@ -280,6 +280,7 @@
true
+
diff --git a/windows/src/engine/keymanhp/keymanhp.vcxproj.filters b/windows/src/engine/keymanhp/keymanhp.vcxproj.filters
index 7c736dcc17..65eddfbff0 100644
--- a/windows/src/engine/keymanhp/keymanhp.vcxproj.filters
+++ b/windows/src/engine/keymanhp/keymanhp.vcxproj.filters
@@ -32,6 +32,9 @@
Header Files
+
+ Header Files
+
diff --git a/windows/src/global/delphi/general/KeymanControlMessages.pas b/windows/src/global/delphi/general/KeymanControlMessages.pas
index 601abee40a..ac143e2825 100644
--- a/windows/src/global/delphi/general/KeymanControlMessages.pas
+++ b/windows/src/global/delphi/general/KeymanControlMessages.pas
@@ -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;