From f1d9f5304863fee2afa012ba57fc977632b9bc20 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:32:39 +1000 Subject: [PATCH 01/22] feat(windows): add right modifier included in HotKey --- windows/src/desktop/kmshell/xml/strings.xml | 16 +++--- .../keyman32/k32_lowlevelkeyboardhook.cpp | 52 +++++++++++++++++++ .../engine/kmcomapi/util/utilkeymanoption.pas | 3 +- .../delphi/general/KeymanOptionNames.pas | 5 +- 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/windows/src/desktop/kmshell/xml/strings.xml b/windows/src/desktop/kmshell/xml/strings.xml index 774a4d5e42..e15ba78945 100644 --- a/windows/src/desktop/kmshell/xml/strings.xml +++ b/windows/src/desktop/kmshell/xml/strings.xml @@ -377,6 +377,11 @@ Simulate AltGr with Ctrl+Alt + + + + Right Modifier keys work with Hotkeys + @@ -792,18 +797,13 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to - Keyman + Keyman Start Keyman - - - - Start %1$s - @@ -860,7 +860,7 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to - Keyman + Keyman @@ -1026,7 +1026,7 @@ keyboard that you use in Windows. Keyman keyboards will adapt automatically to - Keyman + Keyman diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index 8e3fe92a3c..4d842401dd 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -129,6 +129,27 @@ BOOL IsTouchPanelVisible() { return touchPanelVisible; } +/* + Cache UseRightModifierHotKey debug flag for this session +*/ +BOOL UseRightModifierHotKey() { + static BOOL flag_UseRightModifierHotKey = FALSE; + static BOOL loaded = FALSE; + + if (!loaded) { + RegistryReadOnly reg(HKEY_CURRENT_USER); + if (reg.OpenKeyReadOnly(REGSZ_KeymanCU)) { + if (reg.ValueExists(REGSZ_UseRightModifierHotKey)) { + flag_UseRightModifierHotKey = !!reg.ReadInteger(REGSZ_UseRightModifierHotKey); + } + } + loaded = TRUE; // Set loaded to TRUE whether or not the key exists + } + return flag_UseRightModifierHotKey; +} + + + LRESULT _kmnLowLevelKeyboardProc( _In_ int nCode, _In_ WPARAM wParam, @@ -157,6 +178,37 @@ LRESULT _kmnLowLevelKeyboardProc( if (GetKeyState(VK_RMENU) < 0) FHotkeyShiftState |= HK_RALT_INVALID; if (GetKeyState(VK_LSHIFT) < 0) FHotkeyShiftState |= HK_SHIFT; if (GetKeyState(VK_RSHIFT) < 0) FHotkeyShiftState |= HK_RSHIFT_INVALID; + + if (GetKeyState(VK_LCONTROL) < 0) { + FHotkeyShiftState |= HK_CTRL; + // TODO remove + SendDebugMessageFormat("ProcessHotkey VK_LCONTROL [vkCode:%x isUp:%d FHotkeyShiftState:%x useRight:%d", hs->vkCode, isUp, FHotkeyShiftState, UseRightModifierHotKey()); + } + + if (GetKeyState(VK_RCONTROL) < 0) { + FHotkeyShiftState |= UseRightModifierHotKey() ? HK_CTRL : HK_RCTRL_INVALID; + // TODO remove + SendDebugMessageFormat("ProcessHotkey VK_RCONTROL [vkCode:%x isUp:%d FHotkeyShiftState:%x useRight:%d", hs->vkCode, isUp, FHotkeyShiftState, UseRightModifierHotKey()); + } + + if (GetKeyState(VK_LMENU) < 0) { + FHotkeyShiftState |= HK_ALT; + } + + if (GetKeyState(VK_RMENU) < 0) { + FHotkeyShiftState |= UseRightModifierHotKey() ? HK_ALT : HK_RALT_INVALID; + } + + if (GetKeyState(VK_LSHIFT) < 0) { + FHotkeyShiftState |= HK_SHIFT; + } + if (GetKeyState(VK_RSHIFT) < 0) { + FHotkeyShiftState |= UseRightModifierHotKey() ? HK_SHIFT : HK_RSHIFT_INVALID; + } + + + + //TODO: #8064. Can remove debug message once issue #8064 is resolved SendDebugMessageFormat("!UseCachedHotkeyModifierState [FHotkeyShiftState:%x]", FHotkeyShiftState); diff --git a/windows/src/engine/kmcomapi/util/utilkeymanoption.pas b/windows/src/engine/kmcomapi/util/utilkeymanoption.pas index ce1b8af33a..2df38b5c82 100644 --- a/windows/src/engine/kmcomapi/util/utilkeymanoption.pas +++ b/windows/src/engine/kmcomapi/util/utilkeymanoption.pas @@ -121,12 +121,13 @@ type GroupName: string; end; -const KeymanOptionInfo: array[0..15] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552 +const KeymanOptionInfo: array[0..16] of TKeymanOptionInfo = ( // I3331 // I3620 // I4552 // Global options (opt: koKeyboardHotkeysAreToggle; RegistryName: SRegValue_KeyboardHotkeysAreToggle; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'), (opt: koSwitchLanguageForAllApplications; RegistryName: SRegValue_SwitchLanguageForAllApplications; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), // I2277 // I4393 (opt: koAltGrCtrlAlt; RegistryName: SRegValue_AltGrCtrlAlt; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'), + (opt: koRightModifierHK; RegistryName: SRegValue_UseRightModifierHotKey; OptionType: kotBool; BoolValue: False; GroupName: 'kogGeneral'), (opt: koShowHints; RegistryName: SRegValue_EnableHints; OptionType: kotBool; BoolValue: True; GroupName: 'kogGeneral'), (opt: koBaseLayout; RegistryName: SRegValue_UnderlyingLayout; OptionType: kotLong; IntValue: 0; GroupName: 'kogGeneral'), diff --git a/windows/src/global/delphi/general/KeymanOptionNames.pas b/windows/src/global/delphi/general/KeymanOptionNames.pas index 27aef82ab5..73356d19cb 100644 --- a/windows/src/global/delphi/general/KeymanOptionNames.pas +++ b/windows/src/global/delphi/general/KeymanOptionNames.pas @@ -5,7 +5,10 @@ interface type TUtilKeymanOption = ( // General options - koKeyboardHotkeysAreToggle, koAltGrCtrlAlt, koReleaseShiftKeysAfterKeyPress, + koKeyboardHotkeysAreToggle, + koAltGrCtrlAlt, + koRightModifierHK, + koReleaseShiftKeysAfterKeyPress, koShowHints, // I1256 // Startup options koTestKeymanFunctioning, From 2927f57c04fc779d917149ea9fda2ebcddfa9d3c Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:41:31 +1000 Subject: [PATCH 02/22] feat(windows): missed checked in file --- common/windows/delphi/general/RegistryKeys.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/common/windows/delphi/general/RegistryKeys.pas b/common/windows/delphi/general/RegistryKeys.pas index 1557de5865..0553b82306 100644 --- a/common/windows/delphi/general/RegistryKeys.pas +++ b/common/windows/delphi/general/RegistryKeys.pas @@ -115,6 +115,7 @@ const SRegValue_AltGrCtrlAlt = 'simulate altgr'; // CU SRegValue_KeyboardHotKeysAreToggle = 'hotkeys are toggles'; // CU + SRegValue_UseRightModifierHotKey = 'use right modifier for hotkey'; // CU SRegValue_ReleaseShiftKeysAfterKeyPress = 'release shift keys after key press'; // CU SRegValue_TestKeymanFunctioning = 'test keyman functioning'; // CU, default true From 558636886c7a776fcd6eeb3791efae29d432c6d6 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Mon, 26 Aug 2024 19:39:47 +1000 Subject: [PATCH 03/22] feat(windows): remove left modifier only bit flag --- windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index 4d842401dd..e33a610e61 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -172,12 +172,6 @@ LRESULT _kmnLowLevelKeyboardProc( // #5190: Don't cache modifier state because sometimes we won't receive // modifier change events (e.g. on lock screen) FHotkeyShiftState = 0; - if (GetKeyState(VK_LCONTROL) < 0) FHotkeyShiftState |= HK_CTRL; - if (GetKeyState(VK_RCONTROL) < 0) FHotkeyShiftState |= HK_RCTRL_INVALID; - if (GetKeyState(VK_LMENU) < 0) FHotkeyShiftState |= HK_ALT; - if (GetKeyState(VK_RMENU) < 0) FHotkeyShiftState |= HK_RALT_INVALID; - if (GetKeyState(VK_LSHIFT) < 0) FHotkeyShiftState |= HK_SHIFT; - if (GetKeyState(VK_RSHIFT) < 0) FHotkeyShiftState |= HK_RSHIFT_INVALID; if (GetKeyState(VK_LCONTROL) < 0) { FHotkeyShiftState |= HK_CTRL; @@ -207,8 +201,6 @@ LRESULT _kmnLowLevelKeyboardProc( } - - //TODO: #8064. Can remove debug message once issue #8064 is resolved SendDebugMessageFormat("!UseCachedHotkeyModifierState [FHotkeyShiftState:%x]", FHotkeyShiftState); From 930221376c09d8004c81ba22f55a7b25d31b28d5 Mon Sep 17 00:00:00 2001 From: Shawn Schantz Date: Tue, 27 Aug 2024 04:19:51 +0700 Subject: [PATCH 04/22] fix(mac): show package info after keyboard install Move to updated APIs that no longer require window dismissal. Fixes: #9308 --- .../Keyman4MacIM/KMInputMethodAppDelegate.m | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 9189e39d58..0482f78432 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -1119,14 +1119,16 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef * TODO: this should really be refactored */ -- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { - NSButton *button = (NSButton *)[alert.buttons objectAtIndex:0]; - if (button.tag == -1) { +- (void)downloadComplete:(NSModalResponse) returnCode { + os_log_debug([KMLogs uiLog], "downloadComplete, NSModalResponse returnCode: %ld", (long)returnCode); + if (returnCode == NSModalResponseCancel) { + os_log_debug([KMLogs uiLog], "downloadComplete, returnCode == NSModalResponseCancel"); [_connection cancel]; } - else if (button.tag == 1) { - [_downloadKBWindow close]; + else if (returnCode == NSModalResponseOK) { + os_log_debug([KMLogs uiLog], "downloadComplete, returnCode == NSModalResponseOK"); if (self.configWindow.window != nil) { + os_log_debug([KMLogs uiLog], "downloadComplete, self.configWindow.window != nil"); [self.configWindow.window makeKeyAndOrderFront:nil]; if (![[self.configWindow.window childWindows] containsObject:self.infoWindow.window]) { [self.configWindow.window addChildWindow:self.infoWindow.window ordered:NSWindowAbove]; @@ -1135,6 +1137,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [self.infoWindow.window makeKeyAndOrderFront:nil]; } else { + os_log_debug([KMLogs uiLog], "downloadComplete, self.configWindow.window == nil"); [self.infoWindow.window centerInParent]; [self.infoWindow.window makeKeyAndOrderFront:nil]; [self.infoWindow.window setLevel:NSFloatingWindowLevel]; @@ -1152,6 +1155,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSAlert *)downloadInfoView { + os_log_debug([KMLogs uiLog], "downloadInfoView"); if (_downloadInfoView == nil) { _downloadInfoView = [[NSAlert alloc] init]; [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; @@ -1165,6 +1169,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (NSProgressIndicator *)progressIndicator { + os_log_debug([KMLogs uiLog], "progressIndicator"); if (_progressIndicator == nil) { _progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, 300, 20)]; [_progressIndicator setIndeterminate:NO]; @@ -1186,36 +1191,39 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef - (void)downloadKeyboardFromURL:(NSURL *)url { NSURL* downloadUrl = url; - + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, url.path: %{public}@", url.path); + if (downloadUrl && _downloadFilename) { if (_infoWindow.window != nil) [_infoWindow close]; [self.downloadInfoView setInformativeText:self.downloadFilename]; + if (self.configWindow.window != nil) { + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, self.configWindow.window != nil"); [self.configWindow.window makeKeyAndOrderFront:nil]; if (![[self.configWindow.window childWindows] containsObject:self.downloadKBWindow.window]) { [self.configWindow.window addChildWindow:self.downloadKBWindow.window ordered:NSWindowAbove]; } [self.downloadKBWindow.window centerInParent]; [self.downloadKBWindow.window makeKeyAndOrderFront:nil]; - [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; + [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window completionHandler:^(NSModalResponse returnCode) { + [self downloadComplete:returnCode]; + }]; } else { + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, self.configWindow.window == nil"); [self.downloadKBWindow.window centerInParent]; [self.downloadKBWindow.window makeKeyAndOrderFront:nil]; [self.downloadKBWindow.window setLevel:NSFloatingWindowLevel]; - [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; + [self.downloadInfoView beginSheetModalForWindow:self.downloadKBWindow.window completionHandler:^(NSModalResponse returnCode) { + [self downloadComplete:returnCode]; + }]; } if (_connection == nil) { - [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; + os_log_debug([KMLogs uiLog], "downloadKeyboardFromURL, _connection == nil, set button title cancel downloading, tag = -1"); + [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-downloading", nil)]; NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; [button setTitle:NSLocalizedString(@"button-cancel-downloading", nil)]; [button setTag:-1]; @@ -1257,6 +1265,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { + os_log_debug([KMLogs uiLog], "connectionDidFinishLoading"); NSString *filePath = [self.keyboardsPath stringByAppendingPathComponent:self.downloadFilename]; [self.receivedData writeToFile:filePath atomically:YES]; [self unzipFile:filePath]; @@ -1264,6 +1273,7 @@ CGEventRef eventTapFunction(CGEventTapProxy proxy, CGEventType type, CGEventRef [_downloadInfoView setMessageText:NSLocalizedString(@"message-keyboard-download-complete", nil)]; NSButton *button = (NSButton *)[_downloadInfoView.buttons objectAtIndex:0]; + os_log_debug([KMLogs uiLog], "connectionDidFinishLoading, set button title download complete, tag = 1"); [button setTitle:NSLocalizedString(@"button-download-complete", nil)]; [button setTag:1]; [[NSNotificationCenter defaultCenter] postNotificationName:kKeymanKeyboardDownloadCompletedNotification From 500c800bb495ab44db66e3b4558cd40224230f1e Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:01:50 +1000 Subject: [PATCH 05/22] feat(windows): remove developer debug logging --- common/windows/cpp/include/registry.h | 2 +- windows/src/desktop/kmshell/xml/strings.xml | 4 ++-- windows/src/engine/keyman32/hotkeys.cpp | 2 -- .../keyman32/k32_lowlevelkeyboardhook.cpp | 24 ++++--------------- 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/common/windows/cpp/include/registry.h b/common/windows/cpp/include/registry.h index c6d1bf85ec..842176e9ed 100644 --- a/common/windows/cpp/include/registry.h +++ b/common/windows/cpp/include/registry.h @@ -110,7 +110,7 @@ #define REGSZ_KeyboardHotkeysAreToggle "hotkeys are toggles" #define REGSZ_DeadkeyConversionMode "deadkey conversion mode" // CU // I4552 #define REGSZ_ZapVirtualKeyCode "zap virtual key code" // LM, defaults to 0x0E (_VK_PREFIX_DEFAULT) -/* Non-chiral use of hotkeys instead of left-only hotkeys */ +/* Default is to only use left modifier in hotkeys trigger */ #define REGSZ_UseRightModifierHotKey "use right modifier for hotkey" diff --git a/windows/src/desktop/kmshell/xml/strings.xml b/windows/src/desktop/kmshell/xml/strings.xml index ea09ca5b74..9409d6d8c1 100644 --- a/windows/src/desktop/kmshell/xml/strings.xml +++ b/windows/src/desktop/kmshell/xml/strings.xml @@ -379,8 +379,8 @@ - - Right Modifier keys work with Hotkeys + + Right-side modifier keys trigger hotkeys diff --git a/windows/src/engine/keyman32/hotkeys.cpp b/windows/src/engine/keyman32/hotkeys.cpp index e7fdbe3d79..1652397d77 100644 --- a/windows/src/engine/keyman32/hotkeys.cpp +++ b/windows/src/engine/keyman32/hotkeys.cpp @@ -139,8 +139,6 @@ Hotkey *Hotkeys::GetHotkey(DWORD hotkey) { for (int i = 0; i < m_nHotkeys; i++) { if (m_hotkeys[i].HotkeyValue == hotkey) { - SendDebugMessageFormat( - "LanguageHotkey[%d] = {HotkeyValue: %x, hkl: %x} passed in: %x", i, m_hotkeys[i].HotkeyValue, m_hotkeys[i].hkl, hotkey); return &m_hotkeys[i]; } } diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index e33a610e61..8e16d536f2 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -130,7 +130,7 @@ BOOL IsTouchPanelVisible() { } /* - Cache UseRightModifierHotKey debug flag for this session + Cache UseRightModifierHotKey for this session */ BOOL UseRightModifierHotKey() { static BOOL flag_UseRightModifierHotKey = FALSE; @@ -148,8 +148,6 @@ BOOL UseRightModifierHotKey() { return flag_UseRightModifierHotKey; } - - LRESULT _kmnLowLevelKeyboardProc( _In_ int nCode, _In_ WPARAM wParam, @@ -169,20 +167,14 @@ LRESULT _kmnLowLevelKeyboardProc( SendDebugMessageFormat("wparam: %x lparam: %x [vk:%s scan:%x flags:%x extra:%x]", wParam, lParam, Debug_VirtualKey((WORD) hs->vkCode), hs->scanCode, hs->flags, hs->dwExtraInfo); // I4674 - // #5190: Don't cache modifier state because sometimes we won't receive - // modifier change events (e.g. on lock screen) FHotkeyShiftState = 0; - if (GetKeyState(VK_LCONTROL) < 0) { + if (GetKeyState(VK_LCONTROL) < 0) { FHotkeyShiftState |= HK_CTRL; - // TODO remove - SendDebugMessageFormat("ProcessHotkey VK_LCONTROL [vkCode:%x isUp:%d FHotkeyShiftState:%x useRight:%d", hs->vkCode, isUp, FHotkeyShiftState, UseRightModifierHotKey()); } if (GetKeyState(VK_RCONTROL) < 0) { FHotkeyShiftState |= UseRightModifierHotKey() ? HK_CTRL : HK_RCTRL_INVALID; - // TODO remove - SendDebugMessageFormat("ProcessHotkey VK_RCONTROL [vkCode:%x isUp:%d FHotkeyShiftState:%x useRight:%d", hs->vkCode, isUp, FHotkeyShiftState, UseRightModifierHotKey()); } if (GetKeyState(VK_LMENU) < 0) { @@ -200,10 +192,8 @@ LRESULT _kmnLowLevelKeyboardProc( FHotkeyShiftState |= UseRightModifierHotKey() ? HK_SHIFT : HK_RSHIFT_INVALID; } - - //TODO: #8064. Can remove debug message once issue #8064 is resolved - SendDebugMessageFormat("!UseCachedHotkeyModifierState [FHotkeyShiftState:%x]", FHotkeyShiftState); - + //TODO: #8064. Can remove debug message once issue #8064 is resolved + SendDebugMessageFormat("!UseCachedHotkeyModifierState [FHotkeyShiftState:%x]", FHotkeyShiftState); // #7337 Post the modifier state ensuring the serialized queue is in sync // Note that the modifier key may be posted again with WM_KEYMAN_KEY_EVENT, @@ -287,30 +277,24 @@ BOOL ProcessHotkey(UINT vkCode, BOOL isUp, DWORD ShiftState) { Hotkeys *hotkeys = Hotkeys::Instance(); // I4641 if (!hotkeys) { - SendDebugMessageFormat("Failed to get Instance"); return FALSE; } Hotkey *hotkey = hotkeys->GetHotkey(ShiftState | vkCode); // I4641 if (!hotkey) { - SendDebugMessageFormat("GetHotkey Null"); return FALSE; } if (isUp) { - SendDebugMessageFormat("Is Up"); return TRUE; } if (hotkey->HotkeyType == hktInterface) { - SendDebugMessageFormat("PostMasterController"); Globals::PostMasterController(wm_keyman_control, MAKELONG(KMC_INTERFACEHOTKEY, hotkey->Target), 0); } else { - SendDebugMessageFormat("ReportKeyboardChanged"); ReportKeyboardChanged(PC_HOTKEYCHANGE, hotkey->hkl == 0 ? TF_PROFILETYPE_INPUTPROCESSOR : TF_PROFILETYPE_KEYBOARDLAYOUT, 0, hotkey->hkl, GUID_NULL, hotkey->profileGUID); } - SendDebugMessageFormat("PostDummyKeyEvent"); /* Generate a dummy keystroke to block menu activations, etc but let the shift key through */ PostDummyKeyEvent(); // I3301 - this is imperfect because we don't deal with HC_NOREMOVE. But good enough? // I3534 // I4844 From 569a8a8a49f14c6153d688dd39787c1780b1b7d3 Mon Sep 17 00:00:00 2001 From: sgschantz Date: Thu, 29 Aug 2024 15:38:00 +0700 Subject: [PATCH 06/22] fix(mac): eliminate all use of deprecated API beginSheetModalForWindow beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo: was deprecated in macOS 10.10 and replaced by beginSheetModalForWindow:completionHandler: The newer API automatically closes the sheet. Explicitly closing the sheet also seemed to be causing the parent windows to close. Fixes: #9308 --- .../KMConfigurationWindowController.m | 43 +++++++++++-------- .../KMInfoWindow/KMInfoWindowController.m | 2 - .../Keyman4MacIM/KMInputMethodAppDelegate.m | 4 +- .../Keyman4MacIM/KMPackageReader.m | 7 --- mac/Keyman4MacIM/Keyman4MacIM/KeySender.m | 11 ++--- .../KME/OnScreenKeyboard/KeyView.m | 8 +++- .../KME/OnScreenKeyboard/OSKKey.m | 5 ++- .../KME/OnScreenKeyboard/OSKView.m | 2 +- 8 files changed, 43 insertions(+), 39 deletions(-) diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m index 3e2ffe2410..4a5f194241 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMConfiguration/KMConfigurationWindowController.m @@ -398,8 +398,8 @@ } - (void)removeAction:(id)sender { - NSButton *removeButton = (NSButton *)sender; - NSDictionary *info = [self.tableContents objectAtIndex:removeButton.tag]; + NSButton *deleteButton = (NSButton *)sender; + NSDictionary *info = [self.tableContents objectAtIndex:deleteButton.tag]; NSString *deleteKeyboardMessage = NSLocalizedString(@"message-confirm-delete-keyboard", nil); if ([info objectForKey:@"HeaderTitle"] != nil) @@ -407,10 +407,13 @@ else [self.deleteAlertView setMessageText:[NSString localizedStringWithFormat:deleteKeyboardMessage, [info objectForKey:kKMKeyboardNameKey]]]; - [self.deleteAlertView beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:(__bridge void *)([NSNumber numberWithInteger:removeButton.tag])]; + [self.deleteAlertView beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) { + if (returnCode == NSAlertFirstButtonReturn) { + os_log_debug([KMLogs uiLog], "confirm delete keyboard alert dismissed"); + [self deleteFileAtIndex:[NSNumber numberWithInteger:deleteButton.tag]]; + self.deleteAlertView = nil; + } + }]; } - (IBAction)downloadAction:(id)sender { @@ -438,25 +441,29 @@ } - (void)handleRequestToInstallPackage:(KMPackage *) package { + os_log_debug([KMLogs dataLog], "handleRequestToInstallPackage"); NSString *keyboardInfoString = NSLocalizedString(@"info-install-keyboard-filename", nil); [self.confirmKmpInstallAlertView setInformativeText:[NSString localizedStringWithFormat:keyboardInfoString, package.getOrigKmpFilename]]; os_log_debug([KMLogs uiLog], "Asking user to confirm installation of %{public}@, KMP - temp file name: %{public}@", package.getOrigKmpFilename, package.getTempKmpFilename); - [self.confirmKmpInstallAlertView beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:(__bridge void *)(package)]; + [self.confirmKmpInstallAlertView beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) { + os_log_debug([KMLogs uiLog], "confirm keyboard installation alert dismissed"); + if (returnCode == NSAlertFirstButtonReturn) { + [self installPackageFile: package.getTempKmpFilename]; + self.confirmKmpInstallAlertView = nil; + } + }]; } - (void)installPackageFile:(NSString *)kmpFile { // kmpFile could be a temp file (in fact, it always is!), so don't display the name. - - os_log_debug([KMLogs dataLog], "KMP - Ready to unzip/install Package File: %{public}@", kmpFile); + os_log_debug([KMLogs dataLog], "kmpFile - ready to unzip/install Package File: %{public}@", kmpFile); BOOL didUnzip = [self.AppDelegate unzipFile:kmpFile]; if (!didUnzip) { + os_log_debug([KMLogs dataLog], "kmpFile, unzipFile failed"); NSAlert *failure = [[NSAlert alloc] init]; [failure addButtonWithTitle:NSLocalizedString(@"button-keyboard-file-unreadable", @"Alert button")]; @@ -465,13 +472,12 @@ [failure setIcon:[[NSBundle mainBundle] imageForResource:@"logo.png"]]; [failure setAlertStyle:NSAlertStyleWarning]; - [failure beginSheetModalForWindow:self.window - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; + [failure beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) { + os_log_debug([KMLogs uiLog], "kmpFile, keyboard file unreadable alert dismissed with returnCode: %ld", (long)returnCode); + }]; } else { - os_log_debug([KMLogs dataLog], "Completed installation of KMP file."); + os_log_debug([KMLogs dataLog], "kmpFile, completed installation of KMP file"); } } @@ -547,6 +553,7 @@ return _confirmKmpInstallAlertView; } +/* - (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { os_log_debug([KMLogs uiLog], "User responded to NSAlert"); if (alert == _deleteAlertView) { @@ -568,7 +575,7 @@ } // else, just a message - nothing to do. } - +*/ - (void)deleteFileAtIndex:(NSNumber *) n { NSInteger index = [n integerValue]; NSString *path2Remove = nil; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m index 6be446ddd2..32a8377b64 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInfoWindow/KMInfoWindowController.m @@ -85,8 +85,6 @@ // TODO: refactor: any reason for this to be HTML? hard to read stringWithFormat applied to template with 16 arguments - (NSString *)detailsHtml { - NSString *errorString = NSLocalizedString(@"message-keyboard-file-unreadable", nil); - @try { NSString *htmlFormat = @"" diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m index 0482f78432..d95982687b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMInputMethodAppDelegate.m @@ -1340,7 +1340,9 @@ extern const CGKeyCode kProcessPendingBuffer; NSError *error = nil; NSString *fileName = filePath.lastPathComponent; NSString *folderName = [fileName stringByDeletingPathExtension]; - + + os_log_debug([KMLogs keyboardLog], "unzipFile for filePath: %{public}@", filePath); + // First we unzip into a temp folder, and check kmp.json for the fileVersion // before we continue installation. We don't want to overwrite existing // package if it is there if the files are not compatible with the installed diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m index 7406488a8a..6ee4402cb9 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KMPackageReader.m @@ -251,14 +251,12 @@ typedef enum { NSString *s = [line substringFromIndex:kName.length+1]; NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; builder.packageName = v1; } else if ([[line lowercaseString] hasPrefix:[kVersion lowercaseString]]) { NSString *s = [line substringFromIndex:kVersion.length+1]; NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; builder.packageVersion = v1; } else if ([[line lowercaseString] hasPrefix:[kAuthor lowercaseString]]) { @@ -273,14 +271,12 @@ typedef enum { NSString *s = [line substringFromIndex:kCopyright.length+1]; NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; builder.copyright = v1; } else if ([[line lowercaseString] hasPrefix:[kWebSite lowercaseString]]) { NSString *s = [line substringFromIndex:kWebSite.length+1]; NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *v1 = [[vs objectAtIndex:0] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *v2 = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; builder.website = v1; } @@ -294,20 +290,17 @@ typedef enum { NSString *s = [line substringFromIndex:x+2]; if ([[s lowercaseString] hasPrefix:[kFile lowercaseString]]) { NSArray *vs = [s componentsSeparatedByString:@"\","]; - NSString *v1 = [[[vs objectAtIndex:0] substringFromIndex:kFile.length+1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; NSString *fileName = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; [files addObject:fileName]; } else if ([[s lowercaseString] hasPrefix:[kFont lowercaseString]]) { NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *fontName = [[[vs objectAtIndex:0] substringFromIndex:kFont.length+1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *fontFileName = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; [fontArray addObject:fontName]; } else if ([[s lowercaseString] hasPrefix:[kKeyboard lowercaseString]]) { NSArray *vs = [s componentsSeparatedByString:@"\","]; NSString *keyboardName = [[[vs objectAtIndex:0] substringFromIndex:kKeyboard.length+1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; - NSString *keyboardFileName = [[vs objectAtIndex:1] stringByReplacingOccurrencesOfString:@"\"" withString:@""]; KMKeyboardInfoBuilder *builder = [[KMKeyboardInfoBuilder alloc] init]; builder.name = keyboardName; diff --git a/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m b/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m index 417475c777..dc73edc11b 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/KeySender.m @@ -1,9 +1,6 @@ /** * Keyman is copyright (C) SIL International. MIT License. * - * KeySender.m - * Keyman - * * Created by Shawn Schantz on 2023-04-17. * * Sends keydown events for the provided keycode to the frontmost application. @@ -56,15 +53,13 @@ const CGKeyCode kKeymanEventKeyCode = 0xFF; } /** - sendKeymanKeyCodeForEvent sends the kKeymanEventKeyCode to the - frontmost application to indicate that all the backspaces have been processed - and we can insert the queuedText to the client + * sendKeymanKeyCodeForEvent sends the kKeymanEventKeyCode to the + * frontmost application to indicate that all the backspaces have been processed + * and we can insert the queuedText to the client */ - (void)sendKeymanKeyCodeForEvent:(NSEvent *)event { os_log_debug([KMLogs keyLog], "KeySender sendKeymanKeyCodeForEvent"); - - ProcessSerialNumber psn; // Returns the frontmost app, which is the app that receives key events. NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication; diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m index c1dfa75a87..9dfd39856b 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/KeyView.m @@ -41,7 +41,10 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f; - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { - os_log_debug([KMELogs oskLog], "KeyView initWithFrame: %{public}@, bounds: %{public}@, default clipsToBounds %{public}@", NSStringFromRect(frame), NSStringFromRect(self.bounds), self.clipsToBounds?@"YES":@"NO"); + /* + // usually too much, but uncomment for debugging + os_log_debug([KMELogs oskLog], "KeyView initWithFrame: %{public}@, bounds: %{public}@, default clipsToBounds %{public}@", NSStringFromRect(frame), NSStringFromRect(self.bounds), self.clipsToBounds?@"YES":@"NO"); + */ self.clipsToBounds = true; CGSize size = frame.size; CGFloat x = size.width*0.05; @@ -70,7 +73,10 @@ static CGFloat const kRelativeModifierLabelHeight = 0.30f; } - (void)drawRect:(NSRect)rect { + /* + // usually too much, but uncomment for debugging os_log_debug([KMELogs uiLog], "KeyView drawRect: %{public}@, bounds: %{public}@, keyCode: 0x%lx, caption: %{public}@, label: %{public}@", NSStringFromRect(rect), NSStringFromRect(self.bounds), self.keyCode, self.caption.stringValue, self.label.stringValue); + */ [[self getOpaqueColorWithRed:241 green:242 blue:242] setFill]; NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver); diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m index d81097d3e2..7ff40ccffe 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKKey.m @@ -14,7 +14,10 @@ - (id)initWithKeyCode:(NSUInteger)keyCode caption:(NSString *)caption scale:(CGFloat)scale { self = [super init]; if (self) { - os_log_debug([KMELogs oskLog], "OSKKey initWithKeyCode: 0x%lx, caption: %{public}@, scale: %f", keyCode, caption, scale); + /* + // usually too much, but uncomment for debugging + os_log_debug([KMELogs oskLog], "OSKKey initWithKeyCode: 0x%lx, caption: %{public}@, scale: %f", keyCode, caption, scale); + */ _keyCode = keyCode; if (caption == nil) diff --git a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m index f5154fa76d..512920e052 100644 --- a/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m +++ b/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m @@ -43,7 +43,7 @@ } - (void)drawRect:(NSRect)rect { - os_log_debug([KMELogs uiLog], "OSKView drawRect: %{public}@", NSStringFromRect(rect)); + os_log_debug([KMELogs oskLog], "OSKView drawRect: %{public}@", NSStringFromRect(rect)); CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext]; CGContextSetLineJoin(context, kCGLineJoinRound); From 028a03c998f1a781816ee9ff71c2415a720457c7 Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Thu, 29 Aug 2024 22:22:12 +1000 Subject: [PATCH 07/22] feat(windows): add sil global strings --- oem/firstvoices/windows/src/xml/keyman_support.xsl | 12 ++++++++++-- oem/firstvoices/windows/src/xml/strings.xml | 10 ++++++++++ windows/src/desktop/kmshell/xml/keyman_support.xsl | 12 ++++++++++-- windows/src/desktop/kmshell/xml/strings.xml | 10 ++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/oem/firstvoices/windows/src/xml/keyman_support.xsl b/oem/firstvoices/windows/src/xml/keyman_support.xsl index dfd8c8445b..81f72fdb66 100644 --- a/oem/firstvoices/windows/src/xml/keyman_support.xsl +++ b/oem/firstvoices/windows/src/xml/keyman_support.xsl @@ -32,11 +32,19 @@
- + + + + +
- + + + + +