mirror of
https://github.com/microsoft/PowerToys
synced 2025-09-01 15:05:12 +00:00
Add the list item requested shortcuts back (#38573)
* [x] Re-adds the context menu shortcut text * [x] Hooks up the keybindings to the search box so that you can just press the keys while you have an item selected, and do a context command * [x] Hook these keybindings up to the context flyout itself * [x] Adds a sample for testing Solves #38271
This commit is contained in:
@@ -7,11 +7,15 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
|||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||||
|
using Microsoft.CommandPalette.Extensions;
|
||||||
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
using Windows.System;
|
||||||
|
|
||||||
namespace Microsoft.CmdPal.UI.ViewModels;
|
namespace Microsoft.CmdPal.UI.ViewModels;
|
||||||
|
|
||||||
public partial class CommandBarViewModel : ObservableObject,
|
public partial class CommandBarViewModel : ObservableObject,
|
||||||
IRecipient<UpdateCommandBarMessage>
|
IRecipient<UpdateCommandBarMessage>,
|
||||||
|
IRecipient<UpdateItemKeybindingsMessage>
|
||||||
{
|
{
|
||||||
public ICommandBarContext? SelectedItem
|
public ICommandBarContext? SelectedItem
|
||||||
{
|
{
|
||||||
@@ -49,13 +53,18 @@ public partial class CommandBarViewModel : ObservableObject,
|
|||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
public partial ObservableCollection<CommandContextItemViewModel> ContextCommands { get; set; } = [];
|
public partial ObservableCollection<CommandContextItemViewModel> ContextCommands { get; set; } = [];
|
||||||
|
|
||||||
|
private Dictionary<KeyChord, CommandContextItemViewModel>? _contextKeybindings;
|
||||||
|
|
||||||
public CommandBarViewModel()
|
public CommandBarViewModel()
|
||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
|
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
|
||||||
|
WeakReferenceMessenger.Default.Register<UpdateItemKeybindingsMessage>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Receive(UpdateCommandBarMessage message) => SelectedItem = message.ViewModel;
|
public void Receive(UpdateCommandBarMessage message) => SelectedItem = message.ViewModel;
|
||||||
|
|
||||||
|
public void Receive(UpdateItemKeybindingsMessage message) => _contextKeybindings = message.Keys;
|
||||||
|
|
||||||
private void SetSelectedItem(ICommandBarContext? value)
|
private void SetSelectedItem(ICommandBarContext? value)
|
||||||
{
|
{
|
||||||
if (value != null)
|
if (value != null)
|
||||||
@@ -131,4 +140,22 @@ public partial class CommandBarViewModel : ObservableObject,
|
|||||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(SecondaryCommand.Command.Model, SecondaryCommand.Model));
|
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(SecondaryCommand.Command.Model, SecondaryCommand.Model));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
|
||||||
|
{
|
||||||
|
if (_contextKeybindings != null)
|
||||||
|
{
|
||||||
|
// Does the pressed key match any of the keybindings?
|
||||||
|
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
|
||||||
|
if (_contextKeybindings.TryGetValue(pressedKeyChord, out var item))
|
||||||
|
{
|
||||||
|
// TODO GH #245: This is a bit of a hack, but we need to make sure that the keybindings are updated before we send the message
|
||||||
|
// so that the correct item is activated.
|
||||||
|
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,12 +9,16 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
|||||||
|
|
||||||
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context) : CommandItemViewModel(new(contextItem), context)
|
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context) : CommandItemViewModel(new(contextItem), context)
|
||||||
{
|
{
|
||||||
|
private readonly KeyChord nullKeyChord = new(0, 0, 0);
|
||||||
|
|
||||||
public new ExtensionObject<ICommandContextItem> Model { get; } = new(contextItem);
|
public new ExtensionObject<ICommandContextItem> Model { get; } = new(contextItem);
|
||||||
|
|
||||||
public bool IsCritical { get; private set; }
|
public bool IsCritical { get; private set; }
|
||||||
|
|
||||||
public KeyChord? RequestedShortcut { get; private set; }
|
public KeyChord? RequestedShortcut { get; private set; }
|
||||||
|
|
||||||
|
public bool HasRequestedShortcut => RequestedShortcut != null && (RequestedShortcut.Value != nullKeyChord);
|
||||||
|
|
||||||
public override void InitializeProperties()
|
public override void InitializeProperties()
|
||||||
{
|
{
|
||||||
if (IsInitialized)
|
if (IsInitialized)
|
||||||
@@ -31,6 +35,9 @@ public partial class CommandContextItemViewModel(ICommandContextItem contextItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
IsCritical = contextItem.IsCritical;
|
IsCritical = contextItem.IsCritical;
|
||||||
|
|
||||||
|
// I actually don't think this will ever actually be null, because
|
||||||
|
// KeyChord is a struct, which isn't nullable in WinRT
|
||||||
if (contextItem.RequestedShortcut != null)
|
if (contextItem.RequestedShortcut != null)
|
||||||
{
|
{
|
||||||
RequestedShortcut = new(
|
RequestedShortcut = new(
|
||||||
|
@@ -398,6 +398,23 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
|||||||
base.SafeCleanup();
|
base.SafeCleanup();
|
||||||
Initialized |= InitializedState.CleanedUp;
|
Initialized |= InitializedState.CleanedUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a mapping of key -> command item for this particular item's
|
||||||
|
/// MoreCommands. (This won't include the primary Command, but it will
|
||||||
|
/// include the secondary one). This map can be used to quickly check if a
|
||||||
|
/// shortcut key was pressed
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
|
||||||
|
/// that have a shortcut key set.</returns>
|
||||||
|
internal Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
|
||||||
|
{
|
||||||
|
return MoreCommands
|
||||||
|
.Where(c => c.HasRequestedShortcut)
|
||||||
|
.ToDictionary(
|
||||||
|
c => c.RequestedShortcut ?? new KeyChord(0, 0, 0),
|
||||||
|
c => c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
@@ -344,6 +344,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(item));
|
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(item));
|
||||||
|
|
||||||
|
WeakReferenceMessenger.Default.Send<UpdateItemKeybindingsMessage>(new(item.Keybindings()));
|
||||||
|
|
||||||
if (ShowDetails && item.HasDetails)
|
if (ShowDetails && item.HasDetails)
|
||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Send<ShowDetailsMessage>(new(item.Details));
|
WeakReferenceMessenger.Default.Send<ShowDetailsMessage>(new(item.Details));
|
||||||
|
@@ -51,6 +51,12 @@ public record PerformCommandMessage
|
|||||||
Context = context.Unsafe;
|
Context = context.Unsafe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PerformCommandMessage(CommandContextItemViewModel contextCommand)
|
||||||
|
{
|
||||||
|
Command = contextCommand.Command.Model;
|
||||||
|
Context = contextCommand.Model.Unsafe;
|
||||||
|
}
|
||||||
|
|
||||||
public PerformCommandMessage(ConfirmResultViewModel vm)
|
public PerformCommandMessage(ConfirmResultViewModel vm)
|
||||||
{
|
{
|
||||||
Command = vm.PrimaryCommand.Model;
|
Command = vm.PrimaryCommand.Model;
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
// 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 Microsoft.CommandPalette.Extensions;
|
||||||
|
|
||||||
|
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||||
|
|
||||||
|
public record UpdateItemKeybindingsMessage(Dictionary<KeyChord, CommandContextItemViewModel>? Keys);
|
@@ -53,14 +53,14 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Bind Title, Mode=OneWay}" />
|
Text="{x:Bind Title, Mode=OneWay}" />
|
||||||
<!--<TextBlock
|
<TextBlock
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="16,0,0,0"
|
Margin="16,0,0,0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Foreground="{ThemeResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"
|
Foreground="{ThemeResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"
|
||||||
Style="{StaticResource CaptionTextBlockStyle}"
|
Style="{StaticResource CaptionTextBlockStyle}"
|
||||||
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />-->
|
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
@@ -263,6 +263,7 @@
|
|||||||
ItemClick="CommandsDropdown_ItemClick"
|
ItemClick="CommandsDropdown_ItemClick"
|
||||||
ItemTemplate="{StaticResource ContextMenuViewModelTemplate}"
|
ItemTemplate="{StaticResource ContextMenuViewModelTemplate}"
|
||||||
ItemsSource="{x:Bind ViewModel.ContextCommands, Mode=OneWay}"
|
ItemsSource="{x:Bind ViewModel.ContextCommands, Mode=OneWay}"
|
||||||
|
KeyDown="CommandsDropdown_KeyDown"
|
||||||
SelectionMode="None">
|
SelectionMode="None">
|
||||||
<ListView.ItemContainerStyle>
|
<ListView.ItemContainerStyle>
|
||||||
<Style BasedOn="{StaticResource DefaultListViewItemStyle}" TargetType="ListViewItem">
|
<Style BasedOn="{StaticResource DefaultListViewItemStyle}" TargetType="ListViewItem">
|
||||||
|
@@ -6,10 +6,13 @@ using CommunityToolkit.Mvvm.Messaging;
|
|||||||
using Microsoft.CmdPal.UI.ViewModels;
|
using Microsoft.CmdPal.UI.ViewModels;
|
||||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||||
using Microsoft.CmdPal.UI.Views;
|
using Microsoft.CmdPal.UI.Views;
|
||||||
|
using Microsoft.UI.Input;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
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.System;
|
||||||
|
using Windows.UI.Core;
|
||||||
|
|
||||||
namespace Microsoft.CmdPal.UI.Controls;
|
namespace Microsoft.CmdPal.UI.Controls;
|
||||||
|
|
||||||
@@ -89,4 +92,23 @@ public sealed partial class CommandBar : UserControl,
|
|||||||
MoreCommandsButton.Flyout.Hide();
|
MoreCommandsButton.Flyout.Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CommandsDropdown_KeyDown(object sender, KeyRoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Handled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
var altPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
var winPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.LeftWindows).HasFlag(CoreVirtualKeyStates.Down) ||
|
||||||
|
InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.RightWindows).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
|
||||||
|
if (ViewModel?.CheckKeybinding(ctrlPressed, altPressed, shiftPressed, winPressed, e.Key) ?? false)
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,8 @@ using CommunityToolkit.WinUI;
|
|||||||
using Microsoft.CmdPal.UI.ViewModels;
|
using Microsoft.CmdPal.UI.ViewModels;
|
||||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||||
using Microsoft.CmdPal.UI.Views;
|
using Microsoft.CmdPal.UI.Views;
|
||||||
|
using Microsoft.CommandPalette.Extensions;
|
||||||
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
using Microsoft.UI.Dispatching;
|
using Microsoft.UI.Dispatching;
|
||||||
using Microsoft.UI.Input;
|
using Microsoft.UI.Input;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
@@ -21,6 +23,7 @@ namespace Microsoft.CmdPal.UI.Controls;
|
|||||||
public sealed partial class SearchBar : UserControl,
|
public sealed partial class SearchBar : UserControl,
|
||||||
IRecipient<GoHomeMessage>,
|
IRecipient<GoHomeMessage>,
|
||||||
IRecipient<FocusSearchBoxMessage>,
|
IRecipient<FocusSearchBoxMessage>,
|
||||||
|
IRecipient<UpdateItemKeybindingsMessage>,
|
||||||
ICurrentPageAware
|
ICurrentPageAware
|
||||||
{
|
{
|
||||||
private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread();
|
private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread();
|
||||||
@@ -31,6 +34,8 @@ public sealed partial class SearchBar : UserControl,
|
|||||||
private readonly DispatcherQueueTimer _debounceTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
|
private readonly DispatcherQueueTimer _debounceTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
|
||||||
private bool _isBackspaceHeld;
|
private bool _isBackspaceHeld;
|
||||||
|
|
||||||
|
private Dictionary<KeyChord, CommandContextItemViewModel>? _keyBindings;
|
||||||
|
|
||||||
public PageViewModel? CurrentPageViewModel
|
public PageViewModel? CurrentPageViewModel
|
||||||
{
|
{
|
||||||
get => (PageViewModel?)GetValue(CurrentPageViewModelProperty);
|
get => (PageViewModel?)GetValue(CurrentPageViewModelProperty);
|
||||||
@@ -69,6 +74,7 @@ public sealed partial class SearchBar : UserControl,
|
|||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
WeakReferenceMessenger.Default.Register<GoHomeMessage>(this);
|
WeakReferenceMessenger.Default.Register<GoHomeMessage>(this);
|
||||||
WeakReferenceMessenger.Default.Register<FocusSearchBoxMessage>(this);
|
WeakReferenceMessenger.Default.Register<FocusSearchBoxMessage>(this);
|
||||||
|
WeakReferenceMessenger.Default.Register<UpdateItemKeybindingsMessage>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearSearch()
|
public void ClearSearch()
|
||||||
@@ -105,7 +111,9 @@ public sealed partial class SearchBar : UserControl,
|
|||||||
|
|
||||||
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
|
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
var altPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
|
var altPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
|
var winPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.LeftWindows).HasFlag(CoreVirtualKeyStates.Down) ||
|
||||||
|
InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.RightWindows).HasFlag(CoreVirtualKeyStates.Down);
|
||||||
if (ctrlPressed && e.Key == VirtualKey.Enter)
|
if (ctrlPressed && e.Key == VirtualKey.Enter)
|
||||||
{
|
{
|
||||||
// ctrl+enter
|
// ctrl+enter
|
||||||
@@ -164,6 +172,19 @@ public sealed partial class SearchBar : UserControl,
|
|||||||
{
|
{
|
||||||
WeakReferenceMessenger.Default.Send<NavigateBackMessage>(new());
|
WeakReferenceMessenger.Default.Send<NavigateBackMessage>(new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_keyBindings != null)
|
||||||
|
{
|
||||||
|
// Does the pressed key match any of the keybindings?
|
||||||
|
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrlPressed, altPressed, shiftPressed, winPressed, (int)e.Key, 0);
|
||||||
|
if (_keyBindings.TryGetValue(pressedKeyChord, out var item))
|
||||||
|
{
|
||||||
|
// TODO GH #245: This is a bit of a hack, but we need to make sure that the keybindings are updated before we send the message
|
||||||
|
// so that the correct item is activated.
|
||||||
|
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item));
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FilterBox_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
private void FilterBox_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
|
||||||
@@ -282,4 +303,9 @@ public sealed partial class SearchBar : UserControl,
|
|||||||
public void Receive(GoHomeMessage message) => ClearSearch();
|
public void Receive(GoHomeMessage message) => ClearSearch();
|
||||||
|
|
||||||
public void Receive(FocusSearchBoxMessage message) => this.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
|
public void Receive(FocusSearchBoxMessage message) => this.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
|
||||||
|
|
||||||
|
public void Receive(UpdateItemKeybindingsMessage message)
|
||||||
|
{
|
||||||
|
_keyBindings = message.Keys;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -187,6 +187,8 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
|||||||
|
|
||||||
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(null));
|
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(null));
|
||||||
|
|
||||||
|
WeakReferenceMessenger.Default.Send<UpdateItemKeybindingsMessage>(new(null));
|
||||||
|
|
||||||
var isMainPage = command is MainListPage;
|
var isMainPage = command is MainListPage;
|
||||||
|
|
||||||
// Construct our ViewModel of the appropriate type and pass it the UI Thread context.
|
// Construct our ViewModel of the appropriate type and pass it the UI Thread context.
|
||||||
@@ -427,8 +429,6 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
|||||||
}
|
}
|
||||||
|
|
||||||
_settingsWindow.Activate();
|
_settingsWindow.Activate();
|
||||||
|
|
||||||
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(null));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
GetForegroundWindow
|
||||||
|
GetWindowTextLength
|
||||||
|
GetWindowText
|
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
using Microsoft.CommandPalette.Extensions;
|
using Microsoft.CommandPalette.Extensions;
|
||||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
using Windows.System;
|
||||||
|
using Windows.Win32;
|
||||||
|
|
||||||
namespace SamplePagesExtension;
|
namespace SamplePagesExtension;
|
||||||
|
|
||||||
@@ -65,6 +67,68 @@ internal sealed partial class SampleListPage : ListPage
|
|||||||
Subtitle = "and I'll take you to a page with markdown content",
|
Subtitle = "and I'll take you to a page with markdown content",
|
||||||
Tags = [new Tag("Sample Tag")],
|
Tags = [new Tag("Sample Tag")],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
new ListItem(
|
||||||
|
new AnonymousCommand(() =>
|
||||||
|
{
|
||||||
|
var t = new ToastStatusMessage(new StatusMessage()
|
||||||
|
{
|
||||||
|
Message = "Primary command invoked",
|
||||||
|
State = MessageState.Info,
|
||||||
|
});
|
||||||
|
t.Show();
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Result = CommandResult.KeepOpen(),
|
||||||
|
Icon = new IconInfo("\uE712"),
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Title = "You can add context menu items too. Press Ctrl+k",
|
||||||
|
Subtitle = "Try pressing Ctrl+1 with me selected",
|
||||||
|
Icon = new IconInfo("\uE712"),
|
||||||
|
MoreCommands = [
|
||||||
|
new CommandContextItem(
|
||||||
|
new AnonymousCommand(() =>
|
||||||
|
{
|
||||||
|
var t = new ToastStatusMessage(new StatusMessage()
|
||||||
|
{
|
||||||
|
Message = "Secondary command invoked",
|
||||||
|
State = MessageState.Warning,
|
||||||
|
});
|
||||||
|
t.Show();
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Name = "Secondary command",
|
||||||
|
Icon = new IconInfo("\uF147"), // Dial 2
|
||||||
|
Result = CommandResult.KeepOpen(),
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Title = "I'm a second command",
|
||||||
|
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number1),
|
||||||
|
},
|
||||||
|
new CommandContextItem(
|
||||||
|
new AnonymousCommand(() =>
|
||||||
|
{
|
||||||
|
var t = new ToastStatusMessage(new StatusMessage()
|
||||||
|
{
|
||||||
|
Message = "Third command invoked",
|
||||||
|
State = MessageState.Error,
|
||||||
|
});
|
||||||
|
t.Show();
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Name = "Do it",
|
||||||
|
Icon = new IconInfo("\uF148"), // dial 3
|
||||||
|
Result = CommandResult.KeepOpen(),
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Title = "A third command too",
|
||||||
|
Icon = new IconInfo("\uF148"),
|
||||||
|
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number2),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
new ListItem(new SendMessageCommand())
|
new ListItem(new SendMessageCommand())
|
||||||
{
|
{
|
||||||
Title = "I send lots of messages",
|
Title = "I send lots of messages",
|
||||||
@@ -91,7 +155,35 @@ internal sealed partial class SampleListPage : ListPage
|
|||||||
})
|
})
|
||||||
{
|
{
|
||||||
Title = "Confirm twice before doing something",
|
Title = "Confirm twice before doing something",
|
||||||
}
|
},
|
||||||
|
new ListItem(
|
||||||
|
new AnonymousCommand(() =>
|
||||||
|
{
|
||||||
|
var fg = PInvoke.GetForegroundWindow();
|
||||||
|
var bufferSize = PInvoke.GetWindowTextLength(fg) + 1;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (char* windowNameChars = new char[bufferSize])
|
||||||
|
{
|
||||||
|
if (PInvoke.GetWindowText(fg, windowNameChars, bufferSize) == 0)
|
||||||
|
{
|
||||||
|
var emptyToast = new ToastStatusMessage(new StatusMessage() { Message = "FG Window didn't have a title", State = MessageState.Warning });
|
||||||
|
emptyToast.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
var windowName = new string(windowNameChars);
|
||||||
|
var nameToast = new ToastStatusMessage(new StatusMessage() { Message = $"FG Window is {windowName}", State = MessageState.Success });
|
||||||
|
nameToast.Show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Result = CommandResult.KeepOpen(),
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Title = "Get the name of the Foreground window",
|
||||||
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,12 @@
|
|||||||
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Windows.CsWin32">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
<!--
|
<!--
|
||||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||||
|
@@ -2,14 +2,19 @@
|
|||||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using Windows.Foundation;
|
|
||||||
using Windows.System;
|
using Windows.System;
|
||||||
|
|
||||||
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
|
||||||
public partial class KeyChordHelpers
|
public partial class KeyChordHelpers
|
||||||
{
|
{
|
||||||
public static KeyChord FromModifiers(bool ctrl, bool alt, bool shift, bool win, int vkey, int scanCode)
|
public static KeyChord FromModifiers(
|
||||||
|
bool ctrl = false,
|
||||||
|
bool alt = false,
|
||||||
|
bool shift = false,
|
||||||
|
bool win = false,
|
||||||
|
int vkey = 0,
|
||||||
|
int scanCode = 0)
|
||||||
{
|
{
|
||||||
var modifiers = (ctrl ? VirtualKeyModifiers.Control : VirtualKeyModifiers.None)
|
var modifiers = (ctrl ? VirtualKeyModifiers.Control : VirtualKeyModifiers.None)
|
||||||
| (alt ? VirtualKeyModifiers.Menu : VirtualKeyModifiers.None)
|
| (alt ? VirtualKeyModifiers.Menu : VirtualKeyModifiers.None)
|
||||||
@@ -18,4 +23,15 @@ public partial class KeyChordHelpers
|
|||||||
;
|
;
|
||||||
return new(modifiers, vkey, scanCode);
|
return new(modifiers, vkey, scanCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static KeyChord FromModifiers(
|
||||||
|
bool ctrl = false,
|
||||||
|
bool alt = false,
|
||||||
|
bool shift = false,
|
||||||
|
bool win = false,
|
||||||
|
VirtualKey vkey = VirtualKey.None,
|
||||||
|
int scanCode = 0)
|
||||||
|
{
|
||||||
|
return FromModifiers(ctrl, alt, shift, win, (int)vkey, scanCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user