From a496af361458dcf6c185c1d7923b78f7a21017ec Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Apr 2022 14:19:59 -0500 Subject: [PATCH 1/5] Allow windows created by console apps to appear above the Terminal (#12799) ## Window shenanigans, part the third: Hooks the Terminal's focus state up to the underlying ConPTY. This is LOAD BEARING for allowing windows created by console applications to bring themselves to the foreground. We're using the [FocusIn/FocusOut](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-FocusIn_FocusOut) sequences to communicate to ConPTY when a control gains/loses focus. Theoretically, other terminals could do this as well. ## References #11682 tracks _real_ support for this sequence in Console & conpty. When we do that, we should consider even if a client application disables this mode, the Terminal & conpty should always request this from the hosting terminal (and just ignore internally to ConPTY). See also #12515, #12526, which are the other two parts of this effort. This was tested with all three merged together, and they worked beautifully for all our scenarios. They are kept separate for ease of review. ## PR Checklist * [x] This is prototype 3 for #2988 * [x] I work here * [ ] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments This allows windows spawned by console processes to bring themselves to the foreground _when the console is focused_. (Historically, this is also called in the WndProc, when focus changes). Notably, before this, ConPTY was _never_ focused, so windows could never bring themselves to the foreground when run from a ConPTY console. We're not blanket granting the SetForeground right to all console apps when run in ConPTY. It's the responsibility of the hosting terminal emulator to always tell ConPTY when a particular instance is focused. ## Validation Steps Performed (gif below) --- src/cascadia/TerminalControl/ControlCore.cpp | 21 ++++++++++++++ src/cascadia/TerminalControl/ControlCore.h | 3 ++ .../TerminalControl/ControlInteractivity.cpp | 4 +++ src/host/CursorBlinker.cpp | 4 ++- src/server/IoDispatchers.cpp | 17 ++++++++++- src/terminal/adapter/IInteractDispatch.hpp | 2 ++ src/terminal/adapter/InteractDispatch.cpp | 29 +++++++++++++++++++ src/terminal/adapter/InteractDispatch.hpp | 2 ++ .../parser/InputStateMachineEngine.cpp | 13 ++++++++- .../parser/InputStateMachineEngine.hpp | 2 ++ .../parser/ut_parser/InputEngineTest.cpp | 7 +++++ 11 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index c550839bf91..c2618b0bc7f 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1696,6 +1696,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation } } + // Method Description: + // - When the control gains focus, it needs to tell ConPTY about this. + // Usually, these sequences are reserved for applications that + // specifically request SET_FOCUS_EVENT_MOUSE, ?1004h. ConPTY uses this + // sequence REGARDLESS to communicate if the control was focused or not. + // - Even if a client application disables this mode, the Terminal & conpty + // should always request this from the hosting terminal (and just ignore + // internally to ConPTY). + // - Full support for this sequence is tracked in GH#11682. + // - This is related to work done for GH#2988. + void ControlCore::GotFocus() + { + _connection.WriteInput(L"\x1b[I"); + } + + // See GotFocus. + void ControlCore::LostFocus() + { + _connection.WriteInput(L"\x1b[O"); + } + bool ControlCore::_isBackgroundTransparent() { // If we're: diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h index fa4135c2653..0d265375bc6 100644 --- a/src/cascadia/TerminalControl/ControlCore.h +++ b/src/cascadia/TerminalControl/ControlCore.h @@ -81,6 +81,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation void PasteText(const winrt::hstring& hstr); bool CopySelectionToClipboard(bool singleLine, const Windows::Foundation::IReference& formats); + void GotFocus(); + void LostFocus(); + void ToggleShaderEffects(); void AdjustOpacity(const double adjustment); void ResumeRendering(); diff --git a/src/cascadia/TerminalControl/ControlInteractivity.cpp b/src/cascadia/TerminalControl/ControlInteractivity.cpp index 015942e4ac1..24fb712f1d1 100644 --- a/src/cascadia/TerminalControl/ControlInteractivity.cpp +++ b/src/cascadia/TerminalControl/ControlInteractivity.cpp @@ -111,6 +111,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation THROW_IF_FAILED(_uiaEngine->Enable()); } + _core->GotFocus(); + _updateSystemParameterSettings(); } @@ -120,6 +122,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation { THROW_IF_FAILED(_uiaEngine->Disable()); } + + _core->LostFocus(); } // Method Description diff --git a/src/host/CursorBlinker.cpp b/src/host/CursorBlinker.cpp index f3aee7a4798..e15456d2e1c 100644 --- a/src/host/CursorBlinker.cpp +++ b/src/host/CursorBlinker.cpp @@ -82,8 +82,10 @@ void CursorBlinker::TimerRoutine(SCREEN_INFORMATION& ScreenInfo) const noexcept auto& cursor = buffer.GetCursor(); auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); auto* const pAccessibilityNotifier = ServiceLocator::LocateAccessibilityNotifier(); + const bool inConpty{ gci.IsInVtIoMode() }; - if (!WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS)) + // GH#2988: ConPTY can now be focused, but it doesn't need to do any of this work either. + if (inConpty || !WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS)) { goto DoScroll; } diff --git a/src/server/IoDispatchers.cpp b/src/server/IoDispatchers.cpp index e19526cccf5..52ac5f0b2a9 100644 --- a/src/server/IoDispatchers.cpp +++ b/src/server/IoDispatchers.cpp @@ -456,7 +456,22 @@ PCONSOLE_API_MSG IoDispatchers::ConsoleHandleConnectionRequest(_In_ PCONSOLE_API return pReceiveMsg; } - gci.ProcessHandleList.ModifyConsoleProcessFocus(WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS)); + // For future code archeologists: GH#2988 + // + // Here, the console calls ConsoleControl(ConsoleSetForeground,...) with a + // flag depending on if the console is focused or not. This is surprisingly + // load bearing. This allows windows spawned by console processes to bring + // themselves to the foreground _when the console is focused_. + // (Historically, this is also called in the WndProc, when focus changes). + // + // Notably, before 2022, ConPTY was _never_ focused, so windows could never + // bring themselves to the foreground when run from a ConPTY console. We're + // not blanket granting the SetForeground right to all console apps when run + // in ConPTY. It's the responsibility of the hosting terminal emulator to + // always tell ConPTY when a particular instance is focused. + const bool hasFocus{ WI_IsFlagSet(gci.Flags, CONSOLE_HAS_FOCUS) }; + const auto grantSetForeground{ hasFocus }; + gci.ProcessHandleList.ModifyConsoleProcessFocus(grantSetForeground); // Create the handles. diff --git a/src/terminal/adapter/IInteractDispatch.hpp b/src/terminal/adapter/IInteractDispatch.hpp index acbaf5ff23a..97b22b3edde 100644 --- a/src/terminal/adapter/IInteractDispatch.hpp +++ b/src/terminal/adapter/IInteractDispatch.hpp @@ -42,5 +42,7 @@ namespace Microsoft::Console::VirtualTerminal const size_t col) = 0; virtual bool IsVtInputEnabled() const = 0; + + virtual bool FocusChanged(const bool focused) const = 0; }; } diff --git a/src/terminal/adapter/InteractDispatch.cpp b/src/terminal/adapter/InteractDispatch.cpp index 32a30c6f927..c93092c4102 100644 --- a/src/terminal/adapter/InteractDispatch.cpp +++ b/src/terminal/adapter/InteractDispatch.cpp @@ -181,3 +181,32 @@ bool InteractDispatch::IsVtInputEnabled() const { return _pConApi->IsVtInputEnabled(); } + +// Method Description: +// - Inform the console that the window is focused. This is used by ConPTY. +// Terminals can send ConPTY a FocusIn/FocusOut sequence on the input pipe, +// which will end up here. This will update the console's internal tracker if +// it's focused or not, as to match the end-terminal's state. +// - Used to call ConsoleControl(ConsoleSetForeground,...). +// - Full support for this sequence is tracked in GH#11682. +// Arguments: +// - focused: if the terminal is now focused +// Return Value: +// - true always. +bool InteractDispatch::FocusChanged(const bool focused) const +{ + // When we do GH#11682, we should make sure that ConPTY requests this mode + // from the terminal when it starts up, and ConPTY never unsets that flag. + // It should only ever internally disable the events from flowing to the + // client application. + + auto& g = ServiceLocator::LocateGlobals(); + auto& gci = g.getConsoleInformation(); + WI_UpdateFlag(gci.Flags, CONSOLE_HAS_FOCUS, focused); + gci.ProcessHandleList.ModifyConsoleProcessFocus(focused); + + // Theoretically, this could be propagated as a focus event as well, to the + // input buffer. That should be considered when implementing GH#11682. + + return true; +} diff --git a/src/terminal/adapter/InteractDispatch.hpp b/src/terminal/adapter/InteractDispatch.hpp index d903d83e9c6..e521244eb2e 100644 --- a/src/terminal/adapter/InteractDispatch.hpp +++ b/src/terminal/adapter/InteractDispatch.hpp @@ -35,6 +35,8 @@ namespace Microsoft::Console::VirtualTerminal bool IsVtInputEnabled() const override; + bool FocusChanged(const bool focused) const override; + private: std::unique_ptr _pConApi; }; diff --git a/src/terminal/parser/InputStateMachineEngine.cpp b/src/terminal/parser/InputStateMachineEngine.cpp index 40a9d0c4094..7fcec6b92da 100644 --- a/src/terminal/parser/InputStateMachineEngine.cpp +++ b/src/terminal/parser/InputStateMachineEngine.cpp @@ -362,9 +362,14 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter // win32-input-mode, and if they did, then we'll just translate the // INPUT_RECORD back to the same sequence we say here later on, when the // client reads it. + // + // Focus events in conpty are special, so don't flush those through either. + // See GH#12799, GH#12900 for details if (_pDispatch->IsVtInputEnabled() && _pfnFlushToInputQueue && - id != CsiActionCodes::Win32KeyboardInput) + id != CsiActionCodes::Win32KeyboardInput && + id != CsiActionCodes::FocusIn && + id != CsiActionCodes::FocusOut) { return _pfnFlushToInputQueue(); } @@ -426,6 +431,12 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter case CsiActionCodes::DTTERM_WindowManipulation: success = _pDispatch->WindowManipulation(parameters.at(0), parameters.at(1), parameters.at(2)); break; + case CsiActionCodes::FocusIn: + success = _pDispatch->FocusChanged(true); + break; + case CsiActionCodes::FocusOut: + success = _pDispatch->FocusChanged(false); + break; case CsiActionCodes::Win32KeyboardInput: { // Use WriteCtrlKey here, even for keys that _aren't_ control keys, diff --git a/src/terminal/parser/InputStateMachineEngine.hpp b/src/terminal/parser/InputStateMachineEngine.hpp index 8409617204a..c4a814a1eeb 100644 --- a/src/terminal/parser/InputStateMachineEngine.hpp +++ b/src/terminal/parser/InputStateMachineEngine.hpp @@ -58,6 +58,8 @@ namespace Microsoft::Console::VirtualTerminal ArrowLeft = VTID("D"), Home = VTID("H"), End = VTID("F"), + FocusIn = VTID("I"), + FocusOut = VTID("O"), MouseDown = VTID(">&)> _pfnWriteInputCallback; TestState* _testState; // non-ownership pointer @@ -399,6 +401,11 @@ bool TestInteractDispatch::IsVtInputEnabled() const return true; } +bool TestInteractDispatch::FocusChanged(const bool /*focused*/) const +{ + return false; +} + void InputEngineTest::C0Test() { auto pfn = std::bind(&TestState::TestInputCallback, &testState, std::placeholders::_1); From 0da5bd77269f6060a38e6e075ce97a9b0e3e6991 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 19 Apr 2022 16:26:33 -0500 Subject: [PATCH 2/5] Ensure a terminal requesting FG rights actually has them (#12899) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### ⚠️ _Targets #12799_ ⚠️ This is an atomic bit of code that partners with #12799. It's separated as an individual PR to keep diffs more simple. This ensures that when a terminal tells ConPTY that it's focused, that ConPTY doesn't do the `ConsoleControl(CONSOLE_FOREGROUND` thing unless the terminal application is actually in the foreground. This prevents a trivial exploit whereby a `malicious.exe` could create a PTY, tell ConPTY it has focus (when it doesn't), then use this mechanism to launch an instance of itself into the foreground. When the terminal tells us it's in the foreground, we're gonna look at the owner of the ConPTY window handle. If that owner has focus, then cool, this is allowed. Otherwise, we won't grant them the FG right. For this to work, the terminal just have already called `ReparentPseudoConsole`. * built on top of #12799 and #12526 * [x] Part of #2988 * [x] Tested manually. --- src/host/outputStream.cpp | 4 +- src/interactivity/inc/ServiceLocator.hpp | 2 +- src/terminal/adapter/InteractDispatch.cpp | 59 ++++++++++++++++++++--- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index 3955cfd9350..e863d61ba01 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -378,8 +378,8 @@ void ConhostInternalGetSet::ReparentWindow(const uint64_t handle) // If the window hasn't been created yet, by some other call to // LocatePseudoWindow, then this will also initialize the owner of the // window. - if (const auto psuedoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast(handle)) }) + if (const auto pseudoHwnd{ ServiceLocator::LocatePseudoWindow(reinterpret_cast(handle)) }) { - LOG_LAST_ERROR_IF_NULL(::SetParent(psuedoHwnd, reinterpret_cast(handle))); + LOG_LAST_ERROR_IF_NULL(::SetParent(pseudoHwnd, reinterpret_cast(handle))); } } diff --git a/src/interactivity/inc/ServiceLocator.hpp b/src/interactivity/inc/ServiceLocator.hpp index ff0bde14270..e83cbb12562 100644 --- a/src/interactivity/inc/ServiceLocator.hpp +++ b/src/interactivity/inc/ServiceLocator.hpp @@ -84,7 +84,7 @@ namespace Microsoft::Console::Interactivity static Globals& LocateGlobals(); - static HWND LocatePseudoWindow(const HWND owner = 0 /*HWND_DESKTOP*/); + static HWND LocatePseudoWindow(const HWND owner = nullptr /*HWND_DESKTOP = 0*/); protected: ServiceLocator(ServiceLocator const&) = delete; diff --git a/src/terminal/adapter/InteractDispatch.cpp b/src/terminal/adapter/InteractDispatch.cpp index c93092c4102..5294b74292f 100644 --- a/src/terminal/adapter/InteractDispatch.cpp +++ b/src/terminal/adapter/InteractDispatch.cpp @@ -195,15 +195,60 @@ bool InteractDispatch::IsVtInputEnabled() const // - true always. bool InteractDispatch::FocusChanged(const bool focused) const { - // When we do GH#11682, we should make sure that ConPTY requests this mode - // from the terminal when it starts up, and ConPTY never unsets that flag. - // It should only ever internally disable the events from flowing to the - // client application. - auto& g = ServiceLocator::LocateGlobals(); auto& gci = g.getConsoleInformation(); - WI_UpdateFlag(gci.Flags, CONSOLE_HAS_FOCUS, focused); - gci.ProcessHandleList.ModifyConsoleProcessFocus(focused); + + // This should likely always be true - we shouldn't ever have an + // InteractDispatch outside ConPTY mode, but just in case... + if (gci.IsInVtIoMode()) + { + bool shouldActuallyFocus = false; + + // From https://github.com/microsoft/terminal/pull/12799#issuecomment-1086289552 + // Make sure that the process that's telling us it's focused, actually + // _is_ in the FG. We don't want to allow malicious.exe to say "yep I'm + // in the foreground, also, here's a popup" if it isn't actually in the + // FG. + if (focused) + { + if (const auto pseudoHwnd{ ServiceLocator::LocatePseudoWindow() }) + { + // They want focus, we found a pseudo hwnd. + + // Note: ::GetParent(pseudoHwnd) will return 0. GetAncestor works though. + // GA_PARENT and GA_ROOT seemingly return the same thing for + // Terminal. We're going with GA_ROOT since it seems + // semantically more correct here. + if (const auto ownerHwnd{ ::GetAncestor(pseudoHwnd, GA_ROOT) }) + { + // We have an owner from a previous call to ReparentWindow + + if (const auto currentFgWindow{ ::GetForegroundWindow() }) + { + // There is a window in the foreground (it's possible there + // isn't one) + + // Get the PID of the current FG window, and compare with our owner's PID. + DWORD currentFgPid{ 0 }; + DWORD ownerPid{ 0 }; + GetWindowThreadProcessId(currentFgWindow, ¤tFgPid); + GetWindowThreadProcessId(ownerHwnd, &ownerPid); + + if (ownerPid == currentFgPid) + { + // Huzzah, the app that owns us is actually the FG + // process. They're allowed to grand FG rights. + shouldActuallyFocus = true; + } + } + } + } + } + + WI_UpdateFlag(gci.Flags, CONSOLE_HAS_FOCUS, shouldActuallyFocus); + gci.ProcessHandleList.ModifyConsoleProcessFocus(shouldActuallyFocus); + } + // Does nothing outside of ConPTY. If there's a real HWND, then the HWND is solely in charge. // Theoretically, this could be propagated as a focus event as well, to the // input buffer. That should be considered when implementing GH#11682. From 7af134cc7f597cd9c69c2aedc96e809b9499c053 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Wed, 20 Apr 2022 13:21:41 +0200 Subject: [PATCH 3/5] Introduce VTInt to represent VT parameters (#12207) This commit replaces our use of `size_t` to represent VT parameters with `int32_t`. While unsigned integers have the inherent benefit of being less ambiguous and enjoying two's complement, our buffer coordinates use signed integers. Since a number of VT functions need to convert their parameters to coordinates, this commit makes the conversion easier. The benefit of this change becomes even more apparent if one considers that a number of places performed unsafe conversions of their size_t parameters to int or short already. Files that had to be modified were converted to use til wrappers instead of COORD or SMALL_RECT wherever possible. ## References This commit contains about 20% of the work for #4015. ## PR Checklist * [x] I work here * [x] Tests added/passed ## Validation Steps Performed I'm mostly relying on our unit tests here. Both OpenConsole and WT appear to work fine. --- src/cascadia/TerminalCore/ITerminalApi.hpp | 10 +- src/cascadia/TerminalCore/Terminal.cpp | 2 +- src/cascadia/TerminalCore/Terminal.hpp | 10 +- src/cascadia/TerminalCore/TerminalApi.cpp | 61 +++++------- .../TerminalCore/TerminalDispatch.cpp | 52 ++++------ .../TerminalCore/TerminalDispatch.hpp | 22 +++-- .../UnitTests_TerminalCore/SelectionTest.cpp | 18 ++-- .../TerminalApiTest.cpp | 10 +- src/host/outputStream.cpp | 6 +- src/host/outputStream.hpp | 2 +- src/host/ut_host/ScreenBufferTests.cpp | 6 +- src/inc/til/point.h | 28 +++++- src/inc/til/rect.h | 93 +++++++++++++++++- src/inc/til/size.h | 13 +++ src/interactivity/win32/windowio.cpp | 2 +- src/terminal/adapter/DispatchTypes.hpp | 86 ++++++++--------- src/terminal/adapter/FontBuffer.cpp | 4 +- src/terminal/adapter/FontBuffer.hpp | 4 +- src/terminal/adapter/IInteractDispatch.hpp | 4 +- src/terminal/adapter/ITermDispatch.hpp | 56 +++++------ src/terminal/adapter/InteractDispatch.cpp | 31 ++---- src/terminal/adapter/InteractDispatch.hpp | 2 +- src/terminal/adapter/adaptDispatch.cpp | 95 ++++++++++--------- src/terminal/adapter/adaptDispatch.hpp | 92 +++++++++--------- src/terminal/adapter/conGetSet.hpp | 2 +- src/terminal/adapter/termDispatch.hpp | 56 +++++------ .../adapter/ut_adapter/MouseInputTest.cpp | 30 +++--- .../adapter/ut_adapter/WexHelpers.hpp | 63 ++++++------ .../adapter/ut_adapter/adapterTest.cpp | 56 +++++------ src/terminal/input/mouseInput.cpp | 36 +++---- src/terminal/input/terminalInput.hpp | 10 +- .../parser/InputStateMachineEngine.cpp | 6 +- src/terminal/parser/stateMachine.cpp | 4 +- src/terminal/parser/stateMachine.hpp | 6 +- .../parser/ut_parser/InputEngineTest.cpp | 43 ++++----- .../parser/ut_parser/OutputEngineTest.cpp | 46 ++++----- 36 files changed, 575 insertions(+), 492 deletions(-) diff --git a/src/cascadia/TerminalCore/ITerminalApi.hpp b/src/cascadia/TerminalCore/ITerminalApi.hpp index 7f41e0ce71f..e8ac69392e8 100644 --- a/src/cascadia/TerminalCore/ITerminalApi.hpp +++ b/src/cascadia/TerminalCore/ITerminalApi.hpp @@ -27,15 +27,15 @@ namespace Microsoft::Terminal::Core virtual void SetTextAttributes(const TextAttribute& attrs) = 0; virtual Microsoft::Console::Types::Viewport GetBufferSize() = 0; - virtual void SetCursorPosition(short x, short y) = 0; - virtual COORD GetCursorPosition() = 0; + virtual void SetCursorPosition(til::point pos) = 0; + virtual til::point GetCursorPosition() = 0; virtual void SetCursorVisibility(const bool visible) = 0; virtual void CursorLineFeed(const bool withReturn) = 0; virtual void EnableCursorBlinking(const bool enable) = 0; - virtual void DeleteCharacter(const size_t count) = 0; - virtual void InsertCharacter(const size_t count) = 0; - virtual void EraseCharacters(const size_t numChars) = 0; + virtual void DeleteCharacter(const til::CoordType count) = 0; + virtual void InsertCharacter(const til::CoordType count) = 0; + virtual void EraseCharacters(const til::CoordType numChars) = 0; virtual bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) = 0; virtual bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) = 0; diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 90928513fce..81fb6c7edb7 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -708,7 +708,7 @@ bool Terminal::SendMouseEvent(const COORD viewportPos, const unsigned int uiButt #pragma warning(suppress : 26496) // analysis can't tell we're assigning through a reference below auto clampedPos{ viewportPos }; _GetMutableViewport().ToOrigin().Clamp(clampedPos); - return _terminalInput->HandleMouse(clampedPos, uiButton, GET_KEYSTATE_WPARAM(states.Value()), wheelDelta, state); + return _terminalInput->HandleMouse(til::point{ clampedPos }, uiButton, GET_KEYSTATE_WPARAM(states.Value()), wheelDelta, state); } // Method Description: diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index df882f3eed0..de84a964c91 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -101,14 +101,14 @@ class Microsoft::Terminal::Core::Terminal final : TextAttribute GetTextAttributes() const override; void SetTextAttributes(const TextAttribute& attrs) override; Microsoft::Console::Types::Viewport GetBufferSize() override; - void SetCursorPosition(short x, short y) override; - COORD GetCursorPosition() override; + void SetCursorPosition(til::point pos) override; + til::point GetCursorPosition() override; void SetCursorVisibility(const bool visible) override; void EnableCursorBlinking(const bool enable) override; void CursorLineFeed(const bool withReturn) override; - void DeleteCharacter(const size_t count) override; - void InsertCharacter(const size_t count) override; - void EraseCharacters(const size_t numChars) override; + void DeleteCharacter(const til::CoordType count) override; + void InsertCharacter(const til::CoordType count) override; + void EraseCharacters(const til::CoordType numChars) override; bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; void WarningBell() override; diff --git a/src/cascadia/TerminalCore/TerminalApi.cpp b/src/cascadia/TerminalCore/TerminalApi.cpp index 5b9dfe8e8ec..6baeea51bf8 100644 --- a/src/cascadia/TerminalCore/TerminalApi.cpp +++ b/src/cascadia/TerminalCore/TerminalApi.cpp @@ -41,28 +41,22 @@ Viewport Terminal::GetBufferSize() return _activeBuffer().GetSize(); } -void Terminal::SetCursorPosition(short x, short y) +void Terminal::SetCursorPosition(til::point pos) { const auto viewport = _GetMutableViewport(); - const auto viewOrigin = viewport.Origin(); - const short absoluteX = viewOrigin.X + x; - const short absoluteY = viewOrigin.Y + y; - COORD newPos{ absoluteX, absoluteY }; + const til::point viewOrigin{ viewport.Origin() }; + auto newPos = til::unwrap_coord(viewOrigin + pos); viewport.Clamp(newPos); _activeBuffer().GetCursor().SetPosition(newPos); } -COORD Terminal::GetCursorPosition() +til::point Terminal::GetCursorPosition() { - const auto absoluteCursorPos = _activeBuffer().GetCursor().GetPosition(); + const til::point absoluteCursorPos{ _activeBuffer().GetCursor().GetPosition() }; const auto viewport = _GetMutableViewport(); - const auto viewOrigin = viewport.Origin(); - const short relativeX = absoluteCursorPos.X - viewOrigin.X; - const short relativeY = absoluteCursorPos.Y - viewOrigin.Y; - COORD newPos{ relativeX, relativeY }; - + const til::point viewOrigin{ viewport.Origin() }; // TODO assert that the coord is > (0, 0) && <(view.W, view.H) - return newPos; + return absoluteCursorPos - viewOrigin; } // Method Description: @@ -97,21 +91,17 @@ void Terminal::CursorLineFeed(const bool withReturn) // - count, the number of characters to delete // Return value: // - -void Terminal::DeleteCharacter(const size_t count) +void Terminal::DeleteCharacter(const til::CoordType count) { - SHORT dist; - THROW_IF_FAILED(SizeTToShort(count, &dist)); const auto cursorPos = _activeBuffer().GetCursor().GetPosition(); const auto copyToPos = cursorPos; - const COORD copyFromPos{ cursorPos.X + dist, cursorPos.Y }; + const til::point copyFromPos{ cursorPos.X + count, cursorPos.Y }; const auto viewport = _GetMutableViewport(); const auto sourceWidth = viewport.RightExclusive() - copyFromPos.X; - SHORT width; - THROW_IF_FAILED(UIntToShort(sourceWidth, &width)); // Get a rectangle of the source - auto source = Viewport::FromDimensions(copyFromPos, width, 1); + auto source = Viewport::FromDimensions(til::unwrap_coord(copyFromPos), gsl::narrow(sourceWidth), 1); // Get a rectangle of the target const auto target = Viewport::FromDimensions(copyToPos, source.Dimensions()); @@ -137,28 +127,23 @@ void Terminal::DeleteCharacter(const size_t count) // - count, the number of spaces to insert // Return value: // - -void Terminal::InsertCharacter(const size_t count) +void Terminal::InsertCharacter(const til::CoordType count) { // NOTE: the code below is _extremely_ similar to DeleteCharacter // We will want to use this same logic and implement a helper function instead // that does the 'move a region from here to there' operation // TODO: GitHub issue #2163 - SHORT dist; - THROW_IF_FAILED(SizeTToShort(count, &dist)); const auto cursorPos = _activeBuffer().GetCursor().GetPosition(); const auto copyFromPos = cursorPos; - const COORD copyToPos{ cursorPos.X + dist, cursorPos.Y }; + const til::point copyToPos{ cursorPos.X + count, cursorPos.Y }; const auto viewport = _GetMutableViewport(); const auto sourceWidth = viewport.RightExclusive() - copyFromPos.X; - SHORT width; - THROW_IF_FAILED(UIntToShort(sourceWidth, &width)); // Get a rectangle of the source - auto source = Viewport::FromDimensions(copyFromPos, width, 1); - const auto sourceOrigin = source.Origin(); + auto source = Viewport::FromDimensions(copyFromPos, gsl::narrow(sourceWidth), 1); // Get a rectangle of the target - const auto target = Viewport::FromDimensions(copyToPos, source.Dimensions()); + const auto target = Viewport::FromDimensions(til::unwrap_coord(copyToPos), source.Dimensions()); const auto walkDirection = Viewport::DetermineWalkDirection(source, target); auto sourcePos = source.GetWalkOrigin(walkDirection); @@ -170,16 +155,16 @@ void Terminal::InsertCharacter(const size_t count) const auto data = OutputCell(*(_activeBuffer().GetCellDataAt(sourcePos))); _activeBuffer().Write(OutputCellIterator({ &data, 1 }), targetPos); } while (source.WalkInBounds(sourcePos, walkDirection) && target.WalkInBounds(targetPos, walkDirection)); - const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _activeBuffer().GetCurrentAttributes(), dist); + const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _activeBuffer().GetCurrentAttributes(), count); _activeBuffer().Write(eraseIter, cursorPos); } -void Terminal::EraseCharacters(const size_t numChars) +void Terminal::EraseCharacters(const til::CoordType numChars) { const auto absoluteCursorPos = _activeBuffer().GetCursor().GetPosition(); const auto viewport = _GetMutableViewport(); - const short distanceToRight = viewport.RightExclusive() - absoluteCursorPos.X; - const short fillLimit = std::min(static_cast(numChars), distanceToRight); + const auto distanceToRight = viewport.RightExclusive() - absoluteCursorPos.X; + const auto fillLimit = std::min(numChars, distanceToRight); const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _activeBuffer().GetCurrentAttributes(), fillLimit); _activeBuffer().Write(eraseIter, absoluteCursorPos); } @@ -198,7 +183,7 @@ bool Terminal::EraseInLine(const ::Microsoft::Console::VirtualTerminal::Dispatch { const auto cursorPos = _activeBuffer().GetCursor().GetPosition(); const auto viewport = _GetMutableViewport(); - COORD startPos = { 0 }; + til::point startPos; startPos.Y = cursorPos.Y; // nlength determines the number of spaces we need to write DWORD nlength = 0; @@ -224,7 +209,7 @@ bool Terminal::EraseInLine(const ::Microsoft::Console::VirtualTerminal::Dispatch const auto eraseIter = OutputCellIterator(UNICODE_SPACE, _activeBuffer().GetCurrentAttributes(), nlength); // Explicitly turn off end-of-line wrap-flag-setting when erasing cells. - _activeBuffer().Write(eraseIter, startPos, false); + _activeBuffer().Write(eraseIter, til::unwrap_coord(startPos), false); return true; } @@ -275,7 +260,7 @@ bool Terminal::EraseInDisplay(const DispatchTypes::EraseType eraseType) short sNewTop = coordLastChar.Y + 1; // Increment the circular buffer only if the new location of the viewport would be 'below' the buffer - const short delta = (sNewTop + viewport.Height()) - (_activeBuffer().GetSize().Height()); + const auto delta = (sNewTop + viewport.Height()) - (_activeBuffer().GetSize().Height()); for (auto i = 0; i < delta; i++) { _activeBuffer().IncrementCircularBuffer(); @@ -297,7 +282,7 @@ bool Terminal::EraseInDisplay(const DispatchTypes::EraseType eraseType) // and we have to make sure we erase that text const auto eraseStart = viewport.Height(); const auto eraseEnd = _activeBuffer().GetLastNonSpaceCharacter(viewport).Y; - for (SHORT i = eraseStart; i <= eraseEnd; i++) + for (auto i = eraseStart; i <= eraseEnd; i++) { _activeBuffer().GetRowByOffset(i).Reset(_activeBuffer().GetCurrentAttributes()); } @@ -316,7 +301,7 @@ bool Terminal::EraseInDisplay(const DispatchTypes::EraseType eraseType) // Move the viewport, adjust the scroll bar if needed, and restore the old cursor position _mutableViewport = Viewport::FromExclusive(newWin); Terminal::_NotifyScrollEvent(); - SetCursorPosition(relativeCursor.X, relativeCursor.Y); + SetCursorPosition(til::point{ relativeCursor }); return true; } diff --git a/src/cascadia/TerminalCore/TerminalDispatch.cpp b/src/cascadia/TerminalCore/TerminalDispatch.cpp index 689e29de93a..b380acdba15 100644 --- a/src/cascadia/TerminalCore/TerminalDispatch.cpp +++ b/src/cascadia/TerminalCore/TerminalDispatch.cpp @@ -29,19 +29,10 @@ void TerminalDispatch::PrintString(const std::wstring_view string) _terminalApi.PrintString(string); } -bool TerminalDispatch::CursorPosition(const size_t line, - const size_t column) +bool TerminalDispatch::CursorPosition(VTInt line, + VTInt column) { - SHORT x{ 0 }; - SHORT y{ 0 }; - - THROW_IF_FAILED(SizeTToShort(column, &x)); - THROW_IF_FAILED(SizeTToShort(line, &y)); - - THROW_IF_FAILED(ShortSub(x, 1, &x)); - THROW_IF_FAILED(ShortSub(y, 1, &y)); - - _terminalApi.SetCursorPosition(x, y); + _terminalApi.SetCursorPosition({ column - 1, line - 1 }); return true; } @@ -57,27 +48,24 @@ bool TerminalDispatch::EnableCursorBlinking(const bool enable) return true; } -bool TerminalDispatch::CursorForward(const size_t distance) +bool TerminalDispatch::CursorForward(const VTInt distance) { const auto cursorPos = _terminalApi.GetCursorPosition(); - const COORD newCursorPos{ cursorPos.X + gsl::narrow(distance), cursorPos.Y }; - _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y); + _terminalApi.SetCursorPosition({ cursorPos.X + distance, cursorPos.Y }); return true; } -bool TerminalDispatch::CursorBackward(const size_t distance) +bool TerminalDispatch::CursorBackward(const VTInt distance) { const auto cursorPos = _terminalApi.GetCursorPosition(); - const COORD newCursorPos{ cursorPos.X - gsl::narrow(distance), cursorPos.Y }; - _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y); + _terminalApi.SetCursorPosition({ cursorPos.X - distance, cursorPos.Y }); return true; } -bool TerminalDispatch::CursorUp(const size_t distance) +bool TerminalDispatch::CursorUp(const VTInt distance) { const auto cursorPos = _terminalApi.GetCursorPosition(); - const COORD newCursorPos{ cursorPos.X, cursorPos.Y + gsl::narrow(distance) }; - _terminalApi.SetCursorPosition(newCursorPos.X, newCursorPos.Y); + _terminalApi.SetCursorPosition({ cursorPos.X, cursorPos.Y + distance }); return true; } @@ -99,7 +87,7 @@ bool TerminalDispatch::LineFeed(const DispatchTypes::LineFeedType lineFeedType) } } -bool TerminalDispatch::EraseCharacters(const size_t numChars) +bool TerminalDispatch::EraseCharacters(const VTInt numChars) { _terminalApi.EraseCharacters(numChars); return true; @@ -114,7 +102,7 @@ bool TerminalDispatch::WarningBell() bool TerminalDispatch::CarriageReturn() { const auto cursorPos = _terminalApi.GetCursorPosition(); - _terminalApi.SetCursorPosition(0, cursorPos.Y); + _terminalApi.SetCursorPosition({ 0, cursorPos.Y }); return true; } @@ -134,13 +122,13 @@ bool TerminalDispatch::HorizontalTabSet() return true; } -bool TerminalDispatch::ForwardTab(const size_t numTabs) +bool TerminalDispatch::ForwardTab(const VTInt numTabs) { const auto width = _terminalApi.GetBufferSize().Dimensions().X; const auto cursorPosition = _terminalApi.GetCursorPosition(); auto column = cursorPosition.X; const auto row = cursorPosition.Y; - auto tabsPerformed = 0u; + VTInt tabsPerformed = 0; _InitTabStopsForWidth(width); while (column + 1 < width && tabsPerformed < numTabs) { @@ -151,17 +139,17 @@ bool TerminalDispatch::ForwardTab(const size_t numTabs) } } - _terminalApi.SetCursorPosition(column, row); + _terminalApi.SetCursorPosition({ column, row }); return true; } -bool TerminalDispatch::BackwardsTab(const size_t numTabs) +bool TerminalDispatch::BackwardsTab(const VTInt numTabs) { const auto width = _terminalApi.GetBufferSize().Dimensions().X; const auto cursorPosition = _terminalApi.GetCursorPosition(); auto column = cursorPosition.X; const auto row = cursorPosition.Y; - auto tabsPerformed = 0u; + VTInt tabsPerformed = 0; _InitTabStopsForWidth(width); while (column > 0 && tabsPerformed < numTabs) { @@ -172,7 +160,7 @@ bool TerminalDispatch::BackwardsTab(const size_t numTabs) } } - _terminalApi.SetCursorPosition(column, row); + _terminalApi.SetCursorPosition({ column, row }); return true; } @@ -266,7 +254,7 @@ bool TerminalDispatch::EraseInLine(const DispatchTypes::EraseType eraseType) // - count, the number of characters to delete // Return Value: // - True. -bool TerminalDispatch::DeleteCharacter(const size_t count) +bool TerminalDispatch::DeleteCharacter(const VTInt count) { _terminalApi.DeleteCharacter(count); return true; @@ -278,7 +266,7 @@ bool TerminalDispatch::DeleteCharacter(const size_t count) // - count, the number of spaces to add // Return Value: // - True. -bool TerminalDispatch::InsertCharacter(const size_t count) +bool TerminalDispatch::InsertCharacter(const VTInt count) { _terminalApi.InsertCharacter(count); return true; @@ -803,7 +791,7 @@ bool TerminalDispatch::CursorSaveState() // TODO GH#3849: When de-duplicating this, the AdaptDispatch version of this // is more elaborate. const auto attributes = _terminalApi.GetTextAttributes(); - COORD coordCursor = _terminalApi.GetCursorPosition(); + const auto coordCursor = _terminalApi.GetCursorPosition(); // The cursor is given to us by the API as relative to current viewport top. // VT is also 1 based, not 0 based, so correct by 1. diff --git a/src/cascadia/TerminalCore/TerminalDispatch.hpp b/src/cascadia/TerminalCore/TerminalDispatch.hpp index 42188bc4ecf..d358552b78e 100644 --- a/src/cascadia/TerminalCore/TerminalDispatch.hpp +++ b/src/cascadia/TerminalCore/TerminalDispatch.hpp @@ -9,6 +9,8 @@ static constexpr size_t TaskbarMaxProgress{ 100 }; class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatch { + using VTInt = Microsoft::Console::VirtualTerminal::VTInt; + public: TerminalDispatch(::Microsoft::Terminal::Core::ITerminalApi& terminalApi) noexcept; @@ -20,21 +22,21 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc bool PushGraphicsRendition(const ::Microsoft::Console::VirtualTerminal::VTParameters options) override; bool PopGraphicsRendition() override; - bool CursorPosition(const size_t line, - const size_t column) override; // CUP + bool CursorPosition(const VTInt line, + const VTInt column) override; // CUP bool EnableWin32InputMode(const bool win32InputMode) override; // win32-input-mode bool CursorVisibility(const bool isVisible) override; // DECTCEM bool EnableCursorBlinking(const bool enable) override; // ATT610 - bool CursorForward(const size_t distance) override; - bool CursorBackward(const size_t distance) override; - bool CursorUp(const size_t distance) override; + bool CursorForward(const VTInt distance) override; + bool CursorBackward(const VTInt distance) override; + bool CursorUp(const VTInt distance) override; bool LineFeed(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::LineFeedType lineFeedType) override; - bool EraseCharacters(const size_t numChars) override; + bool EraseCharacters(const VTInt numChars) override; bool WarningBell() override; bool CarriageReturn() override; bool SetWindowTitle(std::wstring_view title) override; @@ -43,8 +45,8 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc bool UseMainScreenBuffer() override; // ASBRST bool HorizontalTabSet() override; // HTS - bool ForwardTab(const size_t numTabs) override; // CHT, HT - bool BackwardsTab(const size_t numTabs) override; // CBT + bool ForwardTab(const VTInt numTabs) override; // CHT, HT + bool BackwardsTab(const VTInt numTabs) override; // CBT bool TabClear(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TabClearType clearType) override; // TBC bool SetColorTableEntry(const size_t tableIndex, const DWORD color) override; @@ -56,8 +58,8 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc bool SetDefaultForeground(const DWORD color) override; bool SetDefaultBackground(const DWORD color) override; bool EraseInLine(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; // ED - bool DeleteCharacter(const size_t count) override; - bool InsertCharacter(const size_t count) override; + bool DeleteCharacter(const VTInt count) override; + bool InsertCharacter(const VTInt count) override; bool EraseInDisplay(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::EraseType eraseType) override; bool SetCursorKeysMode(const bool applicationMode) override; // DECCKM diff --git a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp index 81a6313af3c..147b6776a1d 100644 --- a/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/SelectionTest.cpp @@ -394,7 +394,7 @@ namespace TerminalCoreUnitTests const auto burrito = L"\xD83C\xDF2F"; // Insert wide glyph at position (4,10) - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(burrito); // Simulate click at (x,y) = (5,10) @@ -417,7 +417,7 @@ namespace TerminalCoreUnitTests const auto burrito = L"\xD83C\xDF2F"; // Insert wide glyph at position (4,10) - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(burrito); // Simulate click at (x,y) = (5,10) @@ -440,11 +440,11 @@ namespace TerminalCoreUnitTests const auto burrito = L"\xD83C\xDF2F"; // Insert wide glyph at position (4,10) - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(burrito); // Insert wide glyph at position (7,11) - term.SetCursorPosition(7, 11); + term.SetCursorPosition({ 7, 11 }); term.Write(burrito); // Simulate ALT + click at (x,y) = (5,8) @@ -496,7 +496,7 @@ namespace TerminalCoreUnitTests // Insert text at position (4,10) const std::wstring_view text = L"doubleClickMe"; - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(text); // Simulate double click at (x,y) = (5,10) @@ -540,7 +540,7 @@ namespace TerminalCoreUnitTests // Insert text at position (4,10) const std::wstring_view text = L"C:\\Terminal>"; - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(text); // Simulate click at (x,y) = (15,10) @@ -568,7 +568,7 @@ namespace TerminalCoreUnitTests // Insert text at position (4,10) const std::wstring_view text = L"doubleClickMe dragThroughHere"; - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(text); // Simulate double click at (x,y) = (5,10) @@ -597,7 +597,7 @@ namespace TerminalCoreUnitTests // Insert text at position (21,10) const std::wstring_view text = L"doubleClickMe dragThroughHere"; - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(text); // Simulate double click at (x,y) = (21,10) @@ -685,7 +685,7 @@ namespace TerminalCoreUnitTests // Insert text at position (4,10) const std::wstring_view text = L"doubleClickMe dragThroughHere"; - term.SetCursorPosition(4, 10); + term.SetCursorPosition({ 4, 10 }); term.Write(text); // Step 1: Create a selection on "doubleClickMe" diff --git a/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp b/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp index 9acfeb739dd..67555000a3a 100644 --- a/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp +++ b/src/cascadia/UnitTests_TerminalCore/TerminalApiTest.cpp @@ -242,19 +242,19 @@ void TerminalApiTest::CheckDoubleWidthCursor() stateMachine.ProcessString(doubleWidthText); // The last 'A' - term.SetCursorPosition(97, 0); + term.SetCursorPosition({ 97, 0 }); VERIFY_IS_FALSE(term.IsCursorDoubleWidth()); // This and the next CursorPos are taken up by '我‘ - term.SetCursorPosition(98, 0); + term.SetCursorPosition({ 98, 0 }); VERIFY_IS_TRUE(term.IsCursorDoubleWidth()); - term.SetCursorPosition(99, 0); + term.SetCursorPosition({ 99, 0 }); VERIFY_IS_TRUE(term.IsCursorDoubleWidth()); // This and the next CursorPos are taken up by ’愛‘ - term.SetCursorPosition(0, 1); + term.SetCursorPosition({ 0, 1 }); VERIFY_IS_TRUE(term.IsCursorDoubleWidth()); - term.SetCursorPosition(1, 1); + term.SetCursorPosition({ 1, 1 }); VERIFY_IS_TRUE(term.IsCursorDoubleWidth()); } diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index e863d61ba01..8330f7cf932 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -152,12 +152,12 @@ void ConhostInternalGetSet::SetAutoWrapMode(const bool wrapAtEOL) // left and right margins in the future. // Return Value: // - -void ConhostInternalGetSet::SetScrollingRegion(const SMALL_RECT& scrollMargins) +void ConhostInternalGetSet::SetScrollingRegion(const til::inclusive_rect& scrollMargins) { auto& screenInfo = _io.GetActiveOutputBuffer(); auto srScrollMargins = screenInfo.GetRelativeScrollMargins().ToInclusive(); - srScrollMargins.Top = scrollMargins.Top; - srScrollMargins.Bottom = scrollMargins.Bottom; + srScrollMargins.Top = gsl::narrow(scrollMargins.Top); + srScrollMargins.Bottom = gsl::narrow(scrollMargins.Bottom); screenInfo.SetScrollMargins(Viewport::FromInclusive(srScrollMargins)); } diff --git a/src/host/outputStream.hpp b/src/host/outputStream.hpp index 1fc1db2cfb1..c959df7e4ed 100644 --- a/src/host/outputStream.hpp +++ b/src/host/outputStream.hpp @@ -42,7 +42,7 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal:: void SetAutoWrapMode(const bool wrapAtEOL) override; - void SetScrollingRegion(const SMALL_RECT& scrollMargins) override; + void SetScrollingRegion(const til::inclusive_rect& scrollMargins) override; void WarningBell() override; diff --git a/src/host/ut_host/ScreenBufferTests.cpp b/src/host/ut_host/ScreenBufferTests.cpp index cfd86c627c1..9791baff375 100644 --- a/src/host/ut_host/ScreenBufferTests.cpp +++ b/src/host/ut_host/ScreenBufferTests.cpp @@ -3920,11 +3920,13 @@ void ScreenBufferTests::EraseTests() TEST_METHOD_PROPERTY(L"Data:eraseScreen", L"{false, true}") // corresponds to Line (false) or Screen (true) END_TEST_METHOD_PROPERTIES() - DispatchTypes::EraseType eraseType; - VERIFY_SUCCEEDED(TestData::TryGetValue(L"eraseType", (size_t&)eraseType)); + int eraseTypeValue; + VERIFY_SUCCEEDED(TestData::TryGetValue(L"eraseType", eraseTypeValue)); bool eraseScreen; VERIFY_SUCCEEDED(TestData::TryGetValue(L"eraseScreen", eraseScreen)); + const auto eraseType = gsl::narrow(eraseTypeValue); + std::wstringstream escapeSequence; escapeSequence << "\x1b["; diff --git a/src/inc/til/point.h b/src/inc/til/point.h index 98bd50c6d54..f8eea99ccef 100644 --- a/src/inc/til/point.h +++ b/src/inc/til/point.h @@ -23,8 +23,19 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" struct point { - CoordType x = 0; - CoordType y = 0; + // **** TRANSITIONAL **** + // The old COORD type uses uppercase member names. + // We'll migrate to lowercase ones in the future. + union + { + CoordType x = 0; + CoordType X; + }; + union + { + CoordType y = 0; + CoordType Y; + }; constexpr point() noexcept = default; @@ -229,6 +240,19 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" return wil::str_printf(L"(X:%d, Y:%d)", x, y); } }; + + constexpr point wrap_coord(const COORD rect) noexcept + { + return { rect.X, rect.Y }; + } + + constexpr COORD unwrap_coord(const point rect) + { + return { + gsl::narrow(rect.X), + gsl::narrow(rect.Y), + }; + } } #ifdef __WEX_COMMON_H__ diff --git a/src/inc/til/rect.h b/src/inc/til/rect.h index f5116da1978..fb51d1877f7 100644 --- a/src/inc/til/rect.h +++ b/src/inc/til/rect.h @@ -12,6 +12,58 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" { + struct inclusive_rect + { + // **** TRANSITIONAL **** + // The old SMALL_RECT type uses uppercase member names. + // We'll migrate to lowercase ones in the future. + union + { + CoordType left = 0; + CoordType Left; + }; + union + { + CoordType top = 0; + CoordType Top; + }; + union + { + CoordType right = 0; + CoordType Right; + }; + union + { + CoordType bottom = 0; + CoordType Bottom; + }; + + constexpr bool operator==(const inclusive_rect& rhs) const noexcept + { + return __builtin_memcmp(this, &rhs, sizeof(rhs)) == 0; + } + + constexpr bool operator!=(const inclusive_rect& rhs) const noexcept + { + return __builtin_memcmp(this, &rhs, sizeof(rhs)) != 0; + } + }; + + constexpr inclusive_rect wrap_small_rect(const SMALL_RECT& rect) noexcept + { + return { rect.Left, rect.Top, rect.Right, rect.Bottom }; + } + + constexpr SMALL_RECT unwrap_small_rect(const inclusive_rect& rect) + { + return { + gsl::narrow(rect.left), + gsl::narrow(rect.top), + gsl::narrow(rect.right), + gsl::narrow(rect.bottom), + }; + } + namespace details { class _rectangle_const_iterator @@ -89,10 +141,29 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" { using const_iterator = details::_rectangle_const_iterator; - CoordType left = 0; - CoordType top = 0; - CoordType right = 0; - CoordType bottom = 0; + // **** TRANSITIONAL **** + // The old SMALL_RECT type uses uppercase member names. + // We'll migrate to lowercase ones in the future. + union + { + CoordType left = 0; + CoordType Left; + }; + union + { + CoordType top = 0; + CoordType Top; + }; + union + { + CoordType right = 0; + CoordType Right; + }; + union + { + CoordType bottom = 0; + CoordType Bottom; + }; constexpr rect() noexcept = default; @@ -744,6 +815,20 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" gsl::narrow(bottom - 1), }; } + + // NOTE: This will convert from INCLUSIVE on the way in because + // that is generally how SMALL_RECTs are handled in console code and via the APIs. + explicit constexpr rect(const inclusive_rect other) noexcept : + rect{ other.Left, other.Top, other.Right + 1, other.Bottom + 1 } + { + } + + // NOTE: This will convert back to INCLUSIVE on the way out because + // that is generally how SMALL_RECTs are handled in console code and via the APIs. + constexpr inclusive_rect to_inclusive_rect() const + { + return { left, top, right - 1, bottom - 1 }; + } #endif #ifdef _WINDEF_ diff --git a/src/inc/til/size.h b/src/inc/til/size.h index 199f836a3a0..df0b893067e 100644 --- a/src/inc/til/size.h +++ b/src/inc/til/size.h @@ -209,6 +209,19 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned" return wil::str_printf(L"[W:%d, H:%d]", width, height); } }; + + constexpr size wrap_coord_size(const COORD rect) noexcept + { + return { rect.X, rect.Y }; + } + + constexpr COORD unwrap_coord_size(const size rect) + { + return { + gsl::narrow(rect.width), + gsl::narrow(rect.height), + }; + } }; #ifdef __WEX_COMMON_H__ diff --git a/src/interactivity/win32/windowio.cpp b/src/interactivity/win32/windowio.cpp index 2d5d8436ec3..be45dab0e98 100644 --- a/src/interactivity/win32/windowio.cpp +++ b/src/interactivity/win32/windowio.cpp @@ -141,7 +141,7 @@ bool HandleTerminalMouseEvent(const COORD cMousePosition, auto clampedPosition{ cMousePosition }; const auto clampViewport{ gci.GetActiveOutputBuffer().GetViewport().ToOrigin() }; clampViewport.Clamp(clampedPosition); - fWasHandled = gci.GetActiveInputBuffer()->GetTerminalInput().HandleMouse(clampedPosition, uiButton, sModifierKeystate, sWheelDelta, state); + fWasHandled = gci.GetActiveInputBuffer()->GetTerminalInput().HandleMouse(til::wrap_coord(clampedPosition), uiButton, sModifierKeystate, sWheelDelta, state); } return fWasHandled; diff --git a/src/terminal/adapter/DispatchTypes.hpp b/src/terminal/adapter/DispatchTypes.hpp index 4510626f50b..5a048aafb5c 100644 --- a/src/terminal/adapter/DispatchTypes.hpp +++ b/src/terminal/adapter/DispatchTypes.hpp @@ -5,6 +5,8 @@ namespace Microsoft::Console::VirtualTerminal { + using VTInt = int32_t; + class VTID { public: @@ -98,8 +100,8 @@ namespace Microsoft::Console::VirtualTerminal { } - constexpr VTParameter(const size_t rhs) noexcept : - _value{ gsl::narrow_cast(rhs) } + constexpr VTParameter(const VTInt rhs) noexcept : + _value{ rhs } { } @@ -109,31 +111,33 @@ namespace Microsoft::Console::VirtualTerminal return _value >= 0; } - constexpr size_t value() const noexcept + constexpr VTInt value() const noexcept { return _value; } - constexpr size_t value_or(size_t defaultValue) const noexcept + constexpr VTInt value_or(VTInt defaultValue) const noexcept { - return has_value() ? _value : defaultValue; + // A negative value indicates that the parameter was omitted. + return _value < 0 ? defaultValue : _value; } - template = 0> + template>> constexpr operator T() const noexcept { // For most selective parameters, omitted values will default to 0. return static_cast(value_or(0)); } - constexpr operator size_t() const noexcept + constexpr operator VTInt() const noexcept { // For numeric parameters, both 0 and omitted values will default to 1. - return has_value() && _value != 0 ? _value : 1; + // The parameter is omitted if _value is less than 0. + return _value <= 0 ? 1 : _value; } private: - std::make_signed::type _value; + VTInt _value; }; class VTParameters @@ -201,19 +205,13 @@ namespace Microsoft::Console::VirtualTerminal // }; // // It will produce an error if the provided flag value sets multiple bits. - template + template class FlaggedEnumValue { - template - struct ZeroOrOneBitChecker - { - static_assert(Value == 0 || (((Value - 1) & Value) == 0), "zero or one flags expected"); - static constexpr T value = Value; - }; - public: - static constexpr T mask{ ZeroOrOneBitChecker::value }; - constexpr FlaggedEnumValue(const T value) : + static constexpr VTInt mask{ WI_StaticAssertSingleBitSet(Flag) }; + + constexpr FlaggedEnumValue(const VTInt value) : _value{ value } { } @@ -223,25 +221,25 @@ namespace Microsoft::Console::VirtualTerminal { } - template = 0> - constexpr operator U() const noexcept + template>> + constexpr operator T() const noexcept { - return static_cast(_value | mask); + return static_cast(_value | mask); } - constexpr operator T() const noexcept + constexpr operator VTInt() const noexcept { return _value | mask; } private: - T _value; + VTInt _value; }; } namespace Microsoft::Console::VirtualTerminal::DispatchTypes { - enum class EraseType : size_t + enum class EraseType : VTInt { ToEnd = 0, FromBeginning = 1, @@ -249,7 +247,7 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes Scrollback = 3 }; - enum class TaskbarState : size_t + enum class TaskbarState : VTInt { Clear = 0, Set = 1, @@ -258,7 +256,7 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes Paused = 4 }; - enum GraphicsOptions : size_t + enum GraphicsOptions : VTInt { Off = 0, Intense = 1, @@ -337,7 +335,7 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes // Ps = 3 0 => Foreground color. // Ps = 3 1 => Background color. // - enum class SgrSaveRestoreStackOptions : size_t + enum class SgrSaveRestoreStackOptions : VTInt { All = 0, Intense = 1, @@ -354,16 +352,16 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes Max = SaveBackgroundColor }; - enum class AnsiStatusType : size_t + enum class AnsiStatusType : VTInt { OS_OperatingStatus = 5, CPR_CursorPositionReport = 6, }; - using ANSIStandardMode = FlaggedEnumValue; - using DECPrivateMode = FlaggedEnumValue; + using ANSIStandardMode = FlaggedEnumValue<0x00000000>; + using DECPrivateMode = FlaggedEnumValue<0x01000000>; - enum ModeParams : size_t + enum ModeParams : VTInt { DECCKM_CursorKeysMode = DECPrivateMode(1), DECANM_AnsiMode = DECPrivateMode(2), @@ -397,20 +395,20 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes UTF8 = VTID("G") }; - enum TabClearType : size_t + enum TabClearType : VTInt { ClearCurrentColumn = 0, ClearAllColumns = 3 }; - enum WindowManipulationType : size_t + enum WindowManipulationType : VTInt { Invalid = 0, RefreshWindow = 7, ResizeWindowInCharacters = 8, }; - enum class CursorStyle : size_t + enum class CursorStyle : VTInt { UserDefault = 0, // Implemented as "restore cursor to user default". BlinkingBlock = 1, @@ -421,27 +419,27 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes SteadyBar = 6 }; - enum class ReportingPermission : size_t + enum class ReportingPermission : VTInt { Unsolicited = 0, Solicited = 1 }; - enum class LineFeedType : unsigned int + enum class LineFeedType : VTInt { WithReturn, WithoutReturn, DependsOnMode }; - enum class DrcsEraseControl : size_t + enum class DrcsEraseControl : VTInt { AllChars = 0, ReloadedChars = 1, AllRenditions = 2 }; - enum class DrcsCellMatrix : size_t + enum class DrcsCellMatrix : VTInt { Default = 0, Invalid = 1, @@ -450,7 +448,7 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes Size7x10 = 4 }; - enum class DrcsFontSet : size_t + enum class DrcsFontSet : VTInt { Default = 0, Size80x24 = 1, @@ -461,20 +459,20 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes Size132x48 = 22 }; - enum class DrcsFontUsage : size_t + enum class DrcsFontUsage : VTInt { Default = 0, Text = 1, FullCell = 2 }; - enum class DrcsCharsetSize : size_t + enum class DrcsCharsetSize : VTInt { Size94 = 0, Size96 = 1 }; - constexpr short s_sDECCOLMSetColumns = 132; - constexpr short s_sDECCOLMResetColumns = 80; + constexpr VTInt s_sDECCOLMSetColumns = 132; + constexpr VTInt s_sDECCOLMResetColumns = 80; } diff --git a/src/terminal/adapter/FontBuffer.cpp b/src/terminal/adapter/FontBuffer.cpp index 5e6ffb963ef..8f5e8fe584c 100644 --- a/src/terminal/adapter/FontBuffer.cpp +++ b/src/terminal/adapter/FontBuffer.cpp @@ -497,7 +497,7 @@ void FontBuffer::_packAndCenterBitPatterns() // cell height, but now that we know the true height, we need to pack the // buffer data so that each character occupies the exact number of scanlines // that are required. - for (auto srcLine = 0u, dstLine = 0u; srcLine < _buffer.size(); srcLine++) + for (size_t srcLine = 0, dstLine = 0; srcLine < _buffer.size(); srcLine++) { if ((srcLine % MAX_HEIGHT) < _fullHeight) { @@ -515,7 +515,7 @@ void FontBuffer::_fillUnusedCharacters() // with an error glyph (a reverse question mark). This includes every // character prior to the start char, or after the last char. const auto errorPattern = _generateErrorGlyph(); - for (auto ch = 0u; ch < MAX_CHARS; ch++) + for (size_t ch = 0; ch < MAX_CHARS; ch++) { if (ch < _startChar || ch > _lastChar) { diff --git a/src/terminal/adapter/FontBuffer.hpp b/src/terminal/adapter/FontBuffer.hpp index 08115f1b552..275dab0ad04 100644 --- a/src/terminal/adapter/FontBuffer.hpp +++ b/src/terminal/adapter/FontBuffer.hpp @@ -54,8 +54,8 @@ namespace Microsoft::Console::VirtualTerminal DispatchTypes::DrcsCellMatrix _cellMatrix; DispatchTypes::DrcsCellMatrix _pendingCellMatrix; - size_t _cellHeight; - size_t _pendingCellHeight; + VTInt _cellHeight; + VTInt _pendingCellHeight; bool _sizeDeclaredAsMatrix; size_t _declaredWidth; size_t _declaredHeight; diff --git a/src/terminal/adapter/IInteractDispatch.hpp b/src/terminal/adapter/IInteractDispatch.hpp index 97b22b3edde..33b9659c849 100644 --- a/src/terminal/adapter/IInteractDispatch.hpp +++ b/src/terminal/adapter/IInteractDispatch.hpp @@ -38,8 +38,8 @@ namespace Microsoft::Console::VirtualTerminal const VTParameter parameter1, const VTParameter parameter2) = 0; - virtual bool MoveCursor(const size_t row, - const size_t col) = 0; + virtual bool MoveCursor(const VTInt row, + const VTInt col) = 0; virtual bool IsVtInputEnabled() const = 0; diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index f0f48fa2d2f..a097bb9d686 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -32,27 +32,27 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual void Print(const wchar_t wchPrintable) = 0; virtual void PrintString(const std::wstring_view string) = 0; - virtual bool CursorUp(const size_t distance) = 0; // CUU - virtual bool CursorDown(const size_t distance) = 0; // CUD - virtual bool CursorForward(const size_t distance) = 0; // CUF - virtual bool CursorBackward(const size_t distance) = 0; // CUB, BS - virtual bool CursorNextLine(const size_t distance) = 0; // CNL - virtual bool CursorPrevLine(const size_t distance) = 0; // CPL - virtual bool CursorHorizontalPositionAbsolute(const size_t column) = 0; // HPA, CHA - virtual bool VerticalLinePositionAbsolute(const size_t line) = 0; // VPA - virtual bool HorizontalPositionRelative(const size_t distance) = 0; // HPR - virtual bool VerticalPositionRelative(const size_t distance) = 0; // VPR - virtual bool CursorPosition(const size_t line, const size_t column) = 0; // CUP, HVP + virtual bool CursorUp(const VTInt distance) = 0; // CUU + virtual bool CursorDown(const VTInt distance) = 0; // CUD + virtual bool CursorForward(const VTInt distance) = 0; // CUF + virtual bool CursorBackward(const VTInt distance) = 0; // CUB, BS + virtual bool CursorNextLine(const VTInt distance) = 0; // CNL + virtual bool CursorPrevLine(const VTInt distance) = 0; // CPL + virtual bool CursorHorizontalPositionAbsolute(const VTInt column) = 0; // HPA, CHA + virtual bool VerticalLinePositionAbsolute(const VTInt line) = 0; // VPA + virtual bool HorizontalPositionRelative(const VTInt distance) = 0; // HPR + virtual bool VerticalPositionRelative(const VTInt distance) = 0; // VPR + virtual bool CursorPosition(const VTInt line, const VTInt column) = 0; // CUP, HVP virtual bool CursorSaveState() = 0; // DECSC virtual bool CursorRestoreState() = 0; // DECRC virtual bool CursorVisibility(const bool isVisible) = 0; // DECTCEM - virtual bool InsertCharacter(const size_t count) = 0; // ICH - virtual bool DeleteCharacter(const size_t count) = 0; // DCH - virtual bool ScrollUp(const size_t distance) = 0; // SU - virtual bool ScrollDown(const size_t distance) = 0; // SD - virtual bool InsertLine(const size_t distance) = 0; // IL - virtual bool DeleteLine(const size_t distance) = 0; // DL - virtual bool SetColumns(const size_t columns) = 0; // DECCOLM + virtual bool InsertCharacter(const VTInt count) = 0; // ICH + virtual bool DeleteCharacter(const VTInt count) = 0; // DCH + virtual bool ScrollUp(const VTInt distance) = 0; // SU + virtual bool ScrollDown(const VTInt distance) = 0; // SD + virtual bool InsertLine(const VTInt distance) = 0; // IL + virtual bool DeleteLine(const VTInt distance) = 0; // DL + virtual bool SetColumns(const VTInt columns) = 0; // DECCOLM virtual bool SetCursorKeysMode(const bool applicationMode) = 0; // DECCKM virtual bool SetKeypadMode(const bool applicationMode) = 0; // DECKPAM, DECKPNM virtual bool EnableWin32InputMode(const bool win32InputMode) = 0; // win32-input-mode @@ -61,7 +61,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool SetScreenMode(const bool reverseMode) = 0; // DECSCNM virtual bool SetOriginMode(const bool relativeMode) = 0; // DECOM virtual bool SetAutoWrapMode(const bool wrapAtEOL) = 0; // DECAWM - virtual bool SetTopBottomScrollingMargins(const size_t topMargin, const size_t bottomMargin) = 0; // DECSTBM + virtual bool SetTopBottomScrollingMargins(const VTInt topMargin, const VTInt bottomMargin) = 0; // DECSTBM virtual bool WarningBell() = 0; // BEL virtual bool CarriageReturn() = 0; // CR virtual bool LineFeed(const DispatchTypes::LineFeedType lineFeedType) = 0; // IND, NEL, LF, FF, VT @@ -70,8 +70,8 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool UseAlternateScreenBuffer() = 0; // ASBSET virtual bool UseMainScreenBuffer() = 0; // ASBRST virtual bool HorizontalTabSet() = 0; // HTS - virtual bool ForwardTab(const size_t numTabs) = 0; // CHT, HT - virtual bool BackwardsTab(const size_t numTabs) = 0; // CBT + virtual bool ForwardTab(const VTInt numTabs) = 0; // CHT, HT + virtual bool BackwardsTab(const VTInt numTabs) = 0; // CBT virtual bool TabClear(const DispatchTypes::TabClearType clearType) = 0; // TBC virtual bool EnableDECCOLMSupport(const bool enabled) = 0; // ?40 virtual bool EnableVT200MouseMode(const bool enabled) = 0; // ?1000 @@ -87,7 +87,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool EraseInDisplay(const DispatchTypes::EraseType eraseType) = 0; // ED virtual bool EraseInLine(const DispatchTypes::EraseType eraseType) = 0; // EL - virtual bool EraseCharacters(const size_t numChars) = 0; // ECH + virtual bool EraseCharacters(const VTInt numChars) = 0; // ECH virtual bool SetGraphicsRendition(const VTParameters options) = 0; // SGR virtual bool SetLineRendition(const LineRendition rendition) = 0; // DECSWL, DECDWL, DECDHL @@ -107,11 +107,11 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool RequestTerminalParameters(const DispatchTypes::ReportingPermission permission) = 0; // DECREQTPARM virtual bool DesignateCodingSystem(const VTID codingSystem) = 0; // DOCS - virtual bool Designate94Charset(const size_t gsetNumber, const VTID charset) = 0; // SCS - virtual bool Designate96Charset(const size_t gsetNumber, const VTID charset) = 0; // SCS - virtual bool LockingShift(const size_t gsetNumber) = 0; // LS0, LS1, LS2, LS3 - virtual bool LockingShiftRight(const size_t gsetNumber) = 0; // LS1R, LS2R, LS3R - virtual bool SingleShift(const size_t gsetNumber) = 0; // SS2, SS3 + virtual bool Designate94Charset(const VTInt gsetNumber, const VTID charset) = 0; // SCS + virtual bool Designate96Charset(const VTInt gsetNumber, const VTID charset) = 0; // SCS + virtual bool LockingShift(const VTInt gsetNumber) = 0; // LS0, LS1, LS2, LS3 + virtual bool LockingShiftRight(const VTInt gsetNumber) = 0; // LS1R, LS2R, LS3R + virtual bool SingleShift(const VTInt gsetNumber) = 0; // SS2, SS3 virtual bool AcceptC1Controls(const bool enabled) = 0; // DECAC1 virtual bool SoftReset() = 0; // DECSTR @@ -133,7 +133,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool DoConEmuAction(const std::wstring_view string) = 0; - virtual StringHandler DownloadDRCS(const size_t fontNumber, + virtual StringHandler DownloadDRCS(const VTInt fontNumber, const VTParameter startChar, const DispatchTypes::DrcsEraseControl eraseControl, const DispatchTypes::DrcsCellMatrix cellMatrix, diff --git a/src/terminal/adapter/InteractDispatch.cpp b/src/terminal/adapter/InteractDispatch.cpp index 5294b74292f..ace72b0711a 100644 --- a/src/terminal/adapter/InteractDispatch.cpp +++ b/src/terminal/adapter/InteractDispatch.cpp @@ -134,39 +134,26 @@ bool InteractDispatch::WindowManipulation(const DispatchTypes::WindowManipulatio // - col: The column to move the cursor to. // Return value: // - True. -bool InteractDispatch::MoveCursor(const size_t row, const size_t col) +bool InteractDispatch::MoveCursor(const VTInt row, const VTInt col) { - // The parser should never return 0 (0 maps to 1), so this is a failure condition. - THROW_HR_IF(E_INVALIDARG, row == 0); - THROW_HR_IF(E_INVALIDARG, col == 0); - - // In VT, the origin is 1,1. For our array, it's 0,0. So subtract 1. - const size_t rowFixed = row - 1; - const size_t colFixed = col - 1; - // First retrieve some information about the buffer - const auto viewport = _pConApi->GetViewport().to_small_rect(); - auto& cursor = _pConApi->GetTextBuffer().GetCursor(); - auto coordCursor = cursor.GetPosition(); - - // Safely convert the size_t positions we were given into shorts (which is the size the console deals with) - THROW_IF_FAILED(SizeTToShort(rowFixed, &coordCursor.Y)); - THROW_IF_FAILED(SizeTToShort(colFixed, &coordCursor.X)); - - // Set the line and column values as offsets from the viewport edge. Use safe math to prevent overflow. - THROW_IF_FAILED(ShortAdd(coordCursor.Y, viewport.Top, &coordCursor.Y)); - THROW_IF_FAILED(ShortAdd(coordCursor.X, viewport.Left, &coordCursor.X)); + const auto viewport = _pConApi->GetViewport(); + // In VT, the origin is 1,1. For our array, it's 0,0. So subtract 1. // Apply boundary tests to ensure the cursor isn't outside the viewport rectangle. + til::point coordCursor{ col - 1 + viewport.Left, row - 1 + viewport.Top }; coordCursor.Y = std::clamp(coordCursor.Y, viewport.Top, viewport.Bottom); coordCursor.X = std::clamp(coordCursor.X, viewport.Left, viewport.Right); + const auto coordCursorShort = til::unwrap_coord(coordCursor); + // MSFT: 15813316 - Try to use this MoveCursor call to inherit the cursor position. auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - RETURN_IF_FAILED(gci.GetVtIo()->SetCursorPosition(coordCursor)); + RETURN_IF_FAILED(gci.GetVtIo()->SetCursorPosition(coordCursorShort)); // Finally, attempt to set the adjusted cursor position back into the console. - cursor.SetPosition(coordCursor); + auto& cursor = _pConApi->GetTextBuffer().GetCursor(); + cursor.SetPosition(coordCursorShort); cursor.SetHasMoved(true); return true; } diff --git a/src/terminal/adapter/InteractDispatch.hpp b/src/terminal/adapter/InteractDispatch.hpp index e521244eb2e..704e51dd1c9 100644 --- a/src/terminal/adapter/InteractDispatch.hpp +++ b/src/terminal/adapter/InteractDispatch.hpp @@ -31,7 +31,7 @@ namespace Microsoft::Console::VirtualTerminal bool WindowManipulation(const DispatchTypes::WindowManipulationType function, const VTParameter parameter1, const VTParameter parameter2) override; // DTTERM_WindowManipulation - bool MoveCursor(const size_t row, const size_t col) override; + bool MoveCursor(const VTInt row, const VTInt col) override; bool IsVtInputEnabled() const override; diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 53b54f3b5ee..2e1bf050224 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -96,7 +96,7 @@ void AdaptDispatch::PrintString(const std::wstring_view string) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::CursorUp(const size_t distance) +bool AdaptDispatch::CursorUp(const VTInt distance) { return _CursorMovePosition(Offset::Backward(distance), Offset::Unchanged(), true); } @@ -112,7 +112,7 @@ bool AdaptDispatch::CursorUp(const size_t distance) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::CursorDown(const size_t distance) +bool AdaptDispatch::CursorDown(const VTInt distance) { return _CursorMovePosition(Offset::Forward(distance), Offset::Unchanged(), true); } @@ -123,7 +123,7 @@ bool AdaptDispatch::CursorDown(const size_t distance) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::CursorForward(const size_t distance) +bool AdaptDispatch::CursorForward(const VTInt distance) { return _CursorMovePosition(Offset::Unchanged(), Offset::Forward(distance), true); } @@ -134,7 +134,7 @@ bool AdaptDispatch::CursorForward(const size_t distance) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::CursorBackward(const size_t distance) +bool AdaptDispatch::CursorBackward(const VTInt distance) { return _CursorMovePosition(Offset::Unchanged(), Offset::Backward(distance), true); } @@ -146,7 +146,7 @@ bool AdaptDispatch::CursorBackward(const size_t distance) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::CursorNextLine(const size_t distance) +bool AdaptDispatch::CursorNextLine(const VTInt distance) { return _CursorMovePosition(Offset::Forward(distance), Offset::Absolute(1), true); } @@ -158,7 +158,7 @@ bool AdaptDispatch::CursorNextLine(const size_t distance) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::CursorPrevLine(const size_t distance) +bool AdaptDispatch::CursorPrevLine(const VTInt distance) { return _CursorMovePosition(Offset::Backward(distance), Offset::Absolute(1), true); } @@ -289,7 +289,7 @@ void AdaptDispatch::_ApplyCursorMovementFlags(Cursor& cursor) noexcept // - column - Specific X/Column position to move to // Return Value: // - True. -bool AdaptDispatch::CursorHorizontalPositionAbsolute(const size_t column) +bool AdaptDispatch::CursorHorizontalPositionAbsolute(const VTInt column) { return _CursorMovePosition(Offset::Unchanged(), Offset::Absolute(column), false); } @@ -300,7 +300,7 @@ bool AdaptDispatch::CursorHorizontalPositionAbsolute(const size_t column) // - line - Specific Y/Row position to move to // Return Value: // - True. -bool AdaptDispatch::VerticalLinePositionAbsolute(const size_t line) +bool AdaptDispatch::VerticalLinePositionAbsolute(const VTInt line) { return _CursorMovePosition(Offset::Absolute(line), Offset::Unchanged(), false); } @@ -312,7 +312,7 @@ bool AdaptDispatch::VerticalLinePositionAbsolute(const size_t line) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::HorizontalPositionRelative(const size_t distance) +bool AdaptDispatch::HorizontalPositionRelative(const VTInt distance) { return _CursorMovePosition(Offset::Unchanged(), Offset::Forward(distance), false); } @@ -324,7 +324,7 @@ bool AdaptDispatch::HorizontalPositionRelative(const size_t distance) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::VerticalPositionRelative(const size_t distance) +bool AdaptDispatch::VerticalPositionRelative(const VTInt distance) { return _CursorMovePosition(Offset::Forward(distance), Offset::Unchanged(), false); } @@ -336,7 +336,7 @@ bool AdaptDispatch::VerticalPositionRelative(const size_t distance) // - column - Specific X/Column position to move to // Return Value: // - True. -bool AdaptDispatch::CursorPosition(const size_t line, const size_t column) +bool AdaptDispatch::CursorPosition(const VTInt line, const VTInt column) { return _CursorMovePosition(Offset::Absolute(line), Offset::Absolute(column), false); } @@ -396,7 +396,7 @@ bool AdaptDispatch::CursorRestoreState() const auto viewport = _pConApi->GetViewport(); const auto [topMargin, bottomMargin] = _GetVerticalMargins(viewport, false); // VT origin is at 1,1 so we need to add 1 to these margins. - row = std::clamp(row, topMargin + 1u, bottomMargin + 1u); + row = std::clamp(row, topMargin + 1, bottomMargin + 1); } // The saved coordinates are always absolute, so we need reset the origin mode temporarily. @@ -519,7 +519,7 @@ void AdaptDispatch::_ScrollRectHorizontally(TextBuffer& textBuffer, const til::r // - delta - Number of characters to modify (positive if inserting, negative if deleting). // Return Value: // - -void AdaptDispatch::_InsertDeleteCharacterHelper(const int32_t delta) +void AdaptDispatch::_InsertDeleteCharacterHelper(const VTInt delta) { auto& textBuffer = _pConApi->GetTextBuffer(); const auto row = textBuffer.GetCursor().GetPosition().Y; @@ -535,9 +535,9 @@ void AdaptDispatch::_InsertDeleteCharacterHelper(const int32_t delta) // - count - The number of characters to insert // Return Value: // - True. -bool AdaptDispatch::InsertCharacter(const size_t count) +bool AdaptDispatch::InsertCharacter(const VTInt count) { - _InsertDeleteCharacterHelper(gsl::narrow_cast(count)); + _InsertDeleteCharacterHelper(count); return true; } @@ -548,9 +548,9 @@ bool AdaptDispatch::InsertCharacter(const size_t count) // - count - The number of characters to delete // Return Value: // - True. -bool AdaptDispatch::DeleteCharacter(const size_t count) +bool AdaptDispatch::DeleteCharacter(const VTInt count) { - _InsertDeleteCharacterHelper(-gsl::narrow_cast(count)); + _InsertDeleteCharacterHelper(-count); return true; } @@ -587,16 +587,16 @@ void AdaptDispatch::_FillRect(TextBuffer& textBuffer, const til::rect& fillRect, // - numChars - The number of characters to erase. // Return Value: // - True. -bool AdaptDispatch::EraseCharacters(const size_t numChars) +bool AdaptDispatch::EraseCharacters(const VTInt numChars) { auto& textBuffer = _pConApi->GetTextBuffer(); const auto row = textBuffer.GetCursor().GetPosition().Y; const auto startCol = textBuffer.GetCursor().GetPosition().X; - const auto endCol = std::min(startCol + numChars, textBuffer.GetLineWidth(row)); + const auto endCol = std::min(startCol + numChars, textBuffer.GetLineWidth(row)); auto eraseAttributes = textBuffer.GetCurrentAttributes(); eraseAttributes.SetStandardErase(); - _FillRect(textBuffer, { startCol, row, gsl::narrow_cast(endCol), row + 1 }, L' ', eraseAttributes); + _FillRect(textBuffer, { startCol, row, endCol, row + 1 }, L' ', eraseAttributes); return true; } @@ -853,10 +853,10 @@ void AdaptDispatch::_CursorPositionReport() const auto& textBuffer = _pConApi->GetTextBuffer(); // First pull the cursor position relative to the entire buffer out of the console. - auto cursorPosition = textBuffer.GetCursor().GetPosition(); + til::point cursorPosition{ textBuffer.GetCursor().GetPosition() }; // Now adjust it for its position in respect to the current viewport top. - cursorPosition.Y -= gsl::narrow_cast(viewport.top); + cursorPosition.Y -= viewport.top; // NOTE: 1,1 is the top-left corner of the viewport in VT-speak, so add 1. cursorPosition.X++; @@ -866,7 +866,7 @@ void AdaptDispatch::_CursorPositionReport() if (_isOriginModeRelative) { const auto topMargin = _GetVerticalMargins(viewport, false).first; - cursorPosition.Y -= gsl::narrow_cast(topMargin); + cursorPosition.Y -= topMargin; } // Now send it back into the input channel of the console. @@ -913,7 +913,7 @@ void AdaptDispatch::_WriteResponse(const std::wstring_view reply) const // - delta - Distance to move (positive is down, negative is up) // Return Value: // - -void AdaptDispatch::_ScrollMovement(const int32_t delta) +void AdaptDispatch::_ScrollMovement(const VTInt delta) { const auto viewport = _pConApi->GetViewport(); auto& textBuffer = _pConApi->GetTextBuffer(); @@ -928,7 +928,7 @@ void AdaptDispatch::_ScrollMovement(const int32_t delta) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::ScrollUp(const size_t uiDistance) +bool AdaptDispatch::ScrollUp(const VTInt uiDistance) { _ScrollMovement(-gsl::narrow_cast(uiDistance)); return true; @@ -940,7 +940,7 @@ bool AdaptDispatch::ScrollUp(const size_t uiDistance) // - distance - Distance to move // Return Value: // - True. -bool AdaptDispatch::ScrollDown(const size_t uiDistance) +bool AdaptDispatch::ScrollDown(const VTInt uiDistance) { _ScrollMovement(gsl::narrow_cast(uiDistance)); return true; @@ -954,7 +954,7 @@ bool AdaptDispatch::ScrollDown(const size_t uiDistance) // - columns - Number of columns // Return Value: // - True. -bool AdaptDispatch::SetColumns(const size_t columns) +bool AdaptDispatch::SetColumns(const VTInt columns) { const auto viewport = _pConApi->GetViewport(); const auto viewportHeight = viewport.bottom - viewport.top; @@ -969,7 +969,7 @@ bool AdaptDispatch::SetColumns(const size_t columns) // - columns - Number of columns // Return Value: // - True. -bool AdaptDispatch::_DoDECCOLMHelper(const size_t columns) +bool AdaptDispatch::_DoDECCOLMHelper(const VTInt columns) { // Only proceed if DECCOLM is allowed. Return true, as this is technically a successful handling. if (_isDECCOLMAllowed) @@ -1213,7 +1213,7 @@ void AdaptDispatch::_InsertDeleteLineHelper(const int32_t delta) // - distance - number of lines to insert // Return Value: // - True. -bool AdaptDispatch::InsertLine(const size_t distance) +bool AdaptDispatch::InsertLine(const VTInt distance) { _InsertDeleteLineHelper(gsl::narrow_cast(distance)); return true; @@ -1231,7 +1231,7 @@ bool AdaptDispatch::InsertLine(const size_t distance) // - distance - number of lines to delete // Return Value: // - True. -bool AdaptDispatch::DeleteLine(const size_t distance) +bool AdaptDispatch::DeleteLine(const VTInt distance) { _InsertDeleteLineHelper(-gsl::narrow_cast(distance)); return true; @@ -1313,8 +1313,8 @@ bool AdaptDispatch::SetAutoWrapMode(const bool wrapAtEOL) // - bottomMargin - the line number for the bottom margin. // Return Value: // - -void AdaptDispatch::_DoSetTopBottomScrollingMargins(const size_t topMargin, - const size_t bottomMargin) +void AdaptDispatch::_DoSetTopBottomScrollingMargins(const VTInt topMargin, + const VTInt bottomMargin) { // so notes time: (input -> state machine out -> adapter out -> conhost internal) // having only a top param is legal ([3;r -> 3,0 -> 3,h -> 3,h,true) @@ -1373,8 +1373,8 @@ void AdaptDispatch::_DoSetTopBottomScrollingMargins(const size_t topMargin, // - bottomMargin - the line number for the bottom margin. // Return Value: // - True. -bool AdaptDispatch::SetTopBottomScrollingMargins(const size_t topMargin, - const size_t bottomMargin) +bool AdaptDispatch::SetTopBottomScrollingMargins(const VTInt topMargin, + const VTInt bottomMargin) { // When this is called, the cursor should also be moved to home. // Other functions that only need to set/reset the margins should call _DoSetTopBottomScrollingMargins @@ -1534,13 +1534,13 @@ bool AdaptDispatch::HorizontalTabSet() // - numTabs - the number of tabs to perform // Return value: // - True. -bool AdaptDispatch::ForwardTab(const size_t numTabs) +bool AdaptDispatch::ForwardTab(const VTInt numTabs) { auto& textBuffer = _pConApi->GetTextBuffer(); auto& cursor = textBuffer.GetCursor(); const auto width = textBuffer.GetLineWidth(cursor.GetPosition().Y); auto column = cursor.GetPosition().X; - auto tabsPerformed = 0u; + auto tabsPerformed = 0; _InitTabStopsForWidth(width); while (column + 1 < width && tabsPerformed < numTabs) @@ -1564,13 +1564,13 @@ bool AdaptDispatch::ForwardTab(const size_t numTabs) // - numTabs - the number of tabs to perform // Return value: // - True. -bool AdaptDispatch::BackwardsTab(const size_t numTabs) +bool AdaptDispatch::BackwardsTab(const VTInt numTabs) { auto& textBuffer = _pConApi->GetTextBuffer(); auto& cursor = textBuffer.GetCursor(); const auto width = textBuffer.GetLineWidth(cursor.GetPosition().Y); auto column = cursor.GetPosition().X; - auto tabsPerformed = 0u; + auto tabsPerformed = 0; _InitTabStopsForWidth(width); while (column > 0 && tabsPerformed < numTabs) @@ -1660,12 +1660,13 @@ void AdaptDispatch::_ResetTabStops() noexcept // - width - the width of the screen buffer that we need to accommodate // Return value: // - -void AdaptDispatch::_InitTabStopsForWidth(const size_t width) +void AdaptDispatch::_InitTabStopsForWidth(const VTInt width) { + const auto screenWidth = gsl::narrow(width); const auto initialWidth = _tabStopColumns.size(); - if (width > initialWidth) + if (screenWidth > initialWidth) { - _tabStopColumns.resize(width); + _tabStopColumns.resize(screenWidth); if (_initDefaultTabStops) { for (auto column = 8u; column < _tabStopColumns.size(); column += 8) @@ -1725,7 +1726,7 @@ bool AdaptDispatch::DesignateCodingSystem(const VTID codingSystem) // - charset - The identifier indicating the charset that will be used. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const VTID charset) +bool AdaptDispatch::Designate94Charset(const VTInt gsetNumber, const VTID charset) { return _termOutput.Designate94Charset(gsetNumber, charset); } @@ -1740,7 +1741,7 @@ bool AdaptDispatch::Designate94Charset(const size_t gsetNumber, const VTID chars // - charset - The identifier indicating the charset that will be used. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::Designate96Charset(const size_t gsetNumber, const VTID charset) +bool AdaptDispatch::Designate96Charset(const VTInt gsetNumber, const VTID charset) { return _termOutput.Designate96Charset(gsetNumber, charset); } @@ -1751,7 +1752,7 @@ bool AdaptDispatch::Designate96Charset(const size_t gsetNumber, const VTID chars // - gsetNumber - The G-set that will be invoked. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::LockingShift(const size_t gsetNumber) +bool AdaptDispatch::LockingShift(const VTInt gsetNumber) { return _termOutput.LockingShift(gsetNumber); } @@ -1762,7 +1763,7 @@ bool AdaptDispatch::LockingShift(const size_t gsetNumber) // - gsetNumber - The G-set that will be invoked. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::LockingShiftRight(const size_t gsetNumber) +bool AdaptDispatch::LockingShiftRight(const VTInt gsetNumber) { return _termOutput.LockingShiftRight(gsetNumber); } @@ -1773,7 +1774,7 @@ bool AdaptDispatch::LockingShiftRight(const size_t gsetNumber) // - gsetNumber - The G-set that will be invoked. // Return value: // True if handled successfully. False otherwise. -bool AdaptDispatch::SingleShift(const size_t gsetNumber) +bool AdaptDispatch::SingleShift(const VTInt gsetNumber) { return _termOutput.SingleShift(gsetNumber); } @@ -2344,7 +2345,7 @@ bool AdaptDispatch::DoConEmuAction(const std::wstring_view /*string*/) noexcept // - charsetSize - Whether the character set is 94 or 96 characters. // Return Value: // - a function to receive the pixel data or nullptr if parameters are invalid -ITermDispatch::StringHandler AdaptDispatch::DownloadDRCS(const size_t fontNumber, +ITermDispatch::StringHandler AdaptDispatch::DownloadDRCS(const VTInt fontNumber, const VTParameter startChar, const DispatchTypes::DrcsEraseControl eraseControl, const DispatchTypes::DrcsCellMatrix cellMatrix, diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index 89bc2eb3647..becb3180247 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -34,25 +34,25 @@ namespace Microsoft::Console::VirtualTerminal void Print(const wchar_t wchPrintable) override; void PrintString(const std::wstring_view string) override; - bool CursorUp(const size_t distance) override; // CUU - bool CursorDown(const size_t distance) override; // CUD - bool CursorForward(const size_t distance) override; // CUF - bool CursorBackward(const size_t distance) override; // CUB, BS - bool CursorNextLine(const size_t distance) override; // CNL - bool CursorPrevLine(const size_t distance) override; // CPL - bool CursorHorizontalPositionAbsolute(const size_t column) override; // HPA, CHA - bool VerticalLinePositionAbsolute(const size_t line) override; // VPA - bool HorizontalPositionRelative(const size_t distance) override; // HPR - bool VerticalPositionRelative(const size_t distance) override; // VPR - bool CursorPosition(const size_t line, const size_t column) override; // CUP, HVP + bool CursorUp(const VTInt distance) override; // CUU + bool CursorDown(const VTInt distance) override; // CUD + bool CursorForward(const VTInt distance) override; // CUF + bool CursorBackward(const VTInt distance) override; // CUB, BS + bool CursorNextLine(const VTInt distance) override; // CNL + bool CursorPrevLine(const VTInt distance) override; // CPL + bool CursorHorizontalPositionAbsolute(const VTInt column) override; // HPA, CHA + bool VerticalLinePositionAbsolute(const VTInt line) override; // VPA + bool HorizontalPositionRelative(const VTInt distance) override; // HPR + bool VerticalPositionRelative(const VTInt distance) override; // VPR + bool CursorPosition(const VTInt line, const VTInt column) override; // CUP, HVP bool CursorSaveState() override; // DECSC bool CursorRestoreState() override; // DECRC bool CursorVisibility(const bool isVisible) override; // DECTCEM bool EraseInDisplay(const DispatchTypes::EraseType eraseType) override; // ED bool EraseInLine(const DispatchTypes::EraseType eraseType) override; // EL - bool EraseCharacters(const size_t numChars) override; // ECH - bool InsertCharacter(const size_t count) override; // ICH - bool DeleteCharacter(const size_t count) override; // DCH + bool EraseCharacters(const VTInt numChars) override; // ECH + bool InsertCharacter(const VTInt count) override; // ICH + bool DeleteCharacter(const VTInt count) override; // DCH bool SetGraphicsRendition(const VTParameters options) override; // SGR bool SetLineRendition(const LineRendition rendition) override; // DECSWL, DECDWL, DECDHL bool PushGraphicsRendition(const VTParameters options) override; // XTPUSHSGR @@ -63,11 +63,11 @@ namespace Microsoft::Console::VirtualTerminal bool TertiaryDeviceAttributes() override; // DA3 bool Vt52DeviceAttributes() override; // VT52 Identify bool RequestTerminalParameters(const DispatchTypes::ReportingPermission permission) override; // DECREQTPARM - bool ScrollUp(const size_t distance) override; // SU - bool ScrollDown(const size_t distance) override; // SD - bool InsertLine(const size_t distance) override; // IL - bool DeleteLine(const size_t distance) override; // DL - bool SetColumns(const size_t columns) override; // DECCOLM + bool ScrollUp(const VTInt distance) override; // SU + bool ScrollDown(const VTInt distance) override; // SD + bool InsertLine(const VTInt distance) override; // IL + bool DeleteLine(const VTInt distance) override; // DL + bool SetColumns(const VTInt columns) override; // DECCOLM bool SetMode(const DispatchTypes::ModeParams param) override; // DECSET bool ResetMode(const DispatchTypes::ModeParams param) override; // DECRST bool SetCursorKeysMode(const bool applicationMode) override; // DECCKM @@ -78,8 +78,8 @@ namespace Microsoft::Console::VirtualTerminal bool SetScreenMode(const bool reverseMode) override; // DECSCNM bool SetOriginMode(const bool relativeMode) noexcept override; // DECOM bool SetAutoWrapMode(const bool wrapAtEOL) override; // DECAWM - bool SetTopBottomScrollingMargins(const size_t topMargin, - const size_t bottomMargin) override; // DECSTBM + bool SetTopBottomScrollingMargins(const VTInt topMargin, + const VTInt bottomMargin) override; // DECSTBM bool WarningBell() override; // BEL bool CarriageReturn() override; // CR bool LineFeed(const DispatchTypes::LineFeedType lineFeedType) override; // IND, NEL, LF, FF, VT @@ -88,15 +88,15 @@ namespace Microsoft::Console::VirtualTerminal bool UseAlternateScreenBuffer() override; // ASBSET bool UseMainScreenBuffer() override; // ASBRST bool HorizontalTabSet() override; // HTS - bool ForwardTab(const size_t numTabs) override; // CHT, HT - bool BackwardsTab(const size_t numTabs) override; // CBT + bool ForwardTab(const VTInt numTabs) override; // CHT, HT + bool BackwardsTab(const VTInt numTabs) override; // CBT bool TabClear(const DispatchTypes::TabClearType clearType) override; // TBC bool DesignateCodingSystem(const VTID codingSystem) override; // DOCS - bool Designate94Charset(const size_t gsetNumber, const VTID charset) override; // SCS - bool Designate96Charset(const size_t gsetNumber, const VTID charset) override; // SCS - bool LockingShift(const size_t gsetNumber) override; // LS0, LS1, LS2, LS3 - bool LockingShiftRight(const size_t gsetNumber) override; // LS1R, LS2R, LS3R - bool SingleShift(const size_t gsetNumber) override; // SS2, SS3 + bool Designate94Charset(const VTInt gsetNumber, const VTID charset) override; // SCS + bool Designate96Charset(const VTInt gsetNumber, const VTID charset) override; // SCS + bool LockingShift(const VTInt gsetNumber) override; // LS0, LS1, LS2, LS3 + bool LockingShiftRight(const VTInt gsetNumber) override; // LS1R, LS2R, LS3R + bool SingleShift(const VTInt gsetNumber) override; // SS2, SS3 bool AcceptC1Controls(const bool enabled) override; // DECAC1 bool SoftReset() override; // DECSTR bool HardReset() override; // RIS @@ -128,7 +128,7 @@ namespace Microsoft::Console::VirtualTerminal bool DoConEmuAction(const std::wstring_view string) noexcept override; - StringHandler DownloadDRCS(const size_t fontNumber, + StringHandler DownloadDRCS(const VTInt fontNumber, const VTParameter startChar, const DispatchTypes::DrcsEraseControl eraseControl, const DispatchTypes::DrcsCellMatrix cellMatrix, @@ -147,8 +147,8 @@ namespace Microsoft::Console::VirtualTerminal }; struct CursorState { - unsigned int Row = 1; - unsigned int Column = 1; + VTInt Row = 1; + VTInt Column = 1; bool IsOriginModeRelative = false; TextAttribute Attributes = {}; TerminalOutput TermOutput = {}; @@ -157,12 +157,12 @@ namespace Microsoft::Console::VirtualTerminal }; struct Offset { - int Value; + VTInt Value; bool IsAbsolute; // VT origin is at 1,1 so we need to subtract 1 from absolute positions. - static constexpr Offset Absolute(const size_t value) { return { gsl::narrow_cast(value) - 1, true }; }; - static constexpr Offset Forward(const size_t value) { return { gsl::narrow_cast(value), false }; }; - static constexpr Offset Backward(const size_t value) { return { -gsl::narrow_cast(value), false }; }; + static constexpr Offset Absolute(const VTInt value) { return { value - 1, true }; }; + static constexpr Offset Forward(const VTInt value) { return { value, false }; }; + static constexpr Offset Backward(const VTInt value) { return { -value, false }; }; static constexpr Offset Unchanged() { return Forward(0); }; }; @@ -172,14 +172,14 @@ namespace Microsoft::Console::VirtualTerminal void _FillRect(TextBuffer& textBuffer, const til::rect& fillRect, const wchar_t fillChar, const TextAttribute fillAttrs); void _EraseScrollback(); void _EraseAll(); - void _ScrollRectVertically(TextBuffer& textBuffer, const til::rect& scrollRect, const int32_t delta); - void _ScrollRectHorizontally(TextBuffer& textBuffer, const til::rect& scrollRect, const int32_t delta); - void _InsertDeleteCharacterHelper(const int32_t delta); - void _InsertDeleteLineHelper(const int32_t delta); - void _ScrollMovement(const int32_t delta); - - void _DoSetTopBottomScrollingMargins(const size_t topMargin, - const size_t bottomMargin); + void _ScrollRectVertically(TextBuffer& textBuffer, const til::rect& scrollRect, const VTInt delta); + void _ScrollRectHorizontally(TextBuffer& textBuffer, const til::rect& scrollRect, const VTInt delta); + void _InsertDeleteCharacterHelper(const VTInt delta); + void _InsertDeleteLineHelper(const VTInt delta); + void _ScrollMovement(const VTInt delta); + + void _DoSetTopBottomScrollingMargins(const VTInt topMargin, + const VTInt bottomMargin); void _OperatingStatus() const; void _CursorPositionReport(); @@ -188,12 +188,12 @@ namespace Microsoft::Console::VirtualTerminal void _SetParserMode(const StateMachine::Mode mode, const bool enable); bool _SetInputMode(const TerminalInput::Mode mode, const bool enable); bool _ModeParamsHelper(const DispatchTypes::ModeParams param, const bool enable); - bool _DoDECCOLMHelper(const size_t columns); + bool _DoDECCOLMHelper(const VTInt columns); void _ClearSingleTabStop(); void _ClearAllTabStops() noexcept; void _ResetTabStops() noexcept; - void _InitTabStopsForWidth(const size_t width); + void _InitTabStopsForWidth(const VTInt width); void _ReportSGRSetting() const; void _ReportDECSTBMSetting(); @@ -217,7 +217,7 @@ namespace Microsoft::Console::VirtualTerminal std::array _savedCursorState; bool _usingAltBuffer; - SMALL_RECT _scrollMargins; + til::inclusive_rect _scrollMargins; bool _isOriginModeRelative; diff --git a/src/terminal/adapter/conGetSet.hpp b/src/terminal/adapter/conGetSet.hpp index 8c62e932c93..2726dcda5c4 100644 --- a/src/terminal/adapter/conGetSet.hpp +++ b/src/terminal/adapter/conGetSet.hpp @@ -49,7 +49,7 @@ namespace Microsoft::Console::VirtualTerminal virtual void SetAutoWrapMode(const bool wrapAtEOL) = 0; - virtual void SetScrollingRegion(const SMALL_RECT& scrollMargins) = 0; + virtual void SetScrollingRegion(const til::inclusive_rect& scrollMargins) = 0; virtual void WarningBell() = 0; virtual bool GetLineFeedMode() const = 0; virtual void LineFeed(const bool withReturn) = 0; diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index 0d75258ed30..01e9ed20830 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -25,27 +25,27 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons void Print(const wchar_t wchPrintable) override = 0; void PrintString(const std::wstring_view string) override = 0; - bool CursorUp(const size_t /*distance*/) override { return false; } // CUU - bool CursorDown(const size_t /*distance*/) override { return false; } // CUD - bool CursorForward(const size_t /*distance*/) override { return false; } // CUF - bool CursorBackward(const size_t /*distance*/) override { return false; } // CUB, BS - bool CursorNextLine(const size_t /*distance*/) override { return false; } // CNL - bool CursorPrevLine(const size_t /*distance*/) override { return false; } // CPL - bool CursorHorizontalPositionAbsolute(const size_t /*column*/) override { return false; } // HPA, CHA - bool VerticalLinePositionAbsolute(const size_t /*line*/) override { return false; } // VPA - bool HorizontalPositionRelative(const size_t /*distance*/) override { return false; } // HPR - bool VerticalPositionRelative(const size_t /*distance*/) override { return false; } // VPR - bool CursorPosition(const size_t /*line*/, const size_t /*column*/) override { return false; } // CUP, HVP + bool CursorUp(const VTInt /*distance*/) override { return false; } // CUU + bool CursorDown(const VTInt /*distance*/) override { return false; } // CUD + bool CursorForward(const VTInt /*distance*/) override { return false; } // CUF + bool CursorBackward(const VTInt /*distance*/) override { return false; } // CUB, BS + bool CursorNextLine(const VTInt /*distance*/) override { return false; } // CNL + bool CursorPrevLine(const VTInt /*distance*/) override { return false; } // CPL + bool CursorHorizontalPositionAbsolute(const VTInt /*column*/) override { return false; } // HPA, CHA + bool VerticalLinePositionAbsolute(const VTInt /*line*/) override { return false; } // VPA + bool HorizontalPositionRelative(const VTInt /*distance*/) override { return false; } // HPR + bool VerticalPositionRelative(const VTInt /*distance*/) override { return false; } // VPR + bool CursorPosition(const VTInt /*line*/, const VTInt /*column*/) override { return false; } // CUP, HVP bool CursorSaveState() override { return false; } // DECSC bool CursorRestoreState() override { return false; } // DECRC bool CursorVisibility(const bool /*isVisible*/) override { return false; } // DECTCEM - bool InsertCharacter(const size_t /*count*/) override { return false; } // ICH - bool DeleteCharacter(const size_t /*count*/) override { return false; } // DCH - bool ScrollUp(const size_t /*distance*/) override { return false; } // SU - bool ScrollDown(const size_t /*distance*/) override { return false; } // SD - bool InsertLine(const size_t /*distance*/) override { return false; } // IL - bool DeleteLine(const size_t /*distance*/) override { return false; } // DL - bool SetColumns(const size_t /*columns*/) override { return false; } // DECCOLM + bool InsertCharacter(const VTInt /*count*/) override { return false; } // ICH + bool DeleteCharacter(const VTInt /*count*/) override { return false; } // DCH + bool ScrollUp(const VTInt /*distance*/) override { return false; } // SU + bool ScrollDown(const VTInt /*distance*/) override { return false; } // SD + bool InsertLine(const VTInt /*distance*/) override { return false; } // IL + bool DeleteLine(const VTInt /*distance*/) override { return false; } // DL + bool SetColumns(const VTInt /*columns*/) override { return false; } // DECCOLM bool SetCursorKeysMode(const bool /*applicationMode*/) override { return false; } // DECCKM bool SetKeypadMode(const bool /*applicationMode*/) override { return false; } // DECKPAM, DECKPNM bool EnableWin32InputMode(const bool /*win32InputMode*/) override { return false; } // win32-input-mode @@ -54,7 +54,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool SetScreenMode(const bool /*reverseMode*/) override { return false; } // DECSCNM bool SetOriginMode(const bool /*relativeMode*/) override { return false; }; // DECOM bool SetAutoWrapMode(const bool /*wrapAtEOL*/) override { return false; }; // DECAWM - bool SetTopBottomScrollingMargins(const size_t /*topMargin*/, const size_t /*bottomMargin*/) override { return false; } // DECSTBM + bool SetTopBottomScrollingMargins(const VTInt /*topMargin*/, const VTInt /*bottomMargin*/) override { return false; } // DECSTBM bool WarningBell() override { return false; } // BEL bool CarriageReturn() override { return false; } // CR bool LineFeed(const DispatchTypes::LineFeedType /*lineFeedType*/) override { return false; } // IND, NEL, LF, FF, VT @@ -63,8 +63,8 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool UseAlternateScreenBuffer() override { return false; } // ASBSET bool UseMainScreenBuffer() override { return false; } // ASBRST bool HorizontalTabSet() override { return false; } // HTS - bool ForwardTab(const size_t /*numTabs*/) override { return false; } // CHT, HT - bool BackwardsTab(const size_t /*numTabs*/) override { return false; } // CBT + bool ForwardTab(const VTInt /*numTabs*/) override { return false; } // CHT, HT + bool BackwardsTab(const VTInt /*numTabs*/) override { return false; } // CBT bool TabClear(const DispatchTypes::TabClearType /*clearType*/) override { return false; } // TBC bool EnableDECCOLMSupport(const bool /*enabled*/) override { return false; } // ?40 bool EnableVT200MouseMode(const bool /*enabled*/) override { return false; } // ?1000 @@ -80,7 +80,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool EraseInDisplay(const DispatchTypes::EraseType /* eraseType*/) override { return false; } // ED bool EraseInLine(const DispatchTypes::EraseType /* eraseType*/) override { return false; } // EL - bool EraseCharacters(const size_t /*numChars*/) override { return false; } // ECH + bool EraseCharacters(const VTInt /*numChars*/) override { return false; } // ECH bool SetGraphicsRendition(const VTParameters /*options*/) override { return false; } // SGR bool SetLineRendition(const LineRendition /*rendition*/) override { return false; } // DECSWL, DECDWL, DECDHL @@ -100,11 +100,11 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool RequestTerminalParameters(const DispatchTypes::ReportingPermission /*permission*/) override { return false; } // DECREQTPARM bool DesignateCodingSystem(const VTID /*codingSystem*/) override { return false; } // DOCS - bool Designate94Charset(const size_t /*gsetNumber*/, const VTID /*charset*/) override { return false; } // SCS - bool Designate96Charset(const size_t /*gsetNumber*/, const VTID /*charset*/) override { return false; } // SCS - bool LockingShift(const size_t /*gsetNumber*/) override { return false; } // LS0, LS1, LS2, LS3 - bool LockingShiftRight(const size_t /*gsetNumber*/) override { return false; } // LS1R, LS2R, LS3R - bool SingleShift(const size_t /*gsetNumber*/) override { return false; } // SS2, SS3 + bool Designate94Charset(const VTInt /*gsetNumber*/, const VTID /*charset*/) override { return false; } // SCS + bool Designate96Charset(const VTInt /*gsetNumber*/, const VTID /*charset*/) override { return false; } // SCS + bool LockingShift(const VTInt /*gsetNumber*/) override { return false; } // LS0, LS1, LS2, LS3 + bool LockingShiftRight(const VTInt /*gsetNumber*/) override { return false; } // LS1R, LS2R, LS3R + bool SingleShift(const VTInt /*gsetNumber*/) override { return false; } // SS2, SS3 bool AcceptC1Controls(const bool /*enabled*/) override { return false; } // DECAC1 bool SoftReset() override { return false; } // DECSTR @@ -126,7 +126,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool DoConEmuAction(const std::wstring_view /*string*/) override { return false; } - StringHandler DownloadDRCS(const size_t /*fontNumber*/, + StringHandler DownloadDRCS(const VTInt /*fontNumber*/, const VTParameter /*startChar*/, const DispatchTypes::DrcsEraseControl /*eraseControl*/, const DispatchTypes::DrcsCellMatrix /*cellMatrix*/, diff --git a/src/terminal/adapter/ut_adapter/MouseInputTest.cpp b/src/terminal/adapter/ut_adapter/MouseInputTest.cpp index b302928b8c6..37913e7c7cf 100644 --- a/src/terminal/adapter/ut_adapter/MouseInputTest.cpp +++ b/src/terminal/adapter/ut_adapter/MouseInputTest.cpp @@ -29,7 +29,7 @@ static const wchar_t* s_pwszInputExpected; static wchar_t s_pwszExpectedBuffer[BYTE_MAX]; // big enough for anything -static COORD s_rgTestCoords[] = { +static til::point s_rgTestCoords[] = { { 0, 0 }, { 0, 1 }, { 1, 1 }, @@ -302,7 +302,7 @@ class MouseInputTest for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -321,7 +321,7 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -340,7 +340,7 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -383,12 +383,12 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, true); - short MaxCoord = SHORT_MAX - 33; + auto MaxCoord = SHORT_MAX - 33; mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -407,7 +407,7 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -426,7 +426,7 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -476,7 +476,7 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::DefaultMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta); @@ -490,7 +490,7 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::ButtonEventMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta); @@ -509,7 +509,7 @@ class MouseInputTest mouseInput->SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, true); for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta); @@ -554,7 +554,7 @@ class MouseInputTest for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= 94 && Coord.Y <= 94); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -572,10 +572,10 @@ class MouseInputTest // Default Tracking, UTF8 Encoding mouseInput->SetInputMode(TerminalInput::Mode::Utf8MouseEncoding, true); - short MaxCoord = SHORT_MAX - 33; + auto MaxCoord = SHORT_MAX - 33; for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; fExpectedKeyHandled = (Coord.X <= MaxCoord && Coord.Y <= MaxCoord); Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); @@ -596,7 +596,7 @@ class MouseInputTest fExpectedKeyHandled = true; // SGR Mode should be able to handle any arbitrary coords. for (int i = 0; i < s_iTestCoordsLength; i++) { - COORD Coord = s_rgTestCoords[i]; + auto Coord = s_rgTestCoords[i]; Log::Comment(NoThrowString().Format(L"fHandled, x, y = (%d, %d, %d)", fExpectedKeyHandled, Coord.X, Coord.Y)); s_pwszInputExpected = BuildSGRTestOutput(s_rgSgrTestOutput[i], uiButton, sModifierKeystate, sScrollDelta); diff --git a/src/terminal/adapter/ut_adapter/WexHelpers.hpp b/src/terminal/adapter/ut_adapter/WexHelpers.hpp index a0dc274b3a8..3ae563f77a2 100644 --- a/src/terminal/adapter/ut_adapter/WexHelpers.hpp +++ b/src/terminal/adapter/ut_adapter/WexHelpers.hpp @@ -6,20 +6,20 @@ namespace WEX namespace TestExecution { template<> - class VerifyOutputTraits + class VerifyOutputTraits { public: - static WEX::Common::NoThrowString ToString(const SMALL_RECT& sr) + static WEX::Common::NoThrowString ToString(const til::inclusive_rect& sr) { return WEX::Common::NoThrowString().Format(L"(L:%d, R:%d, T:%d, B:%d)", sr.Left, sr.Right, sr.Top, sr.Bottom); } }; template<> - class VerifyCompareTraits + class VerifyCompareTraits { public: - static bool AreEqual(const SMALL_RECT& expected, const SMALL_RECT& actual) + static bool AreEqual(const til::inclusive_rect& expected, const til::inclusive_rect& actual) { return expected.Left == actual.Left && expected.Right == actual.Right && @@ -27,55 +27,54 @@ namespace WEX expected.Bottom == actual.Bottom; } - static bool AreSame(const SMALL_RECT& expected, const SMALL_RECT& actual) + static bool AreSame(const til::inclusive_rect& expected, const til::inclusive_rect& actual) { return &expected == &actual; } - static bool IsLessThan(const SMALL_RECT& /*expectedLess*/, const SMALL_RECT& /*expectedGreater*/) + static bool IsLessThan(const til::inclusive_rect& /*expectedLess*/, const til::inclusive_rect& /*expectedGreater*/) { - VERIFY_FAIL(L"Less than is invalid for SMALL_RECT comparisons."); + VERIFY_FAIL(L"Less than is invalid for til::inclusive_rect comparisons."); return false; } - static bool IsGreaterThan(const SMALL_RECT& /*expectedGreater*/, const SMALL_RECT& /*expectedLess*/) + static bool IsGreaterThan(const til::inclusive_rect& /*expectedGreater*/, const til::inclusive_rect& /*expectedLess*/) { - VERIFY_FAIL(L"Greater than is invalid for SMALL_RECT comparisons."); + VERIFY_FAIL(L"Greater than is invalid for til::inclusive_rect comparisons."); return false; } - static bool IsNull(const SMALL_RECT& object) + static bool IsNull(const til::inclusive_rect& object) { return object.Left == 0 && object.Right == 0 && object.Top == 0 && object.Bottom == 0; } }; template<> - class VerifyOutputTraits + class VerifyOutputTraits { public: - static WEX::Common::NoThrowString ToString(const COORD& coord) + static WEX::Common::NoThrowString ToString(const til::point coord) { return WEX::Common::NoThrowString().Format(L"(X:%d, Y:%d)", coord.X, coord.Y); } }; template<> - class VerifyCompareTraits + class VerifyCompareTraits { public: - static bool AreEqual(const COORD& expected, const COORD& actual) + static bool AreEqual(expected, const til::point actual) { - return expected.X == actual.X && - expected.Y == actual.Y; + return expected == actual; } - static bool AreSame(const COORD& expected, const COORD& actual) + static bool AreSame(const til::point expected, const til::point actual) { return &expected == &actual; } - static bool IsLessThan(const COORD& expectedLess, const COORD& expectedGreater) + static bool IsLessThan(const til::point expectedLess, const til::point expectedGreater) { // less is on a line above greater (Y values less than) return (expectedLess.Y < expectedGreater.Y) || @@ -83,7 +82,7 @@ namespace WEX ((expectedLess.Y == expectedGreater.Y) && (expectedLess.X < expectedGreater.X)); } - static bool IsGreaterThan(const COORD& expectedGreater, const COORD& expectedLess) + static bool IsGreaterThan(const til::point expectedGreater, const til::point expectedLess) { // greater is on a line below less (Y value greater than) return (expectedGreater.Y > expectedLess.Y) || @@ -91,7 +90,7 @@ namespace WEX ((expectedGreater.Y == expectedLess.Y) && (expectedGreater.X > expectedLess.X)); } - static bool IsNull(const COORD& object) + static bool IsNull(const til::point object) { return object.X == 0 && object.Y == 0; } @@ -151,10 +150,10 @@ namespace WEX sbiex.bFullscreenSupported ? L"True" : L"False", sbiex.wAttributes, sbiex.wPopupAttributes, - VerifyOutputTraits::ToString(sbiex.dwCursorPosition).ToCStrWithFallbackTo(L"Fail"), - VerifyOutputTraits::ToString(sbiex.dwSize).ToCStrWithFallbackTo(L"Fail"), - VerifyOutputTraits::ToString(sbiex.dwMaximumWindowSize).ToCStrWithFallbackTo(L"Fail"), - VerifyOutputTraits::ToString(sbiex.srWindow).ToCStrWithFallbackTo(L"Fail"), + VerifyOutputTraits::ToString(sbiex.dwCursorPosition).ToCStrWithFallbackTo(L"Fail"), + VerifyOutputTraits::ToString(sbiex.dwSize).ToCStrWithFallbackTo(L"Fail"), + VerifyOutputTraits::ToString(sbiex.dwMaximumWindowSize).ToCStrWithFallbackTo(L"Fail"), + VerifyOutputTraits::ToString(sbiex.srWindow).ToCStrWithFallbackTo(L"Fail"), sbiex.ColorTable[0], sbiex.ColorTable[1], sbiex.ColorTable[2], @@ -183,10 +182,10 @@ namespace WEX return expected.bFullscreenSupported == actual.bFullscreenSupported && expected.wAttributes == actual.wAttributes && expected.wPopupAttributes == actual.wPopupAttributes && - VerifyCompareTraits::AreEqual(expected.dwCursorPosition, actual.dwCursorPosition) && - VerifyCompareTraits::AreEqual(expected.dwSize, actual.dwSize) && - VerifyCompareTraits::AreEqual(expected.dwMaximumWindowSize, actual.dwMaximumWindowSize) && - VerifyCompareTraits::AreEqual(expected.srWindow, actual.srWindow) && + VerifyCompareTraits::AreEqual(expected.dwCursorPosition, actual.dwCursorPosition) && + VerifyCompareTraits::AreEqual(expected.dwSize, actual.dwSize) && + VerifyCompareTraits::AreEqual(expected.dwMaximumWindowSize, actual.dwMaximumWindowSize) && + VerifyCompareTraits::AreEqual(expected.srWindow, actual.srWindow) && expected.ColorTable[0] == actual.ColorTable[0] && expected.ColorTable[1] == actual.ColorTable[1] && expected.ColorTable[2] == actual.ColorTable[2] && @@ -229,10 +228,10 @@ namespace WEX return object.bFullscreenSupported == 0 && object.wAttributes == 0 && object.wPopupAttributes == 0 && - VerifyCompareTraits::IsNull(object.dwCursorPosition) && - VerifyCompareTraits::IsNull(object.dwSize) && - VerifyCompareTraits::IsNull(object.dwMaximumWindowSize) && - VerifyCompareTraits::IsNull(object.srWindow) && + VerifyCompareTraits::IsNull(object.dwCursorPosition) && + VerifyCompareTraits::IsNull(object.dwSize) && + VerifyCompareTraits::IsNull(object.dwMaximumWindowSize) && + VerifyCompareTraits::IsNull(object.srWindow) && object.ColorTable[0] == 0x0 && object.ColorTable[1] == 0x0 && object.ColorTable[2] == 0x0 && diff --git a/src/terminal/adapter/ut_adapter/adapterTest.cpp b/src/terminal/adapter/ut_adapter/adapterTest.cpp index 1483429e25b..dcb8423eea0 100644 --- a/src/terminal/adapter/ut_adapter/adapterTest.cpp +++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp @@ -39,7 +39,7 @@ enum class CursorX XCENTER }; -enum class CursorDirection : size_t +enum class CursorDirection : Microsoft::Console::VirtualTerminal::VTInt { UP = 0, DOWN = 1, @@ -49,7 +49,7 @@ enum class CursorDirection : size_t PREVLINE = 5 }; -enum class AbsolutePosition : size_t +enum class AbsolutePosition : Microsoft::Console::VirtualTerminal::VTInt { CursorHorizontal = 0, VerticalLine = 1, @@ -124,7 +124,7 @@ class TestGetSet final : public ConGetSet eventsWritten = _events.size(); } - void SetScrollingRegion(const SMALL_RECT& scrollMargins) override + void SetScrollingRegion(const til::inclusive_rect& scrollMargins) override { Log::Comment(L"SetScrollingRegion MOCK called..."); @@ -271,8 +271,8 @@ class TestGetSet final : public ConGetSet { Log::Comment(L"Adjusting cursor within viewport... Expected will match actual when done."); - COORD cursorPos = {}; - const COORD bufferSize = _textBuffer->GetSize().Dimensions(); + til::point cursorPos; + const auto bufferSize = _textBuffer->GetSize().Dimensions(); switch (xact) { @@ -306,13 +306,13 @@ class TestGetSet final : public ConGetSet break; } - _textBuffer->GetCursor().SetPosition(cursorPos); + _textBuffer->GetCursor().SetPosition(til::unwrap_coord(cursorPos)); _expectedCursorPos = cursorPos; } void ValidateExpectedCursorPos() { - VERIFY_ARE_EQUAL(_expectedCursorPos, _textBuffer->GetCursor().GetPosition()); + VERIFY_ARE_EQUAL(_expectedCursorPos, til::point{ _textBuffer->GetCursor().GetPosition() }); } void ValidateInputEvent(_In_ PCWSTR pwszExpectedResponse) @@ -341,7 +341,7 @@ class TestGetSet final : public ConGetSet } } - void _SetMarginsHelper(SMALL_RECT* rect, SHORT top, SHORT bottom) + void _SetMarginsHelper(til::inclusive_rect* rect, til::CoordType top, til::CoordType bottom) { rect->Top = top; rect->Bottom = bottom; @@ -375,11 +375,11 @@ class TestGetSet final : public ConGetSet StateMachine* _stateMachine; DummyRenderer _renderer; std::unique_ptr _textBuffer; - SMALL_RECT _viewport = { 0, 0, 0, 0 }; - SMALL_RECT _expectedScrollRegion = { 0, 0, 0, 0 }; - SMALL_RECT _activeScrollRegion = { 0, 0, 0, 0 }; + til::inclusive_rect _viewport = { 0, 0, 0, 0 }; + til::inclusive_rect _expectedScrollRegion = { 0, 0, 0, 0 }; + til::inclusive_rect _activeScrollRegion = { 0, 0, 0, 0 }; - COORD _expectedCursorPos = { 0, 0 }; + til::point _expectedCursorPos; TextAttribute _expectedAttribute = {}; unsigned int _expectedOutputCP = 0; @@ -451,7 +451,7 @@ class AdapterTest Log::Comment(L"Starting test..."); // Used to switch between the various function options. - typedef bool (AdaptDispatch::*CursorMoveFunc)(size_t); + typedef bool (AdaptDispatch::*CursorMoveFunc)(VTInt); CursorMoveFunc moveFunc = nullptr; // Modify variables based on directionality of this test @@ -601,8 +601,8 @@ class AdapterTest Log::Comment(L"Test 1: Place cursor within the viewport. Start from top left, move to middle."); _testGetSet->PrepData(CursorX::LEFT, CursorY::TOP); - short sCol = (_testGetSet->_viewport.Right - _testGetSet->_viewport.Left) / 2; - short sRow = (_testGetSet->_viewport.Bottom - _testGetSet->_viewport.Top) / 2; + auto sCol = (_testGetSet->_viewport.Right - _testGetSet->_viewport.Left) / 2; + auto sRow = (_testGetSet->_viewport.Bottom - _testGetSet->_viewport.Top) / 2; // The X coordinate is unaffected by the viewport. _testGetSet->_expectedCursorPos.X = sCol - 1; @@ -643,11 +643,11 @@ class AdapterTest Log::Comment(L"Starting test..."); //// Used to switch between the various function options. - typedef bool (AdaptDispatch::*CursorMoveFunc)(size_t); + typedef bool (AdaptDispatch::*CursorMoveFunc)(VTInt); CursorMoveFunc moveFunc = nullptr; - SHORT sRangeEnd = 0; - SHORT sRangeStart = 0; - SHORT* psCursorExpected = nullptr; + auto sRangeEnd = 0; + auto sRangeStart = 0; + til::CoordType* psCursorExpected = nullptr; // Modify variables based on directionality of this test AbsolutePosition direction; @@ -683,7 +683,7 @@ class AdapterTest Log::Comment(L"Test 1: Place cursor within the viewport. Start from top left, move to middle."); _testGetSet->PrepData(CursorX::LEFT, CursorY::TOP); - short sVal = (sRangeEnd - sRangeStart) / 2; + auto sVal = (sRangeEnd - sRangeStart) / 2; *psCursorExpected = sRangeStart + (sVal - 1); @@ -714,7 +714,7 @@ class AdapterTest { Log::Comment(L"Starting test..."); - COORD coordExpected = { 0 }; + til::point coordExpected; Log::Comment(L"Test 1: Restore with no saved data should move to top-left corner, the null/default position."); @@ -1378,7 +1378,7 @@ class AdapterTest _testGetSet->PrepData(CursorX::XCENTER, CursorY::YCENTER); // start with the cursor position in the buffer. - COORD coordCursorExpected = _testGetSet->_textBuffer->GetCursor().GetPosition(); + til::point coordCursorExpected{ _testGetSet->_textBuffer->GetCursor().GetPosition() }; // to get to VT, we have to adjust it to its position relative to the viewport top. coordCursorExpected.Y -= _testGetSet->_viewport.Top; @@ -1695,11 +1695,11 @@ class AdapterTest { Log::Comment(L"Starting test..."); - SMALL_RECT srTestMargins = { 0 }; + til::inclusive_rect srTestMargins; _testGetSet->_textBuffer = std::make_unique(COORD{ 100, 600 }, TextAttribute{}, 0, false, _testGetSet->_renderer); _testGetSet->_viewport.Right = 8; _testGetSet->_viewport.Bottom = 8; - SHORT sScreenHeight = _testGetSet->_viewport.Bottom - _testGetSet->_viewport.Top; + auto sScreenHeight = _testGetSet->_viewport.Bottom - _testGetSet->_viewport.Top; Log::Comment(L"Test 1: Verify having both values is valid."); _testGetSet->_SetMarginsHelper(&srTestMargins, 2, 6); @@ -1731,7 +1731,7 @@ class AdapterTest _testGetSet->_setScrollingRegionResult = TRUE; _testGetSet->_activeScrollRegion = {}; VERIFY_IS_TRUE(_pDispatch->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); - VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); + VERIFY_ARE_EQUAL(til::inclusive_rect{}, _testGetSet->_activeScrollRegion); Log::Comment(L"Test 6: Verify setting margins to (0, height) clears them"); // First set, @@ -1772,7 +1772,7 @@ class AdapterTest _testGetSet->_setScrollingRegionResult = TRUE; _testGetSet->_activeScrollRegion = {}; VERIFY_IS_TRUE(_pDispatch->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); - VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); + VERIFY_ARE_EQUAL(til::inclusive_rect{}, _testGetSet->_activeScrollRegion); Log::Comment(L"Test 10: Verify having top margin out of bounds has no effect."); @@ -1780,7 +1780,7 @@ class AdapterTest _testGetSet->_setScrollingRegionResult = TRUE; _testGetSet->_activeScrollRegion = {}; VERIFY_IS_TRUE(_pDispatch->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); - VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); + VERIFY_ARE_EQUAL(til::inclusive_rect{}, _testGetSet->_activeScrollRegion); Log::Comment(L"Test 11: Verify having bottom margin out of bounds has no effect."); @@ -1788,7 +1788,7 @@ class AdapterTest _testGetSet->_setScrollingRegionResult = TRUE; _testGetSet->_activeScrollRegion = {}; VERIFY_IS_TRUE(_pDispatch->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); - VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); + VERIFY_ARE_EQUAL(til::inclusive_rect{}, _testGetSet->_activeScrollRegion); } TEST_METHOD(LineFeedTest) diff --git a/src/terminal/input/mouseInput.cpp b/src/terminal/input/mouseInput.cpp index cbfbd81282b..a78182ac8b8 100644 --- a/src/terminal/input/mouseInput.cpp +++ b/src/terminal/input/mouseInput.cpp @@ -257,7 +257,7 @@ static constexpr int _windowsButtonToSGREncoding(const unsigned int button, // - coordWinCoordinate - the coordinate to translate // Return value: // - the translated coordinate. -static constexpr COORD _winToVTCoord(const COORD coordWinCoordinate) noexcept +static constexpr til::point _winToVTCoord(const til::point coordWinCoordinate) noexcept { return { coordWinCoordinate.X + 1, coordWinCoordinate.Y + 1 }; } @@ -269,7 +269,7 @@ static constexpr COORD _winToVTCoord(const COORD coordWinCoordinate) noexcept // - sCoordinateValue - the value to encode. // Return value: // - the encoded value. -static constexpr short _encodeDefaultCoordinate(const short sCoordinateValue) noexcept +static constexpr til::CoordType _encodeDefaultCoordinate(const til::CoordType sCoordinateValue) noexcept { return sCoordinateValue + 32; } @@ -297,7 +297,7 @@ bool TerminalInput::IsTrackingMouseInput() const noexcept // - state - the state of the mouse buttons at this moment // Return value: // - true if the event was handled and we should stop event propagation to the default window handler. -bool TerminalInput::HandleMouse(const COORD position, +bool TerminalInput::HandleMouse(const til::point position, const unsigned int button, const short modifierKeyState, const short delta, @@ -426,7 +426,7 @@ bool TerminalInput::HandleMouse(const COORD position, // - delta - the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL) // Return value: // - The generated sequence. Will be empty if we couldn't generate. -std::wstring TerminalInput::_GenerateDefaultSequence(const COORD position, +std::wstring TerminalInput::_GenerateDefaultSequence(const til::point position, const unsigned int button, const bool isHover, const short modifierKeyState, @@ -438,14 +438,14 @@ std::wstring TerminalInput::_GenerateDefaultSequence(const COORD position, // stream without bash.exe trying to convert it into utf8, and generating extra bytes in the process. if (position.X <= s_MaxDefaultCoordinate && position.Y <= s_MaxDefaultCoordinate) { - const COORD vtCoords = _winToVTCoord(position); - const short encodedX = _encodeDefaultCoordinate(vtCoords.X); - const short encodedY = _encodeDefaultCoordinate(vtCoords.Y); + const auto vtCoords = _winToVTCoord(position); + const auto encodedX = _encodeDefaultCoordinate(vtCoords.X); + const auto encodedY = _encodeDefaultCoordinate(vtCoords.Y); std::wstring format{ L"\x1b[Mbxy" }; - format.at(3) = ' ' + gsl::narrow_cast(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); - format.at(4) = encodedX; - format.at(5) = encodedY; + til::at(format, 3) = gsl::narrow_cast(L' ' + _windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); + til::at(format, 4) = gsl::narrow_cast(encodedX); + til::at(format, 5) = gsl::narrow_cast(encodedY); return format; } @@ -463,7 +463,7 @@ std::wstring TerminalInput::_GenerateDefaultSequence(const COORD position, // - delta - the amount that the scroll wheel changed (should be 0 unless button is a WM_MOUSE*WHEEL) // Return value: // - The generated sequence. Will be empty if we couldn't generate. -std::wstring TerminalInput::_GenerateUtf8Sequence(const COORD position, +std::wstring TerminalInput::_GenerateUtf8Sequence(const til::point position, const unsigned int button, const bool isHover, const short modifierKeyState, @@ -485,14 +485,14 @@ std::wstring TerminalInput::_GenerateUtf8Sequence(const COORD position, // TODO: Followup once the UTF-8 input stack is ready, MSFT:8509613 if (position.X <= (SHORT_MAX - 33) && position.Y <= (SHORT_MAX - 33)) { - const COORD vtCoords = _winToVTCoord(position); - const short encodedX = _encodeDefaultCoordinate(vtCoords.X); - const short encodedY = _encodeDefaultCoordinate(vtCoords.Y); + const auto vtCoords = _winToVTCoord(position); + const auto encodedX = _encodeDefaultCoordinate(vtCoords.X); + const auto encodedY = _encodeDefaultCoordinate(vtCoords.Y); std::wstring format{ L"\x1b[Mbxy" }; // The short cast is safe because we know s_WindowsButtonToXEncoding never returns more than xff - format.at(3) = ' ' + gsl::narrow_cast(_windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); - format.at(4) = encodedX; - format.at(5) = encodedY; + til::at(format, 3) = gsl::narrow_cast(L' ' + _windowsButtonToXEncoding(button, isHover, modifierKeyState, delta)); + til::at(format, 4) = gsl::narrow_cast(encodedX); + til::at(format, 5) = gsl::narrow_cast(encodedY); return format; } @@ -514,7 +514,7 @@ std::wstring TerminalInput::_GenerateUtf8Sequence(const COORD position, // Return value: // - true if we were able to successfully generate a sequence. // On success, caller is responsible for delete[]ing *ppwchSequence. -std::wstring TerminalInput::_GenerateSGRSequence(const COORD position, +std::wstring TerminalInput::_GenerateSGRSequence(const til::point position, const unsigned int button, const bool isDown, const bool isHover, diff --git a/src/terminal/input/terminalInput.hpp b/src/terminal/input/terminalInput.hpp index 6b18f5ebc90..0093269cbce 100644 --- a/src/terminal/input/terminalInput.hpp +++ b/src/terminal/input/terminalInput.hpp @@ -66,7 +66,7 @@ namespace Microsoft::Console::VirtualTerminal bool isRightButtonDown; }; - bool HandleMouse(const COORD position, + bool HandleMouse(const til::point position, const unsigned int button, const short modifierKeyState, const short delta, @@ -102,7 +102,7 @@ namespace Microsoft::Console::VirtualTerminal struct MouseInputState { bool inAlternateBuffer{ false }; - COORD lastPos{ -1, -1 }; + til::point lastPos{ -1, -1 }; unsigned int lastButton{ 0 }; int accumulatedDelta{ 0 }; }; @@ -111,17 +111,17 @@ namespace Microsoft::Console::VirtualTerminal #pragma endregion #pragma region MouseInput - static std::wstring _GenerateDefaultSequence(const COORD position, + static std::wstring _GenerateDefaultSequence(const til::point position, const unsigned int button, const bool isHover, const short modifierKeyState, const short delta); - static std::wstring _GenerateUtf8Sequence(const COORD position, + static std::wstring _GenerateUtf8Sequence(const til::point position, const unsigned int button, const bool isHover, const short modifierKeyState, const short delta); - static std::wstring _GenerateSGRSequence(const COORD position, + static std::wstring _GenerateSGRSequence(const til::point position, const unsigned int button, const bool isDown, const bool isHover, diff --git a/src/terminal/parser/InputStateMachineEngine.cpp b/src/terminal/parser/InputStateMachineEngine.cpp index 7fcec6b92da..e039631e108 100644 --- a/src/terminal/parser/InputStateMachineEngine.cpp +++ b/src/terminal/parser/InputStateMachineEngine.cpp @@ -385,8 +385,8 @@ bool InputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParameter { DWORD buttonState = 0; DWORD eventFlags = 0; - const size_t firstParameter = parameters.at(0).value_or(0); - const til::point uiPos{ gsl::narrow_cast(parameters.at(1) - 1), gsl::narrow_cast(parameters.at(2) - 1) }; + const auto firstParameter = parameters.at(0).value_or(0); + const til::point uiPos{ parameters.at(1) - 1, parameters.at(2) - 1 }; modifierState = _GetSGRMouseModifierState(firstParameter); success = _UpdateSGRMouseButtonState(id, firstParameter, buttonState, eventFlags, uiPos); @@ -735,7 +735,7 @@ bool InputStateMachineEngine::_WriteMouseEvent(const til::point uiPos, const DWO { INPUT_RECORD rgInput; rgInput.EventType = MOUSE_EVENT; - rgInput.Event.MouseEvent.dwMousePosition = uiPos.to_win32_coord(); + rgInput.Event.MouseEvent.dwMousePosition = til::unwrap_coord(uiPos); rgInput.Event.MouseEvent.dwButtonState = buttonState; rgInput.Event.MouseEvent.dwControlKeyState = controlKeyState; rgInput.Event.MouseEvent.dwEventFlags = eventFlags; diff --git a/src/terminal/parser/stateMachine.cpp b/src/terminal/parser/stateMachine.cpp index b1ccf49267a..bece213dbb2 100644 --- a/src/terminal/parser/stateMachine.cpp +++ b/src/terminal/parser/stateMachine.cpp @@ -1998,9 +1998,9 @@ void StateMachine::ResetState() noexcept // - value - The value to update with the printable character. See example above. // Return Value: // - - But really it's the update to the given value parameter. -void StateMachine::_AccumulateTo(const wchar_t wch, size_t& value) noexcept +void StateMachine::_AccumulateTo(const wchar_t wch, VTInt& value) noexcept { - const size_t digit = wch - L'0'; + const auto digit = wch - L'0'; value = value * 10 + digit; diff --git a/src/terminal/parser/stateMachine.hpp b/src/terminal/parser/stateMachine.hpp index 704ccc01fda..e4b2bfccae5 100644 --- a/src/terminal/parser/stateMachine.hpp +++ b/src/terminal/parser/stateMachine.hpp @@ -25,7 +25,7 @@ namespace Microsoft::Console::VirtualTerminal // parameter values, so 32767 should be more than enough. At most we might // want to increase this to 65535, since that is what XTerm and VTE support, // but for now 32767 is the safest limit for our existing code base. - constexpr size_t MAX_PARAMETER_VALUE = 32767; + constexpr VTInt MAX_PARAMETER_VALUE = 32767; // The DEC STD 070 reference requires that a minimum of 16 parameter values // are supported, but most modern terminal emulators will allow around twice @@ -126,7 +126,7 @@ namespace Microsoft::Console::VirtualTerminal void _EventDcsPassThrough(const wchar_t wch); void _EventSosPmApcString(const wchar_t wch) noexcept; - void _AccumulateTo(const wchar_t wch, size_t& value) noexcept; + void _AccumulateTo(const wchar_t wch, VTInt& value) noexcept; template bool _SafeExecute(TLambda&& lambda) noexcept; @@ -183,7 +183,7 @@ namespace Microsoft::Console::VirtualTerminal bool _parameterLimitReached; std::wstring _oscString; - size_t _oscParameter; + VTInt _oscParameter; IStateMachineEngine::StringHandler _dcsStringHandler; diff --git a/src/terminal/parser/ut_parser/InputEngineTest.cpp b/src/terminal/parser/ut_parser/InputEngineTest.cpp index 245564577c8..a77a2b02f03 100644 --- a/src/terminal/parser/ut_parser/InputEngineTest.cpp +++ b/src/terminal/parser/ut_parser/InputEngineTest.cpp @@ -71,7 +71,6 @@ class TestState _expectedCursor{ -1, -1 }, _expectedWindowManipulation{ DispatchTypes::WindowManipulationType::Invalid } { - std::fill_n(_expectedParams, ARRAYSIZE(_expectedParams), gsl::narrow(0)); } void RoundtripTerminalInputCallback(_In_ std::deque>& inEvents) @@ -199,9 +198,9 @@ class TestState bool _expectedToCallWindowManipulation; bool _expectSendCtrlC; bool _expectCursorPosition; - COORD _expectedCursor; + til::point _expectedCursor; DispatchTypes::WindowManipulationType _expectedWindowManipulation; - unsigned short _expectedParams[16]; + std::array _expectedParams{}; }; class Microsoft::Console::VirtualTerminal::InputEngineTest @@ -215,21 +214,21 @@ class Microsoft::Console::VirtualTerminal::InputEngineTest void TestInputStringCallback(std::deque>& inEvents); std::wstring GenerateSgrMouseSequence(const CsiMouseButtonCodes button, const unsigned short modifiers, - const COORD position, + const til::point position, const VTID direction); // SGR_PARAMS serves as test input // - the state of the buttons (constructed via InputStateMachineEngine::CsiActionMouseCodes) // - the {x,y} position of the event on the viewport where the top-left is {1,1} // - the direction of the mouse press (constructed via InputStateMachineEngine::CsiActionCodes) - typedef std::tuple SGR_PARAMS; + typedef std::tuple SGR_PARAMS; // MOUSE_EVENT_PARAMS serves as expected output // - buttonState // - controlKeyState // - mousePosition // - eventFlags - typedef std::tuple MOUSE_EVENT_PARAMS; + typedef std::tuple MOUSE_EVENT_PARAMS; void VerifySGRMouseData(const std::vector> testData); @@ -327,8 +326,8 @@ class Microsoft::Console::VirtualTerminal::TestInteractDispatch final : public I const VTParameter parameter2) override; // DTTERM_WindowManipulation virtual bool WriteString(const std::wstring_view string) override; - virtual bool MoveCursor(const size_t row, - const size_t col) override; + virtual bool MoveCursor(const VTInt row, + const VTInt col) override; virtual bool IsVtInputEnabled() const override; @@ -388,10 +387,10 @@ bool TestInteractDispatch::WriteString(const std::wstring_view string) return WriteInput(keyEvents); } -bool TestInteractDispatch::MoveCursor(const size_t row, const size_t col) +bool TestInteractDispatch::MoveCursor(const VTInt row, const VTInt col) { VERIFY_IS_TRUE(_testState->_expectCursorPosition); - COORD received = { static_cast(col), static_cast(row) }; + til::point received{ col, row }; VERIFY_ARE_EQUAL(_testState->_expectedCursor, received); return true; } @@ -635,8 +634,8 @@ void InputEngineTest::WindowManipulationTest() L"Only the valid ones should call the " L"TestInteractDispatch::WindowManipulation callback.")); - const unsigned short param1 = 123; - const unsigned short param2 = 456; + const auto param1 = 123; + const auto param2 = 456; const wchar_t* const wszParam1 = L"123"; const wchar_t* const wszParam2 = L"456"; @@ -1076,7 +1075,7 @@ void InputEngineTest::AltBackspaceEnterTest() // - the SGR VT sequence std::wstring InputEngineTest::GenerateSgrMouseSequence(const CsiMouseButtonCodes button, const unsigned short modifiers, - const COORD position, + const til::point position, const VTID direction) { // we first need to convert "button" and "modifiers" into an 8 bit sequence @@ -1121,7 +1120,7 @@ void InputEngineTest::VerifySGRMouseData(const std::vector(expected); inputRec.Event.MouseEvent.dwControlKeyState = std::get<1>(expected); - inputRec.Event.MouseEvent.dwMousePosition = std::get<2>(expected); + inputRec.Event.MouseEvent.dwMousePosition = til::unwrap_coord(std::get<2>(expected)); inputRec.Event.MouseEvent.dwEventFlags = std::get<3>(expected); testState.vExpectedInput.push_back(inputRec); @@ -1575,7 +1574,7 @@ void InputEngineTest::TestWin32InputOptionals() INIT_TEST_PROPERTY(bool, provideKeyDown, L"If true, pass the KeyDown param in the list of params. Otherwise, leave it as the default param value (0)"); INIT_TEST_PROPERTY(bool, provideActiveModifierKeys, L"If true, pass the ActiveModifierKeys param in the list of params. Otherwise, leave it as the default param value (0)"); INIT_TEST_PROPERTY(bool, provideRepeatCount, L"If true, pass the RepeatCount param in the list of params. Otherwise, leave it as the default param value (0)"); - INIT_TEST_PROPERTY(int, numParams, L"Control how many of the params we send"); + INIT_TEST_PROPERTY(size_t, numParams, L"Control how many of the params we send"); auto pfn = std::bind(&TestState::TestInputCallback, &testState, std::placeholders::_1); auto dispatch = std::make_unique(pfn, &testState); @@ -1583,15 +1582,15 @@ void InputEngineTest::TestWin32InputOptionals() { std::vector params{ - ::base::saturated_cast(provideVirtualKeyCode ? 1 : 0), - ::base::saturated_cast(provideVirtualScanCode ? 2 : 0), - ::base::saturated_cast(provideCharData ? 3 : 0), - ::base::saturated_cast(provideKeyDown ? 4 : 0), - ::base::saturated_cast(provideActiveModifierKeys ? 5 : 0), - ::base::saturated_cast(provideRepeatCount ? 6 : 0) + provideVirtualKeyCode ? 1 : 0, + provideVirtualScanCode ? 2 : 0, + provideCharData ? 3 : 0, + provideKeyDown ? 4 : 0, + provideActiveModifierKeys ? 5 : 0, + provideRepeatCount ? 6 : 0, }; - KeyEvent key = engine->_GenerateWin32Key({ params.data(), static_cast(numParams) }); + KeyEvent key = engine->_GenerateWin32Key({ params.data(), numParams }); VERIFY_ARE_EQUAL((provideVirtualKeyCode && numParams > 0) ? 1 : 0, key.GetVirtualKeyCode()); VERIFY_ARE_EQUAL((provideVirtualScanCode && numParams > 1) ? 2 : 0, diff --git a/src/terminal/parser/ut_parser/OutputEngineTest.cpp b/src/terminal/parser/ut_parser/OutputEngineTest.cpp index f45b68fde2e..cd3ab3de392 100644 --- a/src/terminal/parser/ut_parser/OutputEngineTest.cpp +++ b/src/terminal/parser/ut_parser/OutputEngineTest.cpp @@ -326,9 +326,9 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final VERIFY_ARE_EQUAL(mach._parameters.size(), 4u); VERIFY_IS_FALSE(mach._parameters.at(0).has_value()); - VERIFY_ARE_EQUAL(mach._parameters.at(1), 324u); + VERIFY_ARE_EQUAL(mach._parameters.at(1), 324); VERIFY_IS_FALSE(mach._parameters.at(2).has_value()); - VERIFY_ARE_EQUAL(mach._parameters.at(3), 8u); + VERIFY_ARE_EQUAL(mach._parameters.at(3), 8); } TEST_METHOD(TestCsiMaxParamCount) @@ -361,7 +361,7 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final for (size_t i = 0; i < MAX_PARAMETER_COUNT; i++) { VERIFY_IS_TRUE(mach._parameters.at(i).has_value()); - VERIFY_ARE_EQUAL(mach._parameters.at(i).value(), i % 10); + VERIFY_ARE_EQUAL(mach._parameters.at(i).value(), gsl::narrow_cast(i % 10)); } } @@ -386,7 +386,7 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final mach.ProcessCharacter((wchar_t)(L'1' + i)); VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::CsiParam); } - VERIFY_ARE_EQUAL(mach._parameters.back(), 12345u); + VERIFY_ARE_EQUAL(mach._parameters.back(), 12345); mach.ProcessCharacter(L'J'); VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::Ground); } @@ -564,7 +564,7 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final mach.ProcessCharacter((wchar_t)(L'1' + i)); VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscParam); } - VERIFY_ARE_EQUAL(mach._oscParameter, 12345u); + VERIFY_ARE_EQUAL(mach._oscParameter, 12345); mach.ProcessCharacter(L';'); VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscString); mach.ProcessCharacter(L's'); @@ -594,7 +594,7 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final mach.ProcessCharacter((wchar_t)(L'1' + i)); VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscParam); } - VERIFY_ARE_EQUAL(mach._oscParameter, 12345u); + VERIFY_ARE_EQUAL(mach._oscParameter, 12345); mach.ProcessCharacter(L';'); VERIFY_ARE_EQUAL(mach._state, StateMachine::VTStates::OscString); mach.ProcessCharacter(L's'); @@ -777,9 +777,9 @@ class Microsoft::Console::VirtualTerminal::OutputEngineTest final VERIFY_ARE_EQUAL(mach._parameters.size(), 4u); VERIFY_IS_FALSE(mach._parameters.at(0).has_value()); - VERIFY_ARE_EQUAL(mach._parameters.at(1), 324u); + VERIFY_ARE_EQUAL(mach._parameters.at(1), 324); VERIFY_IS_FALSE(mach._parameters.at(2).has_value()); - VERIFY_ARE_EQUAL(mach._parameters.at(3), 8u); + VERIFY_ARE_EQUAL(mach._parameters.at(3), 8); mach.ProcessCharacter(AsciiChars::ESC); mach.ProcessCharacter(L'\\'); @@ -1064,77 +1064,77 @@ class StatefulDispatch final : public TermDispatch *this = dispatch; } - bool CursorUp(_In_ size_t const uiDistance) noexcept override + bool CursorUp(const VTInt uiDistance) noexcept override { _cursorUp = true; _cursorDistance = uiDistance; return true; } - bool CursorDown(_In_ size_t const uiDistance) noexcept override + bool CursorDown(const VTInt uiDistance) noexcept override { _cursorDown = true; _cursorDistance = uiDistance; return true; } - bool CursorBackward(_In_ size_t const uiDistance) noexcept override + bool CursorBackward(const VTInt uiDistance) noexcept override { _cursorBackward = true; _cursorDistance = uiDistance; return true; } - bool CursorForward(_In_ size_t const uiDistance) noexcept override + bool CursorForward(const VTInt uiDistance) noexcept override { _cursorForward = true; _cursorDistance = uiDistance; return true; } - bool CursorNextLine(_In_ size_t const uiDistance) noexcept override + bool CursorNextLine(const VTInt uiDistance) noexcept override { _cursorNextLine = true; _cursorDistance = uiDistance; return true; } - bool CursorPrevLine(_In_ size_t const uiDistance) noexcept override + bool CursorPrevLine(const VTInt uiDistance) noexcept override { _cursorPreviousLine = true; _cursorDistance = uiDistance; return true; } - bool CursorHorizontalPositionAbsolute(_In_ size_t const uiPosition) noexcept override + bool CursorHorizontalPositionAbsolute(const VTInt uiPosition) noexcept override { _cursorHorizontalPositionAbsolute = true; _cursorDistance = uiPosition; return true; } - bool VerticalLinePositionAbsolute(_In_ size_t const uiPosition) noexcept override + bool VerticalLinePositionAbsolute(const VTInt uiPosition) noexcept override { _verticalLinePositionAbsolute = true; _cursorDistance = uiPosition; return true; } - bool HorizontalPositionRelative(_In_ size_t const uiDistance) noexcept override + bool HorizontalPositionRelative(const VTInt uiDistance) noexcept override { _horizontalPositionRelative = true; _cursorDistance = uiDistance; return true; } - bool VerticalPositionRelative(_In_ size_t const uiDistance) noexcept override + bool VerticalPositionRelative(const VTInt uiDistance) noexcept override { _verticalPositionRelative = true; _cursorDistance = uiDistance; return true; } - bool CursorPosition(_In_ size_t const uiLine, _In_ size_t const uiColumn) noexcept override + bool CursorPosition(const VTInt uiLine, const VTInt uiColumn) noexcept override { _cursorPosition = true; _line = uiLine; @@ -1170,14 +1170,14 @@ class StatefulDispatch final : public TermDispatch return true; } - bool InsertCharacter(_In_ size_t const uiCount) noexcept override + bool InsertCharacter(const VTInt uiCount) noexcept override { _insertCharacter = true; _cursorDistance = uiCount; return true; } - bool DeleteCharacter(_In_ size_t const uiCount) noexcept override + bool DeleteCharacter(const VTInt uiCount) noexcept override { _deleteCharacter = true; _cursorDistance = uiCount; @@ -1308,7 +1308,7 @@ class StatefulDispatch final : public TermDispatch return _ModeParamsHelper(param, false); } - bool SetColumns(_In_ size_t const uiColumns) noexcept override + bool SetColumns(const VTInt uiColumns) noexcept override { _windowWidth = uiColumns; return true; @@ -1387,7 +1387,7 @@ class StatefulDispatch final : public TermDispatch return true; } - bool ForwardTab(const size_t numTabs) noexcept override + bool ForwardTab(const VTInt numTabs) noexcept override { _forwardTab = true; _numTabs = numTabs; From 87f5034db1eb0102358d05eeff82ebcc8032c9be Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 20 Apr 2022 13:22:42 -0500 Subject: [PATCH 4/5] Plumb Focus events through VT Input (#12900) Further builds on #12799. #12799 assumes that the connection is prepared to receive FocusIn/FocusOut events as input. For ConPTY we can be relatively sure of that, but that's not _technically_ correct. In the hypothetical world where the connection is not a ConPTY connection, then the other side might not be expecting those sequences. This remedies the issue by * ConPTY will always request focus event mode (from the terminal) when it starts up * when a client tries to disable focus events in conpty, conpty is gonna note that internally, but never transmit that to the hosting terminal, to leave the terminal in focus event mode. * `TerminalDispatch` and `ControlCore` are hooked up now to only send focus events when the Terminal is in focus event mode (which will be always for conpty) * At this point, it was like, 4LOC in `terminalInput.cpp` to add support for focus events to conhost as well. ## checklist * [x] closes #11682 * This combined with #12515 will finally close out #2988 as well, but we can do that manually. * [x] I work here * [ ] There aren't tests for this. There probably should be. --- src/cascadia/TerminalControl/ControlCore.cpp | 4 +- src/cascadia/TerminalCore/ITerminalInput.hpp | 2 + src/cascadia/TerminalCore/Terminal.cpp | 13 +++++++ src/cascadia/TerminalCore/Terminal.hpp | 2 + .../TerminalCore/TerminalDispatch.cpp | 18 ++++++++- .../TerminalCore/TerminalDispatch.hpp | 1 + src/host/inputBuffer.cpp | 1 + src/renderer/vt/VtSequences.cpp | 5 +++ src/renderer/vt/state.cpp | 1 + src/renderer/vt/vtrenderer.hpp | 2 + src/terminal/adapter/DispatchTypes.hpp | 1 + src/terminal/adapter/ITermDispatch.hpp | 1 + src/terminal/adapter/InteractDispatch.cpp | 5 +-- src/terminal/adapter/adaptDispatch.cpp | 38 ++++++++++++++++++- src/terminal/adapter/adaptDispatch.hpp | 1 + src/terminal/adapter/termDispatch.hpp | 1 + src/terminal/input/terminalInput.cpp | 18 +++++++++ src/terminal/input/terminalInput.hpp | 3 ++ 18 files changed, 108 insertions(+), 9 deletions(-) diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index c2618b0bc7f..811831edead 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -1708,13 +1708,13 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - This is related to work done for GH#2988. void ControlCore::GotFocus() { - _connection.WriteInput(L"\x1b[I"); + _terminal->FocusChanged(true); } // See GotFocus. void ControlCore::LostFocus() { - _connection.WriteInput(L"\x1b[O"); + _terminal->FocusChanged(false); } bool ControlCore::_isBackgroundTransparent() diff --git a/src/cascadia/TerminalCore/ITerminalInput.hpp b/src/cascadia/TerminalCore/ITerminalInput.hpp index c2c7c54ca1b..1db443f51d6 100644 --- a/src/cascadia/TerminalCore/ITerminalInput.hpp +++ b/src/cascadia/TerminalCore/ITerminalInput.hpp @@ -26,6 +26,8 @@ namespace Microsoft::Terminal::Core virtual void TrySnapOnInput() = 0; + virtual void FocusChanged(const bool focused) = 0; + protected: ITerminalInput() = default; }; diff --git a/src/cascadia/TerminalCore/Terminal.cpp b/src/cascadia/TerminalCore/Terminal.cpp index 81fb6c7edb7..d3910abbc59 100644 --- a/src/cascadia/TerminalCore/Terminal.cpp +++ b/src/cascadia/TerminalCore/Terminal.cpp @@ -746,6 +746,19 @@ bool Terminal::SendCharEvent(const wchar_t ch, const WORD scanCode, const Contro return handledDown || handledUp; } +// Method Description: +// - Tell the terminal input that we gained or lost focus. If the client +// requested focus events, this will send a message to them. +// - ConPTY ALWAYS wants focus events. +// Arguments: +// - focused: true if we're focused, false otherwise. +// Return Value: +// - none +void Terminal::FocusChanged(const bool focused) noexcept +{ + _terminalInput->HandleFocus(focused); +} + // Method Description: // - Invalidates the regions described in the given pattern tree for the rendering purposes // Arguments: diff --git a/src/cascadia/TerminalCore/Terminal.hpp b/src/cascadia/TerminalCore/Terminal.hpp index de84a964c91..af491396d76 100644 --- a/src/cascadia/TerminalCore/Terminal.hpp +++ b/src/cascadia/TerminalCore/Terminal.hpp @@ -156,6 +156,8 @@ class Microsoft::Terminal::Core::Terminal final : bool IsTrackingMouseInput() const noexcept; bool ShouldSendAlternateScroll(const unsigned int uiButton, const int32_t delta) const noexcept; + void FocusChanged(const bool focused) noexcept override; + std::wstring GetHyperlinkAtPosition(const COORD position); uint16_t GetHyperlinkIdAtPosition(const COORD position); std::optional::interval> GetHyperlinkIntervalFromPosition(const COORD position); diff --git a/src/cascadia/TerminalCore/TerminalDispatch.cpp b/src/cascadia/TerminalCore/TerminalDispatch.cpp index b380acdba15..082b85b7e10 100644 --- a/src/cascadia/TerminalCore/TerminalDispatch.cpp +++ b/src/cascadia/TerminalCore/TerminalDispatch.cpp @@ -383,7 +383,6 @@ bool TerminalDispatch::EnableButtonEventMouseMode(const bool enabled) //Routine Description: // Enable Any Event mode - send all mouse events to the input. - //Arguments: // - enabled - true to enable, false to disable. // Return value: @@ -394,6 +393,20 @@ bool TerminalDispatch::EnableAnyEventMouseMode(const bool enabled) return true; } +// Method Description: +// - Enables/disables focus event mode. A client may enable this if they want to +// receive focus events. +// - ConPTY always enables this mode and never disables it. For more details, see GH#12900. +// Arguments: +// - enabled - true to enable, false to disable. +// Return Value: +// - True if handled successfully. False otherwise. +bool TerminalDispatch::EnableFocusEventMode(const bool enabled) +{ + _terminalApi.SetInputMode(TerminalInput::Mode::FocusEvent, enabled); + return true; +} + //Routine Description: // Enable Alternate Scroll Mode - When in the Alt Buffer, send CUP and CUD on // scroll up/down events instead of the usual sequences @@ -631,6 +644,9 @@ bool TerminalDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param, case DispatchTypes::ModeParams::SGR_EXTENDED_MODE: success = EnableSGRExtendedMouseMode(enable); break; + case DispatchTypes::ModeParams::FOCUS_EVENT_MODE: + success = EnableFocusEventMode(enable); + break; case DispatchTypes::ModeParams::ALTERNATE_SCROLL: success = EnableAlternateScroll(enable); break; diff --git a/src/cascadia/TerminalCore/TerminalDispatch.hpp b/src/cascadia/TerminalCore/TerminalDispatch.hpp index d358552b78e..a86417cdd18 100644 --- a/src/cascadia/TerminalCore/TerminalDispatch.hpp +++ b/src/cascadia/TerminalCore/TerminalDispatch.hpp @@ -74,6 +74,7 @@ class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatc bool EnableSGRExtendedMouseMode(const bool enabled) override; // ?1006 bool EnableButtonEventMouseMode(const bool enabled) override; // ?1002 bool EnableAnyEventMouseMode(const bool enabled) override; // ?1003 + bool EnableFocusEventMode(const bool enabled) override; // ?1004 bool EnableAlternateScroll(const bool enabled) override; // ?1007 bool EnableXtermBracketedPasteMode(const bool enabled) override; // ?2004 diff --git a/src/host/inputBuffer.cpp b/src/host/inputBuffer.cpp index 8283ef213e1..b2a00fdba5a 100644 --- a/src/host/inputBuffer.cpp +++ b/src/host/inputBuffer.cpp @@ -642,6 +642,7 @@ void InputBuffer::_WriteBuffer(_Inout_ std::deque>& inEvents.pop_front(); if (vtInputMode) { + // GH#11682: TerminalInput::HandleKey can handle both KeyEvents and Focus events seamlessly const bool handled = _termInput.HandleKey(inEvent.get()); if (handled) { diff --git a/src/renderer/vt/VtSequences.cpp b/src/renderer/vt/VtSequences.cpp index 05fd6f95184..56939fb175e 100644 --- a/src/renderer/vt/VtSequences.cpp +++ b/src/renderer/vt/VtSequences.cpp @@ -434,6 +434,11 @@ using namespace Microsoft::Console::Render; return _Write("\x1b[?9001h"); } +[[nodiscard]] HRESULT VtEngine::_RequestFocusEventMode() noexcept +{ + return _Write("\x1b[?1004h"); +} + // Method Description: // - Send a sequence to the connected terminal to switch to the alternate or main screen buffer. // Arguments: diff --git a/src/renderer/vt/state.cpp b/src/renderer/vt/state.cpp index 1f3cf516461..3669a0440eb 100644 --- a/src/renderer/vt/state.cpp +++ b/src/renderer/vt/state.cpp @@ -524,6 +524,7 @@ void VtEngine::SetTerminalCursorTextPosition(const COORD cursor) noexcept HRESULT VtEngine::RequestWin32Input() noexcept { RETURN_IF_FAILED(_RequestWin32Input()); + RETURN_IF_FAILED(_RequestFocusEventMode()); RETURN_IF_FAILED(_Flush()); return S_OK; } diff --git a/src/renderer/vt/vtrenderer.hpp b/src/renderer/vt/vtrenderer.hpp index cd8a3d5d739..cd1d44fff46 100644 --- a/src/renderer/vt/vtrenderer.hpp +++ b/src/renderer/vt/vtrenderer.hpp @@ -200,6 +200,8 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT _RequestWin32Input() noexcept; [[nodiscard]] HRESULT _SwitchScreenBuffer(const bool useAltBuffer) noexcept; + [[nodiscard]] HRESULT _RequestFocusEventMode() noexcept; + [[nodiscard]] virtual HRESULT _MoveCursor(const COORD coord) noexcept = 0; [[nodiscard]] HRESULT _RgbUpdateDrawingBrushes(const TextAttribute& textAttributes) noexcept; [[nodiscard]] HRESULT _16ColorUpdateDrawingBrushes(const TextAttribute& textAttributes) noexcept; diff --git a/src/terminal/adapter/DispatchTypes.hpp b/src/terminal/adapter/DispatchTypes.hpp index 5a048aafb5c..48af68e336f 100644 --- a/src/terminal/adapter/DispatchTypes.hpp +++ b/src/terminal/adapter/DispatchTypes.hpp @@ -375,6 +375,7 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes VT200_MOUSE_MODE = DECPrivateMode(1000), BUTTON_EVENT_MOUSE_MODE = DECPrivateMode(1002), ANY_EVENT_MOUSE_MODE = DECPrivateMode(1003), + FOCUS_EVENT_MODE = DECPrivateMode(1004), UTF8_EXTENDED_MODE = DECPrivateMode(1005), SGR_EXTENDED_MODE = DECPrivateMode(1006), ALTERNATE_SCROLL = DECPrivateMode(1007), diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index a097bb9d686..0433d9662d7 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -79,6 +79,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool EnableSGRExtendedMouseMode(const bool enabled) = 0; // ?1006 virtual bool EnableButtonEventMouseMode(const bool enabled) = 0; // ?1002 virtual bool EnableAnyEventMouseMode(const bool enabled) = 0; // ?1003 + virtual bool EnableFocusEventMode(const bool enabled) = 0; // ?1004 virtual bool EnableAlternateScroll(const bool enabled) = 0; // ?1007 virtual bool EnableXtermBracketedPasteMode(const bool enabled) = 0; // ?2004 virtual bool SetColorTableEntry(const size_t tableIndex, const DWORD color) = 0; // OSCColorTable diff --git a/src/terminal/adapter/InteractDispatch.cpp b/src/terminal/adapter/InteractDispatch.cpp index ace72b0711a..25a440352d5 100644 --- a/src/terminal/adapter/InteractDispatch.cpp +++ b/src/terminal/adapter/InteractDispatch.cpp @@ -175,7 +175,6 @@ bool InteractDispatch::IsVtInputEnabled() const // which will end up here. This will update the console's internal tracker if // it's focused or not, as to match the end-terminal's state. // - Used to call ConsoleControl(ConsoleSetForeground,...). -// - Full support for this sequence is tracked in GH#11682. // Arguments: // - focused: if the terminal is now focused // Return Value: @@ -234,11 +233,9 @@ bool InteractDispatch::FocusChanged(const bool focused) const WI_UpdateFlag(gci.Flags, CONSOLE_HAS_FOCUS, shouldActuallyFocus); gci.ProcessHandleList.ModifyConsoleProcessFocus(shouldActuallyFocus); + gci.pInputBuffer->Write(std::make_unique(focused)); } // Does nothing outside of ConPTY. If there's a real HWND, then the HWND is solely in charge. - // Theoretically, this could be propagated as a focus event as well, to the - // input buffer. That should be considered when implementing GH#11682. - return true; } diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 2e1bf050224..6bf29254e9d 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -1025,7 +1025,24 @@ bool AdaptDispatch::_SetInputMode(const TerminalInput::Mode mode, const bool ena // us that SSH 7.7 _also_ requests mouse input and that can have a user interface // impact on the actual connected terminal. We can't remove this check, // because SSH <=7.7 is out in the wild on all versions of Windows <=2004. - return !(_pConApi->IsConsolePty() && _pConApi->IsVtInputEnabled()); + + // GH#12799 - If the app requested that we disable focus events, DON'T pass + // that through. ConPTY would _always_ like to know about focus events. + + return !_pConApi->IsConsolePty() || + !_pConApi->IsVtInputEnabled() || + (!enable && mode == TerminalInput::Mode::FocusEvent); + + // Another way of writing the above statement is: + // + // const bool inConpty = _pConApi->IsConsolePty(); + // const bool shouldPassthrough = inConpty && _pConApi->IsVtInputEnabled(); + // const bool disabledFocusEvents = inConpty && (!enable && mode == TerminalInput::Mode::FocusEvent); + // return !shouldPassthrough || disabledFocusEvents; + // + // It's like a "filter" left to right. Due to the early return via + // !IsConsolePty, once you're at the !enable part, IsConsolePty can only be + // true anymore. } // Routine Description: @@ -1084,6 +1101,9 @@ bool AdaptDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param, con case DispatchTypes::ModeParams::SGR_EXTENDED_MODE: success = EnableSGRExtendedMouseMode(enable); break; + case DispatchTypes::ModeParams::FOCUS_EVENT_MODE: + success = EnableFocusEventMode(enable); + break; case DispatchTypes::ModeParams::ALTERNATE_SCROLL: success = EnableAlternateScroll(enable); break; @@ -2092,7 +2112,6 @@ bool AdaptDispatch::EnableButtonEventMouseMode(const bool enabled) //Routine Description: // Enable Any Event mode - send all mouse events to the input. - //Arguments: // - enabled - true to enable, false to disable. // Return value: @@ -2102,6 +2121,21 @@ bool AdaptDispatch::EnableAnyEventMouseMode(const bool enabled) return _SetInputMode(TerminalInput::Mode::AnyEventMouseTracking, enabled); } +// Method Description: +// - Enables/disables focus event mode. A client may enable this if they want to +// receive focus events. +// - ConPTY always enables this mode and never disables it. Internally, we'll +// always set this mode, but conpty will never request this to be disabled by +// the hosting terminal. +// Arguments: +// - enabled - true to enable, false to disable. +// Return Value: +// - True if handled successfully. False otherwise. +bool AdaptDispatch::EnableFocusEventMode(const bool enabled) +{ + return _SetInputMode(TerminalInput::Mode::FocusEvent, enabled); +} + //Routine Description: // Enable Alternate Scroll Mode - When in the Alt Buffer, send CUP and CUD on // scroll up/down events instead of the usual sequences diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index becb3180247..3cf677b1947 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -107,6 +107,7 @@ namespace Microsoft::Console::VirtualTerminal bool EnableSGRExtendedMouseMode(const bool enabled) override; // ?1006 bool EnableButtonEventMouseMode(const bool enabled) override; // ?1002 bool EnableAnyEventMouseMode(const bool enabled) override; // ?1003 + bool EnableFocusEventMode(const bool enabled) override; // ?1004 bool EnableAlternateScroll(const bool enabled) override; // ?1007 bool EnableXtermBracketedPasteMode(const bool enabled) noexcept override; // ?2004 bool SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) override; // DECSCUSR diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index 01e9ed20830..386d1ced717 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -72,6 +72,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool EnableSGRExtendedMouseMode(const bool /*enabled*/) override { return false; } // ?1006 bool EnableButtonEventMouseMode(const bool /*enabled*/) override { return false; } // ?1002 bool EnableAnyEventMouseMode(const bool /*enabled*/) override { return false; } // ?1003 + bool EnableFocusEventMode(const bool /*enabled*/) override { return false; } // ?1004 bool EnableAlternateScroll(const bool /*enabled*/) override { return false; } // ?1007 bool EnableXtermBracketedPasteMode(const bool /*enabled*/) override { return false; } // ?2004 bool SetColorTableEntry(const size_t /*tableIndex*/, const DWORD /*color*/) override { return false; } // OSCColorTable diff --git a/src/terminal/input/terminalInput.cpp b/src/terminal/input/terminalInput.cpp index 1408ad56cbd..1210432c6d6 100644 --- a/src/terminal/input/terminalInput.cpp +++ b/src/terminal/input/terminalInput.cpp @@ -522,6 +522,14 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) return false; } + // GH#11682: If this was a focus event, we can handle this. Steal the + // focused state, and return true if we're actually in focus event mode. + if (pInEvent->EventType() == InputEventType::FocusEvent) + { + const auto& focusEvent = *static_cast(pInEvent); + return HandleFocus(focusEvent.GetFocus()); + } + // On key presses, prepare to translate to VT compatible sequences if (pInEvent->EventType() != InputEventType::KeyEvent) { @@ -674,6 +682,16 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) return false; } +bool TerminalInput::HandleFocus(const bool focused) noexcept +{ + const bool enabled{ _inputMode.test(Mode::FocusEvent) }; + if (enabled) + { + _SendInputSequence(focused ? L"\x1b[I" : L"\x1b[O"); + } + return enabled; +} + // Routine Description: // - Sends the given character to the shell. // - Surrogate pairs are being aggregated by this function before being sent. diff --git a/src/terminal/input/terminalInput.hpp b/src/terminal/input/terminalInput.hpp index 0093269cbce..8f0ac5dcbee 100644 --- a/src/terminal/input/terminalInput.hpp +++ b/src/terminal/input/terminalInput.hpp @@ -34,6 +34,7 @@ namespace Microsoft::Console::VirtualTerminal ~TerminalInput() = default; bool HandleKey(const IInputEvent* const pInEvent); + bool HandleFocus(const bool focused) noexcept; enum class Mode : size_t { @@ -49,6 +50,8 @@ namespace Microsoft::Console::VirtualTerminal ButtonEventMouseTracking, AnyEventMouseTracking, + FocusEvent, + AlternateScroll }; From fa25dfbf7ab0fac00fc0dbf953ae9d4c5000258a Mon Sep 17 00:00:00 2001 From: dansmor7 <101892345+dansmor7@users.noreply.github.com> Date: Thu, 21 Apr 2022 15:34:55 -0700 Subject: [PATCH 5/5] Misc visual fixes (#12916) Fixed various small issues: * Made TabView bottom border span the entire window width * Made ScrollBar inner thumb rounded again * Made SplitButton look more like the new add tab button * Adjusted rename box height (24px, like the official compact sizing height) * Adjusted caption button colors to match Windows 11 * ColorPicker can now escape window bounds * Tweaked ColorPicker buttons --- src/cascadia/TerminalApp/App.xaml | 2 +- .../TerminalApp/ColorPickupFlyout.cpp | 3 +- .../TerminalApp/ColorPickupFlyout.xaml | 224 ++++++++++-------- .../TerminalApp/MinMaxCloseControl.xaml | 30 ++- .../TerminalApp/TabHeaderControl.xaml | 20 +- src/cascadia/TerminalApp/TabRowControl.xaml | 166 +++++++------ src/cascadia/TerminalApp/TerminalPage.xaml | 3 + src/cascadia/TerminalApp/TitlebarControl.xaml | 7 + src/cascadia/TerminalControl/TermControl.xaml | 7 +- 9 files changed, 242 insertions(+), 220 deletions(-) diff --git a/src/cascadia/TerminalApp/App.xaml b/src/cascadia/TerminalApp/App.xaml index 1ddf3e82b0b..eb9e6b6b7fb 100644 --- a/src/cascadia/TerminalApp/App.xaml +++ b/src/cascadia/TerminalApp/App.xaml @@ -46,7 +46,7 @@ Color="{ThemeResource SystemErrorTextColor}" /> - 9,0,8,0 + 9,0,5,0 12 diff --git a/src/cascadia/TerminalApp/ColorPickupFlyout.cpp b/src/cascadia/TerminalApp/ColorPickupFlyout.cpp index 3f83899467d..a12160afb2e 100644 --- a/src/cascadia/TerminalApp/ColorPickupFlyout.cpp +++ b/src/cascadia/TerminalApp/ColorPickupFlyout.cpp @@ -34,8 +34,7 @@ namespace winrt::TerminalApp::implementation void ColorPickupFlyout::ColorButton_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const&) { auto button{ sender.as() }; - auto rectangle{ button.Content().as() }; - auto rectClr{ rectangle.Fill().as() }; + auto rectClr{ button.Background().as() }; _ColorSelectedHandlers(rectClr.Color()); Hide(); } diff --git a/src/cascadia/TerminalApp/ColorPickupFlyout.xaml b/src/cascadia/TerminalApp/ColorPickupFlyout.xaml index b7da875af4b..26fbb107c58 100644 --- a/src/cascadia/TerminalApp/ColorPickupFlyout.xaml +++ b/src/cascadia/TerminalApp/ColorPickupFlyout.xaml @@ -5,6 +5,8 @@ xmlns:local="using:TerminalApp" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:muxc="using:Microsoft.UI.Xaml.Controls" + Placement="Bottom" + ShouldConstrainToRootBounds="False" mc:Ignorable="d"> - +