diff --git a/src/cascadia/TerminalSettingsEditor/Actions.cpp b/src/cascadia/TerminalSettingsEditor/Actions.cpp
index 82c9288945..08c7835af3 100644
--- a/src/cascadia/TerminalSettingsEditor/Actions.cpp
+++ b/src/cascadia/TerminalSettingsEditor/Actions.cpp
@@ -7,7 +7,9 @@
#include "LibraryResources.h"
#include "../TerminalSettingsModel/AllShortcutActions.h"
+using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Navigation;
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
@@ -42,4 +44,65 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
}
+
+ // Builds the "view all" flyout lazily on the first click of a
+ // row's "..." button, then caches it on the button so subsequent clicks
+ // just re-show it.
+ void Actions::ViewAllKeyChordsButton_Click(const IInspectable& sender, const RoutedEventArgs& /*e*/)
+ {
+ const auto button = sender.try_as
-
+
+
+
+
+
+
@@ -233,25 +147,23 @@
-
+
+
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
+
-
+
@@ -532,24 +345,14 @@
-
-
-
-
-
-
-
+
-
+
@@ -572,66 +375,35 @@
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/KeyChordVisual.cpp b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.cpp
new file mode 100644
index 0000000000..54bd0686bb
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.cpp
@@ -0,0 +1,131 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "KeyChordVisual.h"
+#include "KeyChordVisual.g.cpp"
+
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+using namespace winrt::Windows::Foundation;
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ DependencyProperty KeyChordVisual::_KeyChordProperty{ nullptr };
+
+ KeyChordVisual::KeyChordVisual()
+ {
+ InitializeComponent();
+ _InitializeProperties();
+ }
+
+ void KeyChordVisual::_InitializeProperties()
+ {
+ if (!_KeyChordProperty)
+ {
+ _KeyChordProperty =
+ DependencyProperty::Register(
+ L"KeyChord",
+ xaml_typename(),
+ xaml_typename(),
+ PropertyMetadata{ nullptr, PropertyChangedCallback{ &KeyChordVisual::_OnKeyChordChanged } });
+ }
+ }
+
+ void KeyChordVisual::_OnKeyChordChanged(const DependencyObject& d, const DependencyPropertyChangedEventArgs& /*e*/)
+ {
+ if (const auto control{ d.try_as() })
+ {
+ const auto controlImpl{ get_self(control) };
+ controlImpl->_UpdateKeyVisuals();
+ }
+ }
+
+ // Capitalizes the first character of the provided string.
+ // Examples: "enter" -> "Enter", "f1" -> "F1", "v" -> "V"
+ static winrt::hstring _formatMainKeyName(std::wstring_view part)
+ {
+ if (part.empty())
+ {
+ return {};
+ }
+
+ std::wstring buffer{ part };
+ buffer[0] = til::toupper_ascii(buffer[0]);
+ return winrt::hstring{ buffer };
+ }
+
+ void KeyChordVisual::_UpdateKeyVisuals()
+ {
+ auto panel{ KeysPanel() };
+ if (!panel)
+ {
+ return;
+ }
+ panel.Children().Clear();
+
+ const auto kc{ KeyChord() };
+ if (!kc)
+ {
+ return;
+ }
+
+ // Reuse the canonical serialization so the key naming stays in sync with the
+ // rest of the app. Then split on '+' (no key name in the table contains a literal
+ // '+'; VK_OEM_PLUS serializes as "plus") and render each part as its own visual.
+ const auto serialized{ Model::KeyChordSerialization::ToString(kc) };
+ if (serialized.empty())
+ {
+ return;
+ }
+
+ const std::wstring_view full{ serialized };
+ for (const auto part : til::split_iterator{ full, L'+' })
+ {
+ if (til::equals_insensitive_ascii(part, L"win"))
+ {
+ _AddGlyphKey();
+ }
+ else if (til::equals_insensitive_ascii(part, L"ctrl"))
+ {
+ _AddTextKey(L"Ctrl");
+ }
+ else if (til::equals_insensitive_ascii(part, L"alt"))
+ {
+ _AddTextKey(L"Alt");
+ }
+ else if (til::equals_insensitive_ascii(part, L"shift"))
+ {
+ _AddTextKey(L"Shift");
+ }
+ else
+ {
+ _AddTextKey(_formatMainKeyName(part));
+ }
+ }
+ }
+
+ void KeyChordVisual::_AddTextKey(const winrt::hstring& text)
+ {
+ const auto tmpl{ Resources().Lookup(box_value(L"KeyChordVisualTextKeyTemplate")).as() };
+ const auto border{ tmpl.LoadContent().as() };
+ if (const auto tb{ border.Child().try_as() })
+ {
+ tb.Text(text);
+ }
+ KeysPanel().Children().Append(border);
+ }
+
+ void KeyChordVisual::_AddGlyphKey()
+ {
+ const auto tmpl{ Resources().Lookup(box_value(L"KeyChordVisualWindowsKeyTemplate")).as() };
+ const auto border{ tmpl.LoadContent().as() };
+
+ // Provide an accessible name for the glyph since it has no text fallback.
+ if (const auto path{ border.Child() })
+ {
+ Automation::AutomationProperties::SetName(path, L"Win");
+ }
+ KeysPanel().Children().Append(border);
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/KeyChordVisual.h b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.h
new file mode 100644
index 0000000000..b8e06e851b
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.h
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#pragma once
+
+#include "KeyChordVisual.g.h"
+#include "Utils.h"
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
+{
+ struct KeyChordVisual : KeyChordVisualT
+ {
+ public:
+ KeyChordVisual();
+
+ DEPENDENCY_PROPERTY(Control::KeyChord, KeyChord);
+
+ private:
+ static void _InitializeProperties();
+ static void _OnKeyChordChanged(const Windows::UI::Xaml::DependencyObject& d, const Windows::UI::Xaml::DependencyPropertyChangedEventArgs& e);
+
+ void _UpdateKeyVisuals();
+ void _AddTextKey(const winrt::hstring& text);
+ void _AddGlyphKey();
+ };
+}
+
+namespace winrt::Microsoft::Terminal::Settings::Editor::factory_implementation
+{
+ BASIC_FACTORY(KeyChordVisual);
+}
diff --git a/src/cascadia/TerminalSettingsEditor/KeyChordVisual.idl b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.idl
new file mode 100644
index 0000000000..7dd32097cc
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.idl
@@ -0,0 +1,13 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+namespace Microsoft.Terminal.Settings.Editor
+{
+ [default_interface] runtimeclass KeyChordVisual : Windows.UI.Xaml.Controls.UserControl
+ {
+ KeyChordVisual();
+
+ Microsoft.Terminal.Control.KeyChord KeyChord;
+ static Windows.UI.Xaml.DependencyProperty KeyChordProperty { get; };
+ }
+}
diff --git a/src/cascadia/TerminalSettingsEditor/KeyChordVisual.xaml b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.xaml
new file mode 100644
index 0000000000..140b72a137
--- /dev/null
+++ b/src/cascadia/TerminalSettingsEditor/KeyChordVisual.xaml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
index ba65864e3f..a3d16e6ea1 100644
--- a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
+++ b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj
@@ -86,6 +86,9 @@
KeyChordListener.xaml
+
+ KeyChordVisual.xaml
+ Launch.xaml
@@ -213,6 +216,9 @@
Designer
+
+ Designer
+ Designer
@@ -294,6 +300,9 @@
KeyChordListener.xaml
+
+ KeyChordVisual.xaml
+ Launch.xaml
@@ -421,6 +430,10 @@
KeyChordListener.xamlCode
+
+ KeyChordVisual.xaml
+ Code
+ Launch.xamlCode
diff --git a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
index 7efa01293a..dd276d82ec 100644
--- a/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
+++ b/src/cascadia/TerminalSettingsEditor/Microsoft.Terminal.Settings.Editor.vcxproj.filters
@@ -52,6 +52,7 @@
+
diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
index 2320638f14..15dd044c37 100644
--- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
@@ -289,8 +289,8 @@
Header for a control to toggle whether the terminal should automatically detect URLs and make them clickable, or not.
- Default URL to use for the "Search web" action
- Header for a control to set the query URL when using the "search web" action.
+ Default URL to use for the "Search web" shortcut
+ Header for a control to set the query URL when using the "search web" shortcut.The placeholder "%s" will be replaced with the search query.
@@ -590,7 +590,7 @@
Additional description for what the "force vt input" setting does. Presented near "Globals_ForceVTInput.Header".
- This allows actions such as Global Summon and Quake Mode actions to work even when no windows are open.
+ This allows shortcuts such as Global Summon and Quake Mode shortcuts to work even when no windows are open.Additional description for what the "allow headless" setting does. Presented near "Globals_AllowHeadless.Header".
@@ -678,12 +678,12 @@
Header for the "defaults" menu item. This navigates to a page that lets you see and modify settings that affect profiles. This is the lowest layer of profile settings that all other profile settings are based on. If a profile doesn't define a setting, this page is responsible for figuring out what that setting is supposed to be.
- Actions
- Header for the "actions" menu item. This navigates to a page that lets you see the available commands in the app.
+ Shortcuts
+ Header for the "shortcuts" menu item. This navigates to a page that lets you see the available keyboard shortcuts in the app. (Resource key kept as "Nav_Actions" for stability.)
- Edit Action...
- Header for the "edit action" page. This is the page that lets you modify a specific command and its key bindings.
+ Edit Shortcut...
+ Header for the "edit shortcut" page. This is the page that lets you modify a specific command and its key bindings. (Resource key kept as "Nav_EditAction" for stability.)Extensions
@@ -1786,28 +1786,28 @@
A description for what the delete unfocused appearance button does.
- Learn more about actions
- Disclaimer presented at the top of the actions page to redirect the user to documentation regarding actions.
+ Learn more about shortcuts
+ Disclaimer presented at the top of the shortcuts page to redirect the user to documentation regarding keyboard shortcuts.
- Delete action
- Button label that deletes the selected action.
+ Delete shortcut
+ Button label that deletes the selected shortcut.
- Action name
- Label for the text box that edits the action name.
+ Shortcut name
+ Label for the text box that edits the shortcut name.
- Action name
- Placeholder text for the text box where the user can edit the action name.
+ Shortcut name
+ Placeholder text for the text box where the user can edit the shortcut name.
- Action type
- Label for the combo box that edits the action type.
+ Shortcut type
+ Label for the combo box that edits the shortcut type (which action runs when this shortcut is invoked).
- Keybindings
- Name for a control which contains the list of keybindings for the current command.
+ Shortcuts
+ Name for a control which contains the list of keyboard shortcuts for the current command.Command details
@@ -1818,44 +1818,44 @@
Label for the list of editable arguments for the currently selected action.
- Keybindings
- Label for the list of editable keybindings for the current command.
+ Shortcuts
+ Label for the list of editable keyboard shortcuts for the current command.
- Add keybinding
- Button label that adds a keybinding to the current action.
+ Add shortcut
+ Button label that adds a keyboard shortcut to the current action.and {} moreText that will be read out by a screen reader indicating that additional keybindings exist for this command. {} will be replaced by the number of additional keybindings.
- Yes, delete key binding
- Button label that confirms deletion of a key binding entry.
+ Yes, delete shortcut
+ Button label that confirms deletion of a keyboard shortcut entry.
- Are you sure you want to delete this key binding?
- Confirmation message displayed when the user attempts to delete a key binding entry.
+ Are you sure you want to delete this shortcut?
+ Confirmation message displayed when the user attempts to delete a keyboard shortcut entry.
- Yes, delete action
- Button label that confirms deletion of an action.
+ Yes, delete shortcut
+ Button label that confirms deletion of a shortcut entry.
- Are you sure you want to delete this action?
- Confirmation message displayed when the user attempts to delete an action.
+ Are you sure you want to delete this shortcut?
+ Confirmation message displayed when the user attempts to delete a shortcut entry.
- Invalid key chord. Please enter a valid key chord.
- Error message displayed when an invalid key chord is input by the user.
+ Invalid shortcut. Please enter a valid keyboard shortcut.
+ Error message displayed when an invalid keyboard shortcut is input by the user.YesButton label that confirms the deletion of a conflicting key binding to allow the current key binding to be registered.
- The provided key chord is already being used by the following action:
- Error message displayed when a key chord that is already in use is input by the user. The name of the conflicting key chord is displayed after this message.
+ The provided shortcut is already being used by the following action:
+ Error message displayed when a keyboard shortcut that is already in use is input by the user. The name of the conflicting shortcut is displayed after this message.Would you like to overwrite it?
@@ -1882,12 +1882,60 @@
Text label for a button that can be used to begin making changes to a key binding entry.
- Add new
- Button label that creates a new action on the actions page.
+ Add new shortcut
+ Button label that creates a new keyboard shortcut on the shortcuts page.
-
- Action
- Label for a control that sets the action of a key binding.
+
+ View all shortcuts
+ Tooltip for a button on each row of the Shortcuts page that opens a flyout listing every keyboard shortcut registered for that action.
+
+
+ No shortcuts
+ Empty-state message shown inside the "view all shortcuts" flyout (opened from each row's "..." button on the Shortcuts page) when the action has no keyboard shortcuts registered.
+
+
+ Shortcut type
+ Header for the shortcut-type setting on the Edit Shortcut page (lets the user pick which action runs when this shortcut is invoked).
+
+
+ Shortcut name
+ Header for the shortcut-name setting on the Edit Shortcut page (lets the user provide a friendly name for this shortcut).
+
+
+ Shortcuts
+ Header for the shortcuts expander on the Edit Shortcut page.
+
+
+ Customize keyboard shortcuts to speed up common actions and workflows.
+ Help text shown under the "Shortcuts" header on the Edit Shortcut page.
+
+
+ New shortcut
+ Header for the "add a new shortcut" row on the Edit Shortcut page.
+
+
+ Add shortcut
+ Label for the accent button that appends a new keyboard shortcut to the current action.
+
+
+ Additional customizations
+ Header for the additional customizations expander on the Edit Action page (contains action name and per-action argument settings).
+
+
+ Fine tune how shortcuts behave.
+ Help text shown under the "Additional customizations" header on the Edit Shortcut page.
+
+
+ Shortcut #{}
+ {Locked="#{}"} Header label for an individual keyboard shortcut inside the "Shortcuts" expander on the Edit Shortcut page. {} is replaced with the 1-based index of the shortcut (e.g. "Shortcut #1").
+
+
+ Delete this shortcut
+ Header for the setting container that holds the "Delete shortcut" button at the bottom of the Edit Shortcut page.
+
+
+ This shortcut will be removed and any shortcuts associated with it will no longer work.
+ Help text shown under the "Delete this shortcut" setting container on the Edit Shortcut page.Use global setting
diff --git a/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml b/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml
index 4efa5be861..426990065e 100644
--- a/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml
+++ b/src/cascadia/TerminalSettingsEditor/SettingContainerStyle.xaml
@@ -121,6 +121,11 @@
0,4,8,416
+
+ 16,8,8,8
+ 64
+ 0,4,0,0
+
+
+
+