mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-21 13:27:53 +00:00
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:
commit
9b80c56810
21 changed files with 218 additions and 170 deletions
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue