mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-08-29 10:09:43 +02:00
fix(shortcutguide): restore excluded-app filtering regression (#50046)
## Summary of the Pull Request **Regression:** PR #48683 changed Shortcut Guide from a process launched per invocation to a persistent background process. Before that change, every activation started a process and evaluated the current foreground app against the latest excluded-app settings. The excluded-app check remained in `Program.Main`, so after #48683 it ran only when the persistent process started. Excluded apps therefore stopped blocking later regular-hotkey and Windows-key-hold activations, and newly saved exclusions had no effect until the process was recycled. This PR restores the pre-#48683 excluded-app behavior by: - starting the persistent Shortcut Guide listener regardless of the startup foreground app; - evaluating the current foreground app against the latest excluded-app settings before each hidden-overlay activation; - applying the same gate to the regular hotkey and Windows-key-hold paths; and - preserving close and hold-surface promotion behavior when the overlay is already visible. ## PR Checklist - [x] Closes: #50030 - [ ] **Communication:** This regression was diagnosed from the issue and recent Shortcut Guide lifecycle changes; it has not yet been discussed with core contributors - [x] **Tests:** Added/updated and all pass - [x] **Localization:** N/A - no end-user-facing strings were added or changed - [x] **Dev docs:** N/A - no public behavior or developer contract changed - [x] **New binaries:** N/A - no binaries or projects were added - [x] **Documentation updated:** N/A - this is a regression fix restoring existing behavior ## Detailed Description of the Pull Request / Additional comments `src/modules/ShortcutGuide/ShortcutGuide.Ui/Program.cs` no longer exits at process startup when the then-foreground application is excluded. The background listener must remain available for later activations. `src/modules/ShortcutGuide/ShortcutGuide.Ui/ShortcutGuideXAML/App.xaml.cs` calls the existing native excluded-app helper for each activation while the overlay is hidden. That helper already reloads `settings.json` and rebuilds its excluded-app list on every call, so no watcher or cache is needed. The result is passed into `src/modules/ShortcutGuide/ShortcutGuide.Ui/Helpers/ShortcutGuideActivationPolicy.cs`, keeping the decision shared by both activation sources and directly testable. The check is intentionally skipped while the overlay is visible. This preserves the regular hotkey's ability to close its guide or take ownership of a guide opened by Windows-key hold. Suppression logging is generic and does not include application names, paths, window titles, or settings content. This is a regression fix rather than a new excluded-app feature or settings-schema change. ## Validation Steps Performed - Built `src/modules/ShortcutGuide/ShortcutGuide.UnitTests/ShortcutGuide.UnitTests.csproj` for x64 Release from the final rebased commit. - Ran the Shortcut Guide test executable: **48 passed, 0 failed, 0 skipped**. - Added cases covering: - regular-hotkey suppression over an excluded app; - Windows-key-hold suppression for taskbar indicators and the full guide; - closing a visible regular guide; and - promoting visible hold indicators with the regular hotkey. - Built a complete local x64 Release payload and confirmed its Runner launched the local Shortcut Guide process and handled open/close activation. Copilot-Session: 8271bded-18e8-474e-8e3b-addd71f67f50
This commit is contained in:
@@ -33,10 +33,16 @@ public static class ShortcutGuideActivationPolicy
|
|||||||
public static ShortcutGuideActivationAction GetActivationAction(
|
public static ShortcutGuideActivationAction GetActivationAction(
|
||||||
ShortcutGuideActivationSource activationSource,
|
ShortcutGuideActivationSource activationSource,
|
||||||
bool isOverlayVisible,
|
bool isOverlayVisible,
|
||||||
|
bool isCurrentWindowExcluded,
|
||||||
ShortcutGuideActivationSource activeSource,
|
ShortcutGuideActivationSource activeSource,
|
||||||
ShortcutGuideOverlaySurface activeSurface,
|
ShortcutGuideOverlaySurface activeSurface,
|
||||||
ShortcutGuideWindowsKeyAction windowsKeyAction)
|
ShortcutGuideWindowsKeyAction windowsKeyAction)
|
||||||
{
|
{
|
||||||
|
if (!isOverlayVisible && isCurrentWindowExcluded)
|
||||||
|
{
|
||||||
|
return ShortcutGuideActivationAction.None;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isOverlayVisible)
|
if (!isOverlayVisible)
|
||||||
{
|
{
|
||||||
activeSource = ShortcutGuideActivationSource.None;
|
activeSource = ShortcutGuideActivationSource.None;
|
||||||
|
|||||||
@@ -55,11 +55,6 @@ namespace ShortcutGuide
|
|||||||
|
|
||||||
Directory.CreateDirectory(ManifestInterpreter.PathOfManifestFiles);
|
Directory.CreateDirectory(ManifestInterpreter.PathOfManifestFiles);
|
||||||
|
|
||||||
if (NativeMethods.IsCurrentWindowExcludedFromShortcutGuide())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy every shipped manifest from the install directory to the per-user manifest folder.
|
// Copy every shipped manifest from the install directory to the per-user manifest folder.
|
||||||
// Enumerating the source folder avoids drift between the deployed assets and a hard-coded list.
|
// Enumerating the source folder avoids drift between the deployed assets and a hard-coded list.
|
||||||
// Todo: Only copy files after an update.
|
// Todo: Only copy files after an update.
|
||||||
|
|||||||
@@ -251,16 +251,24 @@ namespace ShortcutGuide
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool isOverlayVisible = OverlayWindow.AppWindow.IsVisible;
|
bool isOverlayVisible = OverlayWindow.AppWindow.IsVisible;
|
||||||
|
bool isCurrentWindowExcluded =
|
||||||
|
!isOverlayVisible && NativeMethods.IsCurrentWindowExcludedFromShortcutGuide();
|
||||||
var activeSource = (ShortcutGuideActivationSource)Volatile.Read(ref _activeSource);
|
var activeSource = (ShortcutGuideActivationSource)Volatile.Read(ref _activeSource);
|
||||||
var activeSurface = (ShortcutGuideOverlaySurface)Volatile.Read(ref _activeSurface);
|
var activeSurface = (ShortcutGuideOverlaySurface)Volatile.Read(ref _activeSurface);
|
||||||
var windowsKeyAction = (ShortcutGuideWindowsKeyAction)ShortcutGuideProperties.WindowsKeyAction.Value;
|
var windowsKeyAction = (ShortcutGuideWindowsKeyAction)ShortcutGuideProperties.WindowsKeyAction.Value;
|
||||||
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
activationSource,
|
activationSource,
|
||||||
isOverlayVisible,
|
isOverlayVisible,
|
||||||
|
isCurrentWindowExcluded,
|
||||||
activeSource,
|
activeSource,
|
||||||
activeSurface,
|
activeSurface,
|
||||||
windowsKeyAction);
|
windowsKeyAction);
|
||||||
|
|
||||||
|
if (isCurrentWindowExcluded)
|
||||||
|
{
|
||||||
|
Logger.LogInfo("Shortcut Guide activation suppressed because the foreground application is excluded.");
|
||||||
|
}
|
||||||
|
|
||||||
Logger.LogInfo($"Shortcut Guide activation action: {action}.");
|
Logger.LogInfo($"Shortcut Guide activation action: {action}.");
|
||||||
switch (action)
|
switch (action)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public sealed class ShortcutGuideActivationPolicyTests
|
|||||||
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
ShortcutGuideActivationSource.WindowsKeyHold,
|
ShortcutGuideActivationSource.WindowsKeyHold,
|
||||||
isOverlayVisible: false,
|
isOverlayVisible: false,
|
||||||
|
isCurrentWindowExcluded: false,
|
||||||
ShortcutGuideActivationSource.None,
|
ShortcutGuideActivationSource.None,
|
||||||
ShortcutGuideOverlaySurface.Hidden,
|
ShortcutGuideOverlaySurface.Hidden,
|
||||||
windowsKeyAction);
|
windowsKeyAction);
|
||||||
@@ -38,6 +39,7 @@ public sealed class ShortcutGuideActivationPolicyTests
|
|||||||
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
ShortcutGuideActivationSource.RegularHotkey,
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
isOverlayVisible: false,
|
isOverlayVisible: false,
|
||||||
|
isCurrentWindowExcluded: false,
|
||||||
ShortcutGuideActivationSource.None,
|
ShortcutGuideActivationSource.None,
|
||||||
ShortcutGuideOverlaySurface.Hidden,
|
ShortcutGuideOverlaySurface.Hidden,
|
||||||
windowsKeyAction);
|
windowsKeyAction);
|
||||||
@@ -51,6 +53,7 @@ public sealed class ShortcutGuideActivationPolicyTests
|
|||||||
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
ShortcutGuideActivationSource.RegularHotkey,
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
isOverlayVisible: true,
|
isOverlayVisible: true,
|
||||||
|
isCurrentWindowExcluded: false,
|
||||||
ShortcutGuideActivationSource.WindowsKeyHold,
|
ShortcutGuideActivationSource.WindowsKeyHold,
|
||||||
ShortcutGuideOverlaySurface.TaskbarIndicators,
|
ShortcutGuideOverlaySurface.TaskbarIndicators,
|
||||||
ShortcutGuideWindowsKeyAction.TaskbarIndicators);
|
ShortcutGuideWindowsKeyAction.TaskbarIndicators);
|
||||||
@@ -64,6 +67,7 @@ public sealed class ShortcutGuideActivationPolicyTests
|
|||||||
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
ShortcutGuideActivationSource.RegularHotkey,
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
isOverlayVisible: true,
|
isOverlayVisible: true,
|
||||||
|
isCurrentWindowExcluded: false,
|
||||||
ShortcutGuideActivationSource.WindowsKeyHold,
|
ShortcutGuideActivationSource.WindowsKeyHold,
|
||||||
ShortcutGuideOverlaySurface.FullGuide,
|
ShortcutGuideOverlaySurface.FullGuide,
|
||||||
ShortcutGuideWindowsKeyAction.OpenShortcutGuide);
|
ShortcutGuideWindowsKeyAction.OpenShortcutGuide);
|
||||||
@@ -77,6 +81,7 @@ public sealed class ShortcutGuideActivationPolicyTests
|
|||||||
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
ShortcutGuideActivationSource.RegularHotkey,
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
isOverlayVisible: true,
|
isOverlayVisible: true,
|
||||||
|
isCurrentWindowExcluded: false,
|
||||||
ShortcutGuideActivationSource.RegularHotkey,
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
ShortcutGuideOverlaySurface.FullGuide,
|
ShortcutGuideOverlaySurface.FullGuide,
|
||||||
ShortcutGuideWindowsKeyAction.TaskbarIndicators);
|
ShortcutGuideWindowsKeyAction.TaskbarIndicators);
|
||||||
@@ -90,6 +95,7 @@ public sealed class ShortcutGuideActivationPolicyTests
|
|||||||
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
ShortcutGuideActivationSource.WindowsKeyHold,
|
ShortcutGuideActivationSource.WindowsKeyHold,
|
||||||
isOverlayVisible: true,
|
isOverlayVisible: true,
|
||||||
|
isCurrentWindowExcluded: false,
|
||||||
ShortcutGuideActivationSource.RegularHotkey,
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
ShortcutGuideOverlaySurface.FullGuide,
|
ShortcutGuideOverlaySurface.FullGuide,
|
||||||
ShortcutGuideWindowsKeyAction.OpenShortcutGuide);
|
ShortcutGuideWindowsKeyAction.OpenShortcutGuide);
|
||||||
@@ -97,6 +103,50 @@ public sealed class ShortcutGuideActivationPolicyTests
|
|||||||
Assert.AreEqual(ShortcutGuideActivationAction.None, action);
|
Assert.AreEqual(ShortcutGuideActivationAction.None, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(ShortcutGuideActivationSource.RegularHotkey, ShortcutGuideWindowsKeyAction.TaskbarIndicators)]
|
||||||
|
[DataRow(ShortcutGuideActivationSource.WindowsKeyHold, ShortcutGuideWindowsKeyAction.TaskbarIndicators)]
|
||||||
|
[DataRow(ShortcutGuideActivationSource.WindowsKeyHold, ShortcutGuideWindowsKeyAction.OpenShortcutGuide)]
|
||||||
|
public void GetActivationAction_ExcludedApp_SuppressesHiddenOverlay(
|
||||||
|
ShortcutGuideActivationSource activationSource,
|
||||||
|
ShortcutGuideWindowsKeyAction windowsKeyAction)
|
||||||
|
{
|
||||||
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
|
activationSource,
|
||||||
|
isOverlayVisible: false,
|
||||||
|
isCurrentWindowExcluded: true,
|
||||||
|
ShortcutGuideActivationSource.None,
|
||||||
|
ShortcutGuideOverlaySurface.Hidden,
|
||||||
|
windowsKeyAction);
|
||||||
|
|
||||||
|
Assert.AreEqual(ShortcutGuideActivationAction.None, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
[DataRow(
|
||||||
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
|
ShortcutGuideOverlaySurface.FullGuide,
|
||||||
|
ShortcutGuideActivationAction.Close)]
|
||||||
|
[DataRow(
|
||||||
|
ShortcutGuideActivationSource.WindowsKeyHold,
|
||||||
|
ShortcutGuideOverlaySurface.TaskbarIndicators,
|
||||||
|
ShortcutGuideActivationAction.ShowFullGuide)]
|
||||||
|
public void GetActivationAction_ExcludedApp_DoesNotSuppressVisibleOverlay(
|
||||||
|
ShortcutGuideActivationSource activeSource,
|
||||||
|
ShortcutGuideOverlaySurface activeSurface,
|
||||||
|
ShortcutGuideActivationAction expected)
|
||||||
|
{
|
||||||
|
var action = ShortcutGuideActivationPolicy.GetActivationAction(
|
||||||
|
ShortcutGuideActivationSource.RegularHotkey,
|
||||||
|
isOverlayVisible: true,
|
||||||
|
isCurrentWindowExcluded: true,
|
||||||
|
activeSource,
|
||||||
|
activeSurface,
|
||||||
|
ShortcutGuideWindowsKeyAction.TaskbarIndicators);
|
||||||
|
|
||||||
|
Assert.AreEqual(expected, action);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
[DataRow(ShortcutGuideActivationSource.RegularHotkey, ShortcutGuideOverlaySurface.FullGuide, true, false)]
|
[DataRow(ShortcutGuideActivationSource.RegularHotkey, ShortcutGuideOverlaySurface.FullGuide, true, false)]
|
||||||
[DataRow(ShortcutGuideActivationSource.RegularHotkey, ShortcutGuideOverlaySurface.FullGuide, false, false)]
|
[DataRow(ShortcutGuideActivationSource.RegularHotkey, ShortcutGuideOverlaySurface.FullGuide, false, false)]
|
||||||
|
|||||||
Reference in New Issue
Block a user