mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 19:57:57 +01:00
CmdPal: Replace Tapped events with generic ones (#40640)
## Summary of the Pull Request Click event on WinUI buttons handle more than just click and is more versatile that Tapped event. When you tap a Button with a finger or stylus, or press a left mouse button while the pointer is over it, the button raises the Click event. If a button has keyboard focus, pressing the Enter key or the Spacebar key also raises the Click event. This PR also replaces the right-tapped event on items on the list page with context menu handling, allowing other input gestures (such as Shift+F10) to also display the context menu. And finally, it adds a button to the status messages badge so that the flyout can be opened using the keyboard. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] **Closes:** #40616 - [ ] **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 Tested on desktop with keyboard and mouse (no cats), and SB2 with touch and pen. Input gestures seem to work as intended. --------- Co-authored-by: Mike Griese <migrie@microsoft.com>
This commit is contained in:
@@ -76,44 +76,44 @@
|
|||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="IconRoot"
|
x:Name="IconRoot"
|
||||||
Margin="8,0,0,0"
|
Margin="3,0,-5,0"
|
||||||
Tapped="PageIcon_Tapped"
|
|
||||||
Visibility="{x:Bind CurrentPageViewModel.IsNested, Mode=OneWay}">
|
Visibility="{x:Bind CurrentPageViewModel.IsNested, Mode=OneWay}">
|
||||||
<InfoBadge Visibility="{x:Bind CurrentPageViewModel.HasStatusMessage, Mode=OneWay}" Value="{x:Bind CurrentPageViewModel.StatusMessages.Count, Mode=OneWay}" />
|
<Button
|
||||||
<Grid.ContextFlyout>
|
x:Name="StatusMessagesButton"
|
||||||
<Flyout x:Name="StatusMessagesFlyout" Placement="TopEdgeAlignedLeft">
|
x:Uid="StatusMessagesButton"
|
||||||
<ItemsRepeater
|
Padding="4"
|
||||||
x:Name="MessagesDropdown"
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
Margin="-8"
|
Visibility="{x:Bind CurrentPageViewModel.HasStatusMessage, Mode=OneWay}">
|
||||||
ItemsSource="{x:Bind CurrentPageViewModel.StatusMessages, Mode=OneWay}"
|
<InfoBadge Value="{x:Bind CurrentPageViewModel.StatusMessages.Count, Mode=OneWay}" />
|
||||||
Layout="{StaticResource VerticalStackLayout}">
|
<Button.Flyout>
|
||||||
<ItemsRepeater.ItemTemplate>
|
<Flyout x:Name="StatusMessagesFlyout" Placement="TopEdgeAlignedLeft">
|
||||||
<DataTemplate x:DataType="coreViewModels:StatusMessageViewModel">
|
<ItemsRepeater
|
||||||
<StackPanel
|
x:Name="MessagesDropdown"
|
||||||
Grid.Row="0"
|
Margin="-8"
|
||||||
Margin="0"
|
ItemsSource="{x:Bind CurrentPageViewModel.StatusMessages, Mode=OneWay}"
|
||||||
HorizontalAlignment="Stretch"
|
Layout="{StaticResource VerticalStackLayout}">
|
||||||
VerticalAlignment="Bottom"
|
<ItemsRepeater.ItemTemplate>
|
||||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
<DataTemplate x:DataType="coreViewModels:StatusMessageViewModel">
|
||||||
CornerRadius="0">
|
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
|
||||||
<InfoBar
|
<InfoBar
|
||||||
CornerRadius="{ThemeResource ControlCornerRadius}"
|
CornerRadius="{ThemeResource ControlCornerRadius}"
|
||||||
IsClosable="False"
|
IsClosable="False"
|
||||||
IsOpen="True"
|
IsOpen="True"
|
||||||
Message="{x:Bind Message, Mode=OneWay}"
|
Message="{x:Bind Message, Mode=OneWay}"
|
||||||
Severity="{x:Bind State, Mode=OneWay, Converter={StaticResource MessageStateToSeverityConverter}}" />
|
Severity="{x:Bind State, Mode=OneWay, Converter={StaticResource MessageStateToSeverityConverter}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsRepeater.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
</ItemsRepeater>
|
</ItemsRepeater>
|
||||||
</Flyout>
|
</Flyout>
|
||||||
</Grid.ContextFlyout>
|
</Button.Flyout>
|
||||||
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Button
|
<Button
|
||||||
x:Name="SettingsIconButton"
|
x:Name="SettingsIconButton"
|
||||||
x:Uid="SettingsButton"
|
x:Uid="SettingsButton"
|
||||||
|
Click="SettingsIcon_Clicked"
|
||||||
Style="{StaticResource SubtleButtonStyle}"
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
Tapped="SettingsIcon_Tapped"
|
|
||||||
Visibility="{x:Bind CurrentPageViewModel.IsNested, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
|
Visibility="{x:Bind CurrentPageViewModel.IsNested, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<FontIcon
|
<FontIcon
|
||||||
@@ -146,8 +146,8 @@
|
|||||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||||
AutomationProperties.Name="{x:Bind ViewModel.PrimaryCommand.Name, Mode=OneWay}"
|
AutomationProperties.Name="{x:Bind ViewModel.PrimaryCommand.Name, Mode=OneWay}"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
|
Click="PrimaryButton_Clicked"
|
||||||
Style="{StaticResource SubtleButtonStyle}"
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
Tapped="PrimaryButton_Tapped"
|
|
||||||
Visibility="{x:Bind ViewModel.HasPrimaryCommand, Mode=OneWay}">
|
Visibility="{x:Bind ViewModel.HasPrimaryCommand, Mode=OneWay}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -169,8 +169,8 @@
|
|||||||
Padding="6,4,4,4"
|
Padding="6,4,4,4"
|
||||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||||
AutomationProperties.Name="{x:Bind ViewModel.SecondaryCommand.Name, Mode=OneWay}"
|
AutomationProperties.Name="{x:Bind ViewModel.SecondaryCommand.Name, Mode=OneWay}"
|
||||||
|
Click="SecondaryButton_Clicked"
|
||||||
Style="{StaticResource SubtleButtonStyle}"
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
Tapped="SecondaryButton_Tapped"
|
|
||||||
Visibility="{x:Bind ViewModel.HasSecondaryCommand, Mode=OneWay}">
|
Visibility="{x:Bind ViewModel.HasSecondaryCommand, Mode=OneWay}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -200,8 +200,8 @@
|
|||||||
x:Name="MoreCommandsButton"
|
x:Name="MoreCommandsButton"
|
||||||
x:Uid="MoreCommandsButton"
|
x:Uid="MoreCommandsButton"
|
||||||
Padding="4"
|
Padding="4"
|
||||||
|
Click="MoreCommandsButton_Clicked"
|
||||||
Style="{StaticResource SubtleButtonStyle}"
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
Tapped="MoreCommandsButton_Tapped"
|
|
||||||
ToolTipService.ToolTip="Ctrl+K"
|
ToolTipService.ToolTip="Ctrl+K"
|
||||||
Visibility="{x:Bind ViewModel.ShouldShowContextMenu, Mode=OneWay}">
|
Visibility="{x:Bind ViewModel.ShouldShowContextMenu, Mode=OneWay}">
|
||||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||||
|
|||||||
@@ -114,34 +114,23 @@ public sealed partial class CommandBar : UserControl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS has a tendency to delete XAML bound methods over-aggressively")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS has a tendency to delete XAML bound methods over-aggressively")]
|
||||||
private void PrimaryButton_Tapped(object sender, TappedRoutedEventArgs e)
|
private void PrimaryButton_Clicked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.InvokePrimaryCommand();
|
ViewModel.InvokePrimaryCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS has a tendency to delete XAML bound methods over-aggressively")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS has a tendency to delete XAML bound methods over-aggressively")]
|
||||||
private void SecondaryButton_Tapped(object sender, TappedRoutedEventArgs e)
|
private void SecondaryButton_Clicked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel.InvokeSecondaryCommand();
|
ViewModel.InvokeSecondaryCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PageIcon_Tapped(object sender, TappedRoutedEventArgs e)
|
private void SettingsIcon_Clicked(object sender, RoutedEventArgs e)
|
||||||
{
|
|
||||||
if (CurrentPageViewModel?.StatusMessages.Count > 0)
|
|
||||||
{
|
|
||||||
StatusMessagesFlyout.ShowAt(
|
|
||||||
placementTarget: IconRoot,
|
|
||||||
showOptions: new FlyoutShowOptions() { ShowMode = FlyoutShowMode.Standard });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SettingsIcon_Tapped(object sender, TappedRoutedEventArgs e)
|
|
||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Send<OpenSettingsMessage>();
|
WeakReferenceMessenger.Default.Send<OpenSettingsMessage>();
|
||||||
e.Handled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MoreCommandsButton_Tapped(object sender, TappedRoutedEventArgs e)
|
private void MoreCommandsButton_Clicked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(new OpenContextMenuMessage(null, null, null, ContextMenuFilterLocation.Bottom));
|
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(new OpenContextMenuMessage(null, null, null, ContextMenuFilterLocation.Bottom));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,13 +113,14 @@
|
|||||||
<ListView
|
<ListView
|
||||||
x:Name="ItemsList"
|
x:Name="ItemsList"
|
||||||
Padding="0,2,0,0"
|
Padding="0,2,0,0"
|
||||||
|
ContextCanceled="ItemsList_OnContextCanceled"
|
||||||
|
ContextRequested="ItemsList_OnContextRequested"
|
||||||
DoubleTapped="ItemsList_DoubleTapped"
|
DoubleTapped="ItemsList_DoubleTapped"
|
||||||
IsDoubleTapEnabled="True"
|
IsDoubleTapEnabled="True"
|
||||||
IsItemClickEnabled="True"
|
IsItemClickEnabled="True"
|
||||||
ItemClick="ItemsList_ItemClick"
|
ItemClick="ItemsList_ItemClick"
|
||||||
ItemTemplate="{StaticResource ListItemViewModelTemplate}"
|
ItemTemplate="{StaticResource ListItemViewModelTemplate}"
|
||||||
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
||||||
RightTapped="ItemsList_RightTapped"
|
|
||||||
SelectionChanged="ItemsList_SelectionChanged">
|
SelectionChanged="ItemsList_SelectionChanged">
|
||||||
<ListView.ItemContainerTransitions>
|
<ListView.ItemContainerTransitions>
|
||||||
<TransitionCollection />
|
<TransitionCollection />
|
||||||
|
|||||||
@@ -316,30 +316,51 @@ public sealed partial class ListPage : Page,
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ItemsList_RightTapped(object sender, RightTappedRoutedEventArgs e)
|
private void ItemsList_OnContextRequested(UIElement sender, ContextRequestedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.OriginalSource is FrameworkElement element &&
|
var (item, element) = e.OriginalSource switch
|
||||||
element.DataContext is ListItemViewModel item)
|
|
||||||
{
|
{
|
||||||
if (ItemsList.SelectedItem != item)
|
// caused by keyboard shortcut (e.g. Context menu key or Shift+F10)
|
||||||
{
|
ListViewItem listViewItem => (ItemsList.ItemFromContainer(listViewItem) as ListItemViewModel, listViewItem),
|
||||||
ItemsList.SelectedItem = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewModel?.UpdateSelectedItemCommand.Execute(item);
|
// caused by right-click on the ListViewItem
|
||||||
|
FrameworkElement { DataContext: ListItemViewModel itemViewModel } frameworkElement => (itemViewModel, frameworkElement),
|
||||||
|
|
||||||
var pos = e.GetPosition(element);
|
_ => (null, null),
|
||||||
|
};
|
||||||
|
|
||||||
_ = DispatcherQueue.TryEnqueue(
|
if (item == null || element == null)
|
||||||
() =>
|
{
|
||||||
{
|
return;
|
||||||
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(
|
|
||||||
new OpenContextMenuMessage(
|
|
||||||
element,
|
|
||||||
Microsoft.UI.Xaml.Controls.Primitives.FlyoutPlacementMode.BottomEdgeAlignedLeft,
|
|
||||||
pos,
|
|
||||||
ContextMenuFilterLocation.Top));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ItemsList.SelectedItem != item)
|
||||||
|
{
|
||||||
|
ItemsList.SelectedItem = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewModel?.UpdateSelectedItemCommand.Execute(item);
|
||||||
|
|
||||||
|
if (!e.TryGetPosition(element, out var pos))
|
||||||
|
{
|
||||||
|
pos = new(0, element.ActualHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = DispatcherQueue.TryEnqueue(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send<OpenContextMenuMessage>(
|
||||||
|
new OpenContextMenuMessage(
|
||||||
|
element,
|
||||||
|
Microsoft.UI.Xaml.Controls.Primitives.FlyoutPlacementMode.BottomEdgeAlignedLeft,
|
||||||
|
pos,
|
||||||
|
ContextMenuFilterLocation.Top));
|
||||||
|
});
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ItemsList_OnContextCanceled(UIElement sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_ = DispatcherQueue.TryEnqueue(() => WeakReferenceMessenger.Default.Send<CloseContextMenuMessage>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,11 +225,11 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
ui:VisualExtensions.NormalizedCenterPoint="0.5,0.5"
|
||||||
|
Click="BackButton_Clicked"
|
||||||
Content="{ui:FontIcon Glyph=,
|
Content="{ui:FontIcon Glyph=,
|
||||||
FontSize=14}"
|
FontSize=14}"
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
Style="{StaticResource SubtleButtonStyle}"
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
Tapped="BackButton_Tapped"
|
|
||||||
Visibility="{x:Bind ViewModel.CurrentPage.IsNested, Mode=OneWay}">
|
Visibility="{x:Bind ViewModel.CurrentPage.IsNested, Mode=OneWay}">
|
||||||
<animations:Implicit.ShowAnimations>
|
<animations:Implicit.ShowAnimations>
|
||||||
<animations:OpacityAnimation
|
<animations:OpacityAnimation
|
||||||
|
|||||||
@@ -413,7 +413,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BackButton_Tapped(object sender, Microsoft.UI.Xaml.Input.TappedRoutedEventArgs e) => WeakReferenceMessenger.Default.Send<NavigateBackMessage>(new());
|
private void BackButton_Clicked(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) => WeakReferenceMessenger.Default.Send<NavigateBackMessage>(new());
|
||||||
|
|
||||||
private void RootFrame_Navigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e)
|
private void RootFrame_Navigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -428,4 +428,10 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
|||||||
<data name="Settings_ExtensionPage_Alias_ToggleSwitch.OffContent" xml:space="preserve">
|
<data name="Settings_ExtensionPage_Alias_ToggleSwitch.OffContent" xml:space="preserve">
|
||||||
<value>Indirect</value>
|
<value>Indirect</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="StatusMessagesButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
|
<value>Show status messages</value>
|
||||||
|
</data>
|
||||||
|
<data name="StatusMessagesButton.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||||
|
<value>Show status messages</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
Reference in New Issue
Block a user