How to achieve global keyboard shortcuts in UWP apps
We know there is a KeyDown
event which will be fired while pressing the specified key when a UIElement is focused. However, in some case, you would like to fire the KeyDown
event whatever UIElement is focused.
Let's recall how we register a KeyDown
event handler to a UIElement:
-
Assume that a
TextBox
is named asInputBox
. -
In your code-behind: InputBox.KeyDown+=((sender,e)=>{ // Do something});
So, to achieve global keyboard shotcuts, instead of registering the event handler to a specified UIElement, just do this:
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
Wanna handle the logic in your ViewModel?
- First, assume that you have a
BasePage
that contains some base logical code. Define a event handler:
public event EventHandler<KeyEventArgs> GlobalPageKeyDown;
- Then, in this page's OnNavigatedTo & onNavigatedFrom override method, register and safely unregister the event handler(NOTE: if you don't unregister the event, it will cause memory leak and the whole page instance won't be recycled.)
OnNaivagedTo:
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
OnNaivagedFrom:
Window.Current.CoreWindow.KeyDown -= CoreWindow_KeyDown;
Then in CoreWindow_KeyDown
, invoke the event handler we defined above:
GlobalPageKeyDown?.Invoke(sender, args);
- Any page that derived from the
BasePage
can add this in your XAML code:
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:attach="using:JP.Utils.Framework"
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="GlobalPageKeyDown">
<attach:InvokeCommandByKeyDown Command="{x:Bind LoginVM.LoginCommand}" PressedKey="Enter" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
Note that it's using Behavior SDK, which has been updated to support UWP apps recently.
And InvokeCommandByKeyDown
is a custom action we will define below.
- Here is the code of
InvokeCommandByKeyDown
:
public class InvokeCommandByKeyDown:DependencyObject,IAction
{
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(InvokeCommandByKeyDown), new PropertyMetadata(null));
public VirtualKey PressedKey
{
get { return (VirtualKey)GetValue(PressedKeyProperty); }
set { SetValue(PressedKeyProperty, value); }
}
public static readonly DependencyProperty PressedKeyProperty =
DependencyProperty.Register("PressedKey", typeof(VirtualKey), typeof(InvokeCommandByKeyDown), new PropertyMetadata(VirtualKey.None));
public object Execute(object sender, object parameter)
{
KeyRoutedEventArgs keyPrarm = parameter as KeyRoutedEventArgs;
if (keyPrarm != null)
{
if (keyPrarm.Key == PressedKey)
{
Command.Execute(sender);
keyPrarm.Handled = true;
}
}
else
{
KeyEventArgs param = parameter as KeyEventArgs;
if (param != null && param.VirtualKey == PressedKey)
{
Command.Execute(sender);
param.Handled = true;
}
}
return null;
}
}
Subscribe to JuniperPhoton's Blog
Get the latest posts delivered right to your inbox