diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index d35031fe0..791595894 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -109,7 +109,17 @@ ], "type": "string" }, - "Direction": { + "FocusDirection": { + "enum": [ + "left", + "right", + "up", + "down", + "previous" + ], + "type": "string" + }, + "ResizeDirection": { "enum": [ "left", "right", @@ -298,9 +308,9 @@ "properties": { "action": { "type": "string", "pattern": "moveFocus" }, "direction": { - "$ref": "#/definitions/Direction", + "$ref": "#/definitions/FocusDirection", "default": "left", - "description": "The direction to move focus in, between panes" + "description": "The direction to move focus in, between panes. Direction can be 'previous' to move to the most recently used pane." } } } @@ -315,9 +325,9 @@ "properties": { "action": { "type": "string", "pattern": "resizePane" }, "direction": { - "$ref": "#/definitions/Direction", + "$ref": "#/definitions/ResizeDirection", "default": "left", - "description": "The direction to move the pane separator in" + "description": "The direction to move the pane separator in." } } } @@ -332,10 +342,7 @@ }, { "properties": { - "action": { - "type": "string", - "pattern": "sendInput" - }, + "action": { "type": "string", "pattern": "sendInput" }, "input": { "type": "string", "default": "", @@ -375,10 +382,7 @@ }, { "properties": { - "action": { - "type": "string", - "pattern": "openSettings" - }, + "action": { "type": "string", "pattern": "openSettings" }, "target": { "type": "string", "default": "settingsFile", @@ -834,7 +838,8 @@ "desktopWallpaper" ] } - ] + ], + "type": [ "string", "null" ] }, "backgroundImageAlignment": { "default": "center", diff --git a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp index b0b391cbd..f06e57865 100644 --- a/src/cascadia/LocalTests_TerminalApp/TabTests.cpp +++ b/src/cascadia/LocalTests_TerminalApp/TabTests.cpp @@ -664,7 +664,7 @@ namespace TerminalAppLocalTests Log::Comment(L"Move focus. This will cause us to un-zoom."); result = RunOnUIThread([&page]() { // Set up action - MoveFocusArgs args{ Direction::Left }; + MoveFocusArgs args{ FocusDirection::Left }; ActionEventArgs eventArgs{ args }; page->_HandleMoveFocus(nullptr, eventArgs); diff --git a/src/cascadia/TerminalApp/AppActionHandlers.cpp b/src/cascadia/TerminalApp/AppActionHandlers.cpp index a558d9e16..e7e0c45c0 100644 --- a/src/cascadia/TerminalApp/AppActionHandlers.cpp +++ b/src/cascadia/TerminalApp/AppActionHandlers.cpp @@ -228,14 +228,14 @@ namespace winrt::TerminalApp::implementation { if (const auto& realArgs = args.ActionArgs().try_as()) { - if (realArgs.Direction() == Direction::None) + if (realArgs.ResizeDirection() == ResizeDirection::None) { // Do nothing args.Handled(false); } else { - _ResizePane(realArgs.Direction()); + _ResizePane(realArgs.ResizeDirection()); args.Handled(true); } } @@ -246,14 +246,14 @@ namespace winrt::TerminalApp::implementation { if (const auto& realArgs = args.ActionArgs().try_as()) { - if (realArgs.Direction() == Direction::None) + if (realArgs.FocusDirection() == FocusDirection::None) { // Do nothing args.Handled(false); } else { - _MoveFocus(realArgs.Direction()); + _MoveFocus(realArgs.FocusDirection()); args.Handled(true); } } diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index b561ea6ac..3a80e53dd 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -130,7 +130,7 @@ void Pane::Relayout() // decreasing the size of our first child. // Return Value: // - false if we couldn't resize this pane in the given direction, else true. -bool Pane::_Resize(const Direction& direction) +bool Pane::_Resize(const ResizeDirection& direction) { if (!DirectionMatchesSplit(direction, _splitState)) { @@ -138,7 +138,7 @@ bool Pane::_Resize(const Direction& direction) } float amount = .05f; - if (direction == Direction::Right || direction == Direction::Down) + if (direction == ResizeDirection::Right || direction == ResizeDirection::Down) { amount = -amount; } @@ -171,7 +171,7 @@ bool Pane::_Resize(const Direction& direction) // - direction: The direction to move the separator in. // Return Value: // - true if we or a child handled this resize request. -bool Pane::ResizePane(const Direction& direction) +bool Pane::ResizePane(const ResizeDirection& direction) { // If we're a leaf, do nothing. We can't possibly have a descendant with a // separator the correct direction. @@ -223,14 +223,14 @@ bool Pane::ResizePane(const Direction& direction) // - direction: The direction to move the focus in. // Return Value: // - true if we handled this focus move request. -bool Pane::_NavigateFocus(const Direction& direction) +bool Pane::_NavigateFocus(const FocusDirection& direction) { if (!DirectionMatchesSplit(direction, _splitState)) { return false; } - const bool focusSecond = (direction == Direction::Right) || (direction == Direction::Down); + const bool focusSecond = (direction == FocusDirection::Right) || (direction == FocusDirection::Down); const auto newlyFocusedChild = focusSecond ? _secondChild : _firstChild; @@ -261,7 +261,7 @@ bool Pane::_NavigateFocus(const Direction& direction) // - direction: The direction to move the focus in. // Return Value: // - true if we or a child handled this focus move request. -bool Pane::NavigateFocus(const Direction& direction) +bool Pane::NavigateFocus(const FocusDirection& direction) { // If we're a leaf, do nothing. We can't possibly have a descendant with a // separator the correct direction. @@ -655,9 +655,10 @@ void Pane::_CloseChild(const bool closeFirst) // inherited from us, so the flag will be set for both children. _borders = _firstChild->_borders & _secondChild->_borders; - // take the control and profile of the pane that _wasn't_ closed. + // take the control, profile and id of the pane that _wasn't_ closed. _control = remainingChild->_control; _profile = remainingChild->_profile; + _id = remainingChild->Id(); // Add our new event handler before revoking the old one. _connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler }); @@ -1493,6 +1494,9 @@ std::pair, std::shared_ptr> Pane::_Split(SplitState _SetupEntranceAnimation(); + // Clear out our ID, only leaves should have IDs + _id = {}; + return { _firstChild, _secondChild }; } @@ -1566,6 +1570,47 @@ void Pane::Restore(std::shared_ptr zoomedPane) } } +// Method Description: +// - Retrieves the ID of this pane +// - NOTE: The caller should make sure that this pane is a leaf, +// otherwise the ID value will not make sense (leaves have IDs, parents do not) +// Return Value: +// - The ID of this pane +uint16_t Pane::Id() noexcept +{ + return _id.value(); +} + +// Method Description: +// - Sets this pane's ID +// - Panes are given IDs upon creation by TerminalTab +// Arguments: +// - The number to set this pane's ID to +void Pane::Id(uint16_t id) noexcept +{ + _id = id; +} + +// Method Description: +// - Recursive function that focuses a pane with the given ID +// Arguments: +// - The ID of the pane we want to focus +void Pane::FocusPane(const uint16_t id) +{ + if (_IsLeaf() && id == _id) + { + _control.Focus(FocusState::Programmatic); + } + else + { + if (_firstChild && _secondChild) + { + _firstChild->FocusPane(id); + _secondChild->FocusPane(id); + } + } +} + // Method Description: // - Gets the size in pixels of each of our children, given the full size they // should fill. Since these children own their own separators (borders), this diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index 925dd436c..1debee5f7 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -55,8 +55,8 @@ public: const GUID& profile); void ResizeContent(const winrt::Windows::Foundation::Size& newSize); void Relayout(); - bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); - bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); + bool ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction); + bool NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction); bool CanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType); std::pair, std::shared_ptr> Split(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, @@ -75,6 +75,10 @@ public: void Maximize(std::shared_ptr zoomedPane); void Restore(std::shared_ptr zoomedPane); + uint16_t Id() noexcept; + void Id(uint16_t id) noexcept; + void FocusPane(const uint16_t id); + WINRT_CALLBACK(Closed, winrt::Windows::Foundation::EventHandler); DECLARE_EVENT(GotFocus, _GotFocusHandlers, winrt::delegate>); DECLARE_EVENT(PaneRaiseVisualBell, _PaneRaiseVisualBellHandlers, winrt::delegate>); @@ -95,6 +99,8 @@ private: winrt::Microsoft::Terminal::Settings::Model::SplitState _splitState{ winrt::Microsoft::Terminal::Settings::Model::SplitState::None }; float _desiredSplitPosition; + std::optional _id; + bool _lastActive{ false }; std::optional _profile{ std::nullopt }; winrt::event_token _connectionStateChangedToken{ 0 }; @@ -124,8 +130,8 @@ private: void _SetupEntranceAnimation(); void _UpdateBorders(); - bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); - bool _NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); + bool _Resize(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction); + bool _NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction); void _CloseChild(const bool closeFirst); winrt::fire_and_forget _CloseChildRoutine(const bool closeFirst); @@ -156,15 +162,15 @@ private: // - This is used for pane resizing (which will need a pane separator // that's perpendicular to the direction to be able to move the separator // in that direction). - // - Additionally, it will be used for moving focus between panes, which - // again happens _across_ a separator. + // - Also used for moving focus between panes, which again happens _across_ a separator. // Arguments: // - direction: The Direction to compare // - splitType: The winrt::TerminalApp::SplitState to compare // Return Value: // - true iff the direction is perpendicular to the splitType. False for // winrt::TerminalApp::SplitState::None. - static constexpr bool DirectionMatchesSplit(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction, + template + static constexpr bool DirectionMatchesSplit(const T& direction, const winrt::Microsoft::Terminal::Settings::Model::SplitState& splitType) { if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::None) @@ -173,13 +179,13 @@ private: } else if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::Horizontal) { - return direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Up || - direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Down; + return direction == T::Up || + direction == T::Down; } else if (splitType == winrt::Microsoft::Terminal::Settings::Model::SplitState::Vertical) { - return direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Left || - direction == winrt::Microsoft::Terminal::Settings::Model::Direction::Right; + return direction == T::Left || + direction == T::Right; } return false; } diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index a7320c310..3a2613516 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -1395,7 +1395,7 @@ namespace winrt::TerminalApp::implementation // - direction: The direction to move the focus in. // Return Value: // - - void TerminalPage::_MoveFocus(const Direction& direction) + void TerminalPage::_MoveFocus(const FocusDirection& direction) { if (auto index{ _GetFocusedTabIndex() }) { @@ -1669,7 +1669,7 @@ namespace winrt::TerminalApp::implementation // - direction: The direction to move the separator in. // Return Value: // - - void TerminalPage::_ResizePane(const Direction& direction) + void TerminalPage::_ResizePane(const ResizeDirection& direction) { if (auto index{ _GetFocusedTabIndex() }) { diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index ed87a8771..46da0473c 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -175,7 +175,7 @@ namespace winrt::TerminalApp::implementation void _SelectNextTab(const bool bMoveRight); bool _SelectTab(const uint32_t tabIndex); - void _MoveFocus(const Microsoft::Terminal::Settings::Model::Direction& direction); + void _MoveFocus(const Microsoft::Terminal::Settings::Model::FocusDirection& direction); winrt::Microsoft::Terminal::TerminalControl::TermControl _GetActiveControl(); std::optional _GetFocusedTabIndex() const noexcept; @@ -191,7 +191,7 @@ namespace winrt::TerminalApp::implementation // MSFT:20641986: Add keybindings for New Window void _Scroll(ScrollDirection scrollDirection, const Windows::Foundation::IReference& rowsToScroll); void _SplitPane(const Microsoft::Terminal::Settings::Model::SplitState splitType, const Microsoft::Terminal::Settings::Model::SplitType splitMode = Microsoft::Terminal::Settings::Model::SplitType::Manual, const Microsoft::Terminal::Settings::Model::NewTerminalArgs& newTerminalArgs = nullptr); - void _ResizePane(const Microsoft::Terminal::Settings::Model::Direction& direction); + void _ResizePane(const Microsoft::Terminal::Settings::Model::ResizeDirection& direction); void _ScrollPage(ScrollDirection scrollDirection); void _ScrollToBufferEdge(ScrollDirection scrollDirection); void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::TerminalControl::KeyChord& keyChord); diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 919e44ea2..ac0e4934f 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -28,6 +28,10 @@ namespace winrt::TerminalApp::implementation { _rootPane = std::make_shared(profile, control, true); + _rootPane->Id(_nextPaneId); + _mruPanes.insert(_mruPanes.begin(), _nextPaneId); + ++_nextPaneId; + _rootPane->Closed([=](auto&& /*s*/, auto&& /*e*/) { _ClosedHandlers(nullptr, nullptr); }); @@ -268,7 +272,12 @@ namespace winrt::TerminalApp::implementation // - void TerminalTab::SplitPane(SplitState splitType, const GUID& profile, TermControl& control) { + // Make sure to take the ID before calling Split() - Split() will clear out the active pane's ID + const auto activePaneId = _activePane->Id(); auto [first, second] = _activePane->Split(splitType, profile, control); + first->Id(activePaneId); + second->Id(_nextPaneId); + ++_nextPaneId; _activePane = first; _AttachEventHandlersToControl(control); @@ -312,7 +321,7 @@ namespace winrt::TerminalApp::implementation // - direction: The direction to move the separator in. // Return Value: // - - void TerminalTab::ResizePane(const Direction& direction) + void TerminalTab::ResizePane(const ResizeDirection& direction) { // NOTE: This _must_ be called on the root pane, so that it can propagate // throughout the entire tree. @@ -326,11 +335,19 @@ namespace winrt::TerminalApp::implementation // - direction: The direction to move the focus in. // Return Value: // - - void TerminalTab::NavigateFocus(const Direction& direction) + void TerminalTab::NavigateFocus(const FocusDirection& direction) { - // NOTE: This _must_ be called on the root pane, so that it can propagate - // throughout the entire tree. - _rootPane->NavigateFocus(direction); + if (direction == FocusDirection::Previous) + { + // To get to the previous pane, get the id of the previous pane and focus to that + _rootPane->FocusPane(_mruPanes.at(1)); + } + else + { + // NOTE: This _must_ be called on the root pane, so that it can propagate + // throughout the entire tree. + _rootPane->NavigateFocus(direction); + } } // Method Description: @@ -444,6 +461,18 @@ namespace winrt::TerminalApp::implementation // Update our own title text to match the newly-active pane. UpdateTitle(); + // We need to move the pane to the top of our mru list + // If its already somewhere in the list, remove it first + const auto paneId = pane->Id(); + for (auto i = _mruPanes.begin(); i != _mruPanes.end(); ++i) + { + if (*i == paneId) + { + _mruPanes.erase(i); + break; + } + } + _mruPanes.insert(_mruPanes.begin(), paneId); // Raise our own ActivePaneChanged event. _ActivePaneChangedHandlers(); } @@ -460,6 +489,7 @@ namespace winrt::TerminalApp::implementation void TerminalTab::_AttachEventHandlersToPane(std::shared_ptr pane) { auto weakThis{ get_weak() }; + std::weak_ptr weakPane{ pane }; pane->GotFocus([weakThis](std::shared_ptr sender) { // Do nothing if the Tab's lifetime is expired or pane isn't new. @@ -475,7 +505,7 @@ namespace winrt::TerminalApp::implementation // Add a Closed event handler to the Pane. If the pane closes out from // underneath us, and it's zoomed, we want to be able to make sure to // update our state accordingly to un-zoom that pane. See GH#7252. - pane->Closed([weakThis](auto&& /*s*/, auto && /*e*/) -> winrt::fire_and_forget { + pane->Closed([weakThis, weakPane](auto&& /*s*/, auto && /*e*/) -> winrt::fire_and_forget { if (auto tab{ weakThis.get() }) { if (tab->_zoomedPane) @@ -485,6 +515,17 @@ namespace winrt::TerminalApp::implementation tab->Content(tab->_rootPane->GetRootElement()); tab->ExitZoom(); } + if (auto pane = weakPane.lock()) + { + for (auto i = tab->_mruPanes.begin(); i != tab->_mruPanes.end(); ++i) + { + if (*i == pane->Id()) + { + tab->_mruPanes.erase(i); + break; + } + } + } } }); diff --git a/src/cascadia/TerminalApp/TerminalTab.h b/src/cascadia/TerminalApp/TerminalTab.h index b228b45a1..c01c49e33 100644 --- a/src/cascadia/TerminalApp/TerminalTab.h +++ b/src/cascadia/TerminalApp/TerminalTab.h @@ -40,8 +40,8 @@ namespace winrt::TerminalApp::implementation bool PreCalculateCanSplit(winrt::Microsoft::Terminal::Settings::Model::SplitState splitType, winrt::Windows::Foundation::Size availableSpace) const; void ResizeContent(const winrt::Windows::Foundation::Size& newSize); - void ResizePane(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); - void NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::Direction& direction); + void ResizePane(const winrt::Microsoft::Terminal::Settings::Model::ResizeDirection& direction); + void NavigateFocus(const winrt::Microsoft::Terminal::Settings::Model::FocusDirection& direction); void UpdateSettings(const winrt::TerminalApp::TerminalSettings& settings, const GUID& profile); winrt::fire_and_forget UpdateTitle(); @@ -83,6 +83,9 @@ namespace winrt::TerminalApp::implementation winrt::Windows::UI::Xaml::Controls::MenuFlyoutItem _closeTabsAfterMenuItem{}; winrt::TerminalApp::TabHeaderControl _headerControl{}; + std::vector _mruPanes; + uint16_t _nextPaneId{ 0 }; + bool _receivedKeyDown{ false }; winrt::hstring _runtimeTabText{}; diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp index 611e65793..85a4a1967 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.cpp +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.cpp @@ -147,18 +147,18 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation winrt::hstring ResizePaneArgs::GenerateName() const { winrt::hstring directionString; - switch (_Direction) + switch (_ResizeDirection) { - case Direction::Left: + case ResizeDirection::Left: directionString = RS_(L"DirectionLeft"); break; - case Direction::Right: + case ResizeDirection::Right: directionString = RS_(L"DirectionRight"); break; - case Direction::Up: + case ResizeDirection::Up: directionString = RS_(L"DirectionUp"); break; - case Direction::Down: + case ResizeDirection::Down: directionString = RS_(L"DirectionDown"); break; } @@ -171,20 +171,22 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation winrt::hstring MoveFocusArgs::GenerateName() const { winrt::hstring directionString; - switch (_Direction) + switch (_FocusDirection) { - case Direction::Left: + case FocusDirection::Left: directionString = RS_(L"DirectionLeft"); break; - case Direction::Right: + case FocusDirection::Right: directionString = RS_(L"DirectionRight"); break; - case Direction::Up: + case FocusDirection::Up: directionString = RS_(L"DirectionUp"); break; - case Direction::Down: + case FocusDirection::Down: directionString = RS_(L"DirectionDown"); break; + case FocusDirection::Previous: + return RS_(L"MoveFocusToLastUsedPane"); } return winrt::hstring{ fmt::format(std::wstring_view(RS_(L"MoveFocusWithArgCommandKey")), diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.h b/src/cascadia/TerminalSettingsModel/ActionArgs.h index dbe385059..8d4d3d57a 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.h +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.h @@ -223,7 +223,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation struct ResizePaneArgs : public ResizePaneArgsT { ResizePaneArgs() = default; - GETSET_PROPERTY(Model::Direction, Direction, Direction::None); + GETSET_PROPERTY(Model::ResizeDirection, ResizeDirection, ResizeDirection::None); static constexpr std::string_view DirectionKey{ "direction" }; @@ -235,7 +235,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation auto otherAsUs = other.try_as(); if (otherAsUs) { - return otherAsUs->_Direction == _Direction; + return otherAsUs->_ResizeDirection == _ResizeDirection; } return false; }; @@ -243,8 +243,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); - if (args->_Direction == Direction::None) + JsonUtils::GetValueForKey(json, DirectionKey, args->_ResizeDirection); + if (args->_ResizeDirection == ResizeDirection::None) { return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; } @@ -256,7 +256,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation IActionArgs Copy() const { auto copy{ winrt::make_self() }; - copy->_Direction = _Direction; + copy->_ResizeDirection = _ResizeDirection; return *copy; } }; @@ -264,10 +264,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation struct MoveFocusArgs : public MoveFocusArgsT { MoveFocusArgs() = default; - MoveFocusArgs(Model::Direction direction) : - _Direction{ direction } {}; + MoveFocusArgs(Model::FocusDirection direction) : + _FocusDirection{ direction } {}; - GETSET_PROPERTY(Model::Direction, Direction, Direction::None); + GETSET_PROPERTY(Model::FocusDirection, FocusDirection, FocusDirection::None); static constexpr std::string_view DirectionKey{ "direction" }; @@ -279,7 +279,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation auto otherAsUs = other.try_as(); if (otherAsUs) { - return otherAsUs->_Direction == _Direction; + return otherAsUs->_FocusDirection == _FocusDirection; } return false; }; @@ -287,8 +287,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { // LOAD BEARING: Not using make_self here _will_ break you in the future! auto args = winrt::make_self(); - JsonUtils::GetValueForKey(json, DirectionKey, args->_Direction); - if (args->_Direction == Direction::None) + JsonUtils::GetValueForKey(json, DirectionKey, args->_FocusDirection); + if (args->_FocusDirection == FocusDirection::None) { return { nullptr, { SettingsLoadWarnings::MissingRequiredParameter } }; } @@ -300,7 +300,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation IActionArgs Copy() const { auto copy{ winrt::make_self() }; - copy->_Direction = _Direction; + copy->_FocusDirection = _FocusDirection; return *copy; } }; diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl index 9bb545ece..40e4c6e73 100644 --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl @@ -16,7 +16,7 @@ namespace Microsoft.Terminal.Settings.Model IActionArgs ActionArgs { get; }; }; - enum Direction + enum ResizeDirection { None = 0, Left, @@ -25,6 +25,16 @@ namespace Microsoft.Terminal.Settings.Model Down }; + enum FocusDirection + { + None = 0, + Left, + Right, + Up, + Down, + Previous + }; + enum SplitState { Automatic = -1, @@ -103,13 +113,13 @@ namespace Microsoft.Terminal.Settings.Model [default_interface] runtimeclass ResizePaneArgs : IActionArgs { - Direction Direction { get; }; + ResizeDirection ResizeDirection { get; }; }; [default_interface] runtimeclass MoveFocusArgs : IActionArgs { - MoveFocusArgs(Direction direction); - Direction Direction { get; }; + MoveFocusArgs(FocusDirection direction); + FocusDirection FocusDirection { get; }; }; [default_interface] runtimeclass AdjustFontSizeArgs : IActionArgs diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw index 0b4990331..d872e8f89 100644 --- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw @@ -199,6 +199,9 @@ up + + previous + Duplicate pane @@ -224,7 +227,10 @@ Move focus {0} - {0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", or "DirectionDown" + {0} will be replaced with one of the four directions "DirectionLeft", "DirectionRight", "DirectionUp", "DirectionDown" + + + Move focus to the last used pane New tab diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h index a53dabd66..7fb2e8e29 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -328,14 +328,26 @@ struct ::Microsoft::Terminal::Settings::Model::JsonUtils::ConversionTrait<::winr } }; -// Possible Direction values -JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::Direction) +// Possible FocusDirection values +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::FocusDirection) +{ + JSON_MAPPINGS(5) = { + pair_type{ "left", ValueType::Left }, + pair_type{ "right", ValueType::Right }, + pair_type{ "up", ValueType::Up }, + pair_type{ "down", ValueType::Down }, + pair_type{ "previous", ValueType::Previous }, + }; +}; + +// Possible ResizeDirection values +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::ResizeDirection) { JSON_MAPPINGS(4) = { pair_type{ "left", ValueType::Left }, pair_type{ "right", ValueType::Right }, pair_type{ "up", ValueType::Up }, - pair_type{ "down", ValueType::Down }, + pair_type{ "down", ValueType::Down } }; }; diff --git a/src/cascadia/TerminalSettingsModel/defaults.json b/src/cascadia/TerminalSettingsModel/defaults.json index 8acf09c35..cb862728e 100644 --- a/src/cascadia/TerminalSettingsModel/defaults.json +++ b/src/cascadia/TerminalSettingsModel/defaults.json @@ -333,6 +333,7 @@ { "command": { "action": "moveFocus", "direction": "left" }, "keys": "alt+left" }, { "command": { "action": "moveFocus", "direction": "right" }, "keys": "alt+right" }, { "command": { "action": "moveFocus", "direction": "up" }, "keys": "alt+up" }, + { "command": { "action": "moveFocus", "direction": "previous" }, "keys": "ctrl+alt+left" }, { "command": "togglePaneZoom" }, // Clipboard Integration