From 875593e32ee2fd458e800bb3fc1f0b3cb5dee151 Mon Sep 17 00:00:00 2001 From: Shuai Yuan Date: Mon, 7 Jul 2025 11:19:31 +0800 Subject: [PATCH] Added hotkey conflict detection for mouse without border. Signed-off-by: Shuai Yuan --- .../ModuleInterface/dllmain.cpp | 97 +++++++++++++++++++ .../MouseWithoutBordersViewModel.cs | 14 ++- 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/dllmain.cpp b/src/modules/MouseWithoutBorders/ModuleInterface/dllmain.cpp index 66dc75b7d5..84b8725d70 100644 --- a/src/modules/MouseWithoutBorders/ModuleInterface/dllmain.cpp +++ b/src/modules/MouseWithoutBorders/ModuleInterface/dllmain.cpp @@ -134,6 +134,32 @@ private: bool run_in_service_mode = false; PROCESS_INFORMATION p_info = {}; + // Helper function to convert HotkeyObject to Hotkey struct + Hotkey ConvertHotkeyObjectToHotkey(const PowerToysSettings::HotkeyObject& hotkeyObj, const wchar_t* name) + { + Hotkey hotkey; + hotkey.win = hotkeyObj.win_pressed(); + hotkey.ctrl = hotkeyObj.ctrl_pressed(); + hotkey.alt = hotkeyObj.alt_pressed(); + hotkey.shift = hotkeyObj.shift_pressed(); + hotkey.key = static_cast(hotkeyObj.get_code()); + hotkey.name = name; + return hotkey; + } + + // Helper function to create a default disabled hotkey + Hotkey CreateDisabledHotkey(const wchar_t* name) + { + Hotkey hotkey; + hotkey.win = false; + hotkey.ctrl = false; + hotkey.alt = false; + hotkey.shift = false; + hotkey.key = 0; + hotkey.name = name; + return hotkey; + } + bool is_enabled_by_default() const override { return false; @@ -564,6 +590,77 @@ public: return m_enabled; } + virtual size_t get_hotkeys(Hotkey* hotkeys, size_t buffer_size) override + { + constexpr size_t num_hotkeys = 4; // We have 4 hotkeys + + if (hotkeys && buffer_size >= num_hotkeys) + { + try + { + PowerToysSettings::PowerToyValues values = + PowerToysSettings::PowerToyValues::load_from_settings_file(MODULE_NAME); + + // Cache the raw JSON object to avoid multiple parsing + json::JsonObject root_json = values.get_raw_json(); + json::JsonObject properties_json = root_json.GetNamedObject(L"properties", json::JsonObject{}); + + size_t hotkey_index = 0; + + // Helper lambda to extract hotkey from JSON properties + auto extract_hotkey = [&](const wchar_t* property_name, const wchar_t* hotkey_name, bool default_win, bool default_ctrl, bool default_alt, bool default_shift, unsigned char default_key) -> Hotkey { + if (properties_json.HasKey(property_name)) + { + try + { + json::JsonObject hotkey_json = properties_json.GetNamedObject(property_name); + + // Extract hotkey properties directly from JSON + bool win = hotkey_json.GetNamedBoolean(L"win", default_win); + bool ctrl = hotkey_json.GetNamedBoolean(L"ctrl", default_ctrl); + bool alt = hotkey_json.GetNamedBoolean(L"alt", default_alt); + bool shift = hotkey_json.GetNamedBoolean(L"shift", default_shift); + unsigned char key = static_cast( + hotkey_json.GetNamedNumber(L"code", default_key)); + + return { win, ctrl, shift, alt, key, hotkey_name }; + } + catch (...) + { + // If parsing individual hotkey fails, use defaults + return { default_win, default_ctrl, default_shift, default_alt, default_key, hotkey_name }; + } + } + else + { + // Property doesn't exist, use defaults + return { default_win, default_ctrl, default_shift, default_alt, default_key, hotkey_name }; + } + }; + + // Extract all hotkeys using the optimized helper + hotkeys[hotkey_index++] = extract_hotkey(L"ToggleEasyMouseShortcut", TOGGLEEASYMOUSE_SHORTCUT_NAME, false, true, false, true, 0x45); // Ctrl+Shift+E + + hotkeys[hotkey_index++] = extract_hotkey(L"LockMachineShortcut", LOCKMACHINE_SHORTCUT_NAME, false, true, false, true, 0x4C); // Ctrl+Shift+L + + hotkeys[hotkey_index++] = extract_hotkey(L"ReconnectShortcut", RECONNECT_SHORTCUT_NAME, true, true, true, false, 0x52); // Win+Ctrl+Alt+R + + hotkeys[hotkey_index++] = extract_hotkey(L"Switch2AllPCShortcut", SWITCH2ALLPC_SHORTCUT_NAME, false, false, false, false, 0); // Disabled by default + } + catch (std::exception&) + { + // If settings file doesn't exist or is corrupted, use default hotkeys + size_t hotkey_index = 0; + hotkeys[hotkey_index++] = { false, true, false, true, 0x45, TOGGLEEASYMOUSE_SHORTCUT_NAME }; // Ctrl+Shift+E + hotkeys[hotkey_index++] = { false, true, false, true, 0x4C, LOCKMACHINE_SHORTCUT_NAME }; // Ctrl+Shift+L + hotkeys[hotkey_index++] = { true, true, true, false, 0x52, RECONNECT_SHORTCUT_NAME }; // Win+Ctrl+Alt+R + hotkeys[hotkey_index++] = CreateDisabledHotkey(SWITCH2ALLPC_SHORTCUT_NAME); // Disabled + } + } + + return num_hotkeys; + } + void launch_add_firewall_process() { Logger::trace(L"Starting Process to add firewall rule"); diff --git a/src/settings-ui/Settings.UI/ViewModels/MouseWithoutBordersViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/MouseWithoutBordersViewModel.cs index 8b6471141b..93f13f4031 100644 --- a/src/settings-ui/Settings.UI/ViewModels/MouseWithoutBordersViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/MouseWithoutBordersViewModel.cs @@ -1202,6 +1202,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { Settings.Properties.ToggleEasyMouseShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeyToggleEasyMouse; NotifyPropertyChanged(); + NotifyModuleUpdatedSettings(); } } } @@ -1217,6 +1218,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels Settings.Properties.LockMachineShortcut = value; Settings.Properties.LockMachineShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeyLockMachine; NotifyPropertyChanged(); + NotifyModuleUpdatedSettings(); } } } @@ -1232,6 +1234,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels Settings.Properties.ReconnectShortcut = value; Settings.Properties.ReconnectShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeyReconnect; NotifyPropertyChanged(); + NotifyModuleUpdatedSettings(); } } } @@ -1247,6 +1250,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels Settings.Properties.Switch2AllPCShortcut = value; Settings.Properties.Switch2AllPCShortcut = value ?? MouseWithoutBordersProperties.DefaultHotKeySwitch2AllPC; NotifyPropertyChanged(); + NotifyModuleUpdatedSettings(); } } } @@ -1405,11 +1409,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels private void NotifyModuleUpdatedSettings() { SendConfigMSG( - string.Format( - CultureInfo.InvariantCulture, - "{{ \"powertoys\": {{ \"{0}\": {1} }} }}", - MouseWithoutBordersSettings.ModuleName, - JsonSerializer.Serialize(Settings, SourceGenerationContextContext.Default.MouseWithoutBordersSettings))); + string.Format( + CultureInfo.InvariantCulture, + "{{ \"powertoys\": {{ \"{0}\": {1} }} }}", + MouseWithoutBordersSettings.ModuleName, + JsonSerializer.Serialize(Settings, SourceGenerationContextContext.Default.MouseWithoutBordersSettings))); } public void NotifyUpdatedSettings()