diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index 1f28228137a..ebd7ec082ed 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -63,7 +63,7 @@ "setTabColor", "splitPane", "switchToTab", - "tabSwitcher", + "tabSearch", "toggleAlwaysOnTop", "toggleFocusMode", "toggleFullscreen", @@ -423,22 +423,6 @@ ], "required": [ "index" ] }, - "TabSwitcherAction": { - "description": "Arguments corresponding to a Tab Switcher Action", - "allOf": [ - { "$ref": "#/definitions/ShortcutAction" }, - { - "properties": { - "action": { "type": "string", "pattern": "tabSwitcher" }, - "anchorKey": { - "$ref": "#/definitions/AnchorKey", - "default": null, - "description": "If provided, the tab switcher will stay open as long as the anchor key is held down. The anchor key should be part of the keybinding that opens the switcher." - } - } - } - ] - }, "Keybinding": { "additionalProperties": false, "properties": { @@ -460,7 +444,6 @@ { "$ref": "#/definitions/WtAction" }, { "$ref": "#/definitions/CloseOtherTabsAction" }, { "$ref": "#/definitions/CloseTabsAfterAction" }, - { "$ref": "#/definitions/TabSwitcherAction" }, { "type": "null" } ] }, @@ -631,6 +614,11 @@ "default": true, "description": "When set to \"true\" closing a window with multiple tabs open will require confirmation. When set to \"false\", the confirmation dialog will not appear.", "type": "boolean" + }, + "useTabSwitcher": { + "default": true, + "description": "When set to \"true\", the \"nextTab\" and \"prevTab\" commands will use the tab switcher UI.", + "type": "boolean" } }, "required": [ diff --git a/src/cascadia/TerminalApp/ActionAndArgs.cpp b/src/cascadia/TerminalApp/ActionAndArgs.cpp index cda8332904c..76943897177 100644 --- a/src/cascadia/TerminalApp/ActionAndArgs.cpp +++ b/src/cascadia/TerminalApp/ActionAndArgs.cpp @@ -37,9 +37,8 @@ static constexpr std::string_view SendInputKey{ "sendInput" }; static constexpr std::string_view SetColorSchemeKey{ "setColorScheme" }; static constexpr std::string_view SetTabColorKey{ "setTabColor" }; static constexpr std::string_view SplitPaneKey{ "splitPane" }; -static constexpr std::string_view SwitchtoTabKey{ "switchToTab" }; static constexpr std::string_view SwitchToTabKey{ "switchToTab" }; -static constexpr std::string_view TabSwitcherKey{ "tabSwitcher" }; +static constexpr std::string_view TabSearchKey{ "tabSearch" }; static constexpr std::string_view ToggleAlwaysOnTopKey{ "toggleAlwaysOnTop" }; static constexpr std::string_view ToggleCommandPaletteKey{ "commandPalette" }; static constexpr std::string_view ToggleFocusModeKey{ "toggleFocusMode" }; @@ -96,7 +95,7 @@ namespace winrt::TerminalApp::implementation { SetTabColorKey, ShortcutAction::SetTabColor }, { SplitPaneKey, ShortcutAction::SplitPane }, { SwitchToTabKey, ShortcutAction::SwitchToTab }, - { TabSwitcherKey, ShortcutAction::ToggleTabSwitcher }, + { TabSearchKey, ShortcutAction::TabSearch }, { ToggleAlwaysOnTopKey, ShortcutAction::ToggleAlwaysOnTop }, { ToggleCommandPaletteKey, ShortcutAction::ToggleCommandPalette }, { ToggleFocusModeKey, ShortcutAction::ToggleFocusMode }, @@ -130,7 +129,6 @@ namespace winrt::TerminalApp::implementation { ShortcutAction::SetTabColor, SetTabColorArgs::FromJson }, { ShortcutAction::SplitPane, SplitPaneArgs::FromJson }, { ShortcutAction::SwitchToTab, SwitchToTabArgs::FromJson }, - { ShortcutAction::ToggleTabSwitcher, ToggleTabSwitcherArgs::FromJson }, { ShortcutAction::Invalid, nullptr }, }; @@ -280,6 +278,7 @@ namespace winrt::TerminalApp::implementation { ShortcutAction::SetTabColor, RS_(L"ResetTabColorCommandKey") }, { ShortcutAction::SplitPane, RS_(L"SplitPaneCommandKey") }, { ShortcutAction::SwitchToTab, RS_(L"SwitchToTabCommandKey") }, + { ShortcutAction::TabSearch, RS_(L"TabSearchCommandKey") }, { ShortcutAction::ToggleAlwaysOnTop, RS_(L"ToggleAlwaysOnTopCommandKey") }, { ShortcutAction::ToggleCommandPalette, RS_(L"ToggleCommandPaletteCommandKey") }, { ShortcutAction::ToggleFocusMode, RS_(L"ToggleFocusModeCommandKey") }, diff --git a/src/cascadia/TerminalApp/ActionArgs.cpp b/src/cascadia/TerminalApp/ActionArgs.cpp index d1af86df394..046068929b2 100644 --- a/src/cascadia/TerminalApp/ActionArgs.cpp +++ b/src/cascadia/TerminalApp/ActionArgs.cpp @@ -20,7 +20,6 @@ #include "SetTabColorArgs.g.cpp" #include "RenameTabArgs.g.cpp" #include "ExecuteCommandlineArgs.g.cpp" -#include "ToggleTabSwitcherArgs.g.h" #include "Utils.h" @@ -355,22 +354,4 @@ namespace winrt::TerminalApp::implementation _Index) }; } - - winrt::hstring ToggleTabSwitcherArgs::GenerateName() const - { - // If there's an anchor key set, don't generate a name so that - // it won't show up in the command palette. Only an unanchored - // tab switcher should be able to be toggled from the palette. - // TODO: GH#7179 - once this goes in, make sure to hide the - // anchor mode command that was given a name in settings. - if (_AnchorKey != Windows::System::VirtualKey::None) - { - return L""; - } - else - { - return RS_(L"ToggleTabSwitcherCommandKey"); - } - } - } diff --git a/src/cascadia/TerminalApp/ActionArgs.h b/src/cascadia/TerminalApp/ActionArgs.h index 7e140b17d18..c90430a84c6 100644 --- a/src/cascadia/TerminalApp/ActionArgs.h +++ b/src/cascadia/TerminalApp/ActionArgs.h @@ -22,7 +22,6 @@ #include "ExecuteCommandlineArgs.g.h" #include "CloseOtherTabsArgs.g.h" #include "CloseTabsAfterArgs.g.h" -#include "ToggleTabSwitcherArgs.g.h" #include "../../cascadia/inc/cppwinrt_utils.h" #include "Utils.h" @@ -548,34 +547,6 @@ namespace winrt::TerminalApp::implementation return { *args, {} }; } }; - - struct ToggleTabSwitcherArgs : public ToggleTabSwitcherArgsT - { - ToggleTabSwitcherArgs() = default; - GETSET_PROPERTY(Windows::System::VirtualKey, AnchorKey, Windows::System::VirtualKey::None); - - static constexpr std::string_view AnchorJsonKey{ "anchorKey" }; - - public: - hstring GenerateName() const; - - bool Equals(const IActionArgs& other) - { - auto otherAsUs = other.try_as(); - if (otherAsUs) - { - return otherAsUs->_AnchorKey == _AnchorKey; - } - return false; - }; - static FromJsonResult FromJson(const Json::Value& json) - { - // LOAD BEARING: Not using make_self here _will_ break you in the future! - auto args = winrt::make_self(); - JsonUtils::GetValueForKey(json, AnchorJsonKey, args->_AnchorKey); - return { *args, {} }; - } - }; } namespace winrt::TerminalApp::factory_implementation diff --git a/src/cascadia/TerminalApp/ActionArgs.idl b/src/cascadia/TerminalApp/ActionArgs.idl index 15d211e6f63..96b3b04386e 100644 --- a/src/cascadia/TerminalApp/ActionArgs.idl +++ b/src/cascadia/TerminalApp/ActionArgs.idl @@ -141,9 +141,4 @@ namespace TerminalApp { UInt32 Index { get; }; }; - - [default_interface] runtimeclass ToggleTabSwitcherArgs : IActionArgs - { - Windows.System.VirtualKey AnchorKey { get; }; - }; } diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index 9e9378bb411..8b4f4c6b0e1 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -456,27 +456,15 @@ namespace winrt::TerminalApp::implementation } } - void TerminalPage::_HandleToggleTabSwitcher(const IInspectable& /*sender*/, - const TerminalApp::ActionEventArgs& args) + void TerminalPage::_HandleOpenTabSearch(const IInspectable& /*sender*/, + const TerminalApp::ActionEventArgs& args) { - if (const auto& realArgs = args.ActionArgs().try_as()) - { - auto anchorKey = realArgs.AnchorKey(); + auto opt = _GetFocusedTabIndex(); + uint32_t startIdx = opt.value_or(0); - auto opt = _GetFocusedTabIndex(); - uint32_t startIdx = opt ? *opt : 0; + CommandPalette().EnableTabSwitcherMode(true, startIdx); + CommandPalette().Visibility(Visibility::Visible); - if (anchorKey != VirtualKey::None) - { - // TODO: GH#7178 - delta should also have the option of being -1, in the case when - // a user decides to open the tab switcher going to the prev tab. - int delta = 1; - startIdx = (startIdx + _tabs.Size() + delta) % _tabs.Size(); - } - - CommandPalette().EnableTabSwitcherMode(anchorKey, startIdx); - CommandPalette().Visibility(Visibility::Visible); - } args.Handled(true); } } diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp index 148898cd94f..d7adb4f2456 100644 --- a/src/cascadia/TerminalApp/AppLogic.cpp +++ b/src/cascadia/TerminalApp/AppLogic.cpp @@ -938,6 +938,13 @@ namespace winrt::TerminalApp::implementation if (auto focusedElement{ focusedObject.try_as() }) { focusedObject = focusedElement.Parent(); + + // Parent() seems to return null when the focusedElement is created from an ItemTemplate. + // Use the VisualTreeHelper's GetParent as a fallback. + if (!focusedObject) + { + focusedObject = winrt::Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(focusedElement); + } } else { diff --git a/src/cascadia/TerminalApp/CommandPalette.cpp b/src/cascadia/TerminalApp/CommandPalette.cpp index e1c96bc00d0..a8d0cb12d88 100644 --- a/src/cascadia/TerminalApp/CommandPalette.cpp +++ b/src/cascadia/TerminalApp/CommandPalette.cpp @@ -22,7 +22,6 @@ using namespace winrt::Windows::Foundation::Collections; namespace winrt::TerminalApp::implementation { CommandPalette::CommandPalette() : - _anchorKey{ VirtualKey::None }, _switcherStartIdx{ 0 } { InitializeComponent(); @@ -51,20 +50,16 @@ namespace winrt::TerminalApp::implementation RegisterPropertyChangedCallback(UIElement::VisibilityProperty(), [this](auto&&, auto&&) { if (Visibility() == Visibility::Visible) { - if (_currentMode == CommandPaletteMode::TabSwitcherMode) + if (_currentMode == CommandPaletteMode::TabSwitchMode) { - if (_anchorKey != VirtualKey::None) - { - _searchBox().Visibility(Visibility::Collapsed); - _filteredActionsView().Focus(FocusState::Keyboard); - } - else - { - _searchBox().Focus(FocusState::Programmatic); - } - + _searchBox().Visibility(Visibility::Collapsed); + _filteredActionsView().Focus(FocusState::Keyboard); _filteredActionsView().SelectedIndex(_switcherStartIdx); _filteredActionsView().ScrollIntoView(_filteredActionsView().SelectedItem()); + + // Do this right after becoming visible so we can quickly catch scenarios where + // modifiers aren't held down (e.g. command palette invocation). + _anchorKeyUpHandler(); } else { @@ -94,7 +89,7 @@ namespace winrt::TerminalApp::implementation // when the ListView has been measured out and is ready, and we'll immediately // revoke the handler because we only needed to handle it once on initialization. _sizeChangedRevoker = _filteredActionsView().SizeChanged(winrt::auto_revoke, [this](auto /*s*/, auto /*e*/) { - if (_currentMode == CommandPaletteMode::TabSwitcherMode && _anchorKey != VirtualKey::None) + if (_currentMode == CommandPaletteMode::TabSwitchMode) { _filteredActionsView().Focus(FocusState::Keyboard); } @@ -110,7 +105,7 @@ namespace winrt::TerminalApp::implementation // list. Otherwise, we're attempting to move to the previous. // Return Value: // - - void CommandPalette::_selectNextItem(const bool moveDown) + void CommandPalette::SelectNextItem(const bool moveDown) { const auto selected = _filteredActionsView().SelectedIndex(); const int numItems = ::base::saturated_cast(_filteredActionsView().Items().Size()); @@ -134,19 +129,17 @@ namespace winrt::TerminalApp::implementation // Only give anchored tab switcher the ability to cycle through tabs with the tab button. // For unanchored mode, accessibility becomes an issue when we try to hijack tab since it's // a really widely used keyboard navigation key. - if (_currentMode == CommandPaletteMode::TabSwitcherMode && - key == VirtualKey::Tab && - _anchorKey != VirtualKey::None) + if (_currentMode == CommandPaletteMode::TabSwitchMode && key == VirtualKey::Tab) { auto const state = CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift); if (WI_IsFlagSet(state, CoreVirtualKeyStates::Down)) { - _selectNextItem(false); + SelectNextItem(false); e.Handled(true); } else { - _selectNextItem(true); + SelectNextItem(true); e.Handled(true); } } @@ -168,13 +161,13 @@ namespace winrt::TerminalApp::implementation if (key == VirtualKey::Up) { // Action Mode: Move focus to the next item in the list. - _selectNextItem(false); + SelectNextItem(false); e.Handled(true); } else if (key == VirtualKey::Down) { // Action Mode: Move focus to the previous item in the list. - _selectNextItem(true); + SelectNextItem(true); e.Handled(true); } else if (key == VirtualKey::Enter) @@ -202,32 +195,81 @@ namespace winrt::TerminalApp::implementation e.Handled(true); } + else + { + const auto vkey = ::gsl::narrow_cast(e.OriginalKey()); + + // In the interest of not telling all modes to check for keybindings, limit to TabSwitch mode for now. + if (_currentMode == CommandPaletteMode::TabSwitchMode) + { + auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down); + auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down); + auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down); + + auto success = _bindings.TryKeyChord({ + ctrlDown, + altDown, + shiftDown, + vkey, + }); + + if (success) + { + e.Handled(true); + } + } + } + } + + // Method Description: + // - Implements the Alt handler + // Return value: + // - whether the key was handled + bool CommandPalette::OnDirectKeyEvent(const uint32_t vkey, const uint8_t /*scanCode*/, const bool down) + { + auto handled = false; + if (_currentMode == CommandPaletteMode::TabSwitchMode) + { + if (vkey == VK_MENU && !down) + { + _anchorKeyUpHandler(); + handled = true; + } + } + return handled; } void CommandPalette::_keyUpHandler(IInspectable const& /*sender*/, Windows::UI::Xaml::Input::KeyRoutedEventArgs const& e) { - auto key = e.OriginalKey(); + if (_currentMode == CommandPaletteMode::TabSwitchMode) + { + _anchorKeyUpHandler(); + e.Handled(true); + } + } + + // Method Description: + // - Handles anchor key ups during TabSwitchMode. + // We assume that at least one modifier key should be held down in order to "anchor" + // the ATS UI in place. So this function is called to check if any modifiers are + // still held down, and if not, dispatch the selected tab action and close the ATS. + // Return value: + // - + void CommandPalette::_anchorKeyUpHandler() + { + auto const ctrlDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Control), CoreVirtualKeyStates::Down); + auto const altDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Menu), CoreVirtualKeyStates::Down); + auto const shiftDown = WI_IsFlagSet(CoreWindow::GetForCurrentThread().GetKeyState(winrt::Windows::System::VirtualKey::Shift), CoreVirtualKeyStates::Down); - if (_currentMode == CommandPaletteMode::TabSwitcherMode) + if (!ctrlDown && !altDown && !shiftDown) { - if (_anchorKey && key == _anchorKey.value()) + if (const auto selectedItem = _filteredActionsView().SelectedItem()) { - // Once the user lifts the anchor key, we'll switch to the currently selected tab - // then close the tab switcher. - - if (const auto selectedItem = _filteredActionsView().SelectedItem()) + if (const auto data = selectedItem.try_as()) { - if (const auto data = selectedItem.try_as()) - { - const auto actionAndArgs = data.Action(); - _dispatch.DoAction(actionAndArgs); - _updateFilteredActions(); - _dismissPalette(); - } + _dispatchCommand(data); } - - e.Handled(true); } } } @@ -317,7 +359,8 @@ namespace winrt::TerminalApp::implementation } return _allCommands; - case CommandPaletteMode::TabSwitcherMode: + case CommandPaletteMode::TabSearchMode: + case CommandPaletteMode::TabSwitchMode: return _allTabActions; default: return _allCommands; @@ -420,6 +463,11 @@ namespace winrt::TerminalApp::implementation return _filteredActions; } + void CommandPalette::SetKeyBindings(Microsoft::Terminal::TerminalControl::IKeyBindings bindings) + { + _bindings = bindings; + } + void CommandPalette::SetCommands(Collections::IVector const& actions) { _allCommands = actions; @@ -455,7 +503,8 @@ namespace winrt::TerminalApp::implementation // whenever _switchToMode is called. switch (_currentMode) { - case CommandPaletteMode::TabSwitcherMode: + case CommandPaletteMode::TabSearchMode: + case CommandPaletteMode::TabSwitchMode: { SearchBoxText(RS_(L"TabSwitcher_SearchBoxText")); NoMatchesText(RS_(L"TabSwitcher_NoMatchesText")); @@ -530,7 +579,7 @@ namespace winrt::TerminalApp::implementation { // If TabSwitcherMode, just add all as is. We don't want // them to be sorted alphabetically. - if (_currentMode == CommandPaletteMode::TabSwitcherMode) + if (_currentMode == CommandPaletteMode::TabSearchMode || _currentMode == CommandPaletteMode::TabSwitchMode) { for (auto action : commandsToFilter) { @@ -899,11 +948,19 @@ namespace winrt::TerminalApp::implementation } } - void CommandPalette::EnableTabSwitcherMode(const VirtualKey& anchorKey, const uint32_t startIdx) + void CommandPalette::EnableTabSwitcherMode(const bool searchMode, const uint32_t startIdx) { _switcherStartIdx = startIdx; - _anchorKey = anchorKey; - _switchToMode(CommandPaletteMode::TabSwitcherMode); + + if (searchMode) + { + _switchToMode(CommandPaletteMode::TabSearchMode); + } + else + { + _switchToMode(CommandPaletteMode::TabSwitchMode); + } + _updateFilteredActions(); } } diff --git a/src/cascadia/TerminalApp/CommandPalette.h b/src/cascadia/TerminalApp/CommandPalette.h index 97a18ac28cb..97b0f0c8d25 100644 --- a/src/cascadia/TerminalApp/CommandPalette.h +++ b/src/cascadia/TerminalApp/CommandPalette.h @@ -11,7 +11,8 @@ namespace winrt::TerminalApp::implementation enum class CommandPaletteMode { ActionMode = 0, - TabSwitcherMode + TabSearchMode, + TabSwitchMode }; struct CommandPalette : CommandPaletteT @@ -21,12 +22,18 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::Collections::IObservableVector FilteredActions(); void SetCommands(Windows::Foundation::Collections::IVector const& actions); + void SetKeyBindings(Microsoft::Terminal::TerminalControl::IKeyBindings bindings); + void EnableCommandPaletteMode(); void SetDispatch(const winrt::TerminalApp::ShortcutActionDispatch& dispatch); + bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down); + + void SelectNextItem(const bool moveDown); + // Tab Switcher - void EnableTabSwitcherMode(const Windows::System::VirtualKey& anchorKey, const uint32_t startIdx); + void EnableTabSwitcherMode(const bool searchMode, const uint32_t startIdx); void OnTabsChanged(const Windows::Foundation::IInspectable& s, const Windows::Foundation::Collections::IVectorChangedEventArgs& e); WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler); @@ -63,8 +70,6 @@ namespace winrt::TerminalApp::implementation void _listItemClicked(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::Controls::ItemClickEventArgs const& e); - void _selectNextItem(const bool moveDown); - void _updateFilteredActions(); std::vector _collectFilteredActions(); @@ -75,12 +80,14 @@ namespace winrt::TerminalApp::implementation CommandPaletteMode _currentMode; void _switchToMode(CommandPaletteMode mode); + Microsoft::Terminal::TerminalControl::IKeyBindings _bindings; + // Tab Switcher - std::optional _anchorKey; void GenerateCommandForTab(const uint32_t idx, bool inserted, winrt::TerminalApp::Tab& tab); void UpdateTabIndices(const uint32_t startIdx); Windows::Foundation::Collections::IVector _allTabActions{ nullptr }; uint32_t _switcherStartIdx; + void _anchorKeyUpHandler(); winrt::Windows::UI::Xaml::Controls::ListView::SizeChanged_revoker _sizeChangedRevoker; diff --git a/src/cascadia/TerminalApp/CommandPalette.idl b/src/cascadia/TerminalApp/CommandPalette.idl index 793ac8334e4..10cfe967fa9 100644 --- a/src/cascadia/TerminalApp/CommandPalette.idl +++ b/src/cascadia/TerminalApp/CommandPalette.idl @@ -2,10 +2,11 @@ // Licensed under the MIT license. import "Command.idl"; +import "IDirectKeyListener.idl"; namespace TerminalApp { - [default_interface] runtimeclass CommandPalette : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged + [default_interface] runtimeclass CommandPalette : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged, IDirectKeyListener { CommandPalette(); @@ -17,11 +18,14 @@ namespace TerminalApp Windows.Foundation.Collections.IObservableVector FilteredActions { get; }; void SetCommands(Windows.Foundation.Collections.IVector actions); + void SetKeyBindings(Microsoft.Terminal.TerminalControl.IKeyBindings bindings); void EnableCommandPaletteMode(); + void SelectNextItem(Boolean moveDown); + void SetDispatch(ShortcutActionDispatch dispatch); - void EnableTabSwitcherMode(Windows.System.VirtualKey anchorKey, UInt32 startIdx); + void EnableTabSwitcherMode(Boolean searchMode, UInt32 startIdx); void OnTabsChanged(IInspectable s, Windows.Foundation.Collections.IVectorChangedEventArgs e); } } diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.cpp b/src/cascadia/TerminalApp/GlobalAppSettings.cpp index 449502509cd..4cbba508b1f 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.cpp +++ b/src/cascadia/TerminalApp/GlobalAppSettings.cpp @@ -36,6 +36,7 @@ static constexpr std::string_view ConfirmCloseAllKey{ "confirmCloseAllTabs" }; static constexpr std::string_view SnapToGridOnResizeKey{ "snapToGridOnResize" }; static constexpr std::string_view EnableStartupTaskKey{ "startOnUserLogin" }; static constexpr std::string_view AlwaysOnTopKey{ "alwaysOnTop" }; +static constexpr std::string_view UseTabSwitcherKey{ "useTabSwitcher" }; static constexpr std::string_view DebugFeaturesKey{ "debugFeatures" }; @@ -180,6 +181,8 @@ void GlobalAppSettings::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, AlwaysOnTopKey, _AlwaysOnTop); + JsonUtils::GetValueForKey(json, UseTabSwitcherKey, _UseTabSwitcher); + // This is a helper lambda to get the keybindings and commands out of both // and array of objects. We'll use this twice, once on the legacy // `keybindings` key, and again on the newer `bindings` key. diff --git a/src/cascadia/TerminalApp/GlobalAppSettings.h b/src/cascadia/TerminalApp/GlobalAppSettings.h index bc00276f8d4..d78d15a8e34 100644 --- a/src/cascadia/TerminalApp/GlobalAppSettings.h +++ b/src/cascadia/TerminalApp/GlobalAppSettings.h @@ -82,6 +82,7 @@ class TerminalApp::GlobalAppSettings final GETSET_PROPERTY(bool, DebugFeaturesEnabled); // default value set in constructor GETSET_PROPERTY(bool, StartOnUserLogin, false); GETSET_PROPERTY(bool, AlwaysOnTop, false); + GETSET_PROPERTY(bool, UseTabSwitcher, true); private: std::optional _unparsedDefaultProfile; diff --git a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw index 36c10376fa6..f7d58b6d826 100644 --- a/src/cascadia/TerminalApp/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalApp/Resources/en-US/Resources.resw @@ -576,6 +576,9 @@ Select color scheme... + + Search for tab... + New Tab... @@ -585,9 +588,6 @@ Tab Switcher - - Toggle tab switcher - Type a tab name... diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp index 20a43791c2d..cce86db1988 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.cpp @@ -226,9 +226,9 @@ namespace winrt::TerminalApp::implementation _CloseTabsAfterHandlers(*this, *eventArgs); break; } - case ShortcutAction::ToggleTabSwitcher: + case ShortcutAction::TabSearch: { - _ToggleTabSwitcherHandlers(*this, *eventArgs); + _TabSearchHandlers(*this, *eventArgs); break; } default: diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.h b/src/cascadia/TerminalApp/ShortcutActionDispatch.h index 9da3aadcdf2..caecb41ef77 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.h +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.h @@ -60,7 +60,7 @@ namespace winrt::TerminalApp::implementation TYPED_EVENT(ExecuteCommandline, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(CloseOtherTabs, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); TYPED_EVENT(CloseTabsAfter, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); - TYPED_EVENT(ToggleTabSwitcher, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); + TYPED_EVENT(TabSearch, TerminalApp::ShortcutActionDispatch, TerminalApp::ActionEventArgs); // clang-format on private: diff --git a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl index f34256f3a6b..48d9eb923ce 100644 --- a/src/cascadia/TerminalApp/ShortcutActionDispatch.idl +++ b/src/cascadia/TerminalApp/ShortcutActionDispatch.idl @@ -46,7 +46,7 @@ namespace TerminalApp ToggleCommandPalette, CloseOtherTabs, CloseTabsAfter, - ToggleTabSwitcher + TabSearch }; [default_interface] runtimeclass ActionAndArgs { @@ -97,6 +97,6 @@ namespace TerminalApp event Windows.Foundation.TypedEventHandler ExecuteCommandline; event Windows.Foundation.TypedEventHandler CloseOtherTabs; event Windows.Foundation.TypedEventHandler CloseTabsAfter; - event Windows.Foundation.TypedEventHandler ToggleTabSwitcher; + event Windows.Foundation.TypedEventHandler TabSearch; } } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 6de63a6be7b..02d95dee2b5 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -119,6 +119,7 @@ namespace winrt::TerminalApp::implementation if (auto page{ weakThis.get() }) { _UpdateCommandsForPalette(); + CommandPalette().SetKeyBindings(_settings->GetKeybindings()); } } @@ -938,7 +939,7 @@ namespace winrt::TerminalApp::implementation _actionDispatch->ExecuteCommandline({ this, &TerminalPage::_HandleExecuteCommandline }); _actionDispatch->CloseOtherTabs({ this, &TerminalPage::_HandleCloseOtherTabs }); _actionDispatch->CloseTabsAfter({ this, &TerminalPage::_HandleCloseTabsAfter }); - _actionDispatch->ToggleTabSwitcher({ this, &TerminalPage::_HandleToggleTabSwitcher }); + _actionDispatch->TabSearch({ this, &TerminalPage::_HandleOpenTabSearch }); } // Method Description: @@ -1199,7 +1200,21 @@ namespace winrt::TerminalApp::implementation // we clamp the values to the range [0, tabCount) while still supporting moving // leftward from 0 to tabCount - 1. const auto newTabIndex = ((tabCount + *index + (bMoveRight ? 1 : -1)) % tabCount); - _SelectTab(newTabIndex); + + if (_settings->GlobalSettings().UseTabSwitcher()) + { + if (CommandPalette().Visibility() == Visibility::Visible) + { + CommandPalette().SelectNextItem(bMoveRight); + } + + CommandPalette().EnableTabSwitcherMode(false, newTabIndex); + CommandPalette().Visibility(Visibility::Visible); + } + else + { + _SelectTab(newTabIndex); + } } } diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 17724e198a0..02d0af0b53d 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -237,7 +237,7 @@ namespace winrt::TerminalApp::implementation void _HandleToggleCommandPalette(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleCloseOtherTabs(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); void _HandleCloseTabsAfter(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); - void _HandleToggleTabSwitcher(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); + void _HandleOpenTabSearch(const IInspectable& sender, const TerminalApp::ActionEventArgs& args); // Make sure to hook new actions up in _RegisterActionCallbacks! #pragma endregion diff --git a/src/cascadia/TerminalApp/defaults.json b/src/cascadia/TerminalApp/defaults.json index ed96f086d23..818ba8515ca 100644 --- a/src/cascadia/TerminalApp/defaults.json +++ b/src/cascadia/TerminalApp/defaults.json @@ -18,6 +18,7 @@ "showTabsInTitlebar": true, "showTerminalTitleInTitlebar": true, "tabWidthMode": "equal", + "useTabSwitcher": true, // Miscellaneous "confirmCloseAllTabs": true,