Compare commits

...

3 Commits

Author SHA1 Message Date
Shawn Yuan
44d34e45c0
Add telemetry for shortcut conflict detection feature. (#41271)
Some checks failed
Spell checking / Check Spelling (push) Has been cancelled
Spell checking / Report (Push) (push) Has been cancelled
Spell checking / Report (PR) (push) Has been cancelled
Spell checking / Update PR (push) Has been cancelled
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
Add telemetry for shortcut conflict detection.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: #xxx
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Signed-off-by: Shawn Yuan <shuaiyuan@microsoft.com>
Signed-off-by: Shuai Yuan <shuai.yuan.zju@gmail.com>
2025-08-21 09:27:01 +08:00
Jiří Polášek
3c0af323bf
CmdPal: Add Acrylic backdrop to the context menu and tweak its style (#41136)
## Summary of the Pull Request

- Adds acrylic backdrop to the context menu
- Tweaks border of the context menu to match CmdPal aesthetics
- Acrylic backdrop requires ShouldConstrainToRootBounds="False",
otherwise the backdrop is not rendered

After:

Video:



https://github.com/user-attachments/assets/e32741a3-6bbb-4064-9e7f-84d7551b5164


Still:

<img width="1007" height="1313" alt="image"
src="https://github.com/user-attachments/assets/d6a7bd6a-d5d8-4674-9062-91f496f49f0c"
/>


<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #41134
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
2025-08-20 18:32:03 -05:00
Michael Jolley
e0097c94c6
Adding app icon to run context menu item in all apps ext (#40991)
Closes #40978

All apps extension's "Run" command now has the apps icon if available.

<img width="1197" height="741" alt="image"
src="https://github.com/user-attachments/assets/96ce75cb-cc6e-4176-bf4f-c92c2842b258"
/>
2025-08-20 17:54:01 -05:00
8 changed files with 186 additions and 30 deletions

View File

@ -41,14 +41,18 @@
<Style.Setters>
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="Background" Value="{ThemeResource DesktopAcrylicTransparentBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource DividerStrokeColorDefaultBrush}" />
</Style.Setters>
</Style>
<!-- Backdrop requires ShouldConstrainToRootBounds="False" -->
<Flyout
x:Name="ContextMenuFlyout"
FlyoutPresenterStyle="{StaticResource ContextMenuFlyoutStyle}"
Opened="ContextMenuFlyout_Opened"
ShouldConstrainToRootBounds="False">
ShouldConstrainToRootBounds="False"
SystemBackdrop="{ThemeResource AcrylicBackgroundFillColorDefaultBackdrop}">
<cpcontrols:ContextMenu x:Name="ContextControl" />
</Flyout>

View File

@ -26,6 +26,11 @@ public sealed partial class AppCommand : InvokableCommand
Name = Resources.run_command_action;
Id = GenerateId();
if (!string.IsNullOrEmpty(app.IcoPath))
{
Icon = new(app.IcoPath);
}
}
internal static async Task StartApp(string aumid)

View File

@ -0,0 +1,20 @@
// 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 System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events
{
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ShortcutConflictControlClickedEvent : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public int ConflictCount { get; set; }
}
}

View File

@ -0,0 +1,20 @@
// 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 System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events
{
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ShortcutConflictDetectedEvent : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public int ConflictCount { get; set; }
}
}

View File

@ -0,0 +1,20 @@
// 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 System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events
{
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class ShortcutConflictResolvedEvent : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
public string Source { get; set; }
}
}

View File

@ -7,7 +7,9 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
using Microsoft.PowerToys.Settings.UI.SettingsXAML.Controls.Dashboard;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Windows.ApplicationModel.Resources;
@ -18,6 +20,8 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
{
private static readonly ResourceLoader ResourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
private static bool _telemetryEventSent;
public static readonly DependencyProperty AllHotkeyConflictsDataProperty =
DependencyProperty.Register(
nameof(AllHotkeyConflictsData),
@ -92,6 +96,17 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
// Update visibility based on conflict count
Visibility = HasConflicts ? Visibility.Visible : Visibility.Collapsed;
if (!_telemetryEventSent && HasConflicts)
{
// Log telemetry event when conflicts are detected
PowerToysTelemetry.Log.WriteEvent(new ShortcutConflictDetectedEvent()
{
ConflictCount = ConflictCount,
});
_telemetryEventSent = true;
}
}
private void OnPropertyChanged(string propertyName)
@ -115,6 +130,12 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
return;
}
// Log telemetry event when user clicks the shortcut conflict button
PowerToysTelemetry.Log.WriteEvent(new ShortcutConflictControlClickedEvent()
{
ConflictCount = this.ConflictCount,
});
// Create and show the new window instead of dialog
var conflictWindow = new ShortcutConflictWindow();

View File

@ -10,17 +10,26 @@ using CommunityToolkit.WinUI;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
using Microsoft.PowerToys.Settings.UI.Services;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.Windows.ApplicationModel.Resources;
using Windows.System;
namespace Microsoft.PowerToys.Settings.UI.Controls
{
public enum ShortcutControlSource
{
SettingsPage,
ConflictWindow,
}
public sealed partial class ShortcutControl : UserControl, IDisposable
{
private readonly UIntPtr ignoreKeyEventFlag = (UIntPtr)0x5555;
@ -43,6 +52,9 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
public static readonly DependencyProperty HasConflictProperty = DependencyProperty.Register("HasConflict", typeof(bool), typeof(ShortcutControl), new PropertyMetadata(false, OnHasConflictChanged));
public static readonly DependencyProperty TooltipProperty = DependencyProperty.Register("Tooltip", typeof(string), typeof(ShortcutControl), new PropertyMetadata(null, OnTooltipChanged));
// Dependency property to track the source/context of the ShortcutControl
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ShortcutControlSource), typeof(ShortcutControl), new PropertyMetadata(ShortcutControlSource.SettingsPage));
private static ResourceLoader resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
private static void OnAllowDisableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@ -74,6 +86,47 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
}
control.UpdateKeyVisualStyles();
// Check if conflict was resolved (had conflict before, no conflict now)
var oldValue = (bool)(e.OldValue ?? false);
var newValue = (bool)(e.NewValue ?? false);
// General conflict resolution telemetry (for all sources)
if (oldValue && !newValue)
{
// Determine the actual source based on the control's context
var actualSource = DetermineControlSource(control);
// Conflict was resolved - send general telemetry
PowerToysTelemetry.Log.WriteEvent(new ShortcutConflictResolvedEvent()
{
Source = actualSource.ToString(),
});
}
}
private static ShortcutControlSource DetermineControlSource(ShortcutControl control)
{
// Walk up the visual tree to find the parent window/container
DependencyObject parent = control;
while (parent != null)
{
parent = VisualTreeHelper.GetParent(parent);
// Check if we're in a ShortcutConflictWindow
if (parent != null && parent.GetType().Name == "ShortcutConflictWindow")
{
return ShortcutControlSource.ConflictWindow;
}
if (parent != null && (parent.GetType().Name == "MainWindow" || parent.GetType().Name == "ShellPage"))
{
return ShortcutControlSource.SettingsPage;
}
}
// Fallback to the explicitly set value or default
return ShortcutControlSource.ConflictWindow;
}
private static void OnTooltipChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@ -108,6 +161,12 @@ namespace Microsoft.PowerToys.Settings.UI.Controls
set => SetValue(TooltipProperty, value);
}
public ShortcutControlSource Source
{
get => (ShortcutControlSource)GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
public bool Enabled
{
get

View File

@ -29,7 +29,7 @@ using Windows.ApplicationModel.DataTransfer;
namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
public partial class MouseWithoutBordersViewModel : PageViewModelBase, IDisposable
public partial class MouseWithoutBordersViewModel : PageViewModelBase
{
protected override string ModuleName => MouseWithoutBordersSettings.ModuleName;
@ -43,6 +43,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private readonly Lock _machineMatrixStringLock = new();
private bool _disposed;
private static readonly Dictionary<SocketStatus, Brush> StatusColors = new Dictionary<SocketStatus, Brush>()
{
{ SocketStatus.NA, new SolidColorBrush(ColorHelper.FromArgb(0, 0x71, 0x71, 0x71)) },
@ -1262,38 +1264,43 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
protected override void Dispose(bool disposing)
{
if (disposing)
if (!_disposed)
{
// Cancel the cancellation token source
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
if (disposing)
{
// Cancel the cancellation token source
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
// Wait for the machine polling task to complete
try
{
_machinePollingThreadTask?.Wait(TimeSpan.FromSeconds(1));
}
catch (AggregateException)
{
// Task was cancelled, which is expected
// Wait for the machine polling task to complete
try
{
_machinePollingThreadTask?.Wait(TimeSpan.FromSeconds(1));
}
catch (AggregateException)
{
// Task was cancelled, which is expected
}
// Dispose the named pipe stream
try
{
syncHelperStream?.Dispose();
}
catch (Exception ex)
{
Logger.LogError($"Error disposing sync helper stream: {ex}");
}
finally
{
syncHelperStream = null;
}
// Dispose the semaphore
_ipcSemaphore?.Dispose();
}
// Dispose the named pipe stream
try
{
syncHelperStream?.Dispose();
}
catch (Exception ex)
{
Logger.LogError($"Error disposing sync helper stream: {ex}");
}
finally
{
syncHelperStream = null;
}
// Dispose the semaphore
_ipcSemaphore?.Dispose();
_disposed = true;
}
base.Dispose(disposing);