diff --git a/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp b/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp index 0a9bd6734..ec2ef86d1 100644 --- a/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp +++ b/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp @@ -303,7 +303,7 @@ void ConptyRoundtripTests::_resizeConpty(const unsigned short sx, void ConptyRoundtripTests::_clearConpty() { // Taken verbatim from implementation in PtySignalInputThread::_DoClearBuffer - _pConApi->PrivateClearBuffer(); + _pConApi->ClearBuffer(); } [[nodiscard]] std::tuple ConptyRoundtripTests::_performResize(const til::size newSize) diff --git a/src/host/PtySignalInputThread.cpp b/src/host/PtySignalInputThread.cpp index 16b330085..2873fd2a3 100644 --- a/src/host/PtySignalInputThread.cpp +++ b/src/host/PtySignalInputThread.cpp @@ -145,7 +145,7 @@ void PtySignalInputThread::_DoResizeWindow(const ResizeWindowData& data) void PtySignalInputThread::_DoClearBuffer() { - _pConApi->PrivateClearBuffer(); + _pConApi->ClearBuffer(); } // Method Description: diff --git a/src/host/cmdline.h b/src/host/cmdline.h index 3285952b1..5927c002f 100644 --- a/src/host/cmdline.h +++ b/src/host/cmdline.h @@ -148,8 +148,6 @@ void RedrawCommandLine(COOKED_READ_DATA& cookedReadData); bool IsWordDelim(const wchar_t wch); bool IsWordDelim(const std::wstring_view charData); -[[nodiscard]] HRESULT DoSrvSetConsoleTitleW(const std::wstring_view title) noexcept; - bool IsValidStringBuffer(_In_ bool Unicode, _In_reads_bytes_(Size) PVOID Buffer, _In_ ULONG Size, _In_ ULONG Count, ...); void SetCurrentCommandLine(COOKED_READ_DATA& cookedReadData, _In_ SHORT Index); diff --git a/src/host/directio.cpp b/src/host/directio.cpp index 760a7ecf7..dd0601566 100644 --- a/src/host/directio.cpp +++ b/src/host/directio.cpp @@ -443,24 +443,6 @@ void EventsToUnicode(_Inout_ std::deque>& inEvents, CATCH_RETURN(); } -// Routine Description: -// - Writes events to the input buffer already formed into IInputEvents (private call) -// Arguments: -// - context - the input buffer to write to -// - events - the events to written -// - written - on output, the number of events written -// - append - true if events should be written to the end of the input -// buffer, false if they should be written to the front -// Return Value: -// - HRESULT indicating success or failure -[[nodiscard]] HRESULT DoSrvPrivateWriteConsoleInputW(_Inout_ InputBuffer* const pInputBuffer, - _Inout_ std::deque>& events, - _Out_ size_t& eventsWritten, - const bool append) noexcept -{ - return _WriteConsoleInputWImplHelper(*pInputBuffer, events, eventsWritten, append); -} - // Routine Description: // - Writes events to the input buffer, translating from codepage to unicode first // Arguments: @@ -534,32 +516,6 @@ void EventsToUnicode(_Inout_ std::deque>& inEvents, CATCH_RETURN(); } -// Function Description: -// - Writes the input KeyEvent to the console as a console control event. This -// can be used for potentially generating Ctrl-C events, as -// HandleGenericKeyEvent will correctly generate the Ctrl-C response in -// the same way that it'd be handled from the window proc, with the proper -// processed vs raw input handling. -// If the input key is *not* a Ctrl-C key, then it will get written to the -// buffer just the same as any other KeyEvent. -// Arguments: -// - pInputBuffer - the input buffer to write to. Currently unused, as -// HandleGenericKeyEvent just gets the global input buffer, but all -// ConGetSet API's require an input or output object. -// - key - The keyevent to send to the console. -// Return Value: -// - HRESULT indicating success or failure -[[nodiscard]] HRESULT DoSrvPrivateWriteConsoleControlInput(_Inout_ InputBuffer* const /*pInputBuffer*/, - _In_ KeyEvent key) -{ - LockConsole(); - auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); - - HandleGenericKeyEvent(key, false); - - return S_OK; -} - // Routine Description: // - This is used when the app is reading output as cells and needs them converted // into a particular codepage on the way out. diff --git a/src/host/directio.h b/src/host/directio.h index e33d980a8..e8cd977d5 100644 --- a/src/host/directio.h +++ b/src/host/directio.h @@ -21,15 +21,7 @@ Revision History: class SCREEN_INFORMATION; -[[nodiscard]] HRESULT DoSrvPrivateWriteConsoleInputW(_Inout_ InputBuffer* const pInputBuffer, - _Inout_ std::deque>& events, - _Out_ size_t& eventsWritten, - const bool append) noexcept; - [[nodiscard]] NTSTATUS ConsoleCreateScreenBuffer(std::unique_ptr& handle, _In_ PCONSOLE_API_MSG Message, _In_ PCD_CREATE_OBJECT_INFORMATION Information, _In_ PCONSOLE_CREATESCREENBUFFER_MSG a); - -[[nodiscard]] NTSTATUS DoSrvPrivateWriteConsoleControlInput(_Inout_ InputBuffer* const pInputBuffer, - _In_ KeyEvent key); diff --git a/src/host/getset.cpp b/src/host/getset.cpp index 0e18bddeb..d95e4e13e 100644 --- a/src/host/getset.cpp +++ b/src/host/getset.cpp @@ -1059,12 +1059,6 @@ void ApiRoutines::GetConsoleInputCodePageImpl(ULONG& codepage) noexcept CATCH_LOG(); } -void DoSrvGetConsoleOutputCodePage(unsigned int& codepage) -{ - const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - codepage = gci.OutputCP; -} - // Routine Description: // - Gets the codepage used for translating text when calling A versions of functions affecting the output buffer. // Arguments: @@ -1075,9 +1069,8 @@ void ApiRoutines::GetConsoleOutputCodePageImpl(ULONG& codepage) noexcept { LockConsole(); auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); - unsigned int cp; - DoSrvGetConsoleOutputCodePage(cp); - codepage = cp; + const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); + codepage = gci.OutputCP; } CATCH_LOG(); } @@ -1247,289 +1240,6 @@ void ApiRoutines::GetConsoleDisplayModeImpl(ULONG& flags) noexcept CATCH_RETURN(); } -// Routine Description: -// - A private API call for setting the ENABLE_WRAP_AT_EOL_OUTPUT mode. -// This controls whether the cursor moves to the beginning of the next row -// when it reaches the end of the current row. -// Parameters: -// - wrapAtEOL - set to true to wrap, false to overwrite the last character. -// Return value: -// - STATUS_SUCCESS if handled successfully. -[[nodiscard]] NTSTATUS DoSrvPrivateSetAutoWrapMode(const bool wrapAtEOL) -{ - auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - auto& outputMode = gci.GetActiveOutputBuffer().GetActiveBuffer().OutputMode; - WI_UpdateFlag(outputMode, ENABLE_WRAP_AT_EOL_OUTPUT, wrapAtEOL); - return STATUS_SUCCESS; -} - -// Routine Description: -// - A private API call for making the cursor visible or not. Does not modify -// blinking state. -// Parameters: -// - show - set to true to make the cursor visible, false to hide. -// Return value: -// - -void DoSrvPrivateShowCursor(SCREEN_INFORMATION& screenInfo, const bool show) noexcept -{ - screenInfo.GetActiveBuffer().GetTextBuffer().GetCursor().SetIsVisible(show); -} - -// Routine Description: -// - A private API call for enabling or disabling the cursor blinking. -// Parameters: -// - fEnable - set to true to enable blinking, false to disable -// Return value: -// - True if handled successfully. False otherwise. -void DoSrvPrivateAllowCursorBlinking(SCREEN_INFORMATION& screenInfo, const bool fEnable) -{ - screenInfo.GetActiveBuffer().GetTextBuffer().GetCursor().SetBlinkingAllowed(fEnable); - - // GH#2642 - From what we've gathered from other terminals, when blinking is - // disabled, the cursor should remain On always, and have the visibility - // controlled by the IsVisible property. So when you do a printf "\e[?12l" - // to disable blinking, the cursor stays stuck On. At this point, only the - // cursor visibility property controls whether the user can see it or not. - // (Yes, the cursor can be On and NOT Visible) - screenInfo.GetActiveBuffer().GetTextBuffer().GetCursor().SetIsOn(true); -} - -// Routine Description: -// - A private API call for setting the top and bottom scrolling margins for -// the current page. This creates a subsection of the screen that scrolls -// when input reaches the end of the region, leaving the rest of the screen -// untouched. -// Currently only accessible through the use of ANSI sequence DECSTBM -// Parameters: -// - scrollMargins - A rect who's Top and Bottom members will be used to set -// the new values of the top and bottom margins. If (0,0), then the margins -// will be disabled. NOTE: This is a rect in the case that we'll need the -// left and right margins in the future. -// Return value: -// - True if handled successfully. False otherwise. -[[nodiscard]] NTSTATUS DoSrvPrivateSetScrollingRegion(SCREEN_INFORMATION& screenInfo, const SMALL_RECT& scrollMargins) -{ - NTSTATUS Status = STATUS_SUCCESS; - - if (scrollMargins.Top > scrollMargins.Bottom) - { - Status = STATUS_INVALID_PARAMETER; - } - if (NT_SUCCESS(Status)) - { - SMALL_RECT srScrollMargins = screenInfo.GetRelativeScrollMargins().ToInclusive(); - srScrollMargins.Top = scrollMargins.Top; - srScrollMargins.Bottom = scrollMargins.Bottom; - screenInfo.GetActiveBuffer().SetScrollMargins(Viewport::FromInclusive(srScrollMargins)); - } - - return Status; -} - -// Routine Description: -// - A private API call for performing a line feed, possibly preceded by carriage return. -// Moves the cursor down one line, and possibly also to the leftmost column. -// Parameters: -// - screenInfo - A pointer to the screen buffer that should perform the line feed. -// - withReturn - Set to true if a carriage return should be performed as well. -// Return value: -// - STATUS_SUCCESS if handled successfully. Otherwise, an appropriate status code indicating the error. -[[nodiscard]] NTSTATUS DoSrvPrivateLineFeed(SCREEN_INFORMATION& screenInfo, const bool withReturn) -{ - auto& textBuffer = screenInfo.GetTextBuffer(); - auto cursorPosition = textBuffer.GetCursor().GetPosition(); - - // We turn the cursor on before an operation that might scroll the viewport, otherwise - // that can result in an old copy of the cursor being left behind on the screen. - textBuffer.GetCursor().SetIsOn(true); - - // Since we are explicitly moving down a row, clear the wrap status on the row we're leaving - textBuffer.GetRowByOffset(cursorPosition.Y).SetWrapForced(false); - - cursorPosition.Y += 1; - if (withReturn) - { - cursorPosition.X = 0; - } - else - { - cursorPosition = textBuffer.ClampPositionWithinLine(cursorPosition); - } - - return AdjustCursorPosition(screenInfo, cursorPosition, FALSE, nullptr); -} - -// Routine Description: -// - A private API call for performing a "Reverse line feed", essentially, the opposite of '\n'. -// Moves the cursor up one line, and tries to keep its position in the line -// Parameters: -// - screenInfo - a pointer to the screen buffer that should perform the reverse line feed -// Return value: -// - True if handled successfully. False otherwise. -[[nodiscard]] NTSTATUS DoSrvPrivateReverseLineFeed(SCREEN_INFORMATION& screenInfo) -{ - NTSTATUS Status = STATUS_SUCCESS; - - const SMALL_RECT viewport = screenInfo.GetActiveBuffer().GetViewport().ToInclusive(); - const COORD oldCursorPosition = screenInfo.GetTextBuffer().GetCursor().GetPosition(); - COORD newCursorPosition = { oldCursorPosition.X, oldCursorPosition.Y - 1 }; - newCursorPosition = screenInfo.GetTextBuffer().ClampPositionWithinLine(newCursorPosition); - - // If the cursor is at the top of the viewport, we don't want to shift the viewport up. - // We want it to stay exactly where it is. - // In that case, shift the buffer contents down, to emulate inserting a line - // at the top of the buffer. - if (oldCursorPosition.Y > viewport.Top) - { - // Cursor is below the top line of the viewport - Status = AdjustCursorPosition(screenInfo, newCursorPosition, TRUE, nullptr); - } - else - { - // If we don't have margins, or the cursor is within the boundaries of the margins - // It's important to check if the cursor is in the margins, - // If it's not, but the margins are set, then we don't want to scroll anything - if (screenInfo.IsCursorInMargins(oldCursorPosition)) - { - // Cursor is at the top of the viewport - // Rectangle to cut out of the existing buffer. This is inclusive. - // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. - SMALL_RECT srScroll; - srScroll.Left = 0; - srScroll.Right = SHORT_MAX; - srScroll.Top = viewport.Top; - srScroll.Bottom = viewport.Bottom; - // Clip to the DECSTBM margin boundary - if (screenInfo.AreMarginsSet()) - { - srScroll.Bottom = screenInfo.GetAbsoluteScrollMargins().BottomInclusive(); - } - // Paste coordinate for cut text above - COORD coordDestination; - coordDestination.X = 0; - coordDestination.Y = viewport.Top + 1; - - // Note the revealed lines are filled with the standard erase attributes. - Status = NTSTATUS_FROM_HRESULT(DoSrvPrivateScrollRegion(screenInfo, - srScroll, - srScroll, - coordDestination, - true)); - } - } - return Status; -} - -// Routine Description: -// - A private API call for swapping to the alternate screen buffer. In virtual terminals, there exists both a "main" -// screen buffer and an alternate. ASBSET creates a new alternate, and switches to it. If there is an already -// existing alternate, it is discarded. -// Parameters: -// - screenInfo - a reference to the screen buffer that should use an alternate buffer -// Return value: -// - True if handled successfully. False otherwise. -[[nodiscard]] NTSTATUS DoSrvPrivateUseAlternateScreenBuffer(SCREEN_INFORMATION& screenInfo) -{ - return screenInfo.GetActiveBuffer().UseAlternateScreenBuffer(); -} - -// Routine Description: -// - A private API call for swapping to the main screen buffer. From the -// alternate buffer, returns to the main screen buffer. From the main -// screen buffer, does nothing. The alternate is discarded. -// Parameters: -// - screenInfo - a reference to the screen buffer that should use the main buffer -// Return value: -// - True if handled successfully. False otherwise. -void DoSrvPrivateUseMainScreenBuffer(SCREEN_INFORMATION& screenInfo) -{ - screenInfo.GetActiveBuffer().UseMainScreenBuffer(); -} - -// Routine Description: -// - A private API call for performing a VT-style erase all operation on the buffer. -// See SCREEN_INFORMATION::VtEraseAll's description for details. -// Parameters: -// The ScreenBuffer to perform the erase on. -// Return value: -// - S_OK if we succeeded, otherwise the HRESULT of the failure. -[[nodiscard]] HRESULT DoSrvPrivateEraseAll(SCREEN_INFORMATION& screenInfo) -{ - return screenInfo.GetActiveBuffer().VtEraseAll(); -} - -// See SCREEN_INFORMATION::ClearBuffer's description for details. -[[nodiscard]] HRESULT DoSrvPrivateClearBuffer(SCREEN_INFORMATION& screenInfo) -{ - return screenInfo.GetActiveBuffer().ClearBuffer(); -} - -void DoSrvSetCursorStyle(SCREEN_INFORMATION& screenInfo, - const CursorType cursorType) -{ - screenInfo.GetActiveBuffer().GetTextBuffer().GetCursor().SetType(cursorType); -} - -void DoSrvAddHyperlink(SCREEN_INFORMATION& screenInfo, - const std::wstring_view uri, - const std::wstring_view params) -{ - auto attr = screenInfo.GetAttributes(); - const auto id = screenInfo.GetTextBuffer().GetHyperlinkId(uri, params); - attr.SetHyperlinkId(id); - screenInfo.GetTextBuffer().SetCurrentAttributes(attr); - screenInfo.GetTextBuffer().AddHyperlinkToMap(uri, id); -} - -void DoSrvEndHyperlink(SCREEN_INFORMATION& screenInfo) -{ - auto attr = screenInfo.GetAttributes(); - attr.SetHyperlinkId(0); - screenInfo.GetTextBuffer().SetCurrentAttributes(attr); -} - -// Routine Description: -// - A private API call for updating the active soft font. -// Arguments: -// - bitPattern - An array of scanlines representing all the glyphs in the font. -// - cellSize - The cell size for an individual glyph. -// - centeringHint - The horizontal extent that glyphs are offset from center. -// Return Value: -// - S_OK if we succeeded, otherwise the HRESULT of the failure. -[[nodiscard]] HRESULT DoSrvUpdateSoftFont(const gsl::span bitPattern, - const SIZE cellSize, - const size_t centeringHint) noexcept -{ - try - { - auto* pRender = ServiceLocator::LocateGlobals().pRender; - if (pRender) - { - pRender->UpdateSoftFont(bitPattern, cellSize, centeringHint); - } - return S_OK; - } - CATCH_RETURN(); -} - -// Routine Description: -// - A private API call for forcing the renderer to repaint the screen. If the -// input screen buffer is not the active one, then just do nothing. We only -// want to redraw the screen buffer that requested the repaint, and -// switching screen buffers will already force a repaint. -// Parameters: -// The ScreenBuffer to perform the repaint for. -// Return value: -// - None -void DoSrvPrivateRefreshWindow(_In_ const SCREEN_INFORMATION& screenInfo) -{ - Globals& g = ServiceLocator::LocateGlobals(); - if (&screenInfo == &g.getConsoleInformation().GetActiveOutputBuffer().GetActiveBuffer()) - { - g.pRender->TriggerRedrawAll(); - } -} - // Routine Description: // - Gets title information from the console. It can be truncated if the buffer is too small. // Arguments: @@ -1792,219 +1502,6 @@ void DoSrvPrivateRefreshWindow(_In_ const SCREEN_INFORMATION& screenInfo) LockConsole(); auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); - return DoSrvSetConsoleTitleW(title); -} - -[[nodiscard]] HRESULT DoSrvSetConsoleTitleW(const std::wstring_view title) noexcept -{ - CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - gci.SetTitle(title); + ServiceLocator::LocateGlobals().getConsoleInformation().SetTitle(title); return S_OK; } - -// Routine Description: -// - A private API call for forcing the VT Renderer to NOT paint the next resize -// event. This is used by InteractDispatch, to prevent resizes from echoing -// between terminal and host. -// Parameters: -// -// Return value: -// - STATUS_SUCCESS if we succeeded, otherwise the NTSTATUS version of the failure. -[[nodiscard]] NTSTATUS DoSrvPrivateSuppressResizeRepaint() -{ - CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - FAIL_FAST_IF(!(gci.IsInVtIoMode())); - return NTSTATUS_FROM_HRESULT(gci.GetVtIo()->SuppressResizeRepaint()); -} - -// Routine Description: -// - An API call for checking if the console host is acting as a pty. -// Parameters: -// - isPty: receives the bool indicating whether or not we're in pty mode. -// Return value: -// -void DoSrvIsConsolePty(bool& isPty) -{ - const CONSOLE_INFORMATION& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - isPty = gci.IsInVtIoMode(); -} - -// Routine Description: -// - internal logic for adding or removing lines in the active screen buffer -// this also moves the cursor to the left margin, which is expected behavior for IL and DL -// Parameters: -// - count - the number of lines to modify -// - insert - true if inserting lines, false if deleting lines -void DoSrvPrivateModifyLinesImpl(const size_t count, const bool insert) -{ - auto& screenInfo = ServiceLocator::LocateGlobals().getConsoleInformation().GetActiveOutputBuffer().GetActiveBuffer(); - auto& textBuffer = screenInfo.GetTextBuffer(); - const auto cursorPosition = textBuffer.GetCursor().GetPosition(); - if (screenInfo.IsCursorInMargins(cursorPosition)) - { - // Rectangle to cut out of the existing buffer. This is inclusive. - // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. - SMALL_RECT srScroll; - srScroll.Left = 0; - srScroll.Right = SHORT_MAX; - srScroll.Top = cursorPosition.Y; - srScroll.Bottom = screenInfo.GetViewport().BottomInclusive(); - // Clip to the DECSTBM margin boundary - if (screenInfo.AreMarginsSet()) - { - srScroll.Bottom = screenInfo.GetAbsoluteScrollMargins().BottomInclusive(); - } - // Paste coordinate for cut text above - COORD coordDestination; - coordDestination.X = 0; - if (insert) - { - coordDestination.Y = (cursorPosition.Y) + gsl::narrow(count); - } - else - { - coordDestination.Y = (cursorPosition.Y) - gsl::narrow(count); - } - - // Note the revealed lines are filled with the standard erase attributes. - LOG_IF_FAILED(DoSrvPrivateScrollRegion(screenInfo, - srScroll, - srScroll, - coordDestination, - true)); - - // The IL and DL controls are also expected to move the cursor to the left margin. - // For now this is just column 0, since we don't yet support DECSLRM. - LOG_IF_NTSTATUS_FAILED(screenInfo.SetCursorPosition({ 0, cursorPosition.Y }, false)); - } -} - -// Routine Description: -// - a private API call for deleting lines in the active screen buffer. -// Parameters: -// - count - the number of lines to delete -void DoSrvPrivateDeleteLines(const size_t count) -{ - DoSrvPrivateModifyLinesImpl(count, false); -} - -// Routine Description: -// - a private API call for inserting lines in the active screen buffer. -// Parameters: -// - count - the number of lines to insert -void DoSrvPrivateInsertLines(const size_t count) -{ - DoSrvPrivateModifyLinesImpl(count, true); -} - -// Method Description: -// - Snaps the screen buffer's viewport to the "virtual bottom", the last place -//the viewport was before the user scrolled it (with the mouse or scrollbar) -// Arguments: -// - screenInfo: the buffer to move the viewport for. -// Return Value: -// - -void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo) -{ - screenInfo.GetActiveBuffer().MoveToBottom(); -} - -// Routine Description: -// - A private API call for filling a region of the screen buffer. -// Arguments: -// - screenInfo - Reference to screen buffer info. -// - startPosition - The position to begin filling at. -// - fillLength - The number of characters to fill. -// - fillChar - Character to fill the target region with. -// - standardFillAttrs - If true, fill with the standard erase attributes. -// If false, fill with the default attributes. -// Return value: -// - S_OK or failure code from thrown exception -[[nodiscard]] HRESULT DoSrvPrivateFillRegion(SCREEN_INFORMATION& screenInfo, - const COORD startPosition, - const size_t fillLength, - const wchar_t fillChar, - const bool standardFillAttrs) noexcept -{ - try - { - if (fillLength == 0) - { - return S_OK; - } - - LockConsole(); - auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); - - // For most VT erasing operations, the standard requires that the - // erased area be filled with the current background color, but with - // no additional meta attributes set. For all other cases, we just - // fill with the default attributes. - auto fillAttrs = TextAttribute{}; - if (standardFillAttrs) - { - fillAttrs = screenInfo.GetAttributes(); - fillAttrs.SetStandardErase(); - } - - const auto fillData = OutputCellIterator{ fillChar, fillAttrs, fillLength }; - screenInfo.Write(fillData, startPosition, false); - - // Notify accessibility - if (screenInfo.HasAccessibilityEventing()) - { - auto endPosition = startPosition; - const auto bufferSize = screenInfo.GetBufferSize(); - bufferSize.MoveInBounds(fillLength - 1, endPosition); - screenInfo.NotifyAccessibilityEventing(startPosition.X, startPosition.Y, endPosition.X, endPosition.Y); - } - - return S_OK; - } - CATCH_RETURN(); -} - -// Routine Description: -// - A private API call for moving a block of data in the screen buffer, -// optionally limiting the effects of the move to a clipping rectangle. -// Arguments: -// - screenInfo - Reference to screen buffer info. -// - scrollRect - Region to copy/move (source and size). -// - clipRect - Optional clip region to contain buffer change effects. -// - destinationOrigin - Upper left corner of target region. -// - standardFillAttrs - If true, fill with the standard erase attributes. -// If false, fill with the default attributes. -// Return value: -// - S_OK or failure code from thrown exception -[[nodiscard]] HRESULT DoSrvPrivateScrollRegion(SCREEN_INFORMATION& screenInfo, - const SMALL_RECT scrollRect, - const std::optional clipRect, - const COORD destinationOrigin, - const bool standardFillAttrs) noexcept -{ - try - { - LockConsole(); - auto Unlock = wil::scope_exit([&] { UnlockConsole(); }); - - // For most VT scrolling operations, the standard requires that the - // erased area be filled with the current background color, but with - // no additional meta attributes set. For all other cases, we just - // fill with the default attributes. - auto fillAttrs = TextAttribute{}; - if (standardFillAttrs) - { - fillAttrs = screenInfo.GetAttributes(); - fillAttrs.SetStandardErase(); - } - - ScrollRegion(screenInfo, - scrollRect, - clipRect, - destinationOrigin, - UNICODE_SPACE, - fillAttrs); - return S_OK; - } - CATCH_RETURN(); -} diff --git a/src/host/getset.h b/src/host/getset.h index 873d46617..4c042813c 100644 --- a/src/host/getset.h +++ b/src/host/getset.h @@ -18,56 +18,4 @@ Revision History: #include "../inc/conattrs.hpp" class SCREEN_INFORMATION; -[[nodiscard]] NTSTATUS DoSrvPrivateSetAutoWrapMode(const bool wrapAtEOL); - -void DoSrvPrivateShowCursor(SCREEN_INFORMATION& screenInfo, const bool show) noexcept; -void DoSrvPrivateAllowCursorBlinking(SCREEN_INFORMATION& screenInfo, const bool fEnable); - -[[nodiscard]] NTSTATUS DoSrvPrivateSetScrollingRegion(SCREEN_INFORMATION& screenInfo, const SMALL_RECT& scrollMargins); -[[nodiscard]] NTSTATUS DoSrvPrivateLineFeed(SCREEN_INFORMATION& screenInfo, const bool withReturn); -[[nodiscard]] NTSTATUS DoSrvPrivateReverseLineFeed(SCREEN_INFORMATION& screenInfo); - -[[nodiscard]] NTSTATUS DoSrvPrivateUseAlternateScreenBuffer(SCREEN_INFORMATION& screenInfo); -void DoSrvPrivateUseMainScreenBuffer(SCREEN_INFORMATION& screenInfo); - -[[nodiscard]] HRESULT DoSrvPrivateEraseAll(SCREEN_INFORMATION& screenInfo); -[[nodiscard]] HRESULT DoSrvPrivateClearBuffer(SCREEN_INFORMATION& screenInfo); - -void DoSrvSetCursorStyle(SCREEN_INFORMATION& screenInfo, - const CursorType cursorType); - -void DoSrvAddHyperlink(SCREEN_INFORMATION& screenInfo, - const std::wstring_view uri, - const std::wstring_view params); - -void DoSrvEndHyperlink(SCREEN_INFORMATION& screenInfo); - -[[nodiscard]] HRESULT DoSrvUpdateSoftFont(const gsl::span bitPattern, - const SIZE cellSize, - const size_t centeringHint) noexcept; - -void DoSrvPrivateRefreshWindow(const SCREEN_INFORMATION& screenInfo); - [[nodiscard]] HRESULT DoSrvSetConsoleOutputCodePage(const unsigned int codepage); -void DoSrvGetConsoleOutputCodePage(unsigned int& codepage); - -[[nodiscard]] NTSTATUS DoSrvPrivateSuppressResizeRepaint(); - -void DoSrvIsConsolePty(bool& isPty); - -void DoSrvPrivateDeleteLines(const size_t count); -void DoSrvPrivateInsertLines(const size_t count); - -void DoSrvPrivateMoveToBottom(SCREEN_INFORMATION& screenInfo); - -[[nodiscard]] HRESULT DoSrvPrivateFillRegion(SCREEN_INFORMATION& screenInfo, - const COORD startPosition, - const size_t fillLength, - const wchar_t fillChar, - const bool standardFillAttrs) noexcept; - -[[nodiscard]] HRESULT DoSrvPrivateScrollRegion(SCREEN_INFORMATION& screenInfo, - const SMALL_RECT scrollRect, - const std::optional clipRect, - const COORD destinationOrigin, - const bool standardFillAttrs) noexcept; diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index 683874e06..f82eefe67 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -8,6 +8,7 @@ #include "_stream.h" #include "getset.h" #include "directio.h" +#include "output.h" #include "../interactivity/inc/ServiceLocator.hpp" @@ -109,11 +110,10 @@ ConhostInternalGetSet::ConhostInternalGetSet(_In_ IIoProvider& io) : // Arguments: // - screenBufferInfo - Structure to hold screen buffer information like the public API call. // Return Value: -// - true if successful (see DoSrvGetConsoleScreenBufferInfo). false otherwise. -bool ConhostInternalGetSet::GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const +// - +void ConhostInternalGetSet::GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const { ServiceLocator::LocateGlobals().api.GetConsoleScreenBufferInfoExImpl(_io.GetActiveOutputBuffer(), screenBufferInfo); - return true; } // Routine Description: @@ -121,35 +121,34 @@ bool ConhostInternalGetSet::GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_I // Arguments: // - screenBufferInfo - Structure containing screen buffer information like the public API call. // Return Value: -// - true if successful (see DoSrvSetConsoleScreenBufferInfo). false otherwise. -bool ConhostInternalGetSet::SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) +// - +void ConhostInternalGetSet::SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) { - return SUCCEEDED(ServiceLocator::LocateGlobals().api.SetConsoleScreenBufferInfoExImpl(_io.GetActiveOutputBuffer(), screenBufferInfo)); + THROW_IF_FAILED(ServiceLocator::LocateGlobals().api.SetConsoleScreenBufferInfoExImpl(_io.GetActiveOutputBuffer(), screenBufferInfo)); } // Routine Description: -// - Connects the SetConsoleCursorPosition API call directly into our Driver Message servicing call inside Conhost.exe +// - Connects the SetCursorPosition API call directly into our Driver Message servicing call inside Conhost.exe // Arguments: // - position - new cursor position to set like the public API call. // Return Value: -// - true if successful (see DoSrvSetConsoleCursorPosition). false otherwise. -bool ConhostInternalGetSet::SetConsoleCursorPosition(const COORD position) +// - +void ConhostInternalGetSet::SetCursorPosition(const COORD position) { auto& info = _io.GetActiveOutputBuffer(); const auto clampedPosition = info.GetTextBuffer().ClampPositionWithinLine(position); - return SUCCEEDED(ServiceLocator::LocateGlobals().api.SetConsoleCursorPositionImpl(info, clampedPosition)); + THROW_IF_FAILED(ServiceLocator::LocateGlobals().api.SetConsoleCursorPositionImpl(info, clampedPosition)); } // Method Description: // - Retrieves the current TextAttribute of the active screen buffer. // Arguments: -// - attrs: Receives the TextAttribute value. +// - // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::PrivateGetTextAttributes(TextAttribute& attrs) const +// - the TextAttribute value. +TextAttribute ConhostInternalGetSet::GetTextAttributes() const { - attrs = _io.GetActiveOutputBuffer().GetAttributes(); - return true; + return _io.GetActiveOutputBuffer().GetAttributes(); } // Method Description: @@ -158,11 +157,10 @@ bool ConhostInternalGetSet::PrivateGetTextAttributes(TextAttribute& attrs) const // Arguments: // - attrs: The new TextAttribute to use // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::PrivateSetTextAttributes(const TextAttribute& attrs) +// - +void ConhostInternalGetSet::SetTextAttributes(const TextAttribute& attrs) { _io.GetActiveOutputBuffer().SetAttributes(attrs); - return true; } // Method Description: @@ -171,12 +169,11 @@ bool ConhostInternalGetSet::PrivateSetTextAttributes(const TextAttribute& attrs) // Arguments: // - lineRendition: The new LineRendition attribute to use // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::PrivateSetCurrentLineRendition(const LineRendition lineRendition) +// - +void ConhostInternalGetSet::SetCurrentLineRendition(const LineRendition lineRendition) { auto& textBuffer = _io.GetActiveOutputBuffer().GetTextBuffer(); textBuffer.SetCurrentLineRendition(lineRendition); - return true; } // Method Description: @@ -186,12 +183,11 @@ bool ConhostInternalGetSet::PrivateSetCurrentLineRendition(const LineRendition l // - startRow: The row number of first line to be modified // - endRow: The row number following the last line to be modified // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::PrivateResetLineRenditionRange(const size_t startRow, const size_t endRow) +// - +void ConhostInternalGetSet::ResetLineRenditionRange(const size_t startRow, const size_t endRow) { auto& textBuffer = _io.GetActiveOutputBuffer().GetTextBuffer(); textBuffer.ResetLineRenditionRange(startRow, endRow); - return true; } // Method Description: @@ -201,41 +197,35 @@ bool ConhostInternalGetSet::PrivateResetLineRenditionRange(const size_t startRow // - row: The row number of the line to measure // Return Value: // - the number of cells that will fit on the line -SHORT ConhostInternalGetSet::PrivateGetLineWidth(const size_t row) const +SHORT ConhostInternalGetSet::GetLineWidth(const size_t row) const { const auto& textBuffer = _io.GetActiveOutputBuffer().GetTextBuffer(); return textBuffer.GetLineWidth(row); } // Routine Description: -// - Connects the WriteConsoleInput API call directly into our Driver Message servicing call inside Conhost.exe +// - Writes events to the input buffer already formed into IInputEvents // Arguments: // - events - the input events to be copied into the head of the input // buffer for the underlying attached process // - eventsWritten - on output, the number of events written // Return Value: -// - true if successful (see DoSrvWriteConsoleInput). false otherwise. -bool ConhostInternalGetSet::PrivateWriteConsoleInputW(std::deque>& events, - size_t& eventsWritten) +// - +void ConhostInternalGetSet::WriteInput(std::deque>& events, size_t& eventsWritten) { - eventsWritten = 0; - - return SUCCEEDED(DoSrvPrivateWriteConsoleInputW(_io.GetActiveInputBuffer(), - events, - eventsWritten, - true)); // append + eventsWritten = _io.GetActiveInputBuffer()->Write(events); } // Routine Description: -// - Connects the SetConsoleWindowInfo API call directly into our Driver Message servicing call inside Conhost.exe +// - Connects the SetWindowInfo API call directly into our Driver Message servicing call inside Conhost.exe // Arguments: // - absolute - Should the window be moved to an absolute position? If false, the movement is relative to the current pos. // - window - Info about how to move the viewport // Return Value: -// - true if successful (see DoSrvSetConsoleWindowInfo). false otherwise. -bool ConhostInternalGetSet::SetConsoleWindowInfo(const bool absolute, const SMALL_RECT& window) +// - +void ConhostInternalGetSet::SetWindowInfo(const bool absolute, const SMALL_RECT& window) { - return SUCCEEDED(ServiceLocator::LocateGlobals().api.SetConsoleWindowInfoImpl(_io.GetActiveOutputBuffer(), absolute, window)); + THROW_IF_FAILED(ServiceLocator::LocateGlobals().api.SetConsoleWindowInfoImpl(_io.GetActiveOutputBuffer(), absolute, window)); } // Routine Description: @@ -260,7 +250,7 @@ bool ConhostInternalGetSet::SetInputMode(const TerminalInput::Mode mode, const b // 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 !(IsConsolePty() && PrivateIsVtInputEnabled()); + return !(IsConsolePty() && IsVtInputEnabled()); } // Routine Description: @@ -271,12 +261,11 @@ bool ConhostInternalGetSet::SetInputMode(const TerminalInput::Mode mode, const b // - mode - the parser mode to change. // - enabled - set to true to enable the mode, false to disable it. // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::SetParserMode(const StateMachine::Mode mode, const bool enabled) +// - +void ConhostInternalGetSet::SetParserMode(const StateMachine::Mode mode, const bool enabled) { auto& stateMachine = _io.GetActiveOutputBuffer().GetStateMachine(); stateMachine.SetParserMode(mode, enabled); - return true; } // Routine Description: @@ -299,8 +288,8 @@ bool ConhostInternalGetSet::GetParserMode(const Microsoft::Console::VirtualTermi // - mode - the render mode to change. // - enabled - set to true to enable the mode, false to disable it. // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::SetRenderMode(const RenderSettings::Mode mode, const bool enabled) +// - +void ConhostInternalGetSet::SetRenderMode(const RenderSettings::Mode mode, const bool enabled) { auto& g = ServiceLocator::LocateGlobals(); auto& renderSettings = g.getConsoleInformation().GetRenderSettings(); @@ -310,71 +299,75 @@ bool ConhostInternalGetSet::SetRenderMode(const RenderSettings::Mode mode, const { g.pRender->TriggerRedrawAll(); } - - return true; } // Routine Description: -// - Connects the PrivateSetAutoWrapMode call directly into our Driver Message servicing call inside Conhost.exe -// PrivateSetAutoWrapMode is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on out public API surface. +// - Sets the ENABLE_WRAP_AT_EOL_OUTPUT mode. This controls whether the cursor moves +// to the beginning of the next row when it reaches the end of the current row. // Arguments: // - wrapAtEOL - set to true to wrap, false to overwrite the last character. // Return Value: -// - true if successful (see DoSrvPrivateSetAutoWrapMode). false otherwise. -bool ConhostInternalGetSet::PrivateSetAutoWrapMode(const bool wrapAtEOL) +// - +void ConhostInternalGetSet::SetAutoWrapMode(const bool wrapAtEOL) { - return NT_SUCCESS(DoSrvPrivateSetAutoWrapMode(wrapAtEOL)); + auto& outputMode = _io.GetActiveOutputBuffer().OutputMode; + WI_UpdateFlag(outputMode, ENABLE_WRAP_AT_EOL_OUTPUT, wrapAtEOL); } // Routine Description: -// - Connects the PrivateShowCursor call directly into our Driver Message servicing call inside Conhost.exe -// PrivateShowCursor is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on out public API surface. +// - Makes the cursor visible or hidden. Does not modify blinking state. // Arguments: -// - show - set to true to make the cursor visible, false to hide. +// - visible - set to true to make the cursor visible, false to hide. // Return Value: -// - true if successful (see DoSrvPrivateShowCursor). false otherwise. -bool ConhostInternalGetSet::PrivateShowCursor(const bool show) noexcept +// - +void ConhostInternalGetSet::SetCursorVisibility(const bool visible) { - DoSrvPrivateShowCursor(_io.GetActiveOutputBuffer(), show); - return true; + auto& textBuffer = _io.GetActiveOutputBuffer().GetTextBuffer(); + textBuffer.GetCursor().SetIsVisible(visible); } // Routine Description: -// - Connects the PrivateAllowCursorBlinking call directly into our Driver Message servicing call inside Conhost.exe -// PrivateAllowCursorBlinking is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on out public API surface. +// - Enables or disables the cursor blinking. // Arguments: // - fEnable - set to true to enable blinking, false to disable // Return Value: -// - true if successful (see DoSrvPrivateAllowCursorBlinking). false otherwise. -bool ConhostInternalGetSet::PrivateAllowCursorBlinking(const bool fEnable) +// - true if successful. false otherwise. +bool ConhostInternalGetSet::EnableCursorBlinking(const bool fEnable) { - DoSrvPrivateAllowCursorBlinking(_io.GetActiveOutputBuffer(), fEnable); + auto& textBuffer = _io.GetActiveOutputBuffer().GetTextBuffer(); + textBuffer.GetCursor().SetBlinkingAllowed(fEnable); + + // GH#2642 - From what we've gathered from other terminals, when blinking is + // disabled, the cursor should remain On always, and have the visibility + // controlled by the IsVisible property. So when you do a printf "\e[?12l" + // to disable blinking, the cursor stays stuck On. At this point, only the + // cursor visibility property controls whether the user can see it or not. + // (Yes, the cursor can be On and NOT Visible) + textBuffer.GetCursor().SetIsOn(true); - bool isPty; - DoSrvIsConsolePty(isPty); // If we are connected to a pty, return that we could not handle this // so that the VT sequence gets flushed to terminal. - // Note: we technically don't need to handle it ourselves at all if - // we are connected to a pty (i.e. we could have just returned false - // immediately without needing to call DoSrvPrivateAllowCursorBlinking), - // but we call it anyway for consistency, just in case. - return !isPty; + return !IsConsolePty(); } // Routine Description: -// - Connects the PrivateSetScrollingRegion call directly into our Driver Message servicing call inside Conhost.exe -// PrivateSetScrollingRegion is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on out public API surface. +// - Sets the top and bottom scrolling margins for the current page. This creates +// a subsection of the screen that scrolls when input reaches the end of the +// region, leaving the rest of the screen untouched. // Arguments: -// - scrollMargins - The bounds of the region to be the scrolling region of the viewport. +// - scrollMargins - A rect who's Top and Bottom members will be used to set +// the new values of the top and bottom margins. If (0,0), then the margins +// will be disabled. NOTE: This is a rect in the case that we'll need the +// left and right margins in the future. // Return Value: -// - true if successful (see DoSrvPrivateSetScrollingRegion). false otherwise. -bool ConhostInternalGetSet::PrivateSetScrollingRegion(const SMALL_RECT& scrollMargins) +// - +void ConhostInternalGetSet::SetScrollingRegion(const SMALL_RECT& scrollMargins) { - return NT_SUCCESS(DoSrvPrivateSetScrollingRegion(_io.GetActiveOutputBuffer(), scrollMargins)); + auto& screenInfo = _io.GetActiveOutputBuffer(); + auto srScrollMargins = screenInfo.GetRelativeScrollMargins().ToInclusive(); + srScrollMargins.Top = scrollMargins.Top; + srScrollMargins.Bottom = scrollMargins.Bottom; + screenInfo.SetScrollMargins(Viewport::FromInclusive(srScrollMargins)); } // Method Description: @@ -383,146 +376,214 @@ bool ConhostInternalGetSet::PrivateSetScrollingRegion(const SMALL_RECT& scrollMa // - None // Return Value: // - true if a line feed also produces a carriage return. false otherwise. -bool ConhostInternalGetSet::PrivateGetLineFeedMode() const +bool ConhostInternalGetSet::GetLineFeedMode() const { const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); return gci.IsReturnOnNewlineAutomatic(); } // Routine Description: -// - Connects the PrivateLineFeed call directly into our Driver Message servicing call inside Conhost.exe -// PrivateLineFeed is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on our public API surface. +// - Performs a line feed, possibly preceded by carriage return. // Arguments: // - withReturn - Set to true if a carriage return should be performed as well. // Return Value: -// - true if successful (see DoSrvPrivateLineFeed). false otherwise. -bool ConhostInternalGetSet::PrivateLineFeed(const bool withReturn) +// - +void ConhostInternalGetSet::LineFeed(const bool withReturn) { - return NT_SUCCESS(DoSrvPrivateLineFeed(_io.GetActiveOutputBuffer(), withReturn)); + auto& screenInfo = _io.GetActiveOutputBuffer(); + auto& textBuffer = screenInfo.GetTextBuffer(); + auto cursorPosition = textBuffer.GetCursor().GetPosition(); + + // We turn the cursor on before an operation that might scroll the viewport, otherwise + // that can result in an old copy of the cursor being left behind on the screen. + textBuffer.GetCursor().SetIsOn(true); + + // Since we are explicitly moving down a row, clear the wrap status on the row we're leaving + textBuffer.GetRowByOffset(cursorPosition.Y).SetWrapForced(false); + + cursorPosition.Y += 1; + if (withReturn) + { + cursorPosition.X = 0; + } + else + { + cursorPosition = textBuffer.ClampPositionWithinLine(cursorPosition); + } + + THROW_IF_NTSTATUS_FAILED(AdjustCursorPosition(screenInfo, cursorPosition, FALSE, nullptr)); } // Routine Description: // - Sends a notify message to play the "SystemHand" sound event. // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::PrivateWarningBell() +// - +void ConhostInternalGetSet::WarningBell() { - return _io.GetActiveOutputBuffer().SendNotifyBeep(); + _io.GetActiveOutputBuffer().SendNotifyBeep(); } // Routine Description: -// - Connects the PrivateReverseLineFeed call directly into our Driver Message servicing call inside Conhost.exe -// PrivateReverseLineFeed is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on out public API surface. +// - Performs a "Reverse line feed", essentially, the opposite of '\n'. // Return Value: -// - true if successful (see DoSrvPrivateReverseLineFeed). false otherwise. -bool ConhostInternalGetSet::PrivateReverseLineFeed() +// - +void ConhostInternalGetSet::ReverseLineFeed() { - return NT_SUCCESS(DoSrvPrivateReverseLineFeed(_io.GetActiveOutputBuffer())); + auto& screenInfo = _io.GetActiveOutputBuffer(); + const SMALL_RECT viewport = screenInfo.GetViewport().ToInclusive(); + const COORD oldCursorPosition = screenInfo.GetTextBuffer().GetCursor().GetPosition(); + COORD newCursorPosition = { oldCursorPosition.X, oldCursorPosition.Y - 1 }; + newCursorPosition = screenInfo.GetTextBuffer().ClampPositionWithinLine(newCursorPosition); + + // If the cursor is at the top of the viewport, we don't want to shift the viewport up. + // We want it to stay exactly where it is. + // In that case, shift the buffer contents down, to emulate inserting a line + // at the top of the buffer. + if (oldCursorPosition.Y > viewport.Top) + { + // Cursor is below the top line of the viewport + THROW_IF_NTSTATUS_FAILED(AdjustCursorPosition(screenInfo, newCursorPosition, TRUE, nullptr)); + } + else + { + // If we don't have margins, or the cursor is within the boundaries of the margins + // It's important to check if the cursor is in the margins, + // If it's not, but the margins are set, then we don't want to scroll anything + if (screenInfo.IsCursorInMargins(oldCursorPosition)) + { + // Cursor is at the top of the viewport + // Rectangle to cut out of the existing buffer. This is inclusive. + // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. + SMALL_RECT srScroll; + srScroll.Left = 0; + srScroll.Right = SHORT_MAX; + srScroll.Top = viewport.Top; + srScroll.Bottom = viewport.Bottom; + // Clip to the DECSTBM margin boundary + if (screenInfo.AreMarginsSet()) + { + srScroll.Bottom = screenInfo.GetAbsoluteScrollMargins().BottomInclusive(); + } + // Paste coordinate for cut text above + COORD coordDestination; + coordDestination.X = 0; + coordDestination.Y = viewport.Top + 1; + + // Note the revealed lines are filled with the standard erase attributes. + ScrollRegion(srScroll, srScroll, coordDestination, true); + } + } } // Routine Description: -// - Connects the SetConsoleTitleW API call directly into our Driver Message servicing call inside Conhost.exe +// - Sets the title of the console window. // Arguments: // - title - The null-terminated string to set as the window title // Return Value: -// - true if successful (see DoSrvSetConsoleTitle). false otherwise. -bool ConhostInternalGetSet::SetConsoleTitleW(std::wstring_view title) +// - +void ConhostInternalGetSet::SetWindowTitle(std::wstring_view title) { - return SUCCEEDED(DoSrvSetConsoleTitleW(title)); + ServiceLocator::LocateGlobals().getConsoleInformation().SetTitle(title); } // Routine Description: -// - Connects the PrivateUseAlternateScreenBuffer call directly into our Driver Message servicing call inside Conhost.exe -// PrivateUseAlternateScreenBuffer is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on out public API surface. +// - Swaps to the alternate screen buffer. In virtual terminals, there exists both a "main" +// screen buffer and an alternate. This creates a new alternate, and switches to it. +// If there is an already existing alternate, it is discarded. // Return Value: -// - true if successful (see DoSrvPrivateUseAlternateScreenBuffer). false otherwise. -bool ConhostInternalGetSet::PrivateUseAlternateScreenBuffer() +// - +void ConhostInternalGetSet::UseAlternateScreenBuffer() { - return NT_SUCCESS(DoSrvPrivateUseAlternateScreenBuffer(_io.GetActiveOutputBuffer())); + THROW_IF_NTSTATUS_FAILED(_io.GetActiveOutputBuffer().UseAlternateScreenBuffer()); } // Routine Description: -// - Connects the PrivateUseMainScreenBuffer call directly into our Driver Message servicing call inside Conhost.exe -// PrivateUseMainScreenBuffer is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on out public API surface. +// - Swaps to the main screen buffer. From the alternate buffer, returns to the main screen +// buffer. From the main screen buffer, does nothing. The alternate is discarded. // Return Value: -// - true if successful (see DoSrvPrivateUseMainScreenBuffer). false otherwise. -bool ConhostInternalGetSet::PrivateUseMainScreenBuffer() +// - +void ConhostInternalGetSet::UseMainScreenBuffer() { - DoSrvPrivateUseMainScreenBuffer(_io.GetActiveOutputBuffer()); - return true; + _io.GetActiveOutputBuffer().UseMainScreenBuffer(); } // Routine Description: -// - Connects the PrivateEraseAll call directly into our Driver Message servicing call inside Conhost.exe -// PrivateEraseAll is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on our public API surface. -// Arguments: -// +// - Performs a VT-style erase all operation on the buffer. +// See SCREEN_INFORMATION::VtEraseAll's description for details. // Return Value: -// - true if successful (see DoSrvPrivateEraseAll). false otherwise. -bool ConhostInternalGetSet::PrivateEraseAll() +// - +void ConhostInternalGetSet::EraseAll() { - return SUCCEEDED(DoSrvPrivateEraseAll(_io.GetActiveOutputBuffer())); + THROW_IF_FAILED(_io.GetActiveOutputBuffer().VtEraseAll()); } -bool ConhostInternalGetSet::PrivateClearBuffer() +// Routine Description: +// - Clears the entire contents of the viewport, except for the cursor's row, +// which is moved to the top line of the viewport. +// See SCREEN_INFORMATION::ClearBuffer's description for details. +// Return Value: +// - +void ConhostInternalGetSet::ClearBuffer() { - return SUCCEEDED(DoSrvPrivateClearBuffer(_io.GetActiveOutputBuffer())); + THROW_IF_FAILED(_io.GetActiveOutputBuffer().ClearBuffer()); } // Method Description: // - Retrieves the current user default cursor style. // Arguments: -// - style - Structure to receive cursor style. +// - // Return Value: -// - true if successful. false otherwise. -bool ConhostInternalGetSet::GetUserDefaultCursorStyle(CursorType& style) +// - the default cursor style. +CursorType ConhostInternalGetSet::GetUserDefaultCursorStyle() const { const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); - style = gci.GetCursorType(); - return true; + return gci.GetCursorType(); } // Routine Description: -// - Connects the SetCursorStyle call directly into our Driver Message servicing call inside Conhost.exe -// SetCursorStyle is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on our public API surface. +// - Sets the current cursor style. // Arguments: // - style: The style of cursor to change the cursor to. // Return Value: -// - true if successful (see DoSrvSetCursorStyle). false otherwise. -bool ConhostInternalGetSet::SetCursorStyle(const CursorType style) +// - +void ConhostInternalGetSet::SetCursorStyle(const CursorType style) { - DoSrvSetCursorStyle(_io.GetActiveOutputBuffer(), style); - return true; + _io.GetActiveOutputBuffer().GetTextBuffer().GetCursor().SetType(style); } // Routine Description: -// - Connects the PrivatePrependConsoleInput API call directly into our Driver Message servicing call inside Conhost.exe +// - Forces the renderer to repaint the screen. If the input screen buffer is +// not the active one, then just do nothing. We only want to redraw the +// screen buffer that requested the repaint, and switching screen buffers +// will already force a repaint. // Arguments: // - // Return Value: -// - true if successful (see DoSrvPrivateRefreshWindow). false otherwise. -bool ConhostInternalGetSet::PrivateRefreshWindow() +// - +void ConhostInternalGetSet::RefreshWindow() { - DoSrvPrivateRefreshWindow(_io.GetActiveOutputBuffer()); - return true; + auto& g = ServiceLocator::LocateGlobals(); + if (&_io.GetActiveOutputBuffer() == &g.getConsoleInformation().GetActiveOutputBuffer()) + { + g.pRender->TriggerRedrawAll(); + } } // Routine Description: -// - Connects the PrivateWriteConsoleControlInput API call directly into our Driver Message servicing call inside Conhost.exe +// - Writes the input KeyEvent to the console as a console control event. This +// can be used for potentially generating Ctrl-C events, as +// HandleGenericKeyEvent will correctly generate the Ctrl-C response in +// the same way that it'd be handled from the window proc, with the proper +// processed vs raw input handling. +// If the input key is *not* a Ctrl-C key, then it will get written to the +// buffer just the same as any other KeyEvent. // Arguments: -// - key - a KeyEvent representing a special type of keypress, typically Ctrl-C +// - key - The keyevent to send to the console. // Return Value: -// - true if successful (see DoSrvPrivateWriteConsoleControlInput). false otherwise. -bool ConhostInternalGetSet::PrivateWriteConsoleControlInput(const KeyEvent key) +// - +void ConhostInternalGetSet::WriteControlInput(const KeyEvent key) { - return SUCCEEDED(DoSrvPrivateWriteConsoleControlInput(_io.GetActiveInputBuffer(), - key)); + HandleGenericKeyEvent(key, false); } // Routine Description: @@ -530,74 +591,121 @@ bool ConhostInternalGetSet::PrivateWriteConsoleControlInput(const KeyEvent key) // Arguments: // - codepage - the new output codepage of the console. // Return Value: -// - true if successful (see DoSrvSetConsoleOutputCodePage). false otherwise. -bool ConhostInternalGetSet::SetConsoleOutputCP(const unsigned int codepage) +// - +void ConhostInternalGetSet::SetConsoleOutputCP(const unsigned int codepage) { - return SUCCEEDED(DoSrvSetConsoleOutputCodePage(codepage)); + THROW_IF_FAILED(DoSrvSetConsoleOutputCodePage(codepage)); } // Routine Description: -// - Connects the GetConsoleOutputCP API call directly into our Driver Message servicing call inside Conhost.exe -// Arguments: -// - codepage - receives the outputCP of the console. -// Return Value: -// - true if successful (see DoSrvPrivateWriteConsoleControlInput). false otherwise. -bool ConhostInternalGetSet::GetConsoleOutputCP(unsigned int& codepage) -{ - DoSrvGetConsoleOutputCodePage(codepage); - return true; -} - -// Routine Description: -// - Connects the PrivateSuppressResizeRepaint API call directly into our Driver -// Message servicing call inside Conhost.exe +// - Gets the codepage used for translating text when calling A versions of functions affecting the output buffer. // Arguments: // - // Return Value: -// - true if successful (see DoSrvPrivateSuppressResizeRepaint). false otherwise. -bool ConhostInternalGetSet::PrivateSuppressResizeRepaint() +// - the outputCP of the console. +unsigned int ConhostInternalGetSet::GetConsoleOutputCP() const { - return SUCCEEDED(DoSrvPrivateSuppressResizeRepaint()); + return ServiceLocator::LocateGlobals().getConsoleInformation().OutputCP; } // Routine Description: -// - Connects the IsConsolePty call directly into our Driver Message servicing call inside Conhost.exe -// - NOTE: This ONE method behaves differently! The rest of the methods on this -// interface return true if successful. This one just returns the result. +// - Forces the VT Renderer to NOT paint the next resize event. This is used by +// InteractDispatch, to prevent resizes from echoing between terminal and host. // Arguments: -// - isPty: receives the bool indicating whether or not we're in pty mode. +// - +// Return Value: +// - +void ConhostInternalGetSet::SuppressResizeRepaint() +{ + auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); + THROW_IF_FAILED(gci.GetVtIo()->SuppressResizeRepaint()); +} + +// Routine Description: +// - Checks if the console host is acting as a pty. +// Arguments: +// - // Return Value: // - true if we're in pty mode. bool ConhostInternalGetSet::IsConsolePty() const { - bool isPty = false; - DoSrvIsConsolePty(isPty); - return isPty; + return ServiceLocator::LocateGlobals().getConsoleInformation().IsInVtIoMode(); } -bool ConhostInternalGetSet::DeleteLines(const size_t count) +// Routine Description: +// - Deletes lines in the active screen buffer. +// Parameters: +// - count - the number of lines to delete +void ConhostInternalGetSet::DeleteLines(const size_t count) { - DoSrvPrivateDeleteLines(count); - return true; + _modifyLines(count, false); } -bool ConhostInternalGetSet::InsertLines(const size_t count) +// Routine Description: +// - Inserts lines in the active screen buffer. +// Parameters: +// - count - the number of lines to insert +void ConhostInternalGetSet::InsertLines(const size_t count) { - DoSrvPrivateInsertLines(count); - return true; + _modifyLines(count, true); +} + +// Routine Description: +// - internal logic for adding or removing lines in the active screen buffer +// this also moves the cursor to the left margin, which is expected behavior for IL and DL +// Parameters: +// - count - the number of lines to modify +// - insert - true if inserting lines, false if deleting lines +void ConhostInternalGetSet::_modifyLines(const size_t count, const bool insert) +{ + auto& screenInfo = _io.GetActiveOutputBuffer(); + auto& textBuffer = screenInfo.GetTextBuffer(); + const auto cursorPosition = textBuffer.GetCursor().GetPosition(); + if (screenInfo.IsCursorInMargins(cursorPosition)) + { + // Rectangle to cut out of the existing buffer. This is inclusive. + // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. + SMALL_RECT srScroll; + srScroll.Left = 0; + srScroll.Right = SHORT_MAX; + srScroll.Top = cursorPosition.Y; + srScroll.Bottom = screenInfo.GetViewport().BottomInclusive(); + // Clip to the DECSTBM margin boundary + if (screenInfo.AreMarginsSet()) + { + srScroll.Bottom = screenInfo.GetAbsoluteScrollMargins().BottomInclusive(); + } + // Paste coordinate for cut text above + COORD coordDestination; + coordDestination.X = 0; + if (insert) + { + coordDestination.Y = (cursorPosition.Y) + gsl::narrow(count); + } + else + { + coordDestination.Y = (cursorPosition.Y) - gsl::narrow(count); + } + + // Note the revealed lines are filled with the standard erase attributes. + ScrollRegion(srScroll, srScroll, coordDestination, true); + + // The IL and DL controls are also expected to move the cursor to the left margin. + // For now this is just column 0, since we don't yet support DECSLRM. + THROW_IF_NTSTATUS_FAILED(screenInfo.SetCursorPosition({ 0, cursorPosition.Y }, false)); + } } // Method Description: -// - Connects the MoveToBottom call directly into our Driver Message servicing -// call inside Conhost.exe +// - Snaps the screen buffer's viewport to the "virtual bottom", the last place +// the viewport was before the user scrolled it (with the mouse or scrollbar) // Arguments: -// +// - // Return Value: -// - true if successful (see DoSrvPrivateMoveToBottom). false otherwise. -bool ConhostInternalGetSet::MoveToBottom() const +// - +void ConhostInternalGetSet::MoveToBottom() { - DoSrvPrivateMoveToBottom(_io.GetActiveOutputBuffer()); - return true; + _io.GetActiveOutputBuffer().MoveToBottom(); } // Method Description: @@ -606,17 +714,12 @@ bool ConhostInternalGetSet::MoveToBottom() const // - tableIndex: the index of the color table to retrieve. // Return Value: // - the COLORREF value for the color at that index in the table. -COLORREF ConhostInternalGetSet::GetColorTableEntry(const size_t tableIndex) const noexcept -try +COLORREF ConhostInternalGetSet::GetColorTableEntry(const size_t tableIndex) const { auto& g = ServiceLocator::LocateGlobals(); auto& gci = g.getConsoleInformation(); return gci.GetColorTableEntry(tableIndex); } -catch (...) -{ - return INVALID_COLOR; -} // Method Description: // - Updates the value in the colortable at index tableIndex to the new color @@ -626,8 +729,7 @@ catch (...) // - color: the new COLORREF to use as that color table value. // Return Value: // - true if successful. false otherwise. -bool ConhostInternalGetSet::SetColorTableEntry(const size_t tableIndex, const COLORREF color) noexcept -try +bool ConhostInternalGetSet::SetColorTableEntry(const size_t tableIndex, const COLORREF color) { auto& g = ServiceLocator::LocateGlobals(); auto& gci = g.getConsoleInformation(); @@ -646,7 +748,6 @@ try // correct color. return !gci.IsInVtIoMode(); } -CATCH_RETURN_FALSE() // Routine Description: // - Sets the position in the color table for the given color alias. @@ -655,43 +756,61 @@ CATCH_RETURN_FALSE() // - tableIndex: the new position of the alias in the color table. // Return Value: // - -void ConhostInternalGetSet::SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) noexcept +void ConhostInternalGetSet::SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) { auto& renderSettings = ServiceLocator::LocateGlobals().getConsoleInformation().GetRenderSettings(); renderSettings.SetColorAliasIndex(alias, tableIndex); } // Routine Description: -// - Connects the PrivateFillRegion call directly into our Driver Message servicing -// call inside Conhost.exe -// PrivateFillRegion is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on our public API surface. +// - Fills a region of the screen buffer. // Arguments: -// - screenInfo - Reference to screen buffer info. // - startPosition - The position to begin filling at. // - fillLength - The number of characters to fill. // - fillChar - Character to fill the target region with. // - standardFillAttrs - If true, fill with the standard erase attributes. // If false, fill with the default attributes. // Return value: -// - true if successful (see DoSrvPrivateScrollRegion). false otherwise. -bool ConhostInternalGetSet::PrivateFillRegion(const COORD startPosition, - const size_t fillLength, - const wchar_t fillChar, - const bool standardFillAttrs) noexcept +// - +void ConhostInternalGetSet::FillRegion(const COORD startPosition, + const size_t fillLength, + const wchar_t fillChar, + const bool standardFillAttrs) { - return SUCCEEDED(DoSrvPrivateFillRegion(_io.GetActiveOutputBuffer(), - startPosition, - fillLength, - fillChar, - standardFillAttrs)); + auto& screenInfo = _io.GetActiveOutputBuffer(); + + if (fillLength == 0) + { + return; + } + + // For most VT erasing operations, the standard requires that the + // erased area be filled with the current background color, but with + // no additional meta attributes set. For all other cases, we just + // fill with the default attributes. + auto fillAttrs = TextAttribute{}; + if (standardFillAttrs) + { + fillAttrs = screenInfo.GetAttributes(); + fillAttrs.SetStandardErase(); + } + + const auto fillData = OutputCellIterator{ fillChar, fillAttrs, fillLength }; + screenInfo.Write(fillData, startPosition, false); + + // Notify accessibility + if (screenInfo.HasAccessibilityEventing()) + { + auto endPosition = startPosition; + const auto bufferSize = screenInfo.GetBufferSize(); + bufferSize.MoveInBounds(fillLength - 1, endPosition); + screenInfo.NotifyAccessibilityEventing(startPosition.X, startPosition.Y, endPosition.X, endPosition.Y); + } } // Routine Description: -// - Connects the PrivateScrollRegion call directly into our Driver Message servicing -// call inside Conhost.exe -// PrivateScrollRegion is an internal-only "API" call that the vt commands can execute, -// but it is not represented as a function call on our public API surface. +// - Moves a block of data in the screen buffer, optionally limiting the effects +// of the move to a clipping rectangle. // Arguments: // - scrollRect - Region to copy/move (source and size). // - clipRect - Optional clip region to contain buffer change effects. @@ -699,28 +818,37 @@ bool ConhostInternalGetSet::PrivateFillRegion(const COORD startPosition, // - standardFillAttrs - If true, fill with the standard erase attributes. // If false, fill with the default attributes. // Return value: -// - true if successful (see DoSrvPrivateScrollRegion). false otherwise. -bool ConhostInternalGetSet::PrivateScrollRegion(const SMALL_RECT scrollRect, - const std::optional clipRect, - const COORD destinationOrigin, - const bool standardFillAttrs) noexcept +// - +void ConhostInternalGetSet::ScrollRegion(const SMALL_RECT scrollRect, + const std::optional clipRect, + const COORD destinationOrigin, + const bool standardFillAttrs) { - return SUCCEEDED(DoSrvPrivateScrollRegion(_io.GetActiveOutputBuffer(), - scrollRect, - clipRect, - destinationOrigin, - standardFillAttrs)); + auto& screenInfo = _io.GetActiveOutputBuffer(); + + // For most VT scrolling operations, the standard requires that the + // erased area be filled with the current background color, but with + // no additional meta attributes set. For all other cases, we just + // fill with the default attributes. + auto fillAttrs = TextAttribute{}; + if (standardFillAttrs) + { + fillAttrs = screenInfo.GetAttributes(); + fillAttrs.SetStandardErase(); + } + + ::ScrollRegion(screenInfo, scrollRect, clipRect, destinationOrigin, UNICODE_SPACE, fillAttrs); } // Routine Description: // - Checks if the InputBuffer is willing to accept VT Input directly -// PrivateIsVtInputEnabled is an internal-only "API" call that the vt commands can execute, +// IsVtInputEnabled is an internal-only "API" call that the vt commands can execute, // but it is not represented as a function call on our public API surface. // Arguments: // - // Return value: // - true if enabled (see IsInVirtualTerminalInputMode). false otherwise. -bool ConhostInternalGetSet::PrivateIsVtInputEnabled() const +bool ConhostInternalGetSet::IsVtInputEnabled() const { return _io.GetActiveInputBuffer()->IsInVirtualTerminalInputMode(); } @@ -731,17 +859,23 @@ bool ConhostInternalGetSet::PrivateIsVtInputEnabled() const // Arguments: // - The hyperlink URI // Return Value: -// - true -bool ConhostInternalGetSet::PrivateAddHyperlink(const std::wstring_view uri, const std::wstring_view params) const +// - +void ConhostInternalGetSet::AddHyperlink(const std::wstring_view uri, const std::wstring_view params) const { - DoSrvAddHyperlink(_io.GetActiveOutputBuffer(), uri, params); - return true; + auto& screenInfo = _io.GetActiveOutputBuffer(); + auto attr = screenInfo.GetAttributes(); + const auto id = screenInfo.GetTextBuffer().GetHyperlinkId(uri, params); + attr.SetHyperlinkId(id); + screenInfo.GetTextBuffer().SetCurrentAttributes(attr); + screenInfo.GetTextBuffer().AddHyperlinkToMap(uri, id); } -bool ConhostInternalGetSet::PrivateEndHyperlink() const +void ConhostInternalGetSet::EndHyperlink() const { - DoSrvEndHyperlink(_io.GetActiveOutputBuffer()); - return true; + auto& screenInfo = _io.GetActiveOutputBuffer(); + auto attr = screenInfo.GetAttributes(); + attr.SetHyperlinkId(0); + screenInfo.GetTextBuffer().SetCurrentAttributes(attr); } // Routine Description: @@ -751,10 +885,14 @@ bool ConhostInternalGetSet::PrivateEndHyperlink() const // - cellSize - The cell size for an individual glyph. // - centeringHint - The horizontal extent that glyphs are offset from center. // Return Value: -// - true if successful (see DoSrvUpdateSoftFont). false otherwise. -bool ConhostInternalGetSet::PrivateUpdateSoftFont(const gsl::span bitPattern, - const SIZE cellSize, - const size_t centeringHint) noexcept +// - +void ConhostInternalGetSet::UpdateSoftFont(const gsl::span bitPattern, + const SIZE cellSize, + const size_t centeringHint) { - return SUCCEEDED(DoSrvUpdateSoftFont(bitPattern, cellSize, centeringHint)); + auto* pRender = ServiceLocator::LocateGlobals().pRender; + if (pRender) + { + pRender->UpdateSoftFont(bitPattern, cellSize, centeringHint); + } } diff --git a/src/host/outputStream.hpp b/src/host/outputStream.hpp index c74fdf302..537456696 100644 --- a/src/host/outputStream.hpp +++ b/src/host/outputStream.hpp @@ -54,93 +54,93 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal:: public: ConhostInternalGetSet(_In_ Microsoft::Console::IIoProvider& io); - bool GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const override; - bool SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) override; + void GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const override; + void SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) override; - bool SetConsoleCursorPosition(const COORD position) override; + void SetCursorPosition(const COORD position) override; - bool PrivateGetTextAttributes(TextAttribute& attrs) const override; - bool PrivateSetTextAttributes(const TextAttribute& attrs) override; + TextAttribute GetTextAttributes() const override; + void SetTextAttributes(const TextAttribute& attrs) override; - bool PrivateSetCurrentLineRendition(const LineRendition lineRendition) override; - bool PrivateResetLineRenditionRange(const size_t startRow, const size_t endRow) override; - SHORT PrivateGetLineWidth(const size_t row) const override; + void SetCurrentLineRendition(const LineRendition lineRendition) override; + void ResetLineRenditionRange(const size_t startRow, const size_t endRow) override; + SHORT GetLineWidth(const size_t row) const override; - bool PrivateWriteConsoleInputW(std::deque>& events, - size_t& eventsWritten) override; + void WriteInput(std::deque>& events, size_t& eventsWritten) override; - bool SetConsoleWindowInfo(bool const absolute, - const SMALL_RECT& window) override; + void SetWindowInfo(bool const absolute, const SMALL_RECT& window) override; bool SetInputMode(const Microsoft::Console::VirtualTerminal::TerminalInput::Mode mode, const bool enabled) override; - bool SetParserMode(const Microsoft::Console::VirtualTerminal::StateMachine::Mode mode, const bool enabled) override; + void SetParserMode(const Microsoft::Console::VirtualTerminal::StateMachine::Mode mode, const bool enabled) override; bool GetParserMode(const Microsoft::Console::VirtualTerminal::StateMachine::Mode mode) const override; - bool SetRenderMode(const RenderSettings::Mode mode, const bool enabled) override; + void SetRenderMode(const RenderSettings::Mode mode, const bool enabled) override; - bool PrivateSetAutoWrapMode(const bool wrapAtEOL) override; + void SetAutoWrapMode(const bool wrapAtEOL) override; - bool PrivateShowCursor(const bool show) noexcept override; - bool PrivateAllowCursorBlinking(const bool enable) override; + void SetCursorVisibility(const bool visible) override; + bool EnableCursorBlinking(const bool enable) override; - bool PrivateSetScrollingRegion(const SMALL_RECT& scrollMargins) override; + void SetScrollingRegion(const SMALL_RECT& scrollMargins) override; - bool PrivateWarningBell() override; + void WarningBell() override; - bool PrivateGetLineFeedMode() const override; - bool PrivateLineFeed(const bool withReturn) override; - bool PrivateReverseLineFeed() override; + bool GetLineFeedMode() const override; + void LineFeed(const bool withReturn) override; + void ReverseLineFeed() override; - bool SetConsoleTitleW(const std::wstring_view title) override; + void SetWindowTitle(const std::wstring_view title) override; - bool PrivateUseAlternateScreenBuffer() override; + void UseAlternateScreenBuffer() override; - bool PrivateUseMainScreenBuffer() override; + void UseMainScreenBuffer() override; - bool PrivateEraseAll() override; - bool PrivateClearBuffer() override; + void EraseAll() override; + void ClearBuffer() override; - bool GetUserDefaultCursorStyle(CursorType& style) override; - bool SetCursorStyle(CursorType const style) override; + CursorType GetUserDefaultCursorStyle() const override; + void SetCursorStyle(CursorType const style) override; - bool PrivateRefreshWindow() override; + void RefreshWindow() override; - bool PrivateSuppressResizeRepaint() override; + void SuppressResizeRepaint() override; - bool PrivateWriteConsoleControlInput(const KeyEvent key) override; + void WriteControlInput(const KeyEvent key) override; - bool SetConsoleOutputCP(const unsigned int codepage) override; - bool GetConsoleOutputCP(unsigned int& codepage) override; + void SetConsoleOutputCP(const unsigned int codepage) override; + unsigned int GetConsoleOutputCP() const override; bool IsConsolePty() const override; - bool DeleteLines(const size_t count) override; - bool InsertLines(const size_t count) override; + void DeleteLines(const size_t count) override; + void InsertLines(const size_t count) override; - bool MoveToBottom() const override; + void MoveToBottom() override; - COLORREF GetColorTableEntry(const size_t tableIndex) const noexcept override; - bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) noexcept override; - void SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) noexcept override; + COLORREF GetColorTableEntry(const size_t tableIndex) const override; + bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) override; + void SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) override; - bool PrivateFillRegion(const COORD startPosition, - const size_t fillLength, - const wchar_t fillChar, - const bool standardFillAttrs) noexcept override; + void FillRegion(const COORD startPosition, + const size_t fillLength, + const wchar_t fillChar, + const bool standardFillAttrs) override; - bool PrivateScrollRegion(const SMALL_RECT scrollRect, - const std::optional clipRect, - const COORD destinationOrigin, - const bool standardFillAttrs) noexcept override; + void ScrollRegion(const SMALL_RECT scrollRect, + const std::optional clipRect, + const COORD destinationOrigin, + const bool standardFillAttrs) override; - bool PrivateIsVtInputEnabled() const override; + bool IsVtInputEnabled() const override; - bool PrivateAddHyperlink(const std::wstring_view uri, const std::wstring_view params) const override; - bool PrivateEndHyperlink() const override; + void AddHyperlink(const std::wstring_view uri, const std::wstring_view params) const override; + void EndHyperlink() const override; - bool PrivateUpdateSoftFont(const gsl::span bitPattern, - const SIZE cellSize, - const size_t centeringHint) noexcept override; + void UpdateSoftFont(const gsl::span bitPattern, + const SIZE cellSize, + const size_t centeringHint) override; private: + void _modifyLines(const size_t count, const bool insert); + Microsoft::Console::IIoProvider& _io; }; diff --git a/src/host/ut_host/ConptyOutputTests.cpp b/src/host/ut_host/ConptyOutputTests.cpp index bb4033f20..d40a2fc20 100644 --- a/src/host/ut_host/ConptyOutputTests.cpp +++ b/src/host/ut_host/ConptyOutputTests.cpp @@ -384,7 +384,7 @@ void ConptyOutputTests::SetConsoleTitleWithControlChars() std::wstringstream titleText; titleText << L"Hello " << wchar_t(control) << L"World!"; - VERIFY_SUCCEEDED(DoSrvSetConsoleTitleW(titleText.str())); + g.getConsoleInformation().SetTitle(titleText.str()); // This is the standard init sequences for the first frame. expectedOutput.push_back("\x1b[2J"); diff --git a/src/host/ut_host/ScreenBufferTests.cpp b/src/host/ut_host/ScreenBufferTests.cpp index d475c28c8..a722c8bef 100644 --- a/src/host/ut_host/ScreenBufferTests.cpp +++ b/src/host/ut_host/ScreenBufferTests.cpp @@ -416,6 +416,7 @@ void ScreenBufferTests::TestReverseLineFeed() auto& stateMachine = screenInfo.GetStateMachine(); auto& cursor = screenInfo._textBuffer->GetCursor(); auto viewport = screenInfo.GetViewport(); + const auto reverseLineFeed = L"\033M"; VERIFY_ARE_EQUAL(viewport.Top(), 0); @@ -427,7 +428,7 @@ void ScreenBufferTests::TestReverseLineFeed() VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 1); VERIFY_ARE_EQUAL(viewport.Top(), 0); - VERIFY_SUCCEEDED(DoSrvPrivateReverseLineFeed(screenInfo)); + stateMachine.ProcessString(reverseLineFeed); VERIFY_ARE_EQUAL(cursor.GetPosition().X, 3); VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 0); @@ -448,7 +449,7 @@ void ScreenBufferTests::TestReverseLineFeed() VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 0); VERIFY_ARE_EQUAL(screenInfo.GetViewport().Top(), 0); - VERIFY_SUCCEEDED(DoSrvPrivateReverseLineFeed(screenInfo)); + stateMachine.ProcessString(reverseLineFeed); VERIFY_ARE_EQUAL(cursor.GetPosition().X, 9); VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 0); @@ -473,7 +474,7 @@ void ScreenBufferTests::TestReverseLineFeed() VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 5); VERIFY_ARE_EQUAL(screenInfo.GetViewport().Top(), 5); - LOG_IF_FAILED(DoSrvPrivateReverseLineFeed(screenInfo)); + stateMachine.ProcessString(reverseLineFeed); VERIFY_ARE_EQUAL(cursor.GetPosition().X, 8); VERIFY_ARE_EQUAL(cursor.GetPosition().Y, 5); diff --git a/src/terminal/adapter/DispatchCommon.cpp b/src/terminal/adapter/DispatchCommon.cpp index 1449aa8e2..4a00590cb 100644 --- a/src/terminal/adapter/DispatchCommon.cpp +++ b/src/terminal/adapter/DispatchCommon.cpp @@ -24,47 +24,36 @@ bool DispatchCommon::s_ResizeWindow(ConGetSet& conApi, SHORT sColumns = 0; SHORT sRows = 0; + THROW_IF_FAILED(SizeTToShort(width, &sColumns)); + THROW_IF_FAILED(SizeTToShort(height, &sRows)); // We should do nothing if 0 is passed in for a size. - bool success = SUCCEEDED(SizeTToShort(width, &sColumns)) && - SUCCEEDED(SizeTToShort(height, &sRows)) && - (width > 0 && height > 0); + RETURN_BOOL_IF_FALSE(width > 0 && height > 0); - if (success) + CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; + csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + conApi.GetConsoleScreenBufferInfoEx(csbiex); + + const Viewport oldViewport = Viewport::FromInclusive(csbiex.srWindow); + const Viewport newViewport = Viewport::FromDimensions(oldViewport.Origin(), sColumns, sRows); + // Always resize the width of the console + csbiex.dwSize.X = sColumns; + // Only set the screen buffer's height if it's currently less than + // what we're requesting. + if (sRows > csbiex.dwSize.Y) { - CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; - csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - success = conApi.GetConsoleScreenBufferInfoEx(csbiex); - - if (success) - { - const Viewport oldViewport = Viewport::FromInclusive(csbiex.srWindow); - const Viewport newViewport = Viewport::FromDimensions(oldViewport.Origin(), - sColumns, - sRows); - // Always resize the width of the console - csbiex.dwSize.X = sColumns; - // Only set the screen buffer's height if it's currently less than - // what we're requesting. - if (sRows > csbiex.dwSize.Y) - { - csbiex.dwSize.Y = sRows; - } - - // SetConsoleWindowInfo expect inclusive rects - const auto sri = newViewport.ToInclusive(); - - // SetConsoleScreenBufferInfoEx however expects exclusive rects - const auto sre = newViewport.ToExclusive(); - csbiex.srWindow = sre; - - success = conApi.SetConsoleScreenBufferInfoEx(csbiex); - if (success) - { - success = conApi.SetConsoleWindowInfo(true, sri); - } - } + csbiex.dwSize.Y = sRows; } - return success; + + // SetWindowInfo expect inclusive rects + const auto sri = newViewport.ToInclusive(); + + // SetConsoleScreenBufferInfoEx however expects exclusive rects + const auto sre = newViewport.ToExclusive(); + csbiex.srWindow = sre; + + conApi.SetConsoleScreenBufferInfoEx(csbiex); + conApi.SetWindowInfo(true, sri); + return true; } // Routine Description: @@ -72,10 +61,10 @@ bool DispatchCommon::s_ResizeWindow(ConGetSet& conApi, // Arguments: // - conApi: The ConGetSet implementation to call back into. // Return Value: -// True if handled successfully. False otherwise. -bool DispatchCommon::s_RefreshWindow(ConGetSet& conApi) +// - +void DispatchCommon::s_RefreshWindow(ConGetSet& conApi) { - return conApi.PrivateRefreshWindow(); + conApi.RefreshWindow(); } // Routine Description: @@ -86,8 +75,8 @@ bool DispatchCommon::s_RefreshWindow(ConGetSet& conApi) // Arguments: // - conApi: The ConGetSet implementation to call back into. // Return Value: -// True if handled successfully. False otherwise. -bool DispatchCommon::s_SuppressResizeRepaint(ConGetSet& conApi) +// - +void DispatchCommon::s_SuppressResizeRepaint(ConGetSet& conApi) { - return conApi.PrivateSuppressResizeRepaint(); + conApi.SuppressResizeRepaint(); } diff --git a/src/terminal/adapter/DispatchCommon.hpp b/src/terminal/adapter/DispatchCommon.hpp index f7af1e28d..0146d28d3 100644 --- a/src/terminal/adapter/DispatchCommon.hpp +++ b/src/terminal/adapter/DispatchCommon.hpp @@ -26,8 +26,8 @@ namespace Microsoft::Console::VirtualTerminal const size_t width, const size_t height); - static bool s_RefreshWindow(ConGetSet& conApi); + static void s_RefreshWindow(ConGetSet& conApi); - static bool s_SuppressResizeRepaint(ConGetSet& conApi); + static void s_SuppressResizeRepaint(ConGetSet& conApi); }; } diff --git a/src/terminal/adapter/InteractDispatch.cpp b/src/terminal/adapter/InteractDispatch.cpp index e65d39179..5145a188e 100644 --- a/src/terminal/adapter/InteractDispatch.cpp +++ b/src/terminal/adapter/InteractDispatch.cpp @@ -29,11 +29,12 @@ InteractDispatch::InteractDispatch(std::unique_ptr pConApi) : // Arguments: // - inputEvents: a collection of IInputEvents // Return Value: -// True if handled successfully. False otherwise. +// - True. bool InteractDispatch::WriteInput(std::deque>& inputEvents) { size_t written = 0; - return _pConApi->PrivateWriteConsoleInputW(inputEvents, written); + _pConApi->WriteInput(inputEvents, written); + return true; } // Method Description: @@ -44,10 +45,11 @@ bool InteractDispatch::WriteInput(std::deque>& inpu // Arguments: // - event: The key to send to the host. // Return Value: -// True if handled successfully. False otherwise. +// - True. bool InteractDispatch::WriteCtrlKey(const KeyEvent& event) { - return _pConApi->PrivateWriteConsoleControlInput(event); + _pConApi->WriteControlInput(event); + return true; } // Method Description: @@ -56,18 +58,12 @@ bool InteractDispatch::WriteCtrlKey(const KeyEvent& event) // Arguments: // - string : a string to write to the console. // Return Value: -// True if handled successfully. False otherwise. +// - True. bool InteractDispatch::WriteString(const std::wstring_view string) { - if (string.empty()) - { - return true; - } - - unsigned int codepage = 0; - bool success = _pConApi->GetConsoleOutputCP(codepage); - if (success) + if (!string.empty()) { + const auto codepage = _pConApi->GetConsoleOutputCP(); std::deque> keyEvents; for (const auto& wch : string) @@ -79,9 +75,9 @@ bool InteractDispatch::WriteString(const std::wstring_view string) std::back_inserter(keyEvents)); } - success = WriteInput(keyEvents); + WriteInput(keyEvents); } - return success; + return true; } //Method Description: @@ -100,30 +96,25 @@ bool InteractDispatch::WindowManipulation(const DispatchTypes::WindowManipulatio const VTParameter parameter1, const VTParameter parameter2) { - bool success = false; // Other Window Manipulation functions: // MSFT:13271098 - QueryViewport // MSFT:13271146 - QueryScreenSize switch (function) { case DispatchTypes::WindowManipulationType::RefreshWindow: - success = DispatchCommon::s_RefreshWindow(*_pConApi); - break; + DispatchCommon::s_RefreshWindow(*_pConApi); + return true; case DispatchTypes::WindowManipulationType::ResizeWindowInCharacters: // TODO:GH#1765 We should introduce a better `ResizeConpty` function to // the ConGetSet interface, that specifically handles a conpty resize. - success = DispatchCommon::s_ResizeWindow(*_pConApi, parameter2.value_or(0), parameter1.value_or(0)); - if (success) + if (DispatchCommon::s_ResizeWindow(*_pConApi, parameter2.value_or(0), parameter1.value_or(0))) { DispatchCommon::s_SuppressResizeRepaint(*_pConApi); } - break; + return true; default: - success = false; - break; + return false; } - - return success; } //Method Description: @@ -133,71 +124,39 @@ bool InteractDispatch::WindowManipulation(const DispatchTypes::WindowManipulatio // - row: The row to move the cursor to. // - col: The column to move the cursor to. // Return value: -// True if we successfully moved the cursor to the given location. -// False otherwise, including if given invalid coordinates (either component being 0) -// or if any API calls failed. +// - True. bool InteractDispatch::MoveCursor(const size_t row, const size_t col) { - size_t rowFixed = row; - size_t colFixed = 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); - bool success = true; // In VT, the origin is 1,1. For our array, it's 0,0. So subtract 1. - if (row != 0) - { - rowFixed = row - 1; - } - else - { - // The parser should never return 0 (0 maps to 1), so this is a failure condition. - success = false; - } + const size_t rowFixed = row - 1; + const size_t colFixed = col - 1; - if (col != 0) - { - colFixed = col - 1; - } - else - { - // The parser should never return 0 (0 maps to 1), so this is a failure condition. - success = false; - } + // First retrieve some information about the buffer + CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; + csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) - { - // First retrieve some information about the buffer - CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; - csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + COORD coordCursor = csbiex.dwCursorPosition; - if (success) - { - COORD coordCursor = csbiex.dwCursorPosition; + // 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)); - // Safely convert the size_t positions we were given into shorts (which is the size the console deals with) - success = SUCCEEDED(SizeTToShort(rowFixed, &coordCursor.Y)) && - SUCCEEDED(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, csbiex.srWindow.Top, &coordCursor.Y)); + THROW_IF_FAILED(ShortAdd(coordCursor.X, csbiex.srWindow.Left, &coordCursor.X)); - if (success) - { - // Set the line and column values as offsets from the viewport edge. Use safe math to prevent overflow. - success = SUCCEEDED(ShortAdd(coordCursor.Y, csbiex.srWindow.Top, &coordCursor.Y)) && - SUCCEEDED(ShortAdd(coordCursor.X, csbiex.srWindow.Left, &coordCursor.X)); + // Apply boundary tests to ensure the cursor isn't outside the viewport rectangle. + coordCursor.Y = std::clamp(coordCursor.Y, csbiex.srWindow.Top, gsl::narrow(csbiex.srWindow.Bottom - 1)); + coordCursor.X = std::clamp(coordCursor.X, csbiex.srWindow.Left, gsl::narrow(csbiex.srWindow.Right - 1)); - if (success) - { - // Apply boundary tests to ensure the cursor isn't outside the viewport rectangle. - coordCursor.Y = std::clamp(coordCursor.Y, csbiex.srWindow.Top, gsl::narrow(csbiex.srWindow.Bottom - 1)); - coordCursor.X = std::clamp(coordCursor.X, csbiex.srWindow.Left, gsl::narrow(csbiex.srWindow.Right - 1)); - - // Finally, attempt to set the adjusted cursor position back into the console. - success = _pConApi->SetConsoleCursorPosition(coordCursor); - } - } - } - } - - return success; + // Finally, attempt to set the adjusted cursor position back into the console. + _pConApi->SetCursorPosition(coordCursor); + return true; } // Routine Description: @@ -208,5 +167,5 @@ bool InteractDispatch::MoveCursor(const size_t row, const size_t col) // - true if enabled (see IsInVirtualTerminalInputMode). false otherwise. bool InteractDispatch::IsVtInputEnabled() const { - return _pConApi->PrivateIsVtInputEnabled(); + return _pConApi->IsVtInputEnabled(); } diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 4ed06e01e..826233cec 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -68,24 +68,20 @@ void AdaptDispatch::Print(const wchar_t wchPrintable) // - void AdaptDispatch::PrintString(const std::wstring_view string) { - try + if (_termOutput.NeedToTranslate()) { - if (_termOutput.NeedToTranslate()) + std::wstring buffer; + buffer.reserve(string.size()); + for (auto& wch : string) { - std::wstring buffer; - buffer.reserve(string.size()); - for (auto& wch : string) - { - buffer.push_back(_termOutput.TranslateKey(wch)); - } - _pDefaults->PrintString(buffer); - } - else - { - _pDefaults->PrintString(string); + buffer.push_back(_termOutput.TranslateKey(wch)); } + _pDefaults->PrintString(buffer); + } + else + { + _pDefaults->PrintString(string); } - CATCH_LOG(); } // Routine Description: @@ -98,7 +94,7 @@ void AdaptDispatch::PrintString(const std::wstring_view string) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorUp(const size_t distance) { return _CursorMovePosition(Offset::Backward(distance), Offset::Unchanged(), true); @@ -114,7 +110,7 @@ bool AdaptDispatch::CursorUp(const size_t distance) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorDown(const size_t distance) { return _CursorMovePosition(Offset::Forward(distance), Offset::Unchanged(), true); @@ -125,7 +121,7 @@ bool AdaptDispatch::CursorDown(const size_t distance) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorForward(const size_t distance) { return _CursorMovePosition(Offset::Unchanged(), Offset::Forward(distance), true); @@ -136,7 +132,7 @@ bool AdaptDispatch::CursorForward(const size_t distance) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorBackward(const size_t distance) { return _CursorMovePosition(Offset::Unchanged(), Offset::Backward(distance), true); @@ -148,7 +144,7 @@ bool AdaptDispatch::CursorBackward(const size_t distance) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorNextLine(const size_t distance) { return _CursorMovePosition(Offset::Forward(distance), Offset::Absolute(1), true); @@ -160,7 +156,7 @@ bool AdaptDispatch::CursorNextLine(const size_t distance) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorPrevLine(const size_t distance) { return _CursorMovePosition(Offset::Backward(distance), Offset::Absolute(1), true); @@ -173,84 +169,80 @@ bool AdaptDispatch::CursorPrevLine(const size_t distance) // - colOffset - The column to move to // - clampInMargins - Should the position be clamped within the scrolling margins // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::_CursorMovePosition(const Offset rowOffset, const Offset colOffset, const bool clampInMargins) const { - bool success = true; - // First retrieve some information about the buffer CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - success = (_pConApi->MoveToBottom() && _pConApi->GetConsoleScreenBufferInfoEx(csbiex)); + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) + // Calculate the viewport boundaries as inclusive values. + // srWindow is exclusive so we need to subtract 1 from the bottom. + const int viewportTop = csbiex.srWindow.Top; + const int viewportBottom = csbiex.srWindow.Bottom - 1; + + // Calculate the absolute margins of the scrolling area. + const int topMargin = viewportTop + _scrollMargins.Top; + const int bottomMargin = viewportTop + _scrollMargins.Bottom; + const bool marginsSet = topMargin < bottomMargin; + + // For relative movement, the given offsets will be relative to + // the current cursor position. + int row = csbiex.dwCursorPosition.Y; + int col = csbiex.dwCursorPosition.X; + + // But if the row is absolute, it will be relative to the top of the + // viewport, or the top margin, depending on the origin mode. + if (rowOffset.IsAbsolute) { - // Calculate the viewport boundaries as inclusive values. - // srWindow is exclusive so we need to subtract 1 from the bottom. - const int viewportTop = csbiex.srWindow.Top; - const int viewportBottom = csbiex.srWindow.Bottom - 1; - - // Calculate the absolute margins of the scrolling area. - const int topMargin = viewportTop + _scrollMargins.Top; - const int bottomMargin = viewportTop + _scrollMargins.Bottom; - const bool marginsSet = topMargin < bottomMargin; - - // For relative movement, the given offsets will be relative to - // the current cursor position. - int row = csbiex.dwCursorPosition.Y; - int col = csbiex.dwCursorPosition.X; - - // But if the row is absolute, it will be relative to the top of the - // viewport, or the top margin, depending on the origin mode. - if (rowOffset.IsAbsolute) - { - row = _isOriginModeRelative ? topMargin : viewportTop; - } - - // And if the column is absolute, it'll be relative to column 0. - // Horizontal positions are not affected by the viewport. - if (colOffset.IsAbsolute) - { - col = 0; - } - - // Adjust the base position by the given offsets and clamp the results. - // The row is constrained within the viewport's vertical boundaries, - // while the column is constrained by the buffer width. - row = std::clamp(row + rowOffset.Value, viewportTop, viewportBottom); - col = std::clamp(col + colOffset.Value, 0, csbiex.dwSize.X - 1); - - // If the operation needs to be clamped inside the margins, or the origin - // mode is relative (which always requires margin clamping), then the row - // may need to be adjusted further. - if (marginsSet && (clampInMargins || _isOriginModeRelative)) - { - // See microsoft/terminal#2929 - If the cursor is _below_ the top - // margin, it should stay below the top margin. If it's _above_ the - // bottom, it should stay above the bottom. Cursor movements that stay - // outside the margins shouldn't necessarily be affected. For example, - // moving up while below the bottom margin shouldn't just jump straight - // to the bottom margin. See - // ScreenBufferTests::CursorUpDownOutsideMargins for a test of that - // behavior. - if (csbiex.dwCursorPosition.Y >= topMargin) - { - row = std::max(row, topMargin); - } - if (csbiex.dwCursorPosition.Y <= bottomMargin) - { - row = std::min(row, bottomMargin); - } - } - - // Finally, attempt to set the adjusted cursor position back into the console. - const COORD newPos = { gsl::narrow_cast(col), gsl::narrow_cast(row) }; - success = _pConApi->SetConsoleCursorPosition(newPos); + row = _isOriginModeRelative ? topMargin : viewportTop; } - return success; + // And if the column is absolute, it'll be relative to column 0. + // Horizontal positions are not affected by the viewport. + if (colOffset.IsAbsolute) + { + col = 0; + } + + // Adjust the base position by the given offsets and clamp the results. + // The row is constrained within the viewport's vertical boundaries, + // while the column is constrained by the buffer width. + row = std::clamp(row + rowOffset.Value, viewportTop, viewportBottom); + col = std::clamp(col + colOffset.Value, 0, csbiex.dwSize.X - 1); + + // If the operation needs to be clamped inside the margins, or the origin + // mode is relative (which always requires margin clamping), then the row + // may need to be adjusted further. + if (marginsSet && (clampInMargins || _isOriginModeRelative)) + { + // See microsoft/terminal#2929 - If the cursor is _below_ the top + // margin, it should stay below the top margin. If it's _above_ the + // bottom, it should stay above the bottom. Cursor movements that stay + // outside the margins shouldn't necessarily be affected. For example, + // moving up while below the bottom margin shouldn't just jump straight + // to the bottom margin. See + // ScreenBufferTests::CursorUpDownOutsideMargins for a test of that + // behavior. + if (csbiex.dwCursorPosition.Y >= topMargin) + { + row = std::max(row, topMargin); + } + if (csbiex.dwCursorPosition.Y <= bottomMargin) + { + row = std::min(row, bottomMargin); + } + } + + // Finally, attempt to set the adjusted cursor position back into the console. + const COORD newPos = { gsl::narrow_cast(col), gsl::narrow_cast(row) }; + _pConApi->SetCursorPosition(newPos); + + return true; } // Routine Description: @@ -258,7 +250,7 @@ bool AdaptDispatch::_CursorMovePosition(const Offset rowOffset, const Offset col // Arguments: // - column - Specific X/Column position to move to // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorHorizontalPositionAbsolute(const size_t column) { return _CursorMovePosition(Offset::Unchanged(), Offset::Absolute(column), false); @@ -269,7 +261,7 @@ bool AdaptDispatch::CursorHorizontalPositionAbsolute(const size_t column) // Arguments: // - line - Specific Y/Row position to move to // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::VerticalLinePositionAbsolute(const size_t line) { return _CursorMovePosition(Offset::Absolute(line), Offset::Unchanged(), false); @@ -281,7 +273,7 @@ bool AdaptDispatch::VerticalLinePositionAbsolute(const size_t line) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::HorizontalPositionRelative(const size_t distance) { return _CursorMovePosition(Offset::Unchanged(), Offset::Forward(distance), false); @@ -293,7 +285,7 @@ bool AdaptDispatch::HorizontalPositionRelative(const size_t distance) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::VerticalPositionRelative(const size_t distance) { return _CursorMovePosition(Offset::Forward(distance), Offset::Unchanged(), false); @@ -305,7 +297,7 @@ bool AdaptDispatch::VerticalPositionRelative(const size_t distance) // - line - Specific Y/Row/Line position to move to // - column - Specific X/Column position to move to // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorPosition(const size_t line, const size_t column) { return _CursorMovePosition(Offset::Absolute(line), Offset::Absolute(column), false); @@ -318,7 +310,7 @@ bool AdaptDispatch::CursorPosition(const size_t line, const size_t column) // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorSaveState() { // First retrieve some information about the buffer @@ -326,30 +318,27 @@ bool AdaptDispatch::CursorSaveState() csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - bool success = (_pConApi->MoveToBottom() && _pConApi->GetConsoleScreenBufferInfoEx(csbiex)); + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - TextAttribute attributes; - success = success && (_pConApi->PrivateGetTextAttributes(attributes)); + const auto attributes = _pConApi->GetTextAttributes(); - if (success) - { - // The cursor is given to us by the API as relative to the whole buffer. - // But in VT speak, the cursor row should be relative to the current viewport top. - COORD coordCursor = csbiex.dwCursorPosition; - coordCursor.Y -= csbiex.srWindow.Top; + // The cursor is given to us by the API as relative to the whole buffer. + // But in VT speak, the cursor row should be relative to the current viewport top. + COORD coordCursor = csbiex.dwCursorPosition; + coordCursor.Y -= csbiex.srWindow.Top; - // VT is also 1 based, not 0 based, so correct by 1. - auto& savedCursorState = _savedCursorState.at(_usingAltBuffer); - savedCursorState.Column = coordCursor.X + 1; - savedCursorState.Row = coordCursor.Y + 1; - savedCursorState.IsOriginModeRelative = _isOriginModeRelative; - savedCursorState.Attributes = attributes; - savedCursorState.TermOutput = _termOutput; - savedCursorState.C1ControlsAccepted = _pConApi->GetParserMode(StateMachine::Mode::AcceptC1); - _pConApi->GetConsoleOutputCP(savedCursorState.CodePage); - } + // VT is also 1 based, not 0 based, so correct by 1. + auto& savedCursorState = _savedCursorState.at(_usingAltBuffer); + savedCursorState.Column = coordCursor.X + 1; + savedCursorState.Row = coordCursor.Y + 1; + savedCursorState.IsOriginModeRelative = _isOriginModeRelative; + savedCursorState.Attributes = attributes; + savedCursorState.TermOutput = _termOutput; + savedCursorState.C1ControlsAccepted = _pConApi->GetParserMode(StateMachine::Mode::AcceptC1); + savedCursorState.CodePage = _pConApi->GetConsoleOutputCP(); - return success; + return true; } // Routine Description: @@ -359,7 +348,7 @@ bool AdaptDispatch::CursorSaveState() // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorRestoreState() { auto& savedCursorState = _savedCursorState.at(_usingAltBuffer); @@ -377,13 +366,13 @@ bool AdaptDispatch::CursorRestoreState() // The saved coordinates are always absolute, so we need reset the origin mode temporarily. _isOriginModeRelative = false; - bool success = CursorPosition(row, col); + CursorPosition(row, col); // Once the cursor position is restored, we can then restore the actual origin mode. _isOriginModeRelative = savedCursorState.IsOriginModeRelative; // Restore text attributes. - success = (_pConApi->PrivateSetTextAttributes(savedCursorState.Attributes)) && success; + _pConApi->SetTextAttributes(savedCursorState.Attributes); // Restore designated character set. _termOutput = savedCursorState.TermOutput; @@ -394,10 +383,10 @@ bool AdaptDispatch::CursorRestoreState() // Restore the code page if it was previously saved. if (savedCursorState.CodePage != 0) { - success = _pConApi->SetConsoleOutputCP(savedCursorState.CodePage); + _pConApi->SetConsoleOutputCP(savedCursorState.CodePage); } - return success; + return true; } // Routine Description: @@ -405,12 +394,13 @@ bool AdaptDispatch::CursorRestoreState() // Arguments: // - fIsVisible - Turns the cursor rendering on (TRUE) or off (FALSE). // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CursorVisibility(const bool fIsVisible) { // This uses a private API instead of the public one, because the public API // will set the cursor shape back to legacy. - return _pConApi->PrivateShowCursor(fIsVisible); + _pConApi->SetCursorVisibility(fIsVisible); + return true; } // Routine Description: @@ -420,26 +410,26 @@ bool AdaptDispatch::CursorVisibility(const bool fIsVisible) // - count - The number of characters to insert // - isInsert - TRUE if insert mode (cut and paste to the right, away from the cursor). FALSE if delete mode (cut and paste to the left, toward the cursor) // Return Value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_InsertDeleteHelper(const size_t count, const bool isInsert) const +// - +void AdaptDispatch::_InsertDeleteHelper(const size_t count, const bool isInsert) const { // We'll be doing short math on the distance since all console APIs use shorts. So check that we can successfully convert the uint into a short first. SHORT distance; - RETURN_BOOL_IF_FALSE(SUCCEEDED(SizeTToShort(count, &distance))); + THROW_IF_FAILED(SizeTToShort(count, &distance)); // get current cursor, attributes CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - RETURN_BOOL_IF_FALSE(_pConApi->MoveToBottom()); - RETURN_BOOL_IF_FALSE(_pConApi->GetConsoleScreenBufferInfoEx(csbiex)); + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); const auto cursor = csbiex.dwCursorPosition; // Rectangle to cut out of the existing buffer. This is inclusive. SMALL_RECT srScroll; srScroll.Left = cursor.X; - srScroll.Right = _pConApi->PrivateGetLineWidth(cursor.Y) - 1; + srScroll.Right = _pConApi->GetLineWidth(cursor.Y) - 1; srScroll.Top = cursor.Y; srScroll.Bottom = srScroll.Top; @@ -448,25 +438,19 @@ bool AdaptDispatch::_InsertDeleteHelper(const size_t count, const bool isInsert) coordDestination.Y = cursor.Y; coordDestination.X = cursor.X; - bool success = false; if (isInsert) { // Insert makes space by moving characters out to the right. So move the destination of the cut/paste region. - success = SUCCEEDED(ShortAdd(coordDestination.X, distance, &coordDestination.X)); + THROW_IF_FAILED(ShortAdd(coordDestination.X, distance, &coordDestination.X)); } else { // Delete scrolls the affected region to the left, relying on the clipping rect to actually delete the characters. - success = SUCCEEDED(ShortSub(coordDestination.X, distance, &coordDestination.X)); + THROW_IF_FAILED(ShortSub(coordDestination.X, distance, &coordDestination.X)); } - if (success) - { - // Note the revealed characters are filled with the standard erase attributes. - success = _pConApi->PrivateScrollRegion(srScroll, srScroll, coordDestination, true); - } - - return success; + // Note the revealed characters are filled with the standard erase attributes. + _pConApi->ScrollRegion(srScroll, srScroll, coordDestination, true); } // Routine Description: @@ -475,10 +459,11 @@ bool AdaptDispatch::_InsertDeleteHelper(const size_t count, const bool isInsert) // Arguments: // - count - The number of characters to insert // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::InsertCharacter(const size_t count) { - return _InsertDeleteHelper(count, true); + _InsertDeleteHelper(count, true); + return true; } // Routine Description: @@ -487,10 +472,11 @@ bool AdaptDispatch::InsertCharacter(const size_t count) // Arguments: // - count - The number of characters to delete // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::DeleteCharacter(const size_t count) { - return _InsertDeleteHelper(count, false); + _InsertDeleteHelper(count, false); + return true; } // Routine Description: @@ -502,16 +488,13 @@ bool AdaptDispatch::DeleteCharacter(const size_t count) // - lineId - The line number (array index value, starts at 0) of the line to operate on within the buffer. // - This is not aware of circular buffer. Line 0 is always the top visible line if you scrolled the whole way up the window. // Return Value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_EraseSingleLineHelper(const CONSOLE_SCREEN_BUFFER_INFOEX& csbiex, +// - +void AdaptDispatch::_EraseSingleLineHelper(const CONSOLE_SCREEN_BUFFER_INFOEX& csbiex, const DispatchTypes::EraseType eraseType, const size_t lineId) const { COORD coordStartPosition = { 0 }; - if (FAILED(SizeTToShort(lineId, &coordStartPosition.Y))) - { - return false; - } + THROW_IF_FAILED(SizeTToShort(lineId, &coordStartPosition.Y)); // determine start position from the erase type // remember that erases are inclusive of the current cursor position. @@ -538,12 +521,12 @@ bool AdaptDispatch::_EraseSingleLineHelper(const CONSOLE_SCREEN_BUFFER_INFOEX& c case DispatchTypes::EraseType::ToEnd: case DispatchTypes::EraseType::All: // Remember the .X value is 1 farther than the right most column in the buffer. Therefore no +1. - nLength = _pConApi->PrivateGetLineWidth(lineId) - coordStartPosition.X; + nLength = _pConApi->GetLineWidth(lineId) - coordStartPosition.X; break; } // Note that the region is filled with the standard erase attributes. - return _pConApi->PrivateFillRegion(coordStartPosition, nLength, L' ', true); + _pConApi->FillRegion(coordStartPosition, nLength, L' ', true); } // Routine Description: @@ -554,26 +537,24 @@ bool AdaptDispatch::_EraseSingleLineHelper(const CONSOLE_SCREEN_BUFFER_INFOEX& c // Arguments: // - numChars - The number of characters to erase. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::EraseCharacters(const size_t numChars) { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - bool success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) - { - const COORD startPosition = csbiex.dwCursorPosition; + const COORD startPosition = csbiex.dwCursorPosition; - const SHORT remainingSpaces = csbiex.dwSize.X - startPosition.X; - const size_t actualRemaining = gsl::narrow_cast((remainingSpaces < 0) ? 0 : remainingSpaces); - // erase at max the number of characters remaining in the line from the current position. - const auto eraseLength = (numChars <= actualRemaining) ? numChars : actualRemaining; + const SHORT remainingSpaces = csbiex.dwSize.X - startPosition.X; + const size_t actualRemaining = gsl::narrow_cast((remainingSpaces < 0) ? 0 : remainingSpaces); + // erase at max the number of characters remaining in the line from the current position. + const auto eraseLength = (numChars <= actualRemaining) ? numChars : actualRemaining; - // Note that the region is filled with the standard erase attributes. - success = _pConApi->PrivateFillRegion(startPosition, eraseLength, L' ', true); - } - return success; + // Note that the region is filled with the standard erase attributes. + _pConApi->FillRegion(startPosition, eraseLength, L' ', true); + + return true; } // Routine Description: @@ -597,13 +578,12 @@ bool AdaptDispatch::EraseInDisplay(const DispatchTypes::EraseType eraseType) // by moving the current contents of the viewport into the scrollback. if (eraseType == DispatchTypes::EraseType::Scrollback) { - const bool eraseScrollbackResult = _EraseScrollback(); + _EraseScrollback(); // GH#2715 - If this succeeded, but we're in a conpty, return `false` to // make the state machine propagate this ED sequence to the connected // terminal application. While we're in conpty mode, we don't really // have a scrollback, but the attached terminal might. - const bool isPty = _pConApi->IsConsolePty(); - return eraseScrollbackResult && (!isPty); + return !_pConApi->IsConsolePty(); } else if (eraseType == DispatchTypes::EraseType::All) { @@ -613,87 +593,68 @@ bool AdaptDispatch::EraseInDisplay(const DispatchTypes::EraseType eraseType) // requests a Erase All operation, we need to manually tell the // connected terminal to do the same thing, so that the terminal will // move it's own buffer contents into the scrollback. - const bool eraseAllResult = _EraseAll(); - const bool isPty = _pConApi->IsConsolePty(); - return eraseAllResult && (!isPty); + _EraseAll(); + return !_pConApi->IsConsolePty(); } CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - bool success = (_pConApi->MoveToBottom() && _pConApi->GetConsoleScreenBufferInfoEx(csbiex)); + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) + // When erasing the display, every line that is erased in full should be + // reset to single width. When erasing to the end, this could include + // the current line, if the cursor is in the first column. When erasing + // from the beginning, though, the current line would never be included, + // because the cursor could never be in the rightmost column (assuming + // the line is double width). + if (eraseType == DispatchTypes::EraseType::FromBeginning) { - // When erasing the display, every line that is erased in full should be - // reset to single width. When erasing to the end, this could include - // the current line, if the cursor is in the first column. When erasing - // from the beginning, though, the current line would never be included, - // because the cursor could never be in the rightmost column (assuming - // the line is double width). - if (eraseType == DispatchTypes::EraseType::FromBeginning) + const auto endRow = csbiex.dwCursorPosition.Y; + _pConApi->ResetLineRenditionRange(csbiex.srWindow.Top, endRow); + } + if (eraseType == DispatchTypes::EraseType::ToEnd) + { + const auto startRow = csbiex.dwCursorPosition.Y + (csbiex.dwCursorPosition.X > 0 ? 1 : 0); + _pConApi->ResetLineRenditionRange(startRow, csbiex.srWindow.Bottom); + } + + // What we need to erase is grouped into 3 types: + // 1. Lines before cursor + // 2. Cursor Line + // 3. Lines after cursor + // We erase one or more of these based on the erase type: + // A. FromBeginning - Erase 1 and Some of 2. + // B. ToEnd - Erase some of 2 and 3. + // C. All - Erase 1, 2, and 3. + + // 1. Lines before cursor line + if (eraseType == DispatchTypes::EraseType::FromBeginning) + { + // For beginning and all, erase all complete lines before (above vertically) from the cursor position. + for (SHORT startLine = csbiex.srWindow.Top; startLine < csbiex.dwCursorPosition.Y; startLine++) { - const auto endRow = csbiex.dwCursorPosition.Y; - _pConApi->PrivateResetLineRenditionRange(csbiex.srWindow.Top, endRow); - } - if (eraseType == DispatchTypes::EraseType::ToEnd) - { - const auto startRow = csbiex.dwCursorPosition.Y + (csbiex.dwCursorPosition.X > 0 ? 1 : 0); - _pConApi->PrivateResetLineRenditionRange(startRow, csbiex.srWindow.Bottom); - } - - // What we need to erase is grouped into 3 types: - // 1. Lines before cursor - // 2. Cursor Line - // 3. Lines after cursor - // We erase one or more of these based on the erase type: - // A. FromBeginning - Erase 1 and Some of 2. - // B. ToEnd - Erase some of 2 and 3. - // C. All - Erase 1, 2, and 3. - - // 1. Lines before cursor line - if (eraseType == DispatchTypes::EraseType::FromBeginning) - { - // For beginning and all, erase all complete lines before (above vertically) from the cursor position. - for (SHORT startLine = csbiex.srWindow.Top; startLine < csbiex.dwCursorPosition.Y; startLine++) - { - success = _EraseSingleLineHelper(csbiex, DispatchTypes::EraseType::All, startLine); - - if (!success) - { - break; - } - } - } - - if (success) - { - // 2. Cursor Line - success = _EraseSingleLineHelper(csbiex, eraseType, csbiex.dwCursorPosition.Y); - } - - if (success) - { - // 3. Lines after cursor line - if (eraseType == DispatchTypes::EraseType::ToEnd) - { - // For beginning and all, erase all complete lines after (below vertically) the cursor position. - // Remember that the viewport bottom value is 1 beyond the viewable area of the viewport. - for (SHORT startLine = csbiex.dwCursorPosition.Y + 1; startLine < csbiex.srWindow.Bottom; startLine++) - { - success = _EraseSingleLineHelper(csbiex, DispatchTypes::EraseType::All, startLine); - - if (!success) - { - break; - } - } - } + _EraseSingleLineHelper(csbiex, DispatchTypes::EraseType::All, startLine); } } - return success; + // 2. Cursor Line + _EraseSingleLineHelper(csbiex, eraseType, csbiex.dwCursorPosition.Y); + + // 3. Lines after cursor line + if (eraseType == DispatchTypes::EraseType::ToEnd) + { + // For beginning and all, erase all complete lines after (below vertically) the cursor position. + // Remember that the viewport bottom value is 1 beyond the viewable area of the viewport. + for (SHORT startLine = csbiex.dwCursorPosition.Y + 1; startLine < csbiex.srWindow.Bottom; startLine++) + { + _EraseSingleLineHelper(csbiex, DispatchTypes::EraseType::All, startLine); + } + } + + return true; } // Routine Description: @@ -708,14 +669,11 @@ bool AdaptDispatch::EraseInLine(const DispatchTypes::EraseType eraseType) CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - bool success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) - { - success = _EraseSingleLineHelper(csbiex, eraseType, csbiex.dwCursorPosition.Y); - } + _EraseSingleLineHelper(csbiex, eraseType, csbiex.dwCursorPosition.Y); - return success; + return true; } // Routine Description: @@ -724,10 +682,11 @@ bool AdaptDispatch::EraseInLine(const DispatchTypes::EraseType eraseType) // - rendition - Determines whether the line will be rendered as single width, double // width, or as one half of a double height line. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetLineRendition(const LineRendition rendition) { - return _pConApi->PrivateSetCurrentLineRendition(rendition); + _pConApi->SetCurrentLineRendition(rendition); + return true; } // Routine Description: @@ -739,19 +698,17 @@ bool AdaptDispatch::SetLineRendition(const LineRendition rendition) // - True if handled successfully. False otherwise. bool AdaptDispatch::DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType) { - bool success = false; - switch (statusType) { case DispatchTypes::AnsiStatusType::OS_OperatingStatus: - success = _OperatingStatus(); - break; + _OperatingStatus(); + return true; case DispatchTypes::AnsiStatusType::CPR_CursorPositionReport: - success = _CursorPositionReport(); - break; + _CursorPositionReport(); + return true; + default: + return false; } - - return success; } // Routine Description: @@ -760,11 +717,12 @@ bool AdaptDispatch::DeviceStatusReport(const DispatchTypes::AnsiStatusType statu // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::DeviceAttributes() { // See: http://vt100.net/docs/vt100-ug/chapter3.html#DA - return _WriteResponse(L"\x1b[?1;0c"); + _WriteResponse(L"\x1b[?1;0c"); + return true; } // Routine Description: @@ -775,10 +733,11 @@ bool AdaptDispatch::DeviceAttributes() // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SecondaryDeviceAttributes() { - return _WriteResponse(L"\x1b[>0;10;1c"); + _WriteResponse(L"\x1b[>0;10;1c"); + return true; } // Routine Description: @@ -787,10 +746,11 @@ bool AdaptDispatch::SecondaryDeviceAttributes() // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::TertiaryDeviceAttributes() { - return _WriteResponse(L"\x1bP!|00000000\x1b\\"); + _WriteResponse(L"\x1bP!|00000000\x1b\\"); + return true; } // Routine Description: @@ -800,10 +760,11 @@ bool AdaptDispatch::TertiaryDeviceAttributes() // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::Vt52DeviceAttributes() { - return _WriteResponse(L"\x1b/Z"); + _WriteResponse(L"\x1b/Z"); + return true; } // Routine Description: @@ -832,9 +793,11 @@ bool AdaptDispatch::RequestTerminalParameters(const DispatchTypes::ReportingPerm switch (permission) { case DispatchTypes::ReportingPermission::Unsolicited: - return _WriteResponse(L"\x1b[2;1;1;128;128;1;0x"); + _WriteResponse(L"\x1b[2;1;1;128;128;1;0x"); + return true; case DispatchTypes::ReportingPermission::Solicited: - return _WriteResponse(L"\x1b[3;1;1;128;128;1;0x"); + _WriteResponse(L"\x1b[3;1;1;128;128;1;0x"); + return true; default: return false; } @@ -845,11 +808,11 @@ bool AdaptDispatch::RequestTerminalParameters(const DispatchTypes::ReportingPerm // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_OperatingStatus() const +// - +void AdaptDispatch::_OperatingStatus() const { // We always report a good operating condition. - return _WriteResponse(L"\x1b[0n"); + _WriteResponse(L"\x1b[0n"); } // Routine Description: @@ -857,40 +820,36 @@ bool AdaptDispatch::_OperatingStatus() const // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_CursorPositionReport() const +// - +void AdaptDispatch::_CursorPositionReport() const { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - bool success = (_pConApi->MoveToBottom() && _pConApi->GetConsoleScreenBufferInfoEx(csbiex)); + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) + // First pull the cursor position relative to the entire buffer out of the console. + COORD coordCursorPos = csbiex.dwCursorPosition; + + // Now adjust it for its position in respect to the current viewport top. + coordCursorPos.Y -= csbiex.srWindow.Top; + + // NOTE: 1,1 is the top-left corner of the viewport in VT-speak, so add 1. + coordCursorPos.X++; + coordCursorPos.Y++; + + // If the origin mode is relative, line numbers start at top margin of the scrolling region. + if (_isOriginModeRelative) { - // First pull the cursor position relative to the entire buffer out of the console. - COORD coordCursorPos = csbiex.dwCursorPosition; - - // Now adjust it for its position in respect to the current viewport top. - coordCursorPos.Y -= csbiex.srWindow.Top; - - // NOTE: 1,1 is the top-left corner of the viewport in VT-speak, so add 1. - coordCursorPos.X++; - coordCursorPos.Y++; - - // If the origin mode is relative, line numbers start at top margin of the scrolling region. - if (_isOriginModeRelative) - { - coordCursorPos.Y -= _scrollMargins.Top; - } - - // Now send it back into the input channel of the console. - // First format the response string. - const auto response = wil::str_printf(L"\x1b[%d;%dR", coordCursorPos.Y, coordCursorPos.X); - success = _WriteResponse(response); + coordCursorPos.Y -= _scrollMargins.Top; } - return success; + // Now send it back into the input channel of the console. + // First format the response string. + const auto response = wil::str_printf(L"\x1b[%d;%dR", coordCursorPos.Y, coordCursorPos.X); + _WriteResponse(response); } // Routine Description: @@ -900,29 +859,21 @@ bool AdaptDispatch::_CursorPositionReport() const // Arguments: // - reply - The reply string to transmit back to the input stream // Return Value: -// - True if the string was converted to input events and placed into the console input buffer successfully. False otherwise. -bool AdaptDispatch::_WriteResponse(const std::wstring_view reply) const +// - +void AdaptDispatch::_WriteResponse(const std::wstring_view reply) const { - bool success = false; std::deque> inEvents; - try - { - // generate a paired key down and key up event for every - // character to be sent into the console's input buffer - for (const auto& wch : reply) - { - // This wasn't from a real keyboard, so we're leaving key/scan codes blank. - KeyEvent keyEvent{ TRUE, 1, 0, 0, wch, 0 }; - inEvents.push_back(std::make_unique(keyEvent)); - keyEvent.SetKeyDown(false); - inEvents.push_back(std::make_unique(keyEvent)); - } - } - catch (...) + // generate a paired key down and key up event for every + // character to be sent into the console's input buffer + for (const auto& wch : reply) { - LOG_HR(wil::ResultFromCaughtException()); - return false; + // This wasn't from a real keyboard, so we're leaving key/scan codes blank. + KeyEvent keyEvent{ TRUE, 1, 0, 0, wch, 0 }; + + inEvents.push_back(std::make_unique(keyEvent)); + keyEvent.SetKeyDown(false); + inEvents.push_back(std::make_unique(keyEvent)); } size_t eventsWritten; @@ -930,9 +881,7 @@ bool AdaptDispatch::_WriteResponse(const std::wstring_view reply) const // to make sure that "response" input is spooled directly into the application. // We switched this to an append (vs. a prepend) to fix GH#1637, a bug where two CPR // could collide with eachother. - success = _pConApi->PrivateWriteConsoleInputW(inEvents, eventsWritten); - - return success; + _pConApi->WriteInput(inEvents, eventsWritten); } // Routine Description: @@ -941,49 +890,42 @@ bool AdaptDispatch::_WriteResponse(const std::wstring_view reply) const // - scrollDirection - Specific direction to move // - distance - Magnitude of the move // Return Value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_ScrollMovement(const ScrollDirection scrollDirection, const size_t distance) const +// - +void AdaptDispatch::_ScrollMovement(const ScrollDirection scrollDirection, const size_t distance) const { // We'll be doing short math on the distance since all console APIs use shorts. So check that we can successfully convert the size_t into a short first. SHORT dist; - bool success = SUCCEEDED(SizeTToShort(distance, &dist)); + THROW_IF_FAILED(SizeTToShort(distance, &dist)); - if (success) + // get current cursor + CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; + csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + // Make sure to reset the viewport (with MoveToBottom )to where it was + // before the user scrolled the console output + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + + // Rectangle to cut out of the existing buffer. This is inclusive. + // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. + SMALL_RECT srScreen; + srScreen.Left = 0; + srScreen.Right = SHORT_MAX; + srScreen.Top = csbiex.srWindow.Top; + srScreen.Bottom = csbiex.srWindow.Bottom - 1; // srWindow is exclusive, hence the - 1 + // Clip to the DECSTBM margin boundaries + if (_scrollMargins.Top < _scrollMargins.Bottom) { - // get current cursor - CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; - csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - // Make sure to reset the viewport (with MoveToBottom )to where it was - // before the user scrolled the console output - success = (_pConApi->MoveToBottom() && _pConApi->GetConsoleScreenBufferInfoEx(csbiex)); - - if (success) - { - // Rectangle to cut out of the existing buffer. This is inclusive. - // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. - SMALL_RECT srScreen; - srScreen.Left = 0; - srScreen.Right = SHORT_MAX; - srScreen.Top = csbiex.srWindow.Top; - srScreen.Bottom = csbiex.srWindow.Bottom - 1; // srWindow is exclusive, hence the - 1 - // Clip to the DECSTBM margin boundaries - if (_scrollMargins.Top < _scrollMargins.Bottom) - { - srScreen.Top = csbiex.srWindow.Top + _scrollMargins.Top; - srScreen.Bottom = csbiex.srWindow.Top + _scrollMargins.Bottom; - } - - // Paste coordinate for cut text above - COORD coordDestination; - coordDestination.X = srScreen.Left; - coordDestination.Y = srScreen.Top + dist * (scrollDirection == ScrollDirection::Up ? -1 : 1); - - // Note the revealed lines are filled with the standard erase attributes. - success = _pConApi->PrivateScrollRegion(srScreen, srScreen, coordDestination, true); - } + srScreen.Top = csbiex.srWindow.Top + _scrollMargins.Top; + srScreen.Bottom = csbiex.srWindow.Top + _scrollMargins.Bottom; } - return success; + // Paste coordinate for cut text above + COORD coordDestination; + coordDestination.X = srScreen.Left; + coordDestination.Y = srScreen.Top + dist * (scrollDirection == ScrollDirection::Up ? -1 : 1); + + // Note the revealed lines are filled with the standard erase attributes. + _pConApi->ScrollRegion(srScreen, srScreen, coordDestination, true); } // Routine Description: @@ -991,10 +933,11 @@ bool AdaptDispatch::_ScrollMovement(const ScrollDirection scrollDirection, const // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::ScrollUp(const size_t uiDistance) { - return _ScrollMovement(ScrollDirection::Up, uiDistance); + _ScrollMovement(ScrollDirection::Up, uiDistance); + return true; } // Routine Description: @@ -1002,10 +945,11 @@ bool AdaptDispatch::ScrollUp(const size_t uiDistance) // Arguments: // - distance - Distance to move // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::ScrollDown(const size_t uiDistance) { - return _ScrollMovement(ScrollDirection::Down, uiDistance); + _ScrollMovement(ScrollDirection::Down, uiDistance); + return true; } // Routine Description: @@ -1015,24 +959,19 @@ bool AdaptDispatch::ScrollDown(const size_t uiDistance) // Arguments: // - columns - Number of columns // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetColumns(const size_t columns) { SHORT col; - bool success = SUCCEEDED(SizeTToShort(columns, &col)); - if (success) - { - CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; - csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + THROW_IF_FAILED(SizeTToShort(columns, &col)); - if (success) - { - csbiex.dwSize.X = col; - success = _pConApi->SetConsoleScreenBufferInfoEx(csbiex); - } - } - return success; + CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; + csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + csbiex.dwSize.X = col; + _pConApi->SetConsoleScreenBufferInfoEx(csbiex); + + return true; } // Routine Description: @@ -1041,33 +980,19 @@ bool AdaptDispatch::SetColumns(const size_t columns) // Arguments: // - columns - Number of columns // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::_DoDECCOLMHelper(const size_t columns) { - if (!_isDECCOLMAllowed) + // Only proceed if DECCOLM is allowed. Return true, as this is technically a successful handling. + if (_isDECCOLMAllowed) { - // Only proceed if DECCOLM is allowed. Return true, as this is technically a successful handling. - return true; + SetColumns(columns); + SetOriginMode(false); + CursorPosition(1, 1); + EraseInDisplay(DispatchTypes::EraseType::All); + _DoSetTopBottomScrollingMargins(0, 0); } - - bool success = SetColumns(columns); - if (success) - { - success = SetOriginMode(false); - if (success) - { - success = CursorPosition(1, 1); - if (success) - { - success = EraseInDisplay(DispatchTypes::EraseType::All); - if (success) - { - success = _DoSetTopBottomScrollingMargins(0, 0); - } - } - } - } - return success; + return true; } // Routine Description: @@ -1204,7 +1129,7 @@ bool AdaptDispatch::SetCursorKeysMode(const bool applicationMode) // - True if handled successfully. False otherwise. bool AdaptDispatch::EnableCursorBlinking(const bool enable) { - return _pConApi->PrivateAllowCursorBlinking(enable); + return _pConApi->EnableCursorBlinking(enable); } // Routine Description: @@ -1214,10 +1139,11 @@ bool AdaptDispatch::EnableCursorBlinking(const bool enable) // Arguments: // - distance - number of lines to insert // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::InsertLine(const size_t distance) { - return _pConApi->InsertLines(distance); + _pConApi->InsertLines(distance); + return true; } // Routine Description: @@ -1231,17 +1157,18 @@ bool AdaptDispatch::InsertLine(const size_t distance) // Arguments: // - distance - number of lines to delete // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::DeleteLine(const size_t distance) { - return _pConApi->DeleteLines(distance); + _pConApi->DeleteLines(distance); + return true; } // - DECANM - Sets the terminal emulation mode to either ANSI-compatible or VT52. // Arguments: // - ansiMode - set to true to enable the ANSI mode, false for VT52 mode. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetAnsiMode(const bool ansiMode) { // When an attempt is made to update the mode, the designated character sets @@ -1271,7 +1198,8 @@ bool AdaptDispatch::SetScreenMode(const bool reverseMode) return false; } - return _pConApi->SetRenderMode(RenderSettings::Mode::ScreenReversed, reverseMode); + _pConApi->SetRenderMode(RenderSettings::Mode::ScreenReversed, reverseMode); + return true; } // Routine Description: @@ -1281,7 +1209,7 @@ bool AdaptDispatch::SetScreenMode(const bool reverseMode) // Arguments: // - relativeMode - set to true to use relative addressing, false for absolute addressing. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetOriginMode(const bool relativeMode) noexcept { _isOriginModeRelative = relativeMode; @@ -1295,10 +1223,11 @@ bool AdaptDispatch::SetOriginMode(const bool relativeMode) noexcept // Arguments: // - wrapAtEOL - set to true to wrap, false to overwrite the last character. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetAutoWrapMode(const bool wrapAtEOL) { - return _pConApi->PrivateSetAutoWrapMode(wrapAtEOL); + _pConApi->SetAutoWrapMode(wrapAtEOL); + return true; } // Routine Description: @@ -1310,66 +1239,61 @@ bool AdaptDispatch::SetAutoWrapMode(const bool wrapAtEOL) // - topMargin - the line number for the top margin. // - bottomMargin - the line number for the bottom margin. // Return Value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_DoSetTopBottomScrollingMargins(const size_t topMargin, +// - +void AdaptDispatch::_DoSetTopBottomScrollingMargins(const size_t topMargin, const size_t bottomMargin) { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - bool success = (_pConApi->MoveToBottom() && _pConApi->GetConsoleScreenBufferInfoEx(csbiex)); + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); // 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) // having only a bottom param is legal ([;3r -> 0,3 -> 1,3 -> 1,3,true) // having neither uses the defaults ([;r [r -> 0,0 -> 0,0 -> 0,0,false) // an illegal combo (eg, 3;2r) is ignored - if (success) + SHORT actualTop = 0; + SHORT actualBottom = 0; + THROW_IF_FAILED(SizeTToShort(topMargin, &actualTop)); + THROW_IF_FAILED(SizeTToShort(bottomMargin, &actualBottom)); + + const SHORT screenHeight = csbiex.srWindow.Bottom - csbiex.srWindow.Top; + // The default top margin is line 1 + if (actualTop == 0) { - SHORT actualTop = 0; - SHORT actualBottom = 0; - success = SUCCEEDED(SizeTToShort(topMargin, &actualTop)) && SUCCEEDED(SizeTToShort(bottomMargin, &actualBottom)); - if (success) - { - const SHORT screenHeight = csbiex.srWindow.Bottom - csbiex.srWindow.Top; - // The default top margin is line 1 - if (actualTop == 0) - { - actualTop = 1; - } - // The default bottom margin is the screen height - if (actualBottom == 0) - { - actualBottom = screenHeight; - } - // The top margin must be less than the bottom margin, and the - // bottom margin must be less than or equal to the screen height - success = (actualTop < actualBottom && actualBottom <= screenHeight); - if (success) - { - if (actualTop == 1 && actualBottom == screenHeight) - { - // Client requests setting margins to the entire screen - // - clear them instead of setting them. - // This is for apps like `apt` (NOT `apt-get` which set scroll - // margins, but don't use the alt buffer.) - actualTop = 0; - actualBottom = 0; - } - else - { - // In VT, the origin is 1,1. For our array, it's 0,0. So subtract 1. - actualTop -= 1; - actualBottom -= 1; - } - _scrollMargins.Top = actualTop; - _scrollMargins.Bottom = actualBottom; - success = _pConApi->PrivateSetScrollingRegion(_scrollMargins); - } - } + actualTop = 1; + } + // The default bottom margin is the screen height + if (actualBottom == 0) + { + actualBottom = screenHeight; + } + // The top margin must be less than the bottom margin, and the + // bottom margin must be less than or equal to the screen height + if (actualTop < actualBottom && actualBottom <= screenHeight) + { + if (actualTop == 1 && actualBottom == screenHeight) + { + // Client requests setting margins to the entire screen + // - clear them instead of setting them. + // This is for apps like `apt` (NOT `apt-get` which set scroll + // margins, but don't use the alt buffer.) + actualTop = 0; + actualBottom = 0; + } + else + { + // In VT, the origin is 1,1. For our array, it's 0,0. So subtract 1. + actualTop -= 1; + actualBottom -= 1; + } + _scrollMargins.Top = actualTop; + _scrollMargins.Bottom = actualBottom; + _pConApi->SetScrollingRegion(_scrollMargins); } - return success; } // Routine Description: @@ -1381,13 +1305,15 @@ bool AdaptDispatch::_DoSetTopBottomScrollingMargins(const size_t topMargin, // - topMargin - the line number for the top margin. // - bottomMargin - the line number for the bottom margin. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetTopBottomScrollingMargins(const size_t topMargin, const size_t 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 - return _DoSetTopBottomScrollingMargins(topMargin, bottomMargin) && CursorPosition(1, 1); + _DoSetTopBottomScrollingMargins(topMargin, bottomMargin); + CursorPosition(1, 1); + return true; } // Routine Description: @@ -1396,10 +1322,11 @@ bool AdaptDispatch::SetTopBottomScrollingMargins(const size_t topMargin, // Arguments: // - None // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::WarningBell() { - return _pConApi->PrivateWarningBell(); + _pConApi->WarningBell(); + return true; } // Routine Description: @@ -1408,7 +1335,7 @@ bool AdaptDispatch::WarningBell() // Arguments: // - None // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::CarriageReturn() { return _CursorMovePosition(Offset::Unchanged(), Offset::Absolute(1), true); @@ -1426,11 +1353,14 @@ bool AdaptDispatch::LineFeed(const DispatchTypes::LineFeedType lineFeedType) switch (lineFeedType) { case DispatchTypes::LineFeedType::DependsOnMode: - return _pConApi->PrivateLineFeed(_pConApi->PrivateGetLineFeedMode()); + _pConApi->LineFeed(_pConApi->GetLineFeedMode()); + return true; case DispatchTypes::LineFeedType::WithoutReturn: - return _pConApi->PrivateLineFeed(false); + _pConApi->LineFeed(false); + return true; case DispatchTypes::LineFeedType::WithReturn: - return _pConApi->PrivateLineFeed(true); + _pConApi->LineFeed(true); + return true; default: return false; } @@ -1442,10 +1372,11 @@ bool AdaptDispatch::LineFeed(const DispatchTypes::LineFeedType lineFeedType) // Arguments: // - None // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::ReverseLineFeed() { - return _pConApi->PrivateReverseLineFeed(); + _pConApi->ReverseLineFeed(); + return true; } // Routine Description: @@ -1453,10 +1384,11 @@ bool AdaptDispatch::ReverseLineFeed() // Arguments: // - title - The string to set the title to. Must be null terminated. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetWindowTitle(std::wstring_view title) { - return _pConApi->SetConsoleTitleW(title); + _pConApi->SetWindowTitle(title); + return true; } // - ASBSET - Creates and swaps to the alternate screen buffer. In virtual terminals, there exists both a "main" @@ -1465,19 +1397,13 @@ bool AdaptDispatch::SetWindowTitle(std::wstring_view title) // Arguments: // - None // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::UseAlternateScreenBuffer() { - bool success = CursorSaveState(); - if (success) - { - success = _pConApi->PrivateUseAlternateScreenBuffer(); - if (success) - { - _usingAltBuffer = true; - } - } - return success; + CursorSaveState(); + _pConApi->UseAlternateScreenBuffer(); + _usingAltBuffer = true; + return true; } // Routine Description: @@ -1486,19 +1412,13 @@ bool AdaptDispatch::UseAlternateScreenBuffer() // Arguments: // - None // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::UseMainScreenBuffer() { - bool success = _pConApi->PrivateUseMainScreenBuffer(); - if (success) - { - _usingAltBuffer = false; - if (success) - { - success = CursorRestoreState(); - } - } - return success; + _pConApi->UseMainScreenBuffer(); + _usingAltBuffer = false; + CursorRestoreState(); + return true; } //Routine Description: @@ -1506,21 +1426,20 @@ bool AdaptDispatch::UseMainScreenBuffer() //Arguments: // - None // Return value: -// True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::HorizontalTabSet() { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - const bool success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) - { - const auto width = csbiex.dwSize.X; - const auto column = csbiex.dwCursorPosition.X; + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - _InitTabStopsForWidth(width); - _tabStopColumns.at(column) = true; - } - return success; + const auto width = csbiex.dwSize.X; + const auto column = csbiex.dwCursorPosition.X; + + _InitTabStopsForWidth(width); + _tabStopColumns.at(column) = true; + + return true; } //Routine Description: @@ -1531,32 +1450,30 @@ bool AdaptDispatch::HorizontalTabSet() //Arguments: // - numTabs - the number of tabs to perform // Return value: -// True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::ForwardTab(const size_t numTabs) { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - bool success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + + const auto width = csbiex.dwSize.X; + const auto row = csbiex.dwCursorPosition.Y; + auto column = csbiex.dwCursorPosition.X; + auto tabsPerformed = 0u; + + _InitTabStopsForWidth(width); + while (column + 1 < width && tabsPerformed < numTabs) { - const auto width = csbiex.dwSize.X; - const auto row = csbiex.dwCursorPosition.Y; - auto column = csbiex.dwCursorPosition.X; - auto tabsPerformed = 0u; - - _InitTabStopsForWidth(width); - while (column + 1 < width && tabsPerformed < numTabs) + column++; + if (til::at(_tabStopColumns, column)) { - column++; - if (til::at(_tabStopColumns, column)) - { - tabsPerformed++; - } + tabsPerformed++; } - - success = _pConApi->SetConsoleCursorPosition({ column, row }); } - return success; + + _pConApi->SetCursorPosition({ column, row }); + return true; } //Routine Description: @@ -1565,32 +1482,30 @@ bool AdaptDispatch::ForwardTab(const size_t numTabs) //Arguments: // - numTabs - the number of tabs to perform // Return value: -// True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::BackwardsTab(const size_t numTabs) { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - bool success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + + const auto width = csbiex.dwSize.X; + const auto row = csbiex.dwCursorPosition.Y; + auto column = csbiex.dwCursorPosition.X; + auto tabsPerformed = 0u; + + _InitTabStopsForWidth(width); + while (column > 0 && tabsPerformed < numTabs) { - const auto width = csbiex.dwSize.X; - const auto row = csbiex.dwCursorPosition.Y; - auto column = csbiex.dwCursorPosition.X; - auto tabsPerformed = 0u; - - _InitTabStopsForWidth(width); - while (column > 0 && tabsPerformed < numTabs) + column--; + if (til::at(_tabStopColumns, column)) { - column--; - if (til::at(_tabStopColumns, column)) - { - tabsPerformed++; - } + tabsPerformed++; } - - success = _pConApi->SetConsoleCursorPosition({ column, row }); } - return success; + + _pConApi->SetCursorPosition({ column, row }); + return true; } //Routine Description: @@ -1603,20 +1518,17 @@ bool AdaptDispatch::BackwardsTab(const size_t numTabs) // True if handled successfully. False otherwise. bool AdaptDispatch::TabClear(const DispatchTypes::TabClearType clearType) { - bool success = false; switch (clearType) { case DispatchTypes::TabClearType::ClearCurrentColumn: - success = _ClearSingleTabStop(); - break; + _ClearSingleTabStop(); + return true; case DispatchTypes::TabClearType::ClearAllColumns: - success = _ClearAllTabStops(); - break; + _ClearAllTabStops(); + return true; default: - success = false; - break; + return false; } - return success; } // Routine Description: @@ -1624,21 +1536,18 @@ bool AdaptDispatch::TabClear(const DispatchTypes::TabClearType clearType) // Arguments: // - // Return value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_ClearSingleTabStop() +// - +void AdaptDispatch::_ClearSingleTabStop() { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - const bool success = _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) - { - const auto width = csbiex.dwSize.X; - const auto column = csbiex.dwCursorPosition.X; + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - _InitTabStopsForWidth(width); - _tabStopColumns.at(column) = false; - } - return success; + const auto width = csbiex.dwSize.X; + const auto column = csbiex.dwCursorPosition.X; + + _InitTabStopsForWidth(width); + _tabStopColumns.at(column) = false; } // Routine Description: @@ -1647,12 +1556,11 @@ bool AdaptDispatch::_ClearSingleTabStop() // Arguments: // - // Return value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_ClearAllTabStops() noexcept +// - +void AdaptDispatch::_ClearAllTabStops() noexcept { _tabStopColumns.clear(); _initDefaultTabStops = false; - return true; } // Routine Description: @@ -1711,35 +1619,24 @@ bool AdaptDispatch::DesignateCodingSystem(const VTID codingSystem) // This will be used to restore the code page in response to a reset. if (!_initialCodePage.has_value()) { - unsigned int currentCodePage; - _pConApi->GetConsoleOutputCP(currentCodePage); - _initialCodePage = currentCodePage; + _initialCodePage = _pConApi->GetConsoleOutputCP(); } - bool success = false; switch (codingSystem) { case DispatchTypes::CodingSystem::ISO2022: - success = _pConApi->SetConsoleOutputCP(28591); - if (success) - { - AcceptC1Controls(true); - _termOutput.EnableGrTranslation(true); - } - break; + _pConApi->SetConsoleOutputCP(28591); + AcceptC1Controls(true); + _termOutput.EnableGrTranslation(true); + return true; case DispatchTypes::CodingSystem::UTF8: - success = _pConApi->SetConsoleOutputCP(CP_UTF8); - if (success) - { - AcceptC1Controls(false); - _termOutput.EnableGrTranslation(false); - } - break; + _pConApi->SetConsoleOutputCP(CP_UTF8); + AcceptC1Controls(false); + _termOutput.EnableGrTranslation(false); + return true; default: - success = false; - break; + return false; } - return success; } //Routine Description: @@ -1810,10 +1707,11 @@ bool AdaptDispatch::SingleShift(const size_t gsetNumber) //Arguments: // - enabled - true to allow C1 controls to be used, false to disallow. // Return value: -// True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::AcceptC1Controls(const bool enabled) { - return _pConApi->SetParserMode(StateMachine::Mode::AcceptC1, enabled); + _pConApi->SetParserMode(StateMachine::Mode::AcceptC1, enabled); + return true; } //Routine Description: @@ -1849,25 +1747,25 @@ bool AdaptDispatch::AcceptC1Controls(const bool enabled) // True if handled successfully. False otherwise. bool AdaptDispatch::SoftReset() { - bool success = CursorVisibility(true); // Cursor enabled. - success = SetOriginMode(false) && success; // Absolute cursor addressing. - success = SetAutoWrapMode(true) && success; // Wrap at end of line. - success = SetCursorKeysMode(false) && success; // Normal characters. - success = SetKeypadMode(false) && success; // Numeric characters. + CursorVisibility(true); // Cursor enabled. + SetOriginMode(false); // Absolute cursor addressing. + SetAutoWrapMode(true); // Wrap at end of line. + SetCursorKeysMode(false); // Normal characters. + SetKeypadMode(false); // Numeric characters. // Top margin = 1; bottom margin = page length. - success = _DoSetTopBottomScrollingMargins(0, 0) && success; + _DoSetTopBottomScrollingMargins(0, 0); _termOutput = {}; // Reset all character set designations. if (_initialCodePage.has_value()) { // Restore initial code page if previously changed by a DOCS sequence. - success = _pConApi->SetConsoleOutputCP(_initialCodePage.value()) && success; + _pConApi->SetConsoleOutputCP(_initialCodePage.value()); } // Disable parsing of C1 control codes. - success = AcceptC1Controls(false) && success; + AcceptC1Controls(false); - success = SetGraphicsRendition({}) && success; // Normal rendition. + SetGraphicsRendition({}); // Normal rendition. // Reset the saved cursor state. // Note that XTerm only resets the main buffer state, but that @@ -1875,7 +1773,7 @@ bool AdaptDispatch::SoftReset() _savedCursorState.at(0) = {}; // Main buffer _savedCursorState.at(1) = {}; // Alt buffer - return success; + return !_pConApi->IsConsolePty(); } //Routine Description: @@ -1902,50 +1800,43 @@ bool AdaptDispatch::SoftReset() // True if handled successfully. False otherwise. bool AdaptDispatch::HardReset() { - bool success = true; - // If in the alt buffer, switch back to main before doing anything else. if (_usingAltBuffer) { - success = _pConApi->PrivateUseMainScreenBuffer(); - _usingAltBuffer = !success; + _pConApi->UseMainScreenBuffer(); + _usingAltBuffer = false; } // Sets the SGR state to normal - this must be done before EraseInDisplay // to ensure that it clears with the default background color. - success = SoftReset() && success; + SoftReset(); // Clears the screen - Needs to be done in two operations. - success = EraseInDisplay(DispatchTypes::EraseType::All) && success; - success = EraseInDisplay(DispatchTypes::EraseType::Scrollback) && success; + EraseInDisplay(DispatchTypes::EraseType::All); + EraseInDisplay(DispatchTypes::EraseType::Scrollback); // Set the DECSCNM screen mode back to normal. - success = SetScreenMode(false) && success; + SetScreenMode(false); // Cursor to 1,1 - the Soft Reset guarantees this is absolute - success = CursorPosition(1, 1) && success; + CursorPosition(1, 1); // Reset the mouse mode - success = EnableSGRExtendedMouseMode(false) && success; - success = EnableAnyEventMouseMode(false) && success; + EnableSGRExtendedMouseMode(false); + EnableAnyEventMouseMode(false); // Delete all current tab stops and reapply _ResetTabStops(); // Clear the soft font in the renderer and delete the font buffer. - success = _pConApi->PrivateUpdateSoftFont({}, {}, false) && success; + _pConApi->UpdateSoftFont({}, {}, false); _fontBuffer = nullptr; // GH#2715 - If all this succeeded, but we're in a conpty, return `false` to // make the state machine propagate this RIS sequence to the connected // terminal application. We've reset our state, but the connected terminal // might need to do more. - if (_pConApi->IsConsolePty()) - { - return false; - } - - return success; + return !_pConApi->IsConsolePty(); } // Routine Description: @@ -1955,39 +1846,34 @@ bool AdaptDispatch::HardReset() // Arguments: // - None // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::ScreenAlignmentPattern() { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - bool success = _pConApi->MoveToBottom() && _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - if (success) - { - // Fill the screen with the letter E using the default attributes. - auto fillPosition = COORD{ 0, csbiex.srWindow.Top }; - const auto fillLength = (csbiex.srWindow.Bottom - csbiex.srWindow.Top) * csbiex.dwSize.X; - success = _pConApi->PrivateFillRegion(fillPosition, fillLength, L'E', false); - // Reset the line rendition for all of these rows. - success = success && _pConApi->PrivateResetLineRenditionRange(csbiex.srWindow.Top, csbiex.srWindow.Bottom); - // Reset the meta/extended attributes (but leave the colors unchanged). - TextAttribute attr; - if (_pConApi->PrivateGetTextAttributes(attr)) - { - attr.SetStandardErase(); - success = success && _pConApi->PrivateSetTextAttributes(attr); - } - // Reset the origin mode to absolute. - success = success && SetOriginMode(false); - // Clear the scrolling margins. - success = success && _DoSetTopBottomScrollingMargins(0, 0); - // Set the cursor position to home. - success = success && CursorPosition(1, 1); - } + // Fill the screen with the letter E using the default attributes. + auto fillPosition = COORD{ 0, csbiex.srWindow.Top }; + const auto fillLength = (csbiex.srWindow.Bottom - csbiex.srWindow.Top) * csbiex.dwSize.X; + _pConApi->FillRegion(fillPosition, fillLength, L'E', false); + // Reset the line rendition for all of these rows. + _pConApi->ResetLineRenditionRange(csbiex.srWindow.Top, csbiex.srWindow.Bottom); + // Reset the meta/extended attributes (but leave the colors unchanged). + TextAttribute attr = _pConApi->GetTextAttributes(); + attr.SetStandardErase(); + _pConApi->SetTextAttributes(attr); + // Reset the origin mode to absolute. + SetOriginMode(false); + // Clear the scrolling margins. + _DoSetTopBottomScrollingMargins(0, 0); + // Set the cursor position to home. + CursorPosition(1, 1); - return success; + return true; } //Routine Description: @@ -2001,65 +1887,52 @@ bool AdaptDispatch::ScreenAlignmentPattern() // Arguments: // - // Return value: -// - True if handled successfully. False otherwise. -bool AdaptDispatch::_EraseScrollback() +// - +void AdaptDispatch::_EraseScrollback() { CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(csbiex); // Make sure to reset the viewport (with MoveToBottom )to where it was // before the user scrolled the console output - bool success = (_pConApi->GetConsoleScreenBufferInfoEx(csbiex) && _pConApi->MoveToBottom()); - if (success) - { - const SMALL_RECT screen = csbiex.srWindow; - const SHORT height = screen.Bottom - screen.Top; - FAIL_FAST_IF(!(height > 0)); - const COORD cursor = csbiex.dwCursorPosition; + _pConApi->MoveToBottom(); + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); - // Rectangle to cut out of the existing buffer - // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. - SMALL_RECT scroll = screen; - scroll.Left = 0; - scroll.Right = SHORT_MAX; - // Paste coordinate for cut text above - COORD destination; - destination.X = 0; - destination.Y = 0; + const SMALL_RECT screen = csbiex.srWindow; + const SHORT height = screen.Bottom - screen.Top; + THROW_HR_IF(E_UNEXPECTED, height <= 0); + const COORD cursor = csbiex.dwCursorPosition; - // Typically a scroll operation should fill with standard erase attributes, but in - // this case we need to use the default attributes, hence standardFillAttrs is false. - success = _pConApi->PrivateScrollRegion(scroll, std::nullopt, destination, false); - if (success) - { - // Clear everything after the viewport. - const DWORD totalAreaBelow = csbiex.dwSize.X * (csbiex.dwSize.Y - height); - const COORD coordBelowStartPosition = { 0, height }; - // Again we need to use the default attributes, hence standardFillAttrs is false. - success = _pConApi->PrivateFillRegion(coordBelowStartPosition, totalAreaBelow, L' ', false); - // Also reset the line rendition for all of the cleared rows. - success = success && _pConApi->PrivateResetLineRenditionRange(height, csbiex.dwSize.Y); + // Rectangle to cut out of the existing buffer + // It will be clipped to the buffer boundaries so SHORT_MAX gives us the full buffer width. + SMALL_RECT scroll = screen; + scroll.Left = 0; + scroll.Right = SHORT_MAX; + // Paste coordinate for cut text above + COORD destination; + destination.X = 0; + destination.Y = 0; - if (success) - { - // Move the viewport (CAN'T be done in one call with SetConsolescreenBufferInfoEx, because legacy) - SMALL_RECT newViewport; - newViewport.Left = screen.Left; - newViewport.Top = 0; - // SetConsoleWindowInfo uses an inclusive rect, while GetConsolescreenBufferInfo is exclusive - newViewport.Right = screen.Right - 1; - newViewport.Bottom = height - 1; - success = _pConApi->SetConsoleWindowInfo(true, newViewport); - - if (success) - { - // Move the cursor to the same relative location. - const COORD newcursor = { cursor.X, cursor.Y - screen.Top }; - success = _pConApi->SetConsoleCursorPosition(newcursor); - } - } - } - } - return success; + // Typically a scroll operation should fill with standard erase attributes, but in + // this case we need to use the default attributes, hence standardFillAttrs is false. + _pConApi->ScrollRegion(scroll, std::nullopt, destination, false); + // Clear everything after the viewport. + const DWORD totalAreaBelow = csbiex.dwSize.X * (csbiex.dwSize.Y - height); + const COORD coordBelowStartPosition = { 0, height }; + // Again we need to use the default attributes, hence standardFillAttrs is false. + _pConApi->FillRegion(coordBelowStartPosition, totalAreaBelow, L' ', false); + // Also reset the line rendition for all of the cleared rows. + _pConApi->ResetLineRenditionRange(height, csbiex.dwSize.Y); + // Move the viewport (CAN'T be done in one call with SetConsolescreenBufferInfoEx, because legacy) + SMALL_RECT newViewport; + newViewport.Left = screen.Left; + newViewport.Top = 0; + // SetWindowInfo uses an inclusive rect, while GetConsolescreenBufferInfo is exclusive + newViewport.Right = screen.Right - 1; + newViewport.Bottom = height - 1; + _pConApi->SetWindowInfo(true, newViewport); + // Move the cursor to the same relative location. + const COORD newcursor = { cursor.X, cursor.Y - screen.Top }; + _pConApi->SetCursorPosition(newcursor); } //Routine Description: @@ -2072,10 +1945,10 @@ bool AdaptDispatch::_EraseScrollback() //Arguments: // // Return value: -// True if handled successfully. False otherwise. -bool AdaptDispatch::_EraseAll() +// - +void AdaptDispatch::_EraseAll() { - return _pConApi->PrivateEraseAll(); + _pConApi->EraseAll(); } // Routine Description: @@ -2083,7 +1956,7 @@ bool AdaptDispatch::_EraseAll() // Arguments: // - enabled - set to true to allow DECCOLM to be used, false to disallow. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::EnableDECCOLMSupport(const bool enabled) noexcept { _isDECCOLMAllowed = enabled; @@ -2186,8 +2059,8 @@ bool AdaptDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) switch (cursorStyle) { case DispatchTypes::CursorStyle::UserDefault: - _pConApi->GetUserDefaultCursorStyle(actualType); fEnableBlinking = true; + actualType = _pConApi->GetUserDefaultCursorStyle(); break; case DispatchTypes::CursorStyle::BlinkingBlock: fEnableBlinking = true; @@ -2221,20 +2094,12 @@ bool AdaptDispatch::SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) return false; } - bool success = _pConApi->SetCursorStyle(actualType); - if (success) - { - success = _pConApi->PrivateAllowCursorBlinking(fEnableBlinking); - } + _pConApi->SetCursorStyle(actualType); + _pConApi->EnableCursorBlinking(fEnableBlinking); // If we're a conpty, always return false, so that this cursor state will be // sent to the connected terminal - if (_pConApi->IsConsolePty()) - { - return false; - } - - return success; + return !_pConApi->IsConsolePty(); } // Method Description: @@ -2312,23 +2177,20 @@ bool AdaptDispatch::WindowManipulation(const DispatchTypes::WindowManipulationTy const VTParameter parameter1, const VTParameter parameter2) { - bool success = false; // Other Window Manipulation functions: // MSFT:13271098 - QueryViewport // MSFT:13271146 - QueryScreenSize switch (function) { case DispatchTypes::WindowManipulationType::RefreshWindow: - success = DispatchCommon::s_RefreshWindow(*_pConApi); - break; + DispatchCommon::s_RefreshWindow(*_pConApi); + return true; case DispatchTypes::WindowManipulationType::ResizeWindowInCharacters: - success = DispatchCommon::s_ResizeWindow(*_pConApi, parameter2.value_or(0), parameter1.value_or(0)); - break; + DispatchCommon::s_ResizeWindow(*_pConApi, parameter2.value_or(0), parameter1.value_or(0)); + return true; default: - success = false; + return false; } - - return success; } // Method Description: @@ -2339,7 +2201,8 @@ bool AdaptDispatch::WindowManipulation(const DispatchTypes::WindowManipulationTy // - true bool AdaptDispatch::AddHyperlink(const std::wstring_view uri, const std::wstring_view params) { - return _pConApi->PrivateAddHyperlink(uri, params); + _pConApi->AddHyperlink(uri, params); + return true; } // Method Description: @@ -2348,7 +2211,8 @@ bool AdaptDispatch::AddHyperlink(const std::wstring_view uri, const std::wstring // - true bool AdaptDispatch::EndHyperlink() { - return _pConApi->PrivateEndHyperlink(); + _pConApi->EndHyperlink(); + return true; } // Method Description: @@ -2437,7 +2301,7 @@ ITermDispatch::StringHandler AdaptDispatch::DownloadDRCS(const size_t fontNumber const auto bitPattern = _fontBuffer->GetBitPattern(); const auto cellSize = _fontBuffer->GetCellSize(); const auto centeringHint = _fontBuffer->GetTextCenteringHint(); - _pConApi->PrivateUpdateSoftFont(bitPattern, cellSize.to_win32_size(), centeringHint); + _pConApi->UpdateSoftFont(bitPattern, cellSize.to_win32_size(), centeringHint); } return true; }; @@ -2504,53 +2368,50 @@ void AdaptDispatch::_ReportSGRSetting() const fmt::basic_memory_buffer response; response.append(L"\033P1$r0"sv); - TextAttribute attr; - if (_pConApi->PrivateGetTextAttributes(attr)) - { - // For each boolean attribute that is set, we add the appropriate - // parameter value to the response string. - const auto addAttribute = [&](const auto& parameter, const auto enabled) { - if (enabled) - { - response.append(parameter); - } - }; - addAttribute(L";1"sv, attr.IsIntense()); - addAttribute(L";2"sv, attr.IsFaint()); - addAttribute(L";3"sv, attr.IsItalic()); - addAttribute(L";4"sv, attr.IsUnderlined()); - addAttribute(L";5"sv, attr.IsBlinking()); - addAttribute(L";7"sv, attr.IsReverseVideo()); - addAttribute(L";8"sv, attr.IsInvisible()); - addAttribute(L";9"sv, attr.IsCrossedOut()); - addAttribute(L";21"sv, attr.IsDoublyUnderlined()); - addAttribute(L";53"sv, attr.IsOverlined()); + const auto attr = _pConApi->GetTextAttributes(); + // For each boolean attribute that is set, we add the appropriate + // parameter value to the response string. + const auto addAttribute = [&](const auto& parameter, const auto enabled) { + if (enabled) + { + response.append(parameter); + } + }; + addAttribute(L";1"sv, attr.IsIntense()); + addAttribute(L";2"sv, attr.IsFaint()); + addAttribute(L";3"sv, attr.IsItalic()); + addAttribute(L";4"sv, attr.IsUnderlined()); + addAttribute(L";5"sv, attr.IsBlinking()); + addAttribute(L";7"sv, attr.IsReverseVideo()); + addAttribute(L";8"sv, attr.IsInvisible()); + addAttribute(L";9"sv, attr.IsCrossedOut()); + addAttribute(L";21"sv, attr.IsDoublyUnderlined()); + addAttribute(L";53"sv, attr.IsOverlined()); - // We also need to add the appropriate color encoding parameters for - // both the foreground and background colors. - const auto addColor = [&](const auto base, const auto color) { - if (color.IsIndex16()) - { - const auto index = color.GetIndex(); - const auto colorParameter = base + (index >= 8 ? 60 : 0) + (index % 8); - fmt::format_to(std::back_inserter(response), FMT_COMPILE(L";{}"), colorParameter); - } - else if (color.IsIndex256()) - { - const auto index = color.GetIndex(); - fmt::format_to(std::back_inserter(response), FMT_COMPILE(L";{};5;{}"), base + 8, index); - } - else if (color.IsRgb()) - { - const auto r = GetRValue(color.GetRGB()); - const auto g = GetGValue(color.GetRGB()); - const auto b = GetBValue(color.GetRGB()); - fmt::format_to(std::back_inserter(response), FMT_COMPILE(L";{};2;{};{};{}"), base + 8, r, g, b); - } - }; - addColor(30, attr.GetForeground()); - addColor(40, attr.GetBackground()); - } + // We also need to add the appropriate color encoding parameters for + // both the foreground and background colors. + const auto addColor = [&](const auto base, const auto color) { + if (color.IsIndex16()) + { + const auto index = color.GetIndex(); + const auto colorParameter = base + (index >= 8 ? 60 : 0) + (index % 8); + fmt::format_to(std::back_inserter(response), FMT_COMPILE(L";{}"), colorParameter); + } + else if (color.IsIndex256()) + { + const auto index = color.GetIndex(); + fmt::format_to(std::back_inserter(response), FMT_COMPILE(L";{};5;{}"), base + 8, index); + } + else if (color.IsRgb()) + { + const auto r = GetRValue(color.GetRGB()); + const auto g = GetGValue(color.GetRGB()); + const auto b = GetBValue(color.GetRGB()); + fmt::format_to(std::back_inserter(response), FMT_COMPILE(L";{};2;{};{};{}"), base + 8, r, g, b); + } + }; + addColor(30, attr.GetForeground()); + addColor(40, attr.GetBackground()); // The 'm' indicates this is an SGR response, and ST ends the sequence. response.append(L"m\033\\"sv); @@ -2573,20 +2434,19 @@ void AdaptDispatch::_ReportDECSTBMSetting() const CONSOLE_SCREEN_BUFFER_INFOEX csbiex = { 0 }; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); - if (_pConApi->GetConsoleScreenBufferInfoEx(csbiex)) + _pConApi->GetConsoleScreenBufferInfoEx(csbiex); + + auto marginTop = _scrollMargins.Top + 1; + auto marginBottom = _scrollMargins.Bottom + 1; + // If the margin top is greater than or equal to the bottom, then the + // margins aren't actually set, so we need to return the full height + // of the window for the margin range. + if (marginTop >= marginBottom) { - auto marginTop = _scrollMargins.Top + 1; - auto marginBottom = _scrollMargins.Bottom + 1; - // If the margin top is greater than or equal to the bottom, then the - // margins aren't actually set, so we need to return the full height - // of the window for the margin range. - if (marginTop >= marginBottom) - { - marginTop = 1; - marginBottom = csbiex.srWindow.Bottom - csbiex.srWindow.Top; - } - fmt::format_to(std::back_inserter(response), FMT_COMPILE(L"{};{}"), marginTop, marginBottom); + marginTop = 1; + marginBottom = csbiex.srWindow.Bottom - csbiex.srWindow.Top; } + fmt::format_to(std::back_inserter(response), FMT_COMPILE(L"{};{}"), marginTop, marginBottom); // The 'r' indicates this is an DECSTBM response, and ST ends the sequence. response.append(L"r\033\\"sv); diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index be8db832d..97aefa8ae 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -171,25 +171,25 @@ namespace Microsoft::Console::VirtualTerminal }; bool _CursorMovePosition(const Offset rowOffset, const Offset colOffset, const bool clampInMargins) const; - bool _EraseSingleLineHelper(const CONSOLE_SCREEN_BUFFER_INFOEX& csbiex, + void _EraseSingleLineHelper(const CONSOLE_SCREEN_BUFFER_INFOEX& csbiex, const DispatchTypes::EraseType eraseType, const size_t lineId) const; - bool _EraseScrollback(); - bool _EraseAll(); - bool _InsertDeleteHelper(const size_t count, const bool isInsert) const; - bool _ScrollMovement(const ScrollDirection dir, const size_t distance) const; + void _EraseScrollback(); + void _EraseAll(); + void _InsertDeleteHelper(const size_t count, const bool isInsert) const; + void _ScrollMovement(const ScrollDirection dir, const size_t distance) const; - bool _DoSetTopBottomScrollingMargins(const size_t topMargin, + void _DoSetTopBottomScrollingMargins(const size_t topMargin, const size_t bottomMargin); - bool _OperatingStatus() const; - bool _CursorPositionReport() const; + void _OperatingStatus() const; + void _CursorPositionReport() const; - bool _WriteResponse(const std::wstring_view reply) const; + void _WriteResponse(const std::wstring_view reply) const; bool _ModeParamsHelper(const DispatchTypes::ModeParams param, const bool enable); bool _DoDECCOLMHelper(const size_t columns); - bool _ClearSingleTabStop(); - bool _ClearAllTabStops() noexcept; + void _ClearSingleTabStop(); + void _ClearAllTabStops() noexcept; void _ResetTabStops() noexcept; void _InitTabStopsForWidth(const size_t width); diff --git a/src/terminal/adapter/adaptDispatchGraphics.cpp b/src/terminal/adapter/adaptDispatchGraphics.cpp index 5c9c2577e..e955291d9 100644 --- a/src/terminal/adapter/adaptDispatchGraphics.cpp +++ b/src/terminal/adapter/adaptDispatchGraphics.cpp @@ -72,196 +72,192 @@ size_t AdaptDispatch::_SetRgbColorsHelper(const VTParameters options, // - options - An array of options that will be applied from 0 to N, in order, // one at a time by setting or removing flags in the font style properties. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::SetGraphicsRendition(const VTParameters options) { - TextAttribute attr; - bool success = _pConApi->PrivateGetTextAttributes(attr); + TextAttribute attr = _pConApi->GetTextAttributes(); - if (success) + // Run through the graphics options and apply them + for (size_t i = 0; i < options.size(); i++) { - // Run through the graphics options and apply them - for (size_t i = 0; i < options.size(); i++) + const GraphicsOptions opt = options.at(i); + switch (opt) { - const GraphicsOptions opt = options.at(i); - switch (opt) - { - case Off: - attr.SetDefaultForeground(); - attr.SetDefaultBackground(); - attr.SetDefaultMetaAttrs(); - break; - case ForegroundDefault: - attr.SetDefaultForeground(); - break; - case BackgroundDefault: - attr.SetDefaultBackground(); - break; - case Intense: - attr.SetIntense(true); - break; - case RGBColorOrFaint: - attr.SetFaint(true); - break; - case NotIntenseOrFaint: - attr.SetIntense(false); - attr.SetFaint(false); - break; - case Italics: - attr.SetItalic(true); - break; - case NotItalics: - attr.SetItalic(false); - break; - case BlinkOrXterm256Index: - case RapidBlink: // We just interpret rapid blink as an alias of blink. - attr.SetBlinking(true); - break; - case Steady: - attr.SetBlinking(false); - break; - case Invisible: - attr.SetInvisible(true); - break; - case Visible: - attr.SetInvisible(false); - break; - case CrossedOut: - attr.SetCrossedOut(true); - break; - case NotCrossedOut: - attr.SetCrossedOut(false); - break; - case Negative: - attr.SetReverseVideo(true); - break; - case Positive: - attr.SetReverseVideo(false); - break; - case Underline: - attr.SetUnderlined(true); - break; - case DoublyUnderlined: - attr.SetDoublyUnderlined(true); - break; - case NoUnderline: - attr.SetUnderlined(false); - attr.SetDoublyUnderlined(false); - break; - case Overline: - attr.SetOverlined(true); - break; - case NoOverline: - attr.SetOverlined(false); - break; - case ForegroundBlack: - attr.SetIndexedForeground(TextColor::DARK_BLACK); - break; - case ForegroundBlue: - attr.SetIndexedForeground(TextColor::DARK_BLUE); - break; - case ForegroundGreen: - attr.SetIndexedForeground(TextColor::DARK_GREEN); - break; - case ForegroundCyan: - attr.SetIndexedForeground(TextColor::DARK_CYAN); - break; - case ForegroundRed: - attr.SetIndexedForeground(TextColor::DARK_RED); - break; - case ForegroundMagenta: - attr.SetIndexedForeground(TextColor::DARK_MAGENTA); - break; - case ForegroundYellow: - attr.SetIndexedForeground(TextColor::DARK_YELLOW); - break; - case ForegroundWhite: - attr.SetIndexedForeground(TextColor::DARK_WHITE); - break; - case BackgroundBlack: - attr.SetIndexedBackground(TextColor::DARK_BLACK); - break; - case BackgroundBlue: - attr.SetIndexedBackground(TextColor::DARK_BLUE); - break; - case BackgroundGreen: - attr.SetIndexedBackground(TextColor::DARK_GREEN); - break; - case BackgroundCyan: - attr.SetIndexedBackground(TextColor::DARK_CYAN); - break; - case BackgroundRed: - attr.SetIndexedBackground(TextColor::DARK_RED); - break; - case BackgroundMagenta: - attr.SetIndexedBackground(TextColor::DARK_MAGENTA); - break; - case BackgroundYellow: - attr.SetIndexedBackground(TextColor::DARK_YELLOW); - break; - case BackgroundWhite: - attr.SetIndexedBackground(TextColor::DARK_WHITE); - break; - case BrightForegroundBlack: - attr.SetIndexedForeground(TextColor::BRIGHT_BLACK); - break; - case BrightForegroundBlue: - attr.SetIndexedForeground(TextColor::BRIGHT_BLUE); - break; - case BrightForegroundGreen: - attr.SetIndexedForeground(TextColor::BRIGHT_GREEN); - break; - case BrightForegroundCyan: - attr.SetIndexedForeground(TextColor::BRIGHT_CYAN); - break; - case BrightForegroundRed: - attr.SetIndexedForeground(TextColor::BRIGHT_RED); - break; - case BrightForegroundMagenta: - attr.SetIndexedForeground(TextColor::BRIGHT_MAGENTA); - break; - case BrightForegroundYellow: - attr.SetIndexedForeground(TextColor::BRIGHT_YELLOW); - break; - case BrightForegroundWhite: - attr.SetIndexedForeground(TextColor::BRIGHT_WHITE); - break; - case BrightBackgroundBlack: - attr.SetIndexedBackground(TextColor::BRIGHT_BLACK); - break; - case BrightBackgroundBlue: - attr.SetIndexedBackground(TextColor::BRIGHT_BLUE); - break; - case BrightBackgroundGreen: - attr.SetIndexedBackground(TextColor::BRIGHT_GREEN); - break; - case BrightBackgroundCyan: - attr.SetIndexedBackground(TextColor::BRIGHT_CYAN); - break; - case BrightBackgroundRed: - attr.SetIndexedBackground(TextColor::BRIGHT_RED); - break; - case BrightBackgroundMagenta: - attr.SetIndexedBackground(TextColor::BRIGHT_MAGENTA); - break; - case BrightBackgroundYellow: - attr.SetIndexedBackground(TextColor::BRIGHT_YELLOW); - break; - case BrightBackgroundWhite: - attr.SetIndexedBackground(TextColor::BRIGHT_WHITE); - break; - case ForegroundExtended: - i += _SetRgbColorsHelper(options.subspan(i + 1), attr, true); - break; - case BackgroundExtended: - i += _SetRgbColorsHelper(options.subspan(i + 1), attr, false); - break; - } + case Off: + attr.SetDefaultForeground(); + attr.SetDefaultBackground(); + attr.SetDefaultMetaAttrs(); + break; + case ForegroundDefault: + attr.SetDefaultForeground(); + break; + case BackgroundDefault: + attr.SetDefaultBackground(); + break; + case Intense: + attr.SetIntense(true); + break; + case RGBColorOrFaint: + attr.SetFaint(true); + break; + case NotIntenseOrFaint: + attr.SetIntense(false); + attr.SetFaint(false); + break; + case Italics: + attr.SetItalic(true); + break; + case NotItalics: + attr.SetItalic(false); + break; + case BlinkOrXterm256Index: + case RapidBlink: // We just interpret rapid blink as an alias of blink. + attr.SetBlinking(true); + break; + case Steady: + attr.SetBlinking(false); + break; + case Invisible: + attr.SetInvisible(true); + break; + case Visible: + attr.SetInvisible(false); + break; + case CrossedOut: + attr.SetCrossedOut(true); + break; + case NotCrossedOut: + attr.SetCrossedOut(false); + break; + case Negative: + attr.SetReverseVideo(true); + break; + case Positive: + attr.SetReverseVideo(false); + break; + case Underline: + attr.SetUnderlined(true); + break; + case DoublyUnderlined: + attr.SetDoublyUnderlined(true); + break; + case NoUnderline: + attr.SetUnderlined(false); + attr.SetDoublyUnderlined(false); + break; + case Overline: + attr.SetOverlined(true); + break; + case NoOverline: + attr.SetOverlined(false); + break; + case ForegroundBlack: + attr.SetIndexedForeground(TextColor::DARK_BLACK); + break; + case ForegroundBlue: + attr.SetIndexedForeground(TextColor::DARK_BLUE); + break; + case ForegroundGreen: + attr.SetIndexedForeground(TextColor::DARK_GREEN); + break; + case ForegroundCyan: + attr.SetIndexedForeground(TextColor::DARK_CYAN); + break; + case ForegroundRed: + attr.SetIndexedForeground(TextColor::DARK_RED); + break; + case ForegroundMagenta: + attr.SetIndexedForeground(TextColor::DARK_MAGENTA); + break; + case ForegroundYellow: + attr.SetIndexedForeground(TextColor::DARK_YELLOW); + break; + case ForegroundWhite: + attr.SetIndexedForeground(TextColor::DARK_WHITE); + break; + case BackgroundBlack: + attr.SetIndexedBackground(TextColor::DARK_BLACK); + break; + case BackgroundBlue: + attr.SetIndexedBackground(TextColor::DARK_BLUE); + break; + case BackgroundGreen: + attr.SetIndexedBackground(TextColor::DARK_GREEN); + break; + case BackgroundCyan: + attr.SetIndexedBackground(TextColor::DARK_CYAN); + break; + case BackgroundRed: + attr.SetIndexedBackground(TextColor::DARK_RED); + break; + case BackgroundMagenta: + attr.SetIndexedBackground(TextColor::DARK_MAGENTA); + break; + case BackgroundYellow: + attr.SetIndexedBackground(TextColor::DARK_YELLOW); + break; + case BackgroundWhite: + attr.SetIndexedBackground(TextColor::DARK_WHITE); + break; + case BrightForegroundBlack: + attr.SetIndexedForeground(TextColor::BRIGHT_BLACK); + break; + case BrightForegroundBlue: + attr.SetIndexedForeground(TextColor::BRIGHT_BLUE); + break; + case BrightForegroundGreen: + attr.SetIndexedForeground(TextColor::BRIGHT_GREEN); + break; + case BrightForegroundCyan: + attr.SetIndexedForeground(TextColor::BRIGHT_CYAN); + break; + case BrightForegroundRed: + attr.SetIndexedForeground(TextColor::BRIGHT_RED); + break; + case BrightForegroundMagenta: + attr.SetIndexedForeground(TextColor::BRIGHT_MAGENTA); + break; + case BrightForegroundYellow: + attr.SetIndexedForeground(TextColor::BRIGHT_YELLOW); + break; + case BrightForegroundWhite: + attr.SetIndexedForeground(TextColor::BRIGHT_WHITE); + break; + case BrightBackgroundBlack: + attr.SetIndexedBackground(TextColor::BRIGHT_BLACK); + break; + case BrightBackgroundBlue: + attr.SetIndexedBackground(TextColor::BRIGHT_BLUE); + break; + case BrightBackgroundGreen: + attr.SetIndexedBackground(TextColor::BRIGHT_GREEN); + break; + case BrightBackgroundCyan: + attr.SetIndexedBackground(TextColor::BRIGHT_CYAN); + break; + case BrightBackgroundRed: + attr.SetIndexedBackground(TextColor::BRIGHT_RED); + break; + case BrightBackgroundMagenta: + attr.SetIndexedBackground(TextColor::BRIGHT_MAGENTA); + break; + case BrightBackgroundYellow: + attr.SetIndexedBackground(TextColor::BRIGHT_YELLOW); + break; + case BrightBackgroundWhite: + attr.SetIndexedBackground(TextColor::BRIGHT_WHITE); + break; + case ForegroundExtended: + i += _SetRgbColorsHelper(options.subspan(i + 1), attr, true); + break; + case BackgroundExtended: + i += _SetRgbColorsHelper(options.subspan(i + 1), attr, false); + break; } - success = _pConApi->PrivateSetTextAttributes(attr); } + _pConApi->SetTextAttributes(attr); - return success; + return true; } // Method Description: @@ -271,20 +267,12 @@ bool AdaptDispatch::SetGraphicsRendition(const VTParameters options) // be saved. Options that are not supported are ignored. If no options are specified, // all attributes are stored. // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::PushGraphicsRendition(const VTParameters options) { - bool success = true; - TextAttribute currentAttributes; - - success = _pConApi->PrivateGetTextAttributes(currentAttributes); - - if (success) - { - _sgrStack.Push(currentAttributes, options); - } - - return success; + const auto currentAttributes = _pConApi->GetTextAttributes(); + _sgrStack.Push(currentAttributes, options); + return true; } // Method Description: @@ -293,18 +281,10 @@ bool AdaptDispatch::PushGraphicsRendition(const VTParameters options) // Arguments: // - // Return Value: -// - True if handled successfully. False otherwise. +// - True. bool AdaptDispatch::PopGraphicsRendition() { - bool success = true; - TextAttribute currentAttributes; - - success = _pConApi->PrivateGetTextAttributes(currentAttributes); - - if (success) - { - success = _pConApi->PrivateSetTextAttributes(_sgrStack.Pop(currentAttributes)); - } - - return success; + const auto currentAttributes = _pConApi->GetTextAttributes(); + _pConApi->SetTextAttributes(_sgrStack.Pop(currentAttributes)); + return true; } diff --git a/src/terminal/adapter/conGetSet.hpp b/src/terminal/adapter/conGetSet.hpp index aa4d14aef..7eb6e865a 100644 --- a/src/terminal/adapter/conGetSet.hpp +++ b/src/terminal/adapter/conGetSet.hpp @@ -34,80 +34,78 @@ namespace Microsoft::Console::VirtualTerminal public: virtual ~ConGetSet() = default; - virtual bool GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const = 0; - virtual bool SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) = 0; - virtual bool SetConsoleCursorPosition(const COORD position) = 0; + virtual void GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) const = 0; + virtual void SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& screenBufferInfo) = 0; + virtual void SetCursorPosition(const COORD position) = 0; - virtual bool PrivateIsVtInputEnabled() const = 0; + virtual bool IsVtInputEnabled() const = 0; - virtual bool PrivateGetTextAttributes(TextAttribute& attrs) const = 0; - virtual bool PrivateSetTextAttributes(const TextAttribute& attrs) = 0; + virtual TextAttribute GetTextAttributes() const = 0; + virtual void SetTextAttributes(const TextAttribute& attrs) = 0; - virtual bool PrivateSetCurrentLineRendition(const LineRendition lineRendition) = 0; - virtual bool PrivateResetLineRenditionRange(const size_t startRow, const size_t endRow) = 0; - virtual SHORT PrivateGetLineWidth(const size_t row) const = 0; + virtual void SetCurrentLineRendition(const LineRendition lineRendition) = 0; + virtual void ResetLineRenditionRange(const size_t startRow, const size_t endRow) = 0; + virtual SHORT GetLineWidth(const size_t row) const = 0; - virtual bool PrivateWriteConsoleInputW(std::deque>& events, - size_t& eventsWritten) = 0; - virtual bool SetConsoleWindowInfo(const bool absolute, - const SMALL_RECT& window) = 0; + virtual void WriteInput(std::deque>& events, size_t& eventsWritten) = 0; + virtual void SetWindowInfo(const bool absolute, const SMALL_RECT& window) = 0; virtual bool SetInputMode(const TerminalInput::Mode mode, const bool enabled) = 0; - virtual bool SetParserMode(const StateMachine::Mode mode, const bool enabled) = 0; + virtual void SetParserMode(const StateMachine::Mode mode, const bool enabled) = 0; virtual bool GetParserMode(const StateMachine::Mode mode) const = 0; - virtual bool SetRenderMode(const RenderSettings::Mode mode, const bool enabled) = 0; + virtual void SetRenderMode(const RenderSettings::Mode mode, const bool enabled) = 0; - virtual bool PrivateSetAutoWrapMode(const bool wrapAtEOL) = 0; + virtual void SetAutoWrapMode(const bool wrapAtEOL) = 0; - virtual bool PrivateShowCursor(const bool show) = 0; - virtual bool PrivateAllowCursorBlinking(const bool enable) = 0; + virtual void SetCursorVisibility(const bool visible) = 0; + virtual bool EnableCursorBlinking(const bool enable) = 0; - virtual bool PrivateSetScrollingRegion(const SMALL_RECT& scrollMargins) = 0; - virtual bool PrivateWarningBell() = 0; - virtual bool PrivateGetLineFeedMode() const = 0; - virtual bool PrivateLineFeed(const bool withReturn) = 0; - virtual bool PrivateReverseLineFeed() = 0; - virtual bool SetConsoleTitleW(const std::wstring_view title) = 0; - virtual bool PrivateUseAlternateScreenBuffer() = 0; - virtual bool PrivateUseMainScreenBuffer() = 0; + virtual void SetScrollingRegion(const SMALL_RECT& scrollMargins) = 0; + virtual void WarningBell() = 0; + virtual bool GetLineFeedMode() const = 0; + virtual void LineFeed(const bool withReturn) = 0; + virtual void ReverseLineFeed() = 0; + virtual void SetWindowTitle(const std::wstring_view title) = 0; + virtual void UseAlternateScreenBuffer() = 0; + virtual void UseMainScreenBuffer() = 0; - virtual bool PrivateEraseAll() = 0; - virtual bool PrivateClearBuffer() = 0; - virtual bool GetUserDefaultCursorStyle(CursorType& style) = 0; - virtual bool SetCursorStyle(const CursorType style) = 0; - virtual bool PrivateWriteConsoleControlInput(const KeyEvent key) = 0; - virtual bool PrivateRefreshWindow() = 0; + virtual void EraseAll() = 0; + virtual void ClearBuffer() = 0; + virtual CursorType GetUserDefaultCursorStyle() const = 0; + virtual void SetCursorStyle(const CursorType style) = 0; + virtual void WriteControlInput(const KeyEvent key) = 0; + virtual void RefreshWindow() = 0; - virtual bool SetConsoleOutputCP(const unsigned int codepage) = 0; - virtual bool GetConsoleOutputCP(unsigned int& codepage) = 0; + virtual void SetConsoleOutputCP(const unsigned int codepage) = 0; + virtual unsigned int GetConsoleOutputCP() const = 0; - virtual bool PrivateSuppressResizeRepaint() = 0; + virtual void SuppressResizeRepaint() = 0; virtual bool IsConsolePty() const = 0; - virtual bool DeleteLines(const size_t count) = 0; - virtual bool InsertLines(const size_t count) = 0; + virtual void DeleteLines(const size_t count) = 0; + virtual void InsertLines(const size_t count) = 0; - virtual bool MoveToBottom() const = 0; + virtual void MoveToBottom() = 0; virtual COLORREF GetColorTableEntry(const size_t tableIndex) const = 0; virtual bool SetColorTableEntry(const size_t tableIndex, const COLORREF color) = 0; virtual void SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) = 0; - virtual bool PrivateFillRegion(const COORD startPosition, - const size_t fillLength, - const wchar_t fillChar, - const bool standardFillAttrs) = 0; + virtual void FillRegion(const COORD startPosition, + const size_t fillLength, + const wchar_t fillChar, + const bool standardFillAttrs) = 0; - virtual bool PrivateScrollRegion(const SMALL_RECT scrollRect, - const std::optional clipRect, - const COORD destinationOrigin, - const bool standardFillAttrs) = 0; + virtual void ScrollRegion(const SMALL_RECT scrollRect, + const std::optional clipRect, + const COORD destinationOrigin, + const bool standardFillAttrs) = 0; - virtual bool PrivateAddHyperlink(const std::wstring_view uri, const std::wstring_view params) const = 0; - virtual bool PrivateEndHyperlink() const = 0; + virtual void AddHyperlink(const std::wstring_view uri, const std::wstring_view params) const = 0; + virtual void EndHyperlink() const = 0; - virtual bool PrivateUpdateSoftFont(const gsl::span bitPattern, - const SIZE cellSize, - const size_t centeringHint) = 0; + virtual void UpdateSoftFont(const gsl::span bitPattern, + const SIZE cellSize, + const size_t centeringHint) = 0; }; } diff --git a/src/terminal/adapter/ut_adapter/adapterTest.cpp b/src/terminal/adapter/ut_adapter/adapterTest.cpp index 432828972..9ef4c7aaa 100644 --- a/src/terminal/adapter/ut_adapter/adapterTest.cpp +++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp @@ -58,58 +58,43 @@ using namespace Microsoft::Console::VirtualTerminal; class TestGetSet final : public ConGetSet { public: - bool GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& sbiex) const override + void GetConsoleScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX& sbiex) const override { Log::Comment(L"GetConsoleScreenBufferInfoEx MOCK returning data..."); - if (_getConsoleScreenBufferInfoExResult) - { - sbiex.dwSize = _bufferSize; - sbiex.srWindow = _viewport; - sbiex.dwCursorPosition = _cursorPos; - sbiex.wAttributes = _attribute.GetLegacyAttributes(); - } - - return _getConsoleScreenBufferInfoExResult; + THROW_HR_IF(E_FAIL, !_getConsoleScreenBufferInfoExResult); + sbiex.dwSize = _bufferSize; + sbiex.srWindow = _viewport; + sbiex.dwCursorPosition = _cursorPos; + sbiex.wAttributes = _attribute.GetLegacyAttributes(); } - bool SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& sbiex) override + void SetConsoleScreenBufferInfoEx(const CONSOLE_SCREEN_BUFFER_INFOEX& sbiex) override { Log::Comment(L"SetConsoleScreenBufferInfoEx MOCK returning data..."); - if (_setConsoleScreenBufferInfoExResult) - { - VERIFY_ARE_EQUAL(_expectedCursorPos, sbiex.dwCursorPosition); - VERIFY_ARE_EQUAL(_expectedScreenBufferSize, sbiex.dwSize); - VERIFY_ARE_EQUAL(_expectedScreenBufferViewport, sbiex.srWindow); - VERIFY_ARE_EQUAL(_expectedAttribute, TextAttribute{ sbiex.wAttributes }); - } - return _setConsoleScreenBufferInfoExResult; + THROW_HR_IF(E_FAIL, !_setConsoleScreenBufferInfoExResult); + VERIFY_ARE_EQUAL(_expectedCursorPos, sbiex.dwCursorPosition); + VERIFY_ARE_EQUAL(_expectedScreenBufferSize, sbiex.dwSize); + VERIFY_ARE_EQUAL(_expectedScreenBufferViewport, sbiex.srWindow); + VERIFY_ARE_EQUAL(_expectedAttribute, TextAttribute{ sbiex.wAttributes }); } - bool SetConsoleCursorPosition(const COORD position) override + void SetCursorPosition(const COORD position) override { - Log::Comment(L"SetConsoleCursorPosition MOCK called..."); + Log::Comment(L"SetCursorPosition MOCK called..."); - if (_setConsoleCursorPositionResult) - { - VERIFY_ARE_EQUAL(_expectedCursorPos, position); - _cursorPos = position; - } - - return _setConsoleCursorPositionResult; + THROW_HR_IF(E_FAIL, !_setCursorPositionResult); + VERIFY_ARE_EQUAL(_expectedCursorPos, position); + _cursorPos = position; } - bool SetConsoleWindowInfo(const bool absolute, const SMALL_RECT& window) override + void SetWindowInfo(const bool absolute, const SMALL_RECT& window) override { - Log::Comment(L"SetConsoleWindowInfo MOCK called..."); + Log::Comment(L"SetWindowInfo MOCK called..."); - if (_setConsoleWindowInfoResult) - { - VERIFY_ARE_EQUAL(_expectedWindowAbsolute, absolute); - VERIFY_ARE_EQUAL(_expectedConsoleWindow, window); - _viewport = window; - } - - return _setConsoleWindowInfoResult; + THROW_HR_IF(E_FAIL, !_setWindowInfoResult); + VERIFY_ARE_EQUAL(_expectedWindowAbsolute, absolute); + VERIFY_ARE_EQUAL(_expectedConsoleWindow, window); + _viewport = window; } bool SetInputMode(const TerminalInput::Mode mode, const bool enabled) override @@ -125,7 +110,7 @@ public: return _setInputModeResult; } - bool SetParserMode(const StateMachine::Mode mode, const bool enabled) override + void SetParserMode(const StateMachine::Mode mode, const bool enabled) override { Log::Comment(L"SetParserMode MOCK called..."); @@ -134,8 +119,6 @@ public: VERIFY_ARE_EQUAL(_expectedParserMode, mode); VERIFY_ARE_EQUAL(_expectedParserModeEnabled, enabled); } - - return _setParserModeResult; } bool GetParserMode(const StateMachine::Mode /*mode*/) const override @@ -145,263 +128,208 @@ public: return false; } - bool SetRenderMode(const RenderSettings::Mode /*mode*/, const bool /*enabled*/) override + void SetRenderMode(const RenderSettings::Mode /*mode*/, const bool /*enabled*/) override { Log::Comment(L"SetRenderMode MOCK called..."); - - return false; } - bool PrivateSetAutoWrapMode(const bool /*wrapAtEOL*/) override + void SetAutoWrapMode(const bool /*wrapAtEOL*/) override { - Log::Comment(L"PrivateSetAutoWrapMode MOCK called..."); - - return false; + Log::Comment(L"SetAutoWrapMode MOCK called..."); } - bool PrivateShowCursor(const bool show) override + void SetCursorVisibility(const bool visible) override { - Log::Comment(L"PrivateShowCursor MOCK called..."); + Log::Comment(L"SetCursorVisibility MOCK called..."); - if (_privateShowCursorResult) - { - VERIFY_ARE_EQUAL(_expectedShowCursor, show); - } - - return _privateShowCursorResult; + THROW_HR_IF(E_FAIL, !_setCursorVisibilityResult); + VERIFY_ARE_EQUAL(_expectedCursorVisibility, visible); } - bool PrivateAllowCursorBlinking(const bool enable) override + bool EnableCursorBlinking(const bool enable) override { - Log::Comment(L"PrivateAllowCursorBlinking MOCK called..."); + Log::Comment(L"EnableCursorBlinking MOCK called..."); - if (_privateAllowCursorBlinkingResult) + if (_enableCursorBlinkingResult) { VERIFY_ARE_EQUAL(_enable, enable); } - return _privateAllowCursorBlinkingResult; + return _enableCursorBlinkingResult; } - bool PrivateIsVtInputEnabled() const override + bool IsVtInputEnabled() const override { return false; } - bool PrivateGetTextAttributes(TextAttribute& attrs) const + TextAttribute GetTextAttributes() const { - Log::Comment(L"PrivateGetTextAttributes MOCK called..."); + Log::Comment(L"GetTextAttributes MOCK called..."); - if (_privateGetTextAttributesResult) - { - attrs = _attribute; - } - - return _privateGetTextAttributesResult; + THROW_HR_IF(E_FAIL, !_getTextAttributesResult); + return _attribute; } - bool PrivateSetTextAttributes(const TextAttribute& attrs) + void SetTextAttributes(const TextAttribute& attrs) { - Log::Comment(L"PrivateSetTextAttributes MOCK called..."); + Log::Comment(L"SetTextAttributes MOCK called..."); - if (_privateSetTextAttributesResult) - { - VERIFY_ARE_EQUAL(_expectedAttribute, attrs); - _attribute = attrs; - } - - return _privateSetTextAttributesResult; + THROW_HR_IF(E_FAIL, !_setTextAttributesResult); + VERIFY_ARE_EQUAL(_expectedAttribute, attrs); + _attribute = attrs; } - bool PrivateSetCurrentLineRendition(const LineRendition /*lineRendition*/) + void SetCurrentLineRendition(const LineRendition /*lineRendition*/) { - Log::Comment(L"PrivateSetCurrentLineRendition MOCK called..."); - - return false; + Log::Comment(L"SetCurrentLineRendition MOCK called..."); } - bool PrivateResetLineRenditionRange(const size_t /*startRow*/, const size_t /*endRow*/) + void ResetLineRenditionRange(const size_t /*startRow*/, const size_t /*endRow*/) { - Log::Comment(L"PrivateResetLineRenditionRange MOCK called..."); - - return false; + Log::Comment(L"ResetLineRenditionRange MOCK called..."); } - SHORT PrivateGetLineWidth(const size_t /*row*/) const + SHORT GetLineWidth(const size_t /*row*/) const { - Log::Comment(L"PrivateGetLineWidth MOCK called..."); + Log::Comment(L"GetLineWidth MOCK called..."); return _bufferSize.X; } - bool PrivateWriteConsoleInputW(std::deque>& events, - size_t& eventsWritten) override + void WriteInput(std::deque>& events, size_t& eventsWritten) override { - Log::Comment(L"PrivateWriteConsoleInputW MOCK called..."); + Log::Comment(L"WriteInput MOCK called..."); - if (_privateWriteConsoleInputWResult) + THROW_HR_IF(E_FAIL, !_writeInputResult); + + // move all the input events we were given into local storage so we can test against them + Log::Comment(NoThrowString().Format(L"Moving %zu input events into local storage...", events.size())); + + if (_retainInput) { - // move all the input events we were given into local storage so we can test against them - Log::Comment(NoThrowString().Format(L"Moving %zu input events into local storage...", events.size())); - - if (_retainInput) - { - std::move(events.begin(), events.end(), std::back_inserter(_events)); - } - else - { - _events.clear(); - _events.swap(events); - } - eventsWritten = _events.size(); + std::move(events.begin(), events.end(), std::back_inserter(_events)); } - - return _privateWriteConsoleInputWResult; + else + { + _events.clear(); + _events.swap(events); + } + eventsWritten = _events.size(); } - bool PrivateWriteConsoleControlInput(_In_ KeyEvent key) override + void WriteControlInput(_In_ KeyEvent key) override { - Log::Comment(L"PrivateWriteConsoleControlInput MOCK called..."); + Log::Comment(L"WriteControlInput MOCK called..."); - if (_privateWriteConsoleControlInputResult) - { - VERIFY_ARE_EQUAL('C', key.GetVirtualKeyCode()); - VERIFY_ARE_EQUAL(0x3, key.GetCharData()); - VERIFY_ARE_EQUAL(true, key.IsCtrlPressed()); - } - - return _privateWriteConsoleControlInputResult; + THROW_HR_IF(E_FAIL, !_writeControlInputResult); + VERIFY_ARE_EQUAL('C', key.GetVirtualKeyCode()); + VERIFY_ARE_EQUAL(0x3, key.GetCharData()); + VERIFY_ARE_EQUAL(true, key.IsCtrlPressed()); } - bool PrivateSetScrollingRegion(const SMALL_RECT& scrollMargins) override + void SetScrollingRegion(const SMALL_RECT& scrollMargins) override { - Log::Comment(L"PrivateSetScrollingRegion MOCK called..."); + Log::Comment(L"SetScrollingRegion MOCK called..."); - if (_privateSetScrollingRegionResult) + if (_setScrollingRegionResult) { VERIFY_ARE_EQUAL(_expectedScrollRegion, scrollMargins); + _activeScrollRegion = scrollMargins; } - - return _privateSetScrollingRegionResult; } - bool PrivateWarningBell() override + void WarningBell() override { - Log::Comment(L"PrivateWarningBell MOCK called..."); - // We made it through the adapter, woo! Return true. - return TRUE; + Log::Comment(L"WarningBell MOCK called..."); } - bool PrivateGetLineFeedMode() const override + bool GetLineFeedMode() const override { - Log::Comment(L"PrivateGetLineFeedMode MOCK called..."); - return _privateGetLineFeedModeResult; + Log::Comment(L"GetLineFeedMode MOCK called..."); + return _getLineFeedModeResult; } - bool PrivateLineFeed(const bool withReturn) override + void LineFeed(const bool withReturn) override { - Log::Comment(L"PrivateLineFeed MOCK called..."); + Log::Comment(L"LineFeed MOCK called..."); - if (_privateLineFeedResult) - { - VERIFY_ARE_EQUAL(_expectedLineFeedWithReturn, withReturn); - } - - return _privateLineFeedResult; + THROW_HR_IF(E_FAIL, !_lineFeedResult); + VERIFY_ARE_EQUAL(_expectedLineFeedWithReturn, withReturn); } - bool PrivateReverseLineFeed() override + void ReverseLineFeed() override { - Log::Comment(L"PrivateReverseLineFeed MOCK called..."); - // We made it through the adapter, woo! Return true. - return TRUE; + Log::Comment(L"ReverseLineFeed MOCK called..."); } - bool SetConsoleTitleW(const std::wstring_view title) + void SetWindowTitle(const std::wstring_view title) { - Log::Comment(L"SetConsoleTitleW MOCK called..."); + Log::Comment(L"SetWindowTitle MOCK called..."); - if (_setConsoleTitleWResult) + if (_setWindowTitleResult) { // Put into WEX strings for rich logging when they don't compare. VERIFY_ARE_EQUAL(String(_expectedWindowTitle.data(), gsl::narrow(_expectedWindowTitle.size())), String(title.data(), gsl::narrow(title.size()))); } - return TRUE; } - bool PrivateUseAlternateScreenBuffer() override + void UseAlternateScreenBuffer() override { - Log::Comment(L"PrivateUseAlternateScreenBuffer MOCK called..."); - return true; + Log::Comment(L"UseAlternateScreenBuffer MOCK called..."); } - bool PrivateUseMainScreenBuffer() override + void UseMainScreenBuffer() override { - Log::Comment(L"PrivateUseMainScreenBuffer MOCK called..."); - return true; + Log::Comment(L"UseMainScreenBuffer MOCK called..."); } - bool PrivateEraseAll() override + void EraseAll() override { - Log::Comment(L"PrivateEraseAll MOCK called..."); - return TRUE; + Log::Comment(L"EraseAll MOCK called..."); } - bool PrivateClearBuffer() override + void ClearBuffer() override { - Log::Comment(L"PrivateClearBuffer MOCK called..."); - return TRUE; + Log::Comment(L"ClearBuffer MOCK called..."); } - bool GetUserDefaultCursorStyle(CursorType& style) override + CursorType GetUserDefaultCursorStyle() const override { - style = CursorType::Legacy; - return true; + return CursorType::Legacy; } - bool SetCursorStyle(const CursorType cursorType) override + void SetCursorStyle(const CursorType cursorType) override { Log::Comment(L"SetCursorStyle MOCK called..."); - if (_setCursorStyleResult) - { - VERIFY_ARE_EQUAL(_expectedCursorStyle, cursorType); - } - return _setCursorStyleResult; + + THROW_HR_IF(E_FAIL, !_setCursorStyleResult); + VERIFY_ARE_EQUAL(_expectedCursorStyle, cursorType); } - bool PrivateRefreshWindow() override + void RefreshWindow() override { - Log::Comment(L"PrivateRefreshWindow MOCK called..."); - // We made it through the adapter, woo! Return true. - return TRUE; + Log::Comment(L"RefreshWindow MOCK called..."); } - bool PrivateSuppressResizeRepaint() override + void SuppressResizeRepaint() override { - Log::Comment(L"PrivateSuppressResizeRepaint MOCK called..."); + Log::Comment(L"SuppressResizeRepaint MOCK called..."); VERIFY_IS_TRUE(false, L"AdaptDispatch should never be calling this function."); - return FALSE; } - bool SetConsoleOutputCP(const unsigned int codepage) override + void SetConsoleOutputCP(const unsigned int codepage) override { Log::Comment(L"SetConsoleOutputCP MOCK called..."); - if (_setConsoleOutputCPResult) - { - VERIFY_ARE_EQUAL(_expectedOutputCP, codepage); - } - return _setConsoleOutputCPResult; + THROW_HR_IF(E_FAIL, !_setConsoleOutputCPResult); + VERIFY_ARE_EQUAL(_expectedOutputCP, codepage); } - bool GetConsoleOutputCP(unsigned int& codepage) override + unsigned int GetConsoleOutputCP() const override { Log::Comment(L"GetConsoleOutputCP MOCK called..."); - if (_getConsoleOutputCPResult) - { - codepage = _expectedOutputCP; - } - return _getConsoleOutputCPResult; + return _expectedOutputCP; } bool IsConsolePty() const override @@ -410,22 +338,19 @@ public: return _isPty; } - bool DeleteLines(const size_t /*count*/) override + void DeleteLines(const size_t /*count*/) override { Log::Comment(L"DeleteLines MOCK called..."); - return TRUE; } - bool InsertLines(const size_t /*count*/) override + void InsertLines(const size_t /*count*/) override { Log::Comment(L"InsertLines MOCK called..."); - return TRUE; } - bool MoveToBottom() const override + void MoveToBottom() override { Log::Comment(L"MoveToBottom MOCK called..."); - return _moveToBottomResult; } COLORREF GetColorTableEntry(const size_t tableIndex) const noexcept override @@ -460,37 +385,31 @@ public: Log::Comment(L"SetColorAliasIndex MOCK called..."); } - bool PrivateFillRegion(const COORD /*startPosition*/, - const size_t /*fillLength*/, - const wchar_t /*fillChar*/, - const bool /*standardFillAttrs*/) noexcept override + void FillRegion(const COORD /*startPosition*/, + const size_t /*fillLength*/, + const wchar_t /*fillChar*/, + const bool /*standardFillAttrs*/) noexcept override { - Log::Comment(L"PrivateFillRegion MOCK called..."); - - return TRUE; + Log::Comment(L"FillRegion MOCK called..."); } - bool PrivateScrollRegion(const SMALL_RECT /*scrollRect*/, - const std::optional /*clipRect*/, - const COORD /*destinationOrigin*/, - const bool /*standardFillAttrs*/) noexcept override + void ScrollRegion(const SMALL_RECT /*scrollRect*/, + const std::optional /*clipRect*/, + const COORD /*destinationOrigin*/, + const bool /*standardFillAttrs*/) noexcept override { - Log::Comment(L"PrivateScrollRegion MOCK called..."); - - return TRUE; + Log::Comment(L"ScrollRegion MOCK called..."); } - bool PrivateUpdateSoftFont(const gsl::span /*bitPattern*/, - const SIZE cellSize, - const size_t /*centeringHint*/) noexcept override + void UpdateSoftFont(const gsl::span /*bitPattern*/, + const SIZE cellSize, + const size_t /*centeringHint*/) noexcept override { - Log::Comment(L"PrivateUpdateSoftFont MOCK called..."); + Log::Comment(L"UpdateSoftFont MOCK called..."); Log::Comment(NoThrowString().Format(L"Cell size: %dx%d", cellSize.cx, cellSize.cy)); VERIFY_ARE_EQUAL(_expectedCellSize.cx, cellSize.cx); VERIFY_ARE_EQUAL(_expectedCellSize.cy, cellSize.cy); - - return TRUE; } void PrepData() @@ -522,13 +441,13 @@ public: Log::Comment(L"Resetting mock data state."); // APIs succeed by default - _setConsoleCursorPositionResult = TRUE; + _setCursorPositionResult = TRUE; _getConsoleScreenBufferInfoExResult = TRUE; - _privateGetTextAttributesResult = TRUE; - _privateSetTextAttributesResult = TRUE; - _privateWriteConsoleInputWResult = TRUE; - _privateWriteConsoleControlInputResult = TRUE; - _setConsoleWindowInfoResult = TRUE; + _getTextAttributesResult = TRUE; + _setTextAttributesResult = TRUE; + _writeInputResult = TRUE; + _writeControlInputResult = TRUE; + _setWindowInfoResult = TRUE; _moveToBottomResult = true; _bufferSize.X = 100; @@ -618,18 +537,14 @@ public: } } - bool PrivateAddHyperlink(const std::wstring_view /*uri*/, const std::wstring_view /*params*/) const + void AddHyperlink(const std::wstring_view /*uri*/, const std::wstring_view /*params*/) const { - Log::Comment(L"PrivateAddHyperlink MOCK called..."); - - return TRUE; + Log::Comment(L"AddHyperlink MOCK called..."); } - bool PrivateEndHyperlink() const + void EndHyperlink() const { - Log::Comment(L"PrivateEndHyperlink MOCK called..."); - - return TRUE; + Log::Comment(L"EndHyperlink MOCK called..."); } void _SetMarginsHelper(SMALL_RECT* rect, SHORT top, SHORT bottom) @@ -668,6 +583,7 @@ public: SMALL_RECT _expectedConsoleWindow = { 0, 0, 0, 0 }; COORD _cursorPos = { 0, 0 }; SMALL_RECT _expectedScrollRegion = { 0, 0, 0, 0 }; + SMALL_RECT _activeScrollRegion = { 0, 0, 0, 0 }; bool _cursorVisible = false; @@ -678,17 +594,17 @@ public: unsigned int _expectedOutputCP = 0; bool _isPty = false; - bool _privateShowCursorResult = false; - bool _expectedShowCursor = false; + bool _setCursorVisibilityResult = false; + bool _expectedCursorVisibility = false; bool _getConsoleScreenBufferInfoExResult = false; - bool _setConsoleCursorPositionResult = false; - bool _privateGetTextAttributesResult = false; - bool _privateSetTextAttributesResult = false; - bool _privateWriteConsoleInputWResult = false; - bool _privateWriteConsoleControlInputResult = false; + bool _setCursorPositionResult = false; + bool _getTextAttributesResult = false; + bool _setTextAttributesResult = false; + bool _writeInputResult = false; + bool _writeControlInputResult = false; - bool _setConsoleWindowInfoResult = false; + bool _setWindowInfoResult = false; bool _expectedWindowAbsolute = false; bool _setConsoleScreenBufferInfoExResult = false; @@ -700,15 +616,15 @@ public: bool _setParserModeResult = false; StateMachine::Mode _expectedParserMode; bool _expectedParserModeEnabled = false; - bool _privateAllowCursorBlinkingResult = false; + bool _enableCursorBlinkingResult = false; bool _enable = false; // for cursor blinking - bool _privateSetScrollingRegionResult = false; - bool _privateGetLineFeedModeResult = false; - bool _privateLineFeedResult = false; + bool _setScrollingRegionResult = false; + bool _getLineFeedModeResult = false; + bool _lineFeedResult = false; bool _expectedLineFeedWithReturn = false; - bool _privateReverseLineFeedResult = false; + bool _reverseLineFeedResult = false; - bool _setConsoleTitleWResult = false; + bool _setWindowTitleResult = false; std::wstring_view _expectedWindowTitle{}; bool _setCursorStyleResult = false; CursorType _expectedCursorStyle; @@ -920,19 +836,19 @@ public: VERIFY_IS_TRUE((_pDispatch.get()->*(moveFunc))(100)); // error cases - // SetConsoleCursorPosition throws failure. Parameters are otherwise normal. - Log::Comment(L"Test 4: When SetConsoleCursorPosition throws a failure, call fails and cursor doesn't move."); + // SetCursorPosition throws failure. Parameters are otherwise normal. + Log::Comment(L"Test 4: When SetCursorPosition throws a failure, call fails and cursor doesn't move."); _testGetSet->PrepData(direction); - _testGetSet->_setConsoleCursorPositionResult = FALSE; + _testGetSet->_setCursorPositionResult = FALSE; - VERIFY_IS_FALSE((_pDispatch.get()->*(moveFunc))(0)); + VERIFY_THROWS((_pDispatch.get()->*(moveFunc))(0), std::exception); VERIFY_ARE_EQUAL(_testGetSet->_expectedCursorPos, _testGetSet->_cursorPos); // GetConsoleScreenBufferInfo throws failure. Parameters are otherwise normal. Log::Comment(L"Test 5: When GetConsoleScreenBufferInfo throws a failure, call fails and cursor doesn't move."); _testGetSet->PrepData(CursorX::LEFT, CursorY::TOP); _testGetSet->_getConsoleScreenBufferInfoExResult = FALSE; - VERIFY_IS_FALSE((_pDispatch.get()->*(moveFunc))(0)); + VERIFY_THROWS((_pDispatch.get()->*(moveFunc))(0), std::exception); VERIFY_ARE_EQUAL(_testGetSet->_expectedCursorPos, _testGetSet->_cursorPos); } @@ -977,14 +893,14 @@ public: _testGetSet->_getConsoleScreenBufferInfoExResult = FALSE; - VERIFY_IS_FALSE(_pDispatch.get()->CursorPosition(1, 1)); + VERIFY_THROWS(_pDispatch.get()->CursorPosition(1, 1), std::exception); Log::Comment(L"Test 5: SetCursor API returns false. No move, return false."); _testGetSet->PrepData(CursorX::LEFT, CursorY::TOP); - _testGetSet->_setConsoleCursorPositionResult = FALSE; + _testGetSet->_setCursorPositionResult = FALSE; - VERIFY_IS_FALSE(_pDispatch.get()->CursorPosition(1, 1)); + VERIFY_THROWS(_pDispatch.get()->CursorPosition(1, 1), std::exception); } TEST_METHOD(CursorSingleDimensionMoveTest) @@ -1066,16 +982,16 @@ public: sVal = 1; - VERIFY_IS_FALSE((_pDispatch.get()->*(moveFunc))(sVal)); + VERIFY_THROWS((_pDispatch.get()->*(moveFunc))(sVal), std::exception); Log::Comment(L"Test 5: SetCursor API returns false. No move, return false."); _testGetSet->PrepData(CursorX::LEFT, CursorY::TOP); - _testGetSet->_setConsoleCursorPositionResult = FALSE; + _testGetSet->_setCursorPositionResult = FALSE; sVal = 1; - VERIFY_IS_FALSE((_pDispatch.get()->*(moveFunc))(sVal)); + VERIFY_THROWS((_pDispatch.get()->*(moveFunc))(sVal), std::exception); } TEST_METHOD(CursorSaveRestoreTest) @@ -1134,14 +1050,14 @@ public: Log::Comment(L"Test 1: Verify successful API call modifies visibility state."); _testGetSet->PrepData(); _testGetSet->_cursorVisible = fStart; - _testGetSet->_privateShowCursorResult = true; - _testGetSet->_expectedShowCursor = fEnd; + _testGetSet->_setCursorVisibilityResult = true; + _testGetSet->_expectedCursorVisibility = fEnd; VERIFY_IS_TRUE(_pDispatch.get()->CursorVisibility(fEnd)); Log::Comment(L"Test 3: When we fail to set updated cursor information, the dispatch should fail."); _testGetSet->PrepData(); - _testGetSet->_privateShowCursorResult = false; - VERIFY_IS_FALSE(_pDispatch.get()->CursorVisibility(fEnd)); + _testGetSet->_setCursorVisibilityResult = false; + VERIFY_THROWS(_pDispatch.get()->CursorVisibility(fEnd), std::exception); } TEST_METHOD(GraphicsBaseTests) @@ -1160,18 +1076,18 @@ public: Log::Comment(L"Test 2: Gracefully fail when getting attribute data fails."); _testGetSet->PrepData(); - _testGetSet->_privateGetTextAttributesResult = FALSE; + _testGetSet->_getTextAttributesResult = FALSE; - VERIFY_IS_FALSE(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions })); + VERIFY_THROWS(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions }), std::exception); Log::Comment(L"Test 3: Gracefully fail when setting attribute data fails."); _testGetSet->PrepData(); - _testGetSet->_privateSetTextAttributesResult = FALSE; + _testGetSet->_setTextAttributesResult = FALSE; // Need at least one option in order for the call to be able to fail. rgOptions[0] = (DispatchTypes::GraphicsOptions)0; cOptions = 1; - VERIFY_IS_FALSE(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions })); + VERIFY_THROWS(_pDispatch.get()->SetGraphicsRendition({ rgOptions, cOptions }), std::exception); } TEST_METHOD(GraphicsSingleTests) @@ -1815,11 +1731,11 @@ public: PCWSTR pwszExpectedResponse = L"\x1b[?1;0c"; _testGetSet->ValidateInputEvent(pwszExpectedResponse); - Log::Comment(L"Test 2: Verify failure when WriteConsoleInput doesn't work."); + Log::Comment(L"Test 2: Verify failure when WriteInput doesn't work."); _testGetSet->PrepData(); - _testGetSet->_privateWriteConsoleInputWResult = FALSE; + _testGetSet->_writeInputResult = FALSE; - VERIFY_IS_FALSE(_pDispatch.get()->DeviceAttributes()); + VERIFY_THROWS(_pDispatch.get()->DeviceAttributes(), std::exception); } TEST_METHOD(SecondaryDeviceAttributesTests) @@ -1833,11 +1749,11 @@ public: PCWSTR pwszExpectedResponse = L"\x1b[>0;10;1c"; _testGetSet->ValidateInputEvent(pwszExpectedResponse); - Log::Comment(L"Test 2: Verify failure when WriteConsoleInput doesn't work."); + Log::Comment(L"Test 2: Verify failure when WriteInput doesn't work."); _testGetSet->PrepData(); - _testGetSet->_privateWriteConsoleInputWResult = FALSE; + _testGetSet->_writeInputResult = FALSE; - VERIFY_IS_FALSE(_pDispatch.get()->SecondaryDeviceAttributes()); + VERIFY_THROWS(_pDispatch.get()->SecondaryDeviceAttributes(), std::exception); } TEST_METHOD(TertiaryDeviceAttributesTests) @@ -1851,11 +1767,11 @@ public: PCWSTR pwszExpectedResponse = L"\x1bP!|00000000\x1b\\"; _testGetSet->ValidateInputEvent(pwszExpectedResponse); - Log::Comment(L"Test 2: Verify failure when WriteConsoleInput doesn't work."); + Log::Comment(L"Test 2: Verify failure when WriteInput doesn't work."); _testGetSet->PrepData(); - _testGetSet->_privateWriteConsoleInputWResult = FALSE; + _testGetSet->_writeInputResult = FALSE; - VERIFY_IS_FALSE(_pDispatch.get()->TertiaryDeviceAttributes()); + VERIFY_THROWS(_pDispatch.get()->TertiaryDeviceAttributes(), std::exception); } TEST_METHOD(RequestTerminalParametersTests) @@ -1876,10 +1792,10 @@ public: _testGetSet->PrepData(); VERIFY_IS_FALSE(_pDispatch.get()->RequestTerminalParameters((DispatchTypes::ReportingPermission)2)); - Log::Comment(L"Test 4: Verify failure when WriteConsoleInput doesn't work."); + Log::Comment(L"Test 4: Verify failure when WriteInput doesn't work."); _testGetSet->PrepData(); - _testGetSet->_privateWriteConsoleInputWResult = FALSE; - VERIFY_IS_FALSE(_pDispatch.get()->RequestTerminalParameters(DispatchTypes::ReportingPermission::Unsolicited)); + _testGetSet->_writeInputResult = FALSE; + VERIFY_THROWS(_pDispatch.get()->RequestTerminalParameters(DispatchTypes::ReportingPermission::Unsolicited), std::exception); } TEST_METHOD(RequestSettingsTests) @@ -2058,14 +1974,14 @@ public: // success cases // set numeric mode = true Log::Comment(L"Test 1: enable blinking = true"); - _testGetSet->_privateAllowCursorBlinkingResult = TRUE; + _testGetSet->_enableCursorBlinkingResult = TRUE; _testGetSet->_enable = true; VERIFY_IS_TRUE(_pDispatch.get()->EnableCursorBlinking(true)); // set numeric mode = false Log::Comment(L"Test 2: enable blinking = false"); - _testGetSet->_privateAllowCursorBlinkingResult = TRUE; + _testGetSet->_enableCursorBlinkingResult = TRUE; _testGetSet->_enable = false; VERIFY_IS_TRUE(_pDispatch.get()->EnableCursorBlinking(false)); @@ -2084,8 +2000,8 @@ public: Log::Comment(L"Test 1: Verify having both values is valid."); _testGetSet->_SetMarginsHelper(&srTestMargins, 2, 6); - _testGetSet->_privateSetScrollingRegionResult = TRUE; - _testGetSet->_setConsoleCursorPositionResult = true; + _testGetSet->_setScrollingRegionResult = TRUE; + _testGetSet->_setCursorPositionResult = true; _testGetSet->_moveToBottomResult = true; VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); @@ -2093,30 +2009,32 @@ public: _testGetSet->_SetMarginsHelper(&srTestMargins, 7, 0); _testGetSet->_expectedScrollRegion.Bottom = _testGetSet->_viewport.Bottom - 1; // We expect the bottom to be the bottom of the viewport, exclusive. - _testGetSet->_privateSetScrollingRegionResult = TRUE; + _testGetSet->_setScrollingRegionResult = TRUE; VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); Log::Comment(L"Test 3: Verify having only bottom is valid."); _testGetSet->_SetMarginsHelper(&srTestMargins, 0, 7); - _testGetSet->_privateSetScrollingRegionResult = TRUE; + _testGetSet->_setScrollingRegionResult = TRUE; VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); Log::Comment(L"Test 4: Verify having no values is valid."); _testGetSet->_SetMarginsHelper(&srTestMargins, 0, 0); - _testGetSet->_privateSetScrollingRegionResult = TRUE; + _testGetSet->_setScrollingRegionResult = TRUE; VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); - Log::Comment(L"Test 5: Verify having both values, but bad bounds is invalid."); + Log::Comment(L"Test 5: Verify having both values, but bad bounds has no effect."); _testGetSet->_SetMarginsHelper(&srTestMargins, 7, 3); - _testGetSet->_privateSetScrollingRegionResult = TRUE; - VERIFY_IS_FALSE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + _testGetSet->_setScrollingRegionResult = TRUE; + _testGetSet->_activeScrollRegion = {}; + VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); Log::Comment(L"Test 6: Verify setting margins to (0, height) clears them"); // First set, - _testGetSet->_privateSetScrollingRegionResult = TRUE; + _testGetSet->_setScrollingRegionResult = TRUE; _testGetSet->_SetMarginsHelper(&srTestMargins, 2, 6); VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); // Then clear @@ -2127,7 +2045,7 @@ public: Log::Comment(L"Test 7: Verify setting margins to (1, height) clears them"); // First set, - _testGetSet->_privateSetScrollingRegionResult = TRUE; + _testGetSet->_setScrollingRegionResult = TRUE; _testGetSet->_SetMarginsHelper(&srTestMargins, 2, 6); VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); // Then clear @@ -2138,7 +2056,7 @@ public: Log::Comment(L"Test 8: Verify setting margins to (1, 0) clears them"); // First set, - _testGetSet->_privateSetScrollingRegionResult = TRUE; + _testGetSet->_setScrollingRegionResult = TRUE; _testGetSet->_SetMarginsHelper(&srTestMargins, 2, 6); VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); // Then clear @@ -2147,23 +2065,29 @@ public: _testGetSet->_expectedScrollRegion.Bottom = 0; VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); - Log::Comment(L"Test 9: Verify having top and bottom margin the same is invalid."); + Log::Comment(L"Test 9: Verify having top and bottom margin the same has no effect."); _testGetSet->_SetMarginsHelper(&srTestMargins, 4, 4); - _testGetSet->_privateSetScrollingRegionResult = TRUE; - VERIFY_IS_FALSE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + _testGetSet->_setScrollingRegionResult = TRUE; + _testGetSet->_activeScrollRegion = {}; + VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); - Log::Comment(L"Test 10: Verify having top margin out of bounds is invalid."); + Log::Comment(L"Test 10: Verify having top margin out of bounds has no effect."); _testGetSet->_SetMarginsHelper(&srTestMargins, sScreenHeight + 1, sScreenHeight + 10); - _testGetSet->_privateSetScrollingRegionResult = TRUE; - VERIFY_IS_FALSE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + _testGetSet->_setScrollingRegionResult = TRUE; + _testGetSet->_activeScrollRegion = {}; + VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); - Log::Comment(L"Test 11: Verify having bottom margin out of bounds is invalid."); + Log::Comment(L"Test 11: Verify having bottom margin out of bounds has no effect."); _testGetSet->_SetMarginsHelper(&srTestMargins, 1, sScreenHeight + 1); - _testGetSet->_privateSetScrollingRegionResult = TRUE; - VERIFY_IS_FALSE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + _testGetSet->_setScrollingRegionResult = TRUE; + _testGetSet->_activeScrollRegion = {}; + VERIFY_IS_TRUE(_pDispatch.get()->SetTopBottomScrollingMargins(srTestMargins.Top, srTestMargins.Bottom)); + VERIFY_ARE_EQUAL(SMALL_RECT{}, _testGetSet->_activeScrollRegion); } TEST_METHOD(LineFeedTest) @@ -2171,7 +2095,7 @@ public: Log::Comment(L"Starting test..."); // All test cases need the LineFeed call to succeed. - _testGetSet->_privateLineFeedResult = TRUE; + _testGetSet->_lineFeedResult = TRUE; Log::Comment(L"Test 1: Line feed without carriage return."); _testGetSet->_expectedLineFeedWithReturn = false; @@ -2182,12 +2106,12 @@ public: VERIFY_IS_TRUE(_pDispatch.get()->LineFeed(DispatchTypes::LineFeedType::WithReturn)); Log::Comment(L"Test 3: Line feed depends on mode, and mode reset."); - _testGetSet->_privateGetLineFeedModeResult = false; + _testGetSet->_getLineFeedModeResult = false; _testGetSet->_expectedLineFeedWithReturn = false; VERIFY_IS_TRUE(_pDispatch.get()->LineFeed(DispatchTypes::LineFeedType::DependsOnMode)); Log::Comment(L"Test 4: Line feed depends on mode, and mode set."); - _testGetSet->_privateGetLineFeedModeResult = true; + _testGetSet->_getLineFeedModeResult = true; _testGetSet->_expectedLineFeedWithReturn = true; VERIFY_IS_TRUE(_pDispatch.get()->LineFeed(DispatchTypes::LineFeedType::DependsOnMode)); } @@ -2197,13 +2121,13 @@ public: Log::Comment(L"Starting test..."); Log::Comment(L"Test 1: set title to be non-null"); - _testGetSet->_setConsoleTitleWResult = TRUE; + _testGetSet->_setWindowTitleResult = TRUE; _testGetSet->_expectedWindowTitle = L"Foo bar"; VERIFY_IS_TRUE(_pDispatch.get()->SetWindowTitle(_testGetSet->_expectedWindowTitle)); Log::Comment(L"Test 2: set title to be null"); - _testGetSet->_setConsoleTitleWResult = FALSE; + _testGetSet->_setWindowTitleResult = FALSE; _testGetSet->_expectedWindowTitle = {}; VERIFY_IS_TRUE(_pDispatch.get()->SetWindowTitle({})); diff --git a/src/terminal/parser/InputStateMachineEngine.cpp b/src/terminal/parser/InputStateMachineEngine.cpp index 47ad9645e..a7490907b 100644 --- a/src/terminal/parser/InputStateMachineEngine.cpp +++ b/src/terminal/parser/InputStateMachineEngine.cpp @@ -276,19 +276,12 @@ bool InputStateMachineEngine::ActionPassThroughString(const std::wstring_view st // similar to TerminalInput::_SendInputSequence if (!string.empty()) { - try + std::deque> inputEvents; + for (const auto& wch : string) { - std::deque> inputEvents; - for (const auto& wch : string) - { - inputEvents.push_back(std::make_unique(true, 1ui16, 0ui16, 0ui16, wch, 0)); - } - return _pDispatch->WriteInput(inputEvents); - } - catch (...) - { - LOG_HR(wil::ResultFromCaughtException()); + inputEvents.push_back(std::make_unique(true, 1ui16, 0ui16, 0ui16, wch, 0)); } + return _pDispatch->WriteInput(inputEvents); } } return ActionPrintString(string); diff --git a/src/terminal/parser/OutputStateMachineEngine.cpp b/src/terminal/parser/OutputStateMachineEngine.cpp index 1bc23b02c..06eb2a746 100644 --- a/src/terminal/parser/OutputStateMachineEngine.cpp +++ b/src/terminal/parser/OutputStateMachineEngine.cpp @@ -893,8 +893,7 @@ bool OutputStateMachineEngine::_GetOscTitle(const std::wstring_view string, // - True if at least one table index and color was parsed successfully. False otherwise. bool OutputStateMachineEngine::_GetOscSetColorTable(const std::wstring_view string, std::vector& tableIndexes, - std::vector& rgbs) const noexcept -try + std::vector& rgbs) const { const auto parts = Utils::SplitString(string, L';'); if (parts.size() < 2) @@ -922,7 +921,6 @@ try return tableIndexes.size() > 0 && rgbs.size() > 0; } -CATCH_LOG_RETURN_FALSE() #pragma warning(push) #pragma warning(disable : 26445) // Suppress lifetime check for a reference to gsl::span or std::string_view @@ -989,8 +987,7 @@ bool OutputStateMachineEngine::_ParseHyperlink(const std::wstring_view string, // Return Value: // - True if at least one color was parsed successfully. False otherwise. bool OutputStateMachineEngine::_GetOscSetColor(const std::wstring_view string, - std::vector& rgbs) const noexcept -try + std::vector& rgbs) const { const auto parts = Utils::SplitString(string, L';'); if (parts.size() < 1) @@ -1016,7 +1013,6 @@ try return rgbs.size() > 0; } -CATCH_LOG_RETURN_FALSE() // Method Description: // - Sets us up to have another terminal acting as the tty instead of conhost. diff --git a/src/terminal/parser/OutputStateMachineEngine.hpp b/src/terminal/parser/OutputStateMachineEngine.hpp index 92b4f62bd..8f6305bdc 100644 --- a/src/terminal/parser/OutputStateMachineEngine.hpp +++ b/src/terminal/parser/OutputStateMachineEngine.hpp @@ -192,10 +192,10 @@ namespace Microsoft::Console::VirtualTerminal bool _GetOscSetColorTable(const std::wstring_view string, std::vector& tableIndexes, - std::vector& rgbs) const noexcept; + std::vector& rgbs) const; bool _GetOscSetColor(const std::wstring_view string, - std::vector& rgbs) const noexcept; + std::vector& rgbs) const; bool _GetOscSetClipboard(const std::wstring_view string, std::wstring& content, diff --git a/src/terminal/parser/stateMachine.cpp b/src/terminal/parser/stateMachine.cpp index 049c0b60c..b1ccf4926 100644 --- a/src/terminal/parser/stateMachine.cpp +++ b/src/terminal/parser/stateMachine.cpp @@ -385,13 +385,12 @@ static constexpr bool _isActionableFromGround(const wchar_t wch) noexcept // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionExecute(const wchar_t wch) +void StateMachine::_ActionExecute(const wchar_t wch) noexcept { _trace.TraceOnExecute(wch); - const bool success = _engine->ActionExecute(wch); - - // Trace the result. - _trace.DispatchSequenceTrace(success); + _trace.DispatchSequenceTrace(_SafeExecute([=]() { + return _engine->ActionExecute(wch); + })); } // Routine Description: @@ -402,14 +401,12 @@ void StateMachine::_ActionExecute(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionExecuteFromEscape(const wchar_t wch) +void StateMachine::_ActionExecuteFromEscape(const wchar_t wch) noexcept { _trace.TraceOnExecuteFromEscape(wch); - - const bool success = _engine->ActionExecuteFromEscape(wch); - - // Trace the result. - _trace.DispatchSequenceTrace(success); + _trace.DispatchSequenceTrace(_SafeExecute([=]() { + return _engine->ActionExecuteFromEscape(wch); + })); } // Routine Description: @@ -418,14 +415,26 @@ void StateMachine::_ActionExecuteFromEscape(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionPrint(const wchar_t wch) +void StateMachine::_ActionPrint(const wchar_t wch) noexcept { _trace.TraceOnAction(L"Print"); + _trace.DispatchSequenceTrace(_SafeExecute([=]() { + return _engine->ActionPrint(wch); + })); +} - const bool success = _engine->ActionPrint(wch); - - // Trace the result. - _trace.DispatchSequenceTrace(success); +// Routine Description: +// - Triggers the PrintString action to indicate that the listener should render the characters given. +// Arguments: +// - string - Characters to dispatch. +// Return Value: +// - +void StateMachine::_ActionPrintString(const std::wstring_view string) +{ + _SafeExecute([=]() { + return _engine->ActionPrintString(string); + }); + _trace.DispatchPrintRunTrace(string); } // Routine Description: @@ -435,20 +444,12 @@ void StateMachine::_ActionPrint(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionEscDispatch(const wchar_t wch) +void StateMachine::_ActionEscDispatch(const wchar_t wch) noexcept { _trace.TraceOnAction(L"EscDispatch"); - - const bool success = _engine->ActionEscDispatch(_identifier.Finalize(wch)); - - // Trace the result. - _trace.DispatchSequenceTrace(success); - - if (!success) - { - // Suppress it and log telemetry on failed cases - TermTelemetry::Instance().LogFailed(wch); - } + _trace.DispatchSequenceTrace(_SafeExecuteWithLog(wch, [=]() { + return _engine->ActionEscDispatch(_identifier.Finalize(wch)); + })); } // Routine Description: @@ -458,21 +459,12 @@ void StateMachine::_ActionEscDispatch(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionVt52EscDispatch(const wchar_t wch) +void StateMachine::_ActionVt52EscDispatch(const wchar_t wch) noexcept { _trace.TraceOnAction(L"Vt52EscDispatch"); - - const bool success = _engine->ActionVt52EscDispatch(_identifier.Finalize(wch), - { _parameters.data(), _parameters.size() }); - - // Trace the result. - _trace.DispatchSequenceTrace(success); - - if (!success) - { - // Suppress it and log telemetry on failed cases - TermTelemetry::Instance().LogFailed(wch); - } + _trace.DispatchSequenceTrace(_SafeExecuteWithLog(wch, [=]() { + return _engine->ActionVt52EscDispatch(_identifier.Finalize(wch), { _parameters.data(), _parameters.size() }); + })); } // Routine Description: @@ -482,21 +474,12 @@ void StateMachine::_ActionVt52EscDispatch(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionCsiDispatch(const wchar_t wch) +void StateMachine::_ActionCsiDispatch(const wchar_t wch) noexcept { _trace.TraceOnAction(L"CsiDispatch"); - - const bool success = _engine->ActionCsiDispatch(_identifier.Finalize(wch), - { _parameters.data(), _parameters.size() }); - - // Trace the result. - _trace.DispatchSequenceTrace(success); - - if (!success) - { - // Suppress it and log telemetry on failed cases - TermTelemetry::Instance().LogFailed(wch); - } + _trace.DispatchSequenceTrace(_SafeExecuteWithLog(wch, [=]() { + return _engine->ActionCsiDispatch(_identifier.Finalize(wch), { _parameters.data(), _parameters.size() }); + })); } // Routine Description: @@ -649,20 +632,12 @@ void StateMachine::_ActionOscPut(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionOscDispatch(const wchar_t wch) +void StateMachine::_ActionOscDispatch(const wchar_t wch) noexcept { _trace.TraceOnAction(L"OscDispatch"); - - const bool success = _engine->ActionOscDispatch(wch, _oscParameter, _oscString); - - // Trace the result. - _trace.DispatchSequenceTrace(success); - - if (!success) - { - // Suppress it and log telemetry on failed cases - TermTelemetry::Instance().LogFailed(wch); - } + _trace.DispatchSequenceTrace(_SafeExecuteWithLog(wch, [=]() { + return _engine->ActionOscDispatch(wch, _oscParameter, _oscString); + })); } // Routine Description: @@ -672,20 +647,12 @@ void StateMachine::_ActionOscDispatch(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionSs3Dispatch(const wchar_t wch) +void StateMachine::_ActionSs3Dispatch(const wchar_t wch) noexcept { _trace.TraceOnAction(L"Ss3Dispatch"); - - const bool success = _engine->ActionSs3Dispatch(wch, { _parameters.data(), _parameters.size() }); - - // Trace the result. - _trace.DispatchSequenceTrace(success); - - if (!success) - { - // Suppress it and log telemetry on failed cases - TermTelemetry::Instance().LogFailed(wch); - } + _trace.DispatchSequenceTrace(_SafeExecuteWithLog(wch, [=]() { + return _engine->ActionSs3Dispatch(wch, { _parameters.data(), _parameters.size() }); + })); } // Routine Description: @@ -695,15 +662,15 @@ void StateMachine::_ActionSs3Dispatch(const wchar_t wch) // - wch - Character to dispatch. // Return Value: // - -void StateMachine::_ActionDcsDispatch(const wchar_t wch) +void StateMachine::_ActionDcsDispatch(const wchar_t wch) noexcept { _trace.TraceOnAction(L"DcsDispatch"); - _dcsStringHandler = _engine->ActionDcsDispatch(_identifier.Finalize(wch), - { _parameters.data(), _parameters.size() }); - - // If the returned handler is null, the sequence is not supported. - const bool success = _dcsStringHandler != nullptr; + const bool success = _SafeExecuteWithLog(wch, [=]() { + _dcsStringHandler = _engine->ActionDcsDispatch(_identifier.Finalize(wch), { _parameters.data(), _parameters.size() }); + // If the returned handler is null, the sequence is not supported. + return _dcsStringHandler != nullptr; + }); // Trace the result. _trace.DispatchSequenceTrace(success); @@ -715,9 +682,8 @@ void StateMachine::_ActionDcsDispatch(const wchar_t wch) } else { - // Otherwise ignore remaining chars and log telemetry on failed cases + // Otherwise ignore remaining chars. _EnterDcsIgnore(); - TermTelemetry::Instance().LogFailed(wch); } } @@ -1012,7 +978,7 @@ void StateMachine::_EnterSosPmApcString() noexcept // - wch - Character that triggered the event // Return Value: // - -void StateMachine::_EventGround(const wchar_t wch) +void StateMachine::_EventGround(const wchar_t wch) noexcept { _trace.TraceOnEvent(L"Ground"); if (_isC0Code(wch) || _isDelete(wch)) @@ -1127,7 +1093,7 @@ void StateMachine::_EventEscape(const wchar_t wch) // - wch - Character that triggered the event // Return Value: // - -void StateMachine::_EventEscapeIntermediate(const wchar_t wch) +void StateMachine::_EventEscapeIntermediate(const wchar_t wch) noexcept { _trace.TraceOnEvent(L"EscapeIntermediate"); if (_isC0Code(wch)) @@ -1221,7 +1187,7 @@ void StateMachine::_EventCsiEntry(const wchar_t wch) // - wch - Character that triggered the event // Return Value: // - -void StateMachine::_EventCsiIntermediate(const wchar_t wch) +void StateMachine::_EventCsiIntermediate(const wchar_t wch) noexcept { _trace.TraceOnEvent(L"CsiIntermediate"); if (_isC0Code(wch)) @@ -1259,7 +1225,7 @@ void StateMachine::_EventCsiIntermediate(const wchar_t wch) // - wch - Character that triggered the event // Return Value: // - -void StateMachine::_EventCsiIgnore(const wchar_t wch) +void StateMachine::_EventCsiIgnore(const wchar_t wch) noexcept { _trace.TraceOnEvent(L"CsiIgnore"); if (_isC0Code(wch)) @@ -1608,7 +1574,7 @@ void StateMachine::_EventDcsIgnore() noexcept // - wch - Character that triggered the event // Return Value: // - -void StateMachine::_EventDcsIntermediate(const wchar_t wch) +void StateMachine::_EventDcsIntermediate(const wchar_t wch) noexcept { _trace.TraceOnEvent(L"DcsIntermediate"); if (_isC0Code(wch)) @@ -1820,7 +1786,7 @@ void StateMachine::ProcessCharacter(const wchar_t wch) // - // Return Value: // - true if the engine successfully handled the string. -bool StateMachine::FlushToTerminal() +bool StateMachine::FlushToTerminal() noexcept { bool success{ true }; @@ -1829,7 +1795,9 @@ bool StateMachine::FlushToTerminal() // Flush the partial sequence to the terminal before we flush the rest of it. // We always want to clear the sequence, even if we failed, so we don't accumulate bad state // and dump it out elsewhere later. - success = _engine->ActionPassThroughString(*_cachedSequence); + success = _SafeExecute([=]() { + return _engine->ActionPassThroughString(*_cachedSequence); + }); _cachedSequence.reset(); } @@ -1839,7 +1807,9 @@ bool StateMachine::FlushToTerminal() // that pwchCurr was processed. // However, if we're here, then the processing of pwchChar triggered the // engine to request the entire sequence get passed through, including pwchCurr. - success = _engine->ActionPassThroughString(_CurrentRun()); + success = _SafeExecute([=]() { + return _engine->ActionPassThroughString(_CurrentRun()); + }); } return success; @@ -1892,10 +1862,7 @@ void StateMachine::ProcessString(const std::wstring_view string) // trim it off here since we just determined it's actionable // and only pass through everything before it. _runSize -= 1; - const auto allLeadingUpTo = _CurrentRun(); - - _engine->ActionPrintString(allLeadingUpTo); // ... print all the chars leading up to it as part of the run... - _trace.DispatchPrintRunTrace(allLeadingUpTo); + _ActionPrintString(_CurrentRun()); // ... print all the chars leading up to it as part of the run... } _processingIndividually = true; // begin processing future characters individually... @@ -1927,8 +1894,7 @@ void StateMachine::ProcessString(const std::wstring_view string) if (!_processingIndividually && !run.empty()) { // print the rest of the characters in the string - _engine->ActionPrintString(run); - _trace.DispatchPrintRunTrace(run); + _ActionPrintString(run); } else if (_processingIndividually) { @@ -2044,3 +2010,26 @@ void StateMachine::_AccumulateTo(const wchar_t wch, size_t& value) noexcept value = MAX_PARAMETER_VALUE; } } + +template +bool StateMachine::_SafeExecute(TLambda&& lambda) noexcept +try +{ + return lambda(); +} +catch (...) +{ + LOG_HR(wil::ResultFromCaughtException()); + return false; +} + +template +bool StateMachine::_SafeExecuteWithLog(const wchar_t wch, TLambda&& lambda) noexcept +{ + const bool success = _SafeExecute(std::forward(lambda)); + if (!success) + { + TermTelemetry::Instance().LogFailed(wch); + } + return success; +} diff --git a/src/terminal/parser/stateMachine.hpp b/src/terminal/parser/stateMachine.hpp index 2512912d0..704ccc01f 100644 --- a/src/terminal/parser/stateMachine.hpp +++ b/src/terminal/parser/stateMachine.hpp @@ -61,25 +61,26 @@ namespace Microsoft::Console::VirtualTerminal void ResetState() noexcept; - bool FlushToTerminal(); + bool FlushToTerminal() noexcept; const IStateMachineEngine& Engine() const noexcept; IStateMachineEngine& Engine() noexcept; private: - void _ActionExecute(const wchar_t wch); - void _ActionExecuteFromEscape(const wchar_t wch); - void _ActionPrint(const wchar_t wch); - void _ActionEscDispatch(const wchar_t wch); - void _ActionVt52EscDispatch(const wchar_t wch); + void _ActionExecute(const wchar_t wch) noexcept; + void _ActionExecuteFromEscape(const wchar_t wch) noexcept; + void _ActionPrint(const wchar_t wch) noexcept; + void _ActionPrintString(const std::wstring_view string); + void _ActionEscDispatch(const wchar_t wch) noexcept; + void _ActionVt52EscDispatch(const wchar_t wch) noexcept; void _ActionCollect(const wchar_t wch) noexcept; void _ActionParam(const wchar_t wch); - void _ActionCsiDispatch(const wchar_t wch); + void _ActionCsiDispatch(const wchar_t wch) noexcept; void _ActionOscParam(const wchar_t wch) noexcept; void _ActionOscPut(const wchar_t wch); - void _ActionOscDispatch(const wchar_t wch); - void _ActionSs3Dispatch(const wchar_t wch); - void _ActionDcsDispatch(const wchar_t wch); + void _ActionOscDispatch(const wchar_t wch) noexcept; + void _ActionSs3Dispatch(const wchar_t wch) noexcept; + void _ActionDcsDispatch(const wchar_t wch) noexcept; void _ActionClear(); void _ActionIgnore() noexcept; @@ -105,12 +106,12 @@ namespace Microsoft::Console::VirtualTerminal void _EnterDcsPassThrough() noexcept; void _EnterSosPmApcString() noexcept; - void _EventGround(const wchar_t wch); + void _EventGround(const wchar_t wch) noexcept; void _EventEscape(const wchar_t wch); - void _EventEscapeIntermediate(const wchar_t wch); + void _EventEscapeIntermediate(const wchar_t wch) noexcept; void _EventCsiEntry(const wchar_t wch); - void _EventCsiIntermediate(const wchar_t wch); - void _EventCsiIgnore(const wchar_t wch); + void _EventCsiIntermediate(const wchar_t wch) noexcept; + void _EventCsiIgnore(const wchar_t wch) noexcept; void _EventCsiParam(const wchar_t wch); void _EventOscParam(const wchar_t wch) noexcept; void _EventOscString(const wchar_t wch); @@ -120,13 +121,18 @@ namespace Microsoft::Console::VirtualTerminal void _EventVt52Param(const wchar_t wch); void _EventDcsEntry(const wchar_t wch); void _EventDcsIgnore() noexcept; - void _EventDcsIntermediate(const wchar_t wch); + void _EventDcsIntermediate(const wchar_t wch) noexcept; void _EventDcsParam(const wchar_t wch); void _EventDcsPassThrough(const wchar_t wch); void _EventSosPmApcString(const wchar_t wch) noexcept; void _AccumulateTo(const wchar_t wch, size_t& value) noexcept; + template + bool _SafeExecute(TLambda&& lambda) noexcept; + template + bool _SafeExecuteWithLog(const wchar_t wch, TLambda&& lambda) noexcept; + enum class VTStates { Ground,