[Hosts] Add Keyboard Shortcuts (#26019)

* added keyboard shortcuts

* use x:Bind
This commit is contained in:
Davide Giacometti
2023-06-05 14:08:41 +02:00
committed by GitHub
parent 4d5152f78a
commit d426d9afde
4 changed files with 124 additions and 14 deletions

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using Hosts.Helpers; using Hosts.Helpers;
using Microsoft.UI.Windowing;
using WinUIEx; using WinUIEx;
namespace Hosts namespace Hosts

View File

@@ -132,6 +132,9 @@
<data name="AddEntryBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve"> <data name="AddEntryBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>New entry</value> <value>New entry</value>
</data> </data>
<data name="AddEntryBtn.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>New entry (CTRL+N)</value>
</data>
<data name="AdditionalLinesBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve"> <data name="AdditionalLinesBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Additional content</value> <value>Additional content</value>
</data> </data>
@@ -187,6 +190,9 @@
<data name="DuplicateEntryIcon.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve"> <data name="DuplicateEntryIcon.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Duplicate entry</value> <value>Duplicate entry</value>
</data> </data>
<data name="Edit.Text" xml:space="preserve">
<value>Edit</value>
</data>
<data name="Entries.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve"> <data name="Entries.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Entries</value> <value>Entries</value>
</data> </data>

View File

@@ -56,6 +56,11 @@
Glyph="&#xe710;" /> Glyph="&#xe710;" />
<TextBlock x:Uid="AddEntry" /> <TextBlock x:Uid="AddEntry" />
</StackPanel> </StackPanel>
<Button.KeyboardAccelerators>
<KeyboardAccelerator
Modifiers="Control"
Key="N" />
</Button.KeyboardAccelerators>
</Button> </Button>
<StackPanel <StackPanel
@@ -195,8 +200,10 @@
CornerRadius="8" CornerRadius="8"
IsItemClickEnabled="True" IsItemClickEnabled="True"
ItemClick="Entries_ItemClick" ItemClick="Entries_ItemClick"
ItemsSource="{Binding Entries, Mode=TwoWay}" KeyDown="Entries_KeyDown"
SelectedItem="{Binding Selected, Mode=TwoWay}" GotFocus="Entries_GotFocus"
ItemsSource="{x:Bind ViewModel.Entries, Mode=TwoWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}"> Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
<ListView.ItemTemplate> <ListView.ItemTemplate>
<DataTemplate x:DataType="models:Entry"> <DataTemplate x:DataType="models:Entry">
@@ -213,11 +220,27 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<FlyoutBase.AttachedFlyout> <FlyoutBase.AttachedFlyout>
<MenuFlyout> <MenuFlyout Opened="MenuFlyout_Opened">
<MenuFlyoutItem
x:Uid="Edit"
Click="Edit_Click"
Icon="Edit">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator
Modifiers="Control"
Key="E" />
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
<MenuFlyoutItem <MenuFlyoutItem
x:Uid="Ping" x:Uid="Ping"
Click="Ping_Click" Click="Ping_Click"
Icon="TwoBars" /> Icon="TwoBars">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator
Modifiers="Control"
Key="P" />
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
<MenuFlyoutItem <MenuFlyoutItem
x:Uid="MoveUp" x:Uid="MoveUp"
Click="ReorderButtonUp_Click" Click="ReorderButtonUp_Click"
@@ -238,7 +261,11 @@
<MenuFlyoutItem <MenuFlyoutItem
x:Uid="Delete" x:Uid="Delete"
Click="Delete_Click" Click="Delete_Click"
Icon="Delete" /> Icon="Delete">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator Key="Delete" />
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
</MenuFlyout> </MenuFlyout>
</FlyoutBase.AttachedFlyout> </FlyoutBase.AttachedFlyout>
<TextBlock <TextBlock
@@ -346,7 +373,7 @@
x:Name="EntryDialog" x:Name="EntryDialog"
x:Uid="EntryDialog" x:Uid="EntryDialog"
Loaded="ContentDialog_Loaded_ApplyMargin" Loaded="ContentDialog_Loaded_ApplyMargin"
IsPrimaryButtonEnabled="{Binding Valid, Mode=TwoWay}" IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}"
PrimaryButtonStyle="{StaticResource AccentButtonStyle}"> PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext> <ContentDialog.DataContext>
<models:Entry /> <models:Entry />

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
@@ -15,6 +16,8 @@ using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives; using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Input;
using Windows.ApplicationModel.Resources; using Windows.ApplicationModel.Resources;
using Windows.System;
using Windows.UI.Core;
namespace Hosts.Views namespace Hosts.Views
{ {
@@ -60,9 +63,14 @@ namespace Hosts.Views
} }
private async void Entries_ItemClick(object sender, ItemClickEventArgs e) private async void Entries_ItemClick(object sender, ItemClickEventArgs e)
{
await ShowEditDialogAsync(e.ClickedItem as Entry);
}
public async Task ShowEditDialogAsync(Entry entry)
{ {
var resourceLoader = ResourceLoader.GetForViewIndependentUse(); var resourceLoader = ResourceLoader.GetForViewIndependentUse();
ViewModel.Selected = e.ClickedItem as Entry; ViewModel.Selected = entry;
EntryDialog.Title = resourceLoader.GetString("UpdateEntry_Title"); EntryDialog.Title = resourceLoader.GetString("UpdateEntry_Title");
EntryDialog.PrimaryButtonText = resourceLoader.GetString("UpdateBtn"); EntryDialog.PrimaryButtonText = resourceLoader.GetString("UpdateBtn");
EntryDialog.PrimaryButtonCommand = UpdateCommand; EntryDialog.PrimaryButtonCommand = UpdateCommand;
@@ -111,21 +119,40 @@ namespace Hosts.Views
if (menuFlyoutItem != null) if (menuFlyoutItem != null)
{ {
var selectedEntry = menuFlyoutItem.DataContext as Entry; await ShowDeleteDialogAsync(menuFlyoutItem.DataContext as Entry);
ViewModel.Selected = selectedEntry;
DeleteDialog.Title = selectedEntry.Address;
await DeleteDialog.ShowAsync();
} }
} }
public async Task ShowDeleteDialogAsync(Entry entry)
{
ViewModel.Selected = entry;
DeleteDialog.Title = entry.Address;
await DeleteDialog.ShowAsync();
}
private async void Ping_Click(object sender, RoutedEventArgs e) private async void Ping_Click(object sender, RoutedEventArgs e)
{ {
var menuFlyoutItem = sender as MenuFlyoutItem; var menuFlyoutItem = sender as MenuFlyoutItem;
if (menuFlyoutItem != null) if (menuFlyoutItem != null)
{ {
ViewModel.Selected = menuFlyoutItem.DataContext as Entry; await PingAsync(menuFlyoutItem.DataContext as Entry);
await ViewModel.PingSelectedAsync(); }
}
private async Task PingAsync(Entry entry)
{
ViewModel.Selected = entry;
await ViewModel.PingSelectedAsync();
}
private async void Edit_Click(object sender, RoutedEventArgs e)
{
var menuFlyoutItem = sender as MenuFlyoutItem;
if (menuFlyoutItem != null)
{
await ShowEditDialogAsync(menuFlyoutItem.DataContext as Entry);
} }
} }
@@ -197,5 +224,56 @@ namespace Hosts.Views
Logger.LogError("Couldn't set the margin for a content dialog. It will appear on top of the title bar.", ex); Logger.LogError("Couldn't set the margin for a content dialog. It will appear on top of the title bar.", ex);
} }
} }
/// <summary>
/// Handle the keyboard shortcuts at list view level since
/// KeyboardAccelerators in FlyoutBase.AttachedFlyout works only when the flyout is open
/// </summary>
private async void Entries_KeyDown(object sender, KeyRoutedEventArgs e)
{
var listView = sender as ListView;
if (listView != null && e.KeyStatus.WasKeyDown == false)
{
var entry = listView.SelectedItem as Entry;
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down))
{
if (e.Key == VirtualKey.E)
{
await ShowEditDialogAsync(entry);
}
else if (e.Key == VirtualKey.P)
{
await PingAsync(entry);
}
}
else if (e.Key == VirtualKey.Delete)
{
await ShowDeleteDialogAsync(entry);
}
}
}
/// <summary>
/// Focus the first item when the list view gets the focus with keyboard
/// </summary>
private void Entries_GotFocus(object sender, RoutedEventArgs e)
{
var listView = sender as ListView;
if (listView.SelectedItem == null && listView.Items.Count > 0)
{
listView.SelectedIndex = 0;
}
}
private void MenuFlyout_Opened(object sender, object e)
{
// Focus the first item: required for workaround https://github.com/microsoft/PowerToys/issues/21263
var menuFlyout = sender as MenuFlyout;
if (menuFlyout != null && menuFlyout.Items.Count > 0)
{
menuFlyout.Items.First().Focus(FocusState.Programmatic);
}
}
} }
} }