mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
Detect Shortcut: Hold Esc/Enter to Cancel/Accept (#2135)
* Detect Shortcut: Hold Esc/Enter to Discard/Apply changes Bypass shorcut/single key remapping by holding the navigation keys
This commit is contained in:
committed by
GitHub
parent
5d9b71b038
commit
c37884bdb7
@@ -72,15 +72,31 @@ void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, Xam
|
||||
// ContentDialog requires manually setting the XamlRoot (https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)
|
||||
detectShortcutBox.XamlRoot(xamlRoot);
|
||||
detectShortcutBox.Title(box_value(L"Press the keys in shortcut:"));
|
||||
detectShortcutBox.PrimaryButtonText(to_hstring(L"OK"));
|
||||
detectShortcutBox.IsPrimaryButtonEnabled(false);
|
||||
detectShortcutBox.IsSecondaryButtonEnabled(false);
|
||||
detectShortcutBox.CloseButtonText(to_hstring(L"Cancel"));
|
||||
|
||||
// Get the linked text block for the "Type shortcut" button that was clicked
|
||||
TextBlock linkedShortcutText = getSiblingElement(sender).as<TextBlock>();
|
||||
|
||||
// OK button
|
||||
detectShortcutBox.PrimaryButtonClick([=, &shortcutRemapBuffer, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
|
||||
auto unregisterKeys = [&keyboardManagerState]() {
|
||||
std::thread t1(&KeyboardManagerState::UnregisterKeyDelay, &keyboardManagerState, VK_ESCAPE);
|
||||
std::thread t2(&KeyboardManagerState::UnregisterKeyDelay, &keyboardManagerState, VK_RETURN);
|
||||
t1.detach();
|
||||
t2.detach();
|
||||
};
|
||||
|
||||
auto selectDetectedShortcutAndResetKeys = [&keyboardManagerState](DWORD key) {
|
||||
keyboardManagerState.SelectDetectedShortcut(key);
|
||||
keyboardManagerState.ResetDetectedShortcutKey(key);
|
||||
};
|
||||
|
||||
auto onAccept = [linkedShortcutText,
|
||||
detectShortcutBox,
|
||||
&keyboardManagerState,
|
||||
&shortcutRemapBuffer,
|
||||
unregisterKeys,
|
||||
rowIndex,
|
||||
colIndex] {
|
||||
// Save the detected shortcut in the linked text block
|
||||
Shortcut detectedShortcutKeys = keyboardManagerState.GetDetectedShortcut();
|
||||
|
||||
@@ -92,14 +108,71 @@ void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, Xam
|
||||
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
unregisterKeys();
|
||||
detectShortcutBox.Hide();
|
||||
};
|
||||
|
||||
TextBlock primaryButtonText;
|
||||
primaryButtonText.Text(to_hstring(L"OK"));
|
||||
|
||||
Button primaryButton;
|
||||
primaryButton.HorizontalAlignment(HorizontalAlignment::Stretch);
|
||||
primaryButton.Margin({ 2, 2, 2, 2 });
|
||||
primaryButton.Content(primaryButtonText);
|
||||
|
||||
// OK button
|
||||
primaryButton.Click([onAccept](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
onAccept();
|
||||
});
|
||||
|
||||
keyboardManagerState.RegisterKeyDelay(
|
||||
VK_RETURN,
|
||||
selectDetectedShortcutAndResetKeys,
|
||||
[primaryButton, detectShortcutBox](DWORD) {
|
||||
detectShortcutBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
[primaryButton] {
|
||||
primaryButton.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::DarkGray() });
|
||||
});
|
||||
},
|
||||
[onAccept, detectShortcutBox](DWORD) {
|
||||
detectShortcutBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
[onAccept] {
|
||||
onAccept();
|
||||
});
|
||||
});
|
||||
|
||||
TextBlock cancelButtonText;
|
||||
cancelButtonText.Text(to_hstring(L"Cancel"));
|
||||
|
||||
Button cancelButton;
|
||||
cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch);
|
||||
cancelButton.Margin({ 2, 2, 2, 2 });
|
||||
cancelButton.Content(cancelButtonText);
|
||||
// Cancel button
|
||||
detectShortcutBox.CloseButtonClick([&keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
|
||||
cancelButton.Click([detectShortcutBox, unregisterKeys, &keyboardManagerState](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
unregisterKeys();
|
||||
detectShortcutBox.Hide();
|
||||
});
|
||||
|
||||
keyboardManagerState.RegisterKeyDelay(
|
||||
VK_ESCAPE,
|
||||
selectDetectedShortcutAndResetKeys,
|
||||
[&keyboardManagerState, detectShortcutBox, unregisterKeys](DWORD) {
|
||||
detectShortcutBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
[detectShortcutBox] {
|
||||
detectShortcutBox.Hide();
|
||||
});
|
||||
|
||||
keyboardManagerState.ResetUIState();
|
||||
unregisterKeys();
|
||||
},
|
||||
nullptr);
|
||||
|
||||
// StackPanel parent for the displayed text in the dialog
|
||||
Windows::UI::Xaml::Controls::StackPanel stackPanel;
|
||||
detectShortcutBox.Content(stackPanel);
|
||||
@@ -112,9 +185,36 @@ void ShortcutControl::createDetectShortcutWindow(IInspectable const& sender, Xam
|
||||
|
||||
// Target StackPanel to place the selected key
|
||||
Windows::UI::Xaml::Controls::StackPanel keyStackPanel;
|
||||
stackPanel.Children().Append(keyStackPanel);
|
||||
keyStackPanel.Orientation(Orientation::Horizontal);
|
||||
stackPanel.Children().Append(keyStackPanel);
|
||||
|
||||
TextBlock holdEscInfo;
|
||||
holdEscInfo.Text(winrt::to_hstring("Hold Esc to discard"));
|
||||
holdEscInfo.FontSize(12);
|
||||
holdEscInfo.Margin({ 0, 20, 0, 0 });
|
||||
stackPanel.Children().Append(holdEscInfo);
|
||||
|
||||
TextBlock holdEnterInfo;
|
||||
holdEnterInfo.Text(winrt::to_hstring("Hold Enter to apply"));
|
||||
holdEnterInfo.FontSize(12);
|
||||
holdEnterInfo.Margin({ 0, 0, 0, 0 });
|
||||
stackPanel.Children().Append(holdEnterInfo);
|
||||
|
||||
ColumnDefinition primaryButtonColumn;
|
||||
ColumnDefinition cancelButtonColumn;
|
||||
|
||||
Grid buttonPanel;
|
||||
buttonPanel.Margin({ 0, 20, 0, 0 });
|
||||
buttonPanel.HorizontalAlignment(HorizontalAlignment::Stretch);
|
||||
buttonPanel.ColumnDefinitions().Append(primaryButtonColumn);
|
||||
buttonPanel.ColumnDefinitions().Append(cancelButtonColumn);
|
||||
buttonPanel.SetColumn(primaryButton, 0);
|
||||
buttonPanel.SetColumn(cancelButton, 1);
|
||||
|
||||
buttonPanel.Children().Append(primaryButton);
|
||||
buttonPanel.Children().Append(cancelButton);
|
||||
|
||||
stackPanel.Children().Append(buttonPanel);
|
||||
stackPanel.UpdateLayout();
|
||||
|
||||
// Configure the keyboardManagerState to store the UI information.
|
||||
|
||||
@@ -68,21 +68,32 @@ void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, Xa
|
||||
{
|
||||
// ContentDialog for detecting remap key. This is the parent UI element.
|
||||
ContentDialog detectRemapKeyBox;
|
||||
|
||||
|
||||
// TODO: Hardcoded light theme, since the app is not theme aware ATM.
|
||||
detectRemapKeyBox.RequestedTheme(ElementTheme::Light);
|
||||
// ContentDialog requires manually setting the XamlRoot (https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.contentdialog#contentdialog-in-appwindow-or-xaml-islands)
|
||||
detectRemapKeyBox.XamlRoot(xamlRoot);
|
||||
detectRemapKeyBox.Title(box_value(L"Press a key on selected keyboard:"));
|
||||
detectRemapKeyBox.PrimaryButtonText(to_hstring(L"OK"));
|
||||
detectRemapKeyBox.IsPrimaryButtonEnabled(false);
|
||||
detectRemapKeyBox.IsSecondaryButtonEnabled(false);
|
||||
detectRemapKeyBox.CloseButtonText(to_hstring(L"Cancel"));
|
||||
|
||||
// Get the linked text block for the "Type Key" button that was clicked
|
||||
TextBlock linkedRemapText = getSiblingElement(sender).as<TextBlock>();
|
||||
|
||||
// OK button
|
||||
detectRemapKeyBox.PrimaryButtonClick([=, &singleKeyRemapBuffer, &keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
|
||||
auto unregisterKeys = [&keyboardManagerState]() {
|
||||
std::thread t1(&KeyboardManagerState::UnregisterKeyDelay, &keyboardManagerState, VK_ESCAPE);
|
||||
std::thread t2(&KeyboardManagerState::UnregisterKeyDelay, &keyboardManagerState, VK_RETURN);
|
||||
t1.detach();
|
||||
t2.detach();
|
||||
};
|
||||
|
||||
auto onAccept = [linkedRemapText,
|
||||
detectRemapKeyBox,
|
||||
&keyboardManagerState,
|
||||
&singleKeyRemapBuffer,
|
||||
unregisterKeys,
|
||||
rowIndex,
|
||||
colIndex] {
|
||||
// Save the detected key in the linked text block
|
||||
DWORD detectedKey = keyboardManagerState.GetDetectedSingleRemapKey();
|
||||
|
||||
@@ -94,14 +105,69 @@ void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, Xa
|
||||
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
unregisterKeys();
|
||||
detectRemapKeyBox.Hide();
|
||||
};
|
||||
|
||||
TextBlock primaryButtonText;
|
||||
primaryButtonText.Text(to_hstring(L"OK"));
|
||||
|
||||
Button primaryButton;
|
||||
primaryButton.HorizontalAlignment(HorizontalAlignment::Stretch);
|
||||
primaryButton.Margin({ 2, 2, 2, 2 });
|
||||
primaryButton.Content(primaryButtonText);
|
||||
primaryButton.Click([onAccept](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
onAccept();
|
||||
});
|
||||
|
||||
keyboardManagerState.RegisterKeyDelay(
|
||||
VK_RETURN,
|
||||
std::bind(&KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
|
||||
[primaryButton, detectRemapKeyBox](DWORD) {
|
||||
detectRemapKeyBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
[primaryButton] {
|
||||
primaryButton.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::DarkGray() });
|
||||
});
|
||||
},
|
||||
[onAccept, detectRemapKeyBox](DWORD) {
|
||||
detectRemapKeyBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
[onAccept] {
|
||||
onAccept();
|
||||
});
|
||||
});
|
||||
|
||||
TextBlock cancelButtonText;
|
||||
cancelButtonText.Text(to_hstring(L"Cancel"));
|
||||
|
||||
Button cancelButton;
|
||||
cancelButton.HorizontalAlignment(HorizontalAlignment::Stretch);
|
||||
cancelButton.Margin({ 2, 2, 2, 2 });
|
||||
cancelButton.Content(cancelButtonText);
|
||||
// Cancel button
|
||||
detectRemapKeyBox.CloseButtonClick([&keyboardManagerState](Windows::UI::Xaml::Controls::ContentDialog const& sender, ContentDialogButtonClickEventArgs const&) {
|
||||
cancelButton.Click([detectRemapKeyBox, unregisterKeys, &keyboardManagerState](IInspectable const& sender, RoutedEventArgs const&) {
|
||||
// Reset the keyboard manager UI state
|
||||
keyboardManagerState.ResetUIState();
|
||||
unregisterKeys();
|
||||
detectRemapKeyBox.Hide();
|
||||
});
|
||||
|
||||
keyboardManagerState.RegisterKeyDelay(
|
||||
VK_ESCAPE,
|
||||
std::bind(&KeyboardManagerState::SelectDetectedRemapKey, &keyboardManagerState, std::placeholders::_1),
|
||||
[&keyboardManagerState, detectRemapKeyBox, unregisterKeys](DWORD) {
|
||||
detectRemapKeyBox.Dispatcher().RunAsync(
|
||||
Windows::UI::Core::CoreDispatcherPriority::Normal,
|
||||
[detectRemapKeyBox] {
|
||||
detectRemapKeyBox.Hide();
|
||||
});
|
||||
|
||||
keyboardManagerState.ResetUIState();
|
||||
unregisterKeys();
|
||||
},
|
||||
nullptr);
|
||||
|
||||
// StackPanel parent for the displayed text in the dialog
|
||||
Windows::UI::Xaml::Controls::StackPanel stackPanel;
|
||||
detectRemapKeyBox.Content(stackPanel);
|
||||
@@ -114,8 +180,36 @@ void SingleKeyRemapControl::createDetectKeyWindow(IInspectable const& sender, Xa
|
||||
|
||||
// Target StackPanel to place the selected key
|
||||
Windows::UI::Xaml::Controls::StackPanel keyStackPanel;
|
||||
stackPanel.Children().Append(keyStackPanel);
|
||||
keyStackPanel.Orientation(Orientation::Horizontal);
|
||||
stackPanel.Children().Append(keyStackPanel);
|
||||
|
||||
TextBlock holdEscInfo;
|
||||
holdEscInfo.Text(winrt::to_hstring("Hold Esc to discard"));
|
||||
holdEscInfo.FontSize(12);
|
||||
holdEscInfo.Margin({ 0, 20, 0, 0 });
|
||||
stackPanel.Children().Append(holdEscInfo);
|
||||
|
||||
TextBlock holdEnterInfo;
|
||||
holdEnterInfo.Text(winrt::to_hstring("Hold Enter to apply"));
|
||||
holdEnterInfo.FontSize(12);
|
||||
holdEnterInfo.Margin({ 0, 0, 0, 0 });
|
||||
stackPanel.Children().Append(holdEnterInfo);
|
||||
|
||||
ColumnDefinition primaryButtonColumn;
|
||||
ColumnDefinition cancelButtonColumn;
|
||||
|
||||
Grid buttonPanel;
|
||||
buttonPanel.Margin({ 0, 20, 0, 0 });
|
||||
buttonPanel.HorizontalAlignment(HorizontalAlignment::Stretch);
|
||||
buttonPanel.ColumnDefinitions().Append(primaryButtonColumn);
|
||||
buttonPanel.ColumnDefinitions().Append(cancelButtonColumn);
|
||||
buttonPanel.SetColumn(primaryButton, 0);
|
||||
buttonPanel.SetColumn(cancelButton, 1);
|
||||
|
||||
buttonPanel.Children().Append(primaryButton);
|
||||
buttonPanel.Children().Append(cancelButton);
|
||||
|
||||
stackPanel.Children().Append(buttonPanel);
|
||||
stackPanel.UpdateLayout();
|
||||
|
||||
// Configure the keyboardManagerState to store the UI information.
|
||||
|
||||
Reference in New Issue
Block a user