From dc533fbdb3591f57744c8659d2d6f553514dc5df Mon Sep 17 00:00:00 2001 From: Zach Teutsch <88554871+zateutsch@users.noreply.github.com> Date: Thu, 26 Mar 2026 13:20:50 -0400 Subject: [PATCH] [Keyboard Manager] Remove service enable/disable separate from module, fix editor clear shortcut (#46530) Two changes to shortcuts here: 1) Remove toggling the KBM service with a shortcut or via command palette 2) Ensure that shortcut is disabled for editor when shortcut is cleared --- src/common/interop/Constants.cpp | 4 - src/common/interop/Constants.h | 1 - src/common/interop/Constants.idl | 1 - src/common/interop/shared_constants.h | 1 - .../ToggleKeyboardManagerListeningCommand.cs | 24 --- .../Helpers/KeyboardManagerStateService.cs | 15 -- .../Helpers/PowerToysResourcesHelper.cs | 5 - .../KeyboardManagerModuleCommandProvider.cs | 13 -- .../Properties/Resources.resx | 12 -- src/modules/keyboardmanager/dll/dllmain.cpp | 137 +++--------------- .../KeyboardManagerProperties.cs | 5 - .../KeyboardManagerSettings.cs | 4 - .../Views/KeyboardManagerPage.xaml | 20 +-- .../Settings.UI/Strings/en-us/Resources.resw | 6 - .../ViewModels/KeyboardManagerViewModel.cs | 24 +-- 15 files changed, 27 insertions(+), 245 deletions(-) delete mode 100644 src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Commands/KeyboardManager/ToggleKeyboardManagerListeningCommand.cs diff --git a/src/common/interop/Constants.cpp b/src/common/interop/Constants.cpp index 8a2c672a88..e25f98a806 100644 --- a/src/common/interop/Constants.cpp +++ b/src/common/interop/Constants.cpp @@ -300,10 +300,6 @@ namespace winrt::PowerToys::Interop::implementation { return CommonSharedConstants::OPEN_NEW_KEYBOARD_MANAGER_EVENT; } - hstring Constants::ToggleKeyboardManagerActiveEvent() - { - return CommonSharedConstants::TOGGLE_KEYBOARD_MANAGER_ACTIVE_EVENT; - } hstring Constants::KeyboardManagerEngineInstanceMutex() { return CommonSharedConstants::KEYBOARD_MANAGER_ENGINE_INSTANCE_MUTEX; diff --git a/src/common/interop/Constants.h b/src/common/interop/Constants.h index 575c7673e2..ab5d8afdbf 100644 --- a/src/common/interop/Constants.h +++ b/src/common/interop/Constants.h @@ -78,7 +78,6 @@ namespace winrt::PowerToys::Interop::implementation static hstring MWBToggleEasyMouseEvent(); static hstring MWBReconnectEvent(); static hstring OpenNewKeyboardManagerEvent(); - static hstring ToggleKeyboardManagerActiveEvent(); static hstring KeyboardManagerEngineInstanceMutex(); }; } diff --git a/src/common/interop/Constants.idl b/src/common/interop/Constants.idl index 91883a050e..a19bc33f85 100644 --- a/src/common/interop/Constants.idl +++ b/src/common/interop/Constants.idl @@ -75,7 +75,6 @@ namespace PowerToys static String MWBToggleEasyMouseEvent(); static String MWBReconnectEvent(); static String OpenNewKeyboardManagerEvent(); - static String ToggleKeyboardManagerActiveEvent(); static String KeyboardManagerEngineInstanceMutex(); } } diff --git a/src/common/interop/shared_constants.h b/src/common/interop/shared_constants.h index 72e3155e1f..535af74556 100644 --- a/src/common/interop/shared_constants.h +++ b/src/common/interop/shared_constants.h @@ -173,7 +173,6 @@ namespace CommonSharedConstants // Path to events used by Keyboard Manager const wchar_t OPEN_NEW_KEYBOARD_MANAGER_EVENT[] = L"Local\\PowerToysOpenNewKeyboardManagerEvent-9c1d2e3f-4b5a-6c7d-8e9f-0a1b2c3d4e5f"; - const wchar_t TOGGLE_KEYBOARD_MANAGER_ACTIVE_EVENT[] = L"Local\\PowerToysToggleKeyboardManagerActiveEvent-7f3a1d5c-2e94-4ff4-8b6a-90fd2bc4d2a7"; const wchar_t KEYBOARD_MANAGER_ENGINE_INSTANCE_MUTEX[] = L"Local\\PowerToys_KBMEngine_InstanceMutex"; // used from quick access window diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Commands/KeyboardManager/ToggleKeyboardManagerListeningCommand.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Commands/KeyboardManager/ToggleKeyboardManagerListeningCommand.cs deleted file mode 100644 index bbb2e45910..0000000000 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Commands/KeyboardManager/ToggleKeyboardManagerListeningCommand.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation -// The Microsoft Corporation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.CommandPalette.Extensions.Toolkit; -using PowerToysExtension.Helpers; -using PowerToysExtension.Properties; - -namespace PowerToysExtension.Commands; - -internal sealed partial class ToggleKeyboardManagerListeningCommand : InvokableCommand -{ - public ToggleKeyboardManagerListeningCommand() - { - Name = "Toggle Keyboard Manager active state"; - } - - public override CommandResult Invoke() - { - return KeyboardManagerStateService.TryToggleListening() - ? CommandResult.KeepOpen() - : CommandResult.ShowToast(Resources.ResourceManager.GetString("KeyboardManager_ToggleListening_Error", Resources.Culture) ?? "Keyboard Manager is unavailable. Try enabling it in PowerToys settings."); - } -} diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/KeyboardManagerStateService.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/KeyboardManagerStateService.cs index c2c139b60e..5f2f5e600e 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/KeyboardManagerStateService.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/KeyboardManagerStateService.cs @@ -43,21 +43,6 @@ internal static class KeyboardManagerStateService return false; } - internal static bool TryToggleListening() - { - try - { - using var evt = EventWaitHandle.OpenExisting(Constants.ToggleKeyboardManagerActiveEvent()); - var signaled = evt.Set(); - PollStatus(); - return signaled; - } - catch - { - return false; - } - } - private static void PollStatus() { var isListening = IsListening(); diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/PowerToysResourcesHelper.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/PowerToysResourcesHelper.cs index 5427263228..bdceae9058 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/PowerToysResourcesHelper.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Helpers/PowerToysResourcesHelper.cs @@ -14,11 +14,6 @@ internal static class PowerToysResourcesHelper internal static IconInfo IconFromSettingsIcon(string fileName) => IconHelpers.FromRelativePath($"{SettingsIconRoot}{fileName}"); - internal static IconInfo KeyboardManagerListeningIcon(bool isListening) => IconHelpers.FromRelativePath( - isListening - ? $"{AssetsRoot}KeyboardManager\\KeyboardManagerListeningOn.svg" - : $"{AssetsRoot}KeyboardManager\\KeyboardManagerListeningOff.svg"); - #if DEBUG public static IconInfo ProviderIcon() => IconFromSettingsIcon("PowerToys.dark.png"); #else diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Modules/KeyboardManagerModuleCommandProvider.cs b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Modules/KeyboardManagerModuleCommandProvider.cs index d36eafc1ee..0b3938526e 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Modules/KeyboardManagerModuleCommandProvider.cs +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Modules/KeyboardManagerModuleCommandProvider.cs @@ -22,19 +22,6 @@ internal sealed class KeyboardManagerModuleCommandProvider : ModuleCommandProvid var title = module.ModuleDisplayName(); var icon = module.ModuleIcon(); - if (ModuleEnablementService.IsModuleEnabled(module)) - { - var isListening = KeyboardManagerStateService.IsListening(); - yield return new ListItem(new ToggleKeyboardManagerListeningCommand() { Id = "com.microsoft.powertoys.keyboardManager.toggleListening" }) - { - Title = GetResourceString("KeyboardManager_ToggleListening_Title", "Keyboard Manager: Toggle active state"), - Subtitle = isListening - ? GetResourceString("KeyboardManager_ToggleListening_On_Subtitle", "Keyboard Manager is active. Invoke to stop listening.") - : GetResourceString("KeyboardManager_ToggleListening_Off_Subtitle", "Keyboard Manager is paused. Invoke to start listening."), - Icon = PowerToysResourcesHelper.KeyboardManagerListeningIcon(isListening), - }; - } - if (IsUseNewEditorEnabled()) { yield return new ListItem(new OpenNewKeyboardManagerEditorCommand() { Id = "com.microsoft.powertoys.keyboardManager.openNewEditor" }) diff --git a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Properties/Resources.resx b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Properties/Resources.resx index 77887afeb1..a1ccb8b82b 100644 --- a/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Properties/Resources.resx +++ b/src/modules/cmdpal/ext/Microsoft.CmdPal.Ext.PowerToys/Properties/Resources.resx @@ -414,18 +414,6 @@ Open the Keyboard Manager remap editor - - Keyboard Manager: Toggle active state - - - Keyboard Manager is active. Invoke to stop listening. - - - Keyboard Manager is paused. Invoke to start listening. - - - Keyboard Manager is unavailable. Try enabling it in PowerToys settings. - Light Switch: Toggle theme diff --git a/src/modules/keyboardmanager/dll/dllmain.cpp b/src/modules/keyboardmanager/dll/dllmain.cpp index 9756dbb103..5c5331f91d 100644 --- a/src/modules/keyboardmanager/dll/dllmain.cpp +++ b/src/modules/keyboardmanager/dll/dllmain.cpp @@ -38,7 +38,6 @@ namespace const wchar_t JSON_KEY_CTRL[] = L"ctrl"; const wchar_t JSON_KEY_SHIFT[] = L"shift"; const wchar_t JSON_KEY_CODE[] = L"code"; - const wchar_t JSON_KEY_ACTIVATION_SHORTCUT[] = L"ToggleShortcut"; const wchar_t JSON_KEY_EDITOR_SHORTCUT[] = L"EditorShortcut"; const wchar_t JSON_KEY_USE_NEW_EDITOR[] = L"useNewEditor"; } @@ -57,25 +56,21 @@ private: //contains the non localized key of the powertoy std::wstring app_key = KeyboardManagerConstants::ModuleName; - // Hotkey for toggling the module - Hotkey m_hotkey = { .key = 0 }; - // Hotkey for opening the editor Hotkey m_editorHotkey = { .key = 0 }; // Whether to use the new WinUI3 editor bool m_useNewEditor = false; - ULONGLONG m_lastHotkeyToggleTime = 0; + ULONGLONG m_lastHotkeyTime = 0; HANDLE m_hProcess = nullptr; HANDLE m_hEditorProcess = nullptr; HANDLE m_hTerminateEngineEvent = nullptr; HANDLE m_open_new_editor_event_handle{ nullptr }; - HANDLE m_toggle_active_event_handle{ nullptr }; - std::thread m_toggle_thread; - std::atomic m_toggle_thread_running{ false }; + std::thread m_editor_listener_thread; + std::atomic m_editor_listener_running{ false }; void refresh_process_state() @@ -88,19 +83,6 @@ private: } } - void toggle_engine() - { - refresh_process_state(); - if (m_active) - { - stop_engine(); - } - else - { - start_engine(); - } - } - bool start_engine() { refresh_process_state(); @@ -176,35 +158,9 @@ private: void parse_hotkey(PowerToysSettings::PowerToyValues& settings) { auto settingsObject = settings.get_raw_json(); - if (settingsObject.GetView().Size()) - { - try - { - auto jsonHotkeyObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES) - .GetNamedObject(JSON_KEY_ACTIVATION_SHORTCUT); - m_hotkey.win = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_WIN); - m_hotkey.alt = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_ALT); - m_hotkey.shift = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT); - m_hotkey.ctrl = jsonHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL); - m_hotkey.key = static_cast(jsonHotkeyObject.GetNamedNumber(JSON_KEY_CODE)); - } - catch (...) - { - Logger::error("Failed to initialize Keyboard Manager toggle shortcut"); - } - } - - if (!m_hotkey.key) - { - // Set default: Win+Shift+K - m_hotkey.win = true; - m_hotkey.shift = true; - m_hotkey.ctrl = false; - m_hotkey.alt = false; - m_hotkey.key = 'K'; - } // Parse editor shortcut + bool editorShortcutParsed = false; if (settingsObject.GetView().Size()) { try @@ -216,6 +172,7 @@ private: m_editorHotkey.shift = jsonEditorHotkeyObject.GetNamedBoolean(JSON_KEY_SHIFT); m_editorHotkey.ctrl = jsonEditorHotkeyObject.GetNamedBoolean(JSON_KEY_CTRL); m_editorHotkey.key = static_cast(jsonEditorHotkeyObject.GetNamedNumber(JSON_KEY_CODE)); + editorShortcutParsed = true; } catch (...) { @@ -223,9 +180,9 @@ private: } } - if (!m_editorHotkey.key) + if (!editorShortcutParsed && !m_editorHotkey.key) { - // Set default: Win+Shift+Q + // Set default: Win+Shift+Q (only when no setting exists) m_editorHotkey.win = true; m_editorHotkey.shift = true; m_editorHotkey.ctrl = false; @@ -287,7 +244,6 @@ public: } m_open_new_editor_event_handle = CreateDefaultEvent(CommonSharedConstants::OPEN_NEW_KEYBOARD_MANAGER_EVENT); - m_toggle_active_event_handle = CreateDefaultEvent(CommonSharedConstants::TOGGLE_KEYBOARD_MANAGER_ACTIVE_EVENT); init_settings(); }; @@ -306,11 +262,6 @@ public: CloseHandle(m_open_new_editor_event_handle); m_open_new_editor_event_handle = nullptr; } - if (m_toggle_active_event_handle) - { - CloseHandle(m_toggle_active_event_handle); - m_toggle_active_event_handle = nullptr; - } if (m_hEditorProcess) { CloseHandle(m_hEditorProcess); @@ -412,22 +363,12 @@ public: return false; } - // Return the invocation hotkeys for toggling and opening the editor + // Return the invocation hotkey for opening the editor virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override { size_t count = 0; - // Hotkey 0: toggle engine - if (m_hotkey.key) - { - if (hotkeys && buffer_size > count) - { - hotkeys[count] = m_hotkey; - } - count++; - } - - // Hotkey 1: open editor (only when using new editor) + // Hotkey 0: open editor (only when using new editor) if (m_useNewEditor && m_editorHotkey.key) { if (hotkeys && buffer_size > count) @@ -442,69 +383,44 @@ public: void StartOpenEditorListener() { - if (m_toggle_thread_running || (!m_open_new_editor_event_handle && !m_toggle_active_event_handle)) + if (m_editor_listener_running || !m_open_new_editor_event_handle) { return; } - m_toggle_thread_running = true; - m_toggle_thread = std::thread([this]() { - HANDLE handles[2]{}; - DWORD handle_count = 0; - DWORD open_editor_index = MAXDWORD; - DWORD toggle_active_index = MAXDWORD; - - if (m_open_new_editor_event_handle) + m_editor_listener_running = true; + m_editor_listener_thread = std::thread([this]() { + while (m_editor_listener_running) { - open_editor_index = handle_count; - handles[handle_count++] = m_open_new_editor_event_handle; - } - - if (m_toggle_active_event_handle) - { - toggle_active_index = handle_count; - handles[handle_count++] = m_toggle_active_event_handle; - } - - while (m_toggle_thread_running) - { - const DWORD wait_result = WaitForMultipleObjects(handle_count, handles, FALSE, 500); - if (!m_toggle_thread_running) + const DWORD wait_result = WaitForSingleObject(m_open_new_editor_event_handle, 500); + if (!m_editor_listener_running) { break; } - if (open_editor_index != MAXDWORD && wait_result == (WAIT_OBJECT_0 + open_editor_index)) + if (wait_result == WAIT_OBJECT_0) { launch_editor(); } - else if (toggle_active_index != MAXDWORD && wait_result == (WAIT_OBJECT_0 + toggle_active_index)) - { - toggle_engine(); - } } }); } void StopOpenEditorListener() { - if (!m_toggle_thread_running) + if (!m_editor_listener_running) { return; } - m_toggle_thread_running = false; + m_editor_listener_running = false; if (m_open_new_editor_event_handle) { SetEvent(m_open_new_editor_event_handle); } - if (m_toggle_active_event_handle) + if (m_editor_listener_thread.joinable()) { - SetEvent(m_toggle_active_event_handle); - } - if (m_toggle_thread.joinable()) - { - m_toggle_thread.join(); + m_editor_listener_thread.join(); } } @@ -584,22 +500,17 @@ public: return false; } - constexpr ULONGLONG hotkeyToggleDebounceMs = 500; + constexpr ULONGLONG hotkeyDebounceMs = 500; const auto now = GetTickCount64(); - if (now - m_lastHotkeyToggleTime < hotkeyToggleDebounceMs) + if (now - m_lastHotkeyTime < hotkeyDebounceMs) { return true; } - m_lastHotkeyToggleTime = now; + m_lastHotkeyTime = now; if (hotkeyId == 0) { - // Toggle engine on/off - toggle_engine(); - } - else if (hotkeyId == 1) - { - // Open the new editor (only in new editor mode) + // Open the editor launch_editor(); } diff --git a/src/settings-ui/Settings.UI.Library/KeyboardManagerProperties.cs b/src/settings-ui/Settings.UI.Library/KeyboardManagerProperties.cs index a523716577..284e0e2e91 100644 --- a/src/settings-ui/Settings.UI.Library/KeyboardManagerProperties.cs +++ b/src/settings-ui/Settings.UI.Library/KeyboardManagerProperties.cs @@ -21,20 +21,15 @@ namespace Microsoft.PowerToys.Settings.UI.Library [CmdConfigureIgnoreAttribute] public GenericProperty> KeyboardConfigurations { get; set; } - public HotkeySettings DefaultToggleShortcut => new HotkeySettings(true, false, false, true, 0x4B); - public HotkeySettings DefaultEditorShortcut => new HotkeySettings(true, false, false, true, 0x51); public KeyboardManagerProperties() { - ToggleShortcut = DefaultToggleShortcut; EditorShortcut = DefaultEditorShortcut; KeyboardConfigurations = new GenericProperty>(new List { "default", }); ActiveConfiguration = new GenericProperty("default"); } - public HotkeySettings ToggleShortcut { get; set; } - public HotkeySettings EditorShortcut { get; set; } [JsonPropertyName("useNewEditor")] diff --git a/src/settings-ui/Settings.UI.Library/KeyboardManagerSettings.cs b/src/settings-ui/Settings.UI.Library/KeyboardManagerSettings.cs index 406f62cdc9..99a8d2b02e 100644 --- a/src/settings-ui/Settings.UI.Library/KeyboardManagerSettings.cs +++ b/src/settings-ui/Settings.UI.Library/KeyboardManagerSettings.cs @@ -38,10 +38,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library { var hotkeyAccessors = new List { - new HotkeyAccessor( - () => Properties.ToggleShortcut, - value => Properties.ToggleShortcut = value ?? Properties.DefaultToggleShortcut, - "Toggle_Shortcut"), new HotkeyAccessor( () => Properties.EditorShortcut, value => Properties.EditorShortcut = value ?? Properties.DefaultEditorShortcut, diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/KeyboardManagerPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/KeyboardManagerPage.xaml index 9943a26959..ff213f5251 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/KeyboardManagerPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/KeyboardManagerPage.xaml @@ -62,28 +62,12 @@ - - - - - - - - - - - - + diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 73048a88c9..72d31fa4cd 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -1909,12 +1909,6 @@ Made with 💗 by Microsoft and the PowerToys community. Customize the shortcut to activate this module - - - Shortcut - - - Enable or disable this module (Note: the Settings UI will not update) Editor shortcut diff --git a/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs index 3b9fbf8d3e..2246062e28 100644 --- a/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/KeyboardManagerViewModel.cs @@ -181,34 +181,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { var hotkeysDict = new Dictionary { - [ModuleName] = [ToggleShortcut, EditorShortcut], + [ModuleName] = [EditorShortcut], }; return hotkeysDict; } - public HotkeySettings ToggleShortcut - { - get => Settings.Properties.ToggleShortcut; - set - { - if (value != Settings.Properties.ToggleShortcut) - { - Settings.Properties.ToggleShortcut = value == null ? Settings.Properties.DefaultToggleShortcut : value; - - OnPropertyChanged(nameof(ToggleShortcut)); - NotifySettingsChanged(); - - SendConfigMSG( - string.Format( - CultureInfo.InvariantCulture, - "{{ \"powertoys\": {{ \"{0}\": {1} }} }}", - KeyboardManagerSettings.ModuleName, - JsonSerializer.Serialize(Settings, SourceGenerationContextContext.Default.KeyboardManagerSettings))); - } - } - } - public bool UseNewEditor { get => Settings.Properties.UseNewEditor;