terminal/src/host/screenInfo.hpp
James Holderness c69757ec9e
Remove unneeded VT-specific control character handling (#4289)
## Summary of the Pull Request

This PR removes all of the VT-specific functionality from the `WriteCharsLegacy` function that dealt with control characters, since those controls are now handled in the state machine when in VT mode. It also removes most of the control character handling from the `Terminal::_WriteBuffer` method for the same reason.

## References

This is a followup to PR #4171

## PR Checklist
* [x] Closes #3971
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [ ] Tests added/passed
* [ ] Requires documentation to be updated
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: https://github.com/microsoft/terminal/issues/780#issuecomment-570287435

## Detailed Description of the Pull Request / Additional comments

There are four changes to the `WriteCharsLegacy` implementation:

1. The `TAB` character had special case handling in VT mode which is now no longer required. This fixes a bug in the Python REPL editor (when run from a cmd shell in Windows Terminal), which would prevent you tabbing past the end of the line. It also fixes #3971.

2. Following on from point 1, the `WC_NONDESTRUCTIVE_TAB` flag could also now be removed. It only ever applied in VT mode, in which case the `TAB` character isn't handled in `WriteCharsLegacy`, so there isn't a need for a non-destructive version.

3. There used to be special case handling for a `BS` character at the beginning of the line when in VT mode, and that is also no longer required. This fixes an edge-case bug which would prevent a glyph being output for code point 8 when `ENABLE_PROCESSED_OUTPUT` was disabled. 

4. There was quite a lot of special case handling for control characters in the "end-of-line wrap" implementation, which is no longer required. This fixes a bug which would prevent "low ASCII" characters from wrapping when output at the end of a line.

Then in the `Terminal::_WriteBuffer` implementation, I've simply removed all control character handling, except for `LF`. The Terminal is always in VT mode, so the control characters are always handled by the state machine. The exception for the `LF` character is simply because it doesn't have a proper implementation yet, so it still passes the character through to `_WriteBuffer`. That will get cleaned up eventually, but I thought that could wait for a later PR.

Finally, with the removal of the VT mode handling in `WriteCharsLegacy`, there was no longer a need for the `SCREEN_INFORMATION::InVTMode` method to be publicly accessible. That has now been made private.

## Validation Steps Performed

I've only tested manually, making sure the conhost and Windows Terminal still basically work, and confirming that the above-mentioned bugs are fixed by these changes.
2020-01-29 19:18:46 +00:00

321 lines
13 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- screenInfo.hpp
Abstract:
- This module represents the structures and functions required
for rendering one screen of the console host window.
Author(s):
- Michael Niksa (MiNiksa) 10-Apr-2014
- Paul Campbell (PaulCam) 10-Apr-2014
Revision History:
- From components of output.h/.c and resize.c by Therese Stowell (ThereseS) 1990-1991
--*/
#pragma once
#include "conapi.h"
#include "settings.hpp"
#include "outputStream.hpp"
#include "ScreenBufferRenderTarget.hpp"
#include "../buffer/out/OutputCellRect.hpp"
#include "../buffer/out/TextAttribute.hpp"
#include "../buffer/out/textBuffer.hpp"
#include "../buffer/out/textBufferCellIterator.hpp"
#include "../buffer/out/textBufferTextIterator.hpp"
#include "IIoProvider.hpp"
#include "outputStream.hpp"
#include "../terminal/adapter/adaptDispatch.hpp"
#include "../terminal/parser/stateMachine.hpp"
#include "../terminal/parser/OutputStateMachineEngine.hpp"
#include "../server/ObjectHeader.h"
#include "../interactivity/inc/IAccessibilityNotifier.hpp"
#include "../interactivity/inc/IWindowMetrics.hpp"
#include "../inc/ITerminalOutputConnection.hpp"
#include "../renderer/inc/FontInfo.hpp"
#include "../renderer/inc/FontInfoDesired.hpp"
#include "../types/inc/Viewport.hpp"
#include "../types/IConsoleWindow.hpp"
class ConversionAreaInfo; // forward decl window. circular reference
// fwdecl unittest classes
#ifdef UNIT_TESTING
namespace TerminalCoreUnitTests
{
class ConptyRoundtripTests;
};
#endif
class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console::IIoProvider
{
public:
[[nodiscard]] static NTSTATUS CreateInstance(_In_ COORD coordWindowSize,
const FontInfo fontInfo,
_In_ COORD coordScreenBufferSize,
const TextAttribute defaultAttributes,
const TextAttribute popupAttributes,
const UINT uiCursorSize,
_Outptr_ SCREEN_INFORMATION** const ppScreen);
~SCREEN_INFORMATION();
void GetScreenBufferInformation(_Out_ PCOORD pcoordSize,
_Out_ PCOORD pcoordCursorPosition,
_Out_ PSMALL_RECT psrWindow,
_Out_ PWORD pwAttributes,
_Out_ PCOORD pcoordMaximumWindowSize,
_Out_ PWORD pwPopupAttributes,
_Out_writes_(COLOR_TABLE_SIZE) LPCOLORREF lpColorTable) const;
void GetRequiredConsoleSizeInPixels(_Out_ PSIZE const pRequiredSize) const;
void MakeCurrentCursorVisible();
void ClipToScreenBuffer(_Inout_ SMALL_RECT* const psrClip) const;
COORD GetMinWindowSizeInCharacters(const COORD coordFontSize = { 1, 1 }) const;
COORD GetMaxWindowSizeInCharacters(const COORD coordFontSize = { 1, 1 }) const;
COORD GetLargestWindowSizeInCharacters(const COORD coordFontSize = { 1, 1 }) const;
COORD GetScrollBarSizesInCharacters() const;
Microsoft::Console::Types::Viewport GetBufferSize() const;
Microsoft::Console::Types::Viewport GetTerminalBufferSize() const;
COORD GetScreenFontSize() const;
void UpdateFont(const FontInfo* const pfiNewFont);
void RefreshFontWithRenderer();
[[nodiscard]] NTSTATUS ResizeScreenBuffer(const COORD coordNewScreenSize, const bool fDoScrollBarUpdate);
void NotifyAccessibilityEventing(const short sStartX, const short sStartY, const short sEndX, const short sEndY);
void UpdateScrollBars();
void InternalUpdateScrollBars();
bool IsMaximizedBoth() const;
bool IsMaximizedX() const;
bool IsMaximizedY() const;
const Microsoft::Console::Types::Viewport& GetViewport() const noexcept;
void SetViewport(const Microsoft::Console::Types::Viewport& newViewport, const bool updateBottom);
Microsoft::Console::Types::Viewport GetVirtualViewport() const noexcept;
void ProcessResizeWindow(const RECT* const prcClientNew, const RECT* const prcClientOld);
void SetViewportSize(const COORD* const pcoordSize);
// Forwarders to Window if we're the active buffer.
[[nodiscard]] NTSTATUS SetViewportOrigin(const bool fAbsolute, const COORD coordWindowOrigin, const bool updateBottom);
bool SendNotifyBeep() const;
bool PostUpdateWindowSize() const;
// TODO: MSFT 9355062 these methods should probably be a part of construction/destruction. http://osgvsowi/9355062
static void s_InsertScreenBuffer(_In_ SCREEN_INFORMATION* const pScreenInfo);
static void s_RemoveScreenBuffer(_In_ SCREEN_INFORMATION* const pScreenInfo);
OutputCellRect ReadRect(const Microsoft::Console::Types::Viewport location) const;
TextBufferCellIterator GetCellDataAt(const COORD at) const;
TextBufferCellIterator GetCellLineDataAt(const COORD at) const;
TextBufferCellIterator GetCellDataAt(const COORD at, const Microsoft::Console::Types::Viewport limit) const;
TextBufferTextIterator GetTextDataAt(const COORD at) const;
TextBufferTextIterator GetTextLineDataAt(const COORD at) const;
TextBufferTextIterator GetTextDataAt(const COORD at, const Microsoft::Console::Types::Viewport limit) const;
OutputCellIterator Write(const OutputCellIterator it);
OutputCellIterator Write(const OutputCellIterator it,
const COORD target,
const std::optional<bool> wrap = true);
OutputCellIterator WriteRect(const OutputCellIterator it,
const Microsoft::Console::Types::Viewport viewport);
void WriteRect(const OutputCellRect& data,
const COORD location);
void ClearTextData();
std::pair<COORD, COORD> GetWordBoundary(const COORD position) const;
TextBuffer& GetTextBuffer() noexcept;
const TextBuffer& GetTextBuffer() const noexcept;
#pragma region IIoProvider
SCREEN_INFORMATION& GetActiveOutputBuffer() override;
const SCREEN_INFORMATION& GetActiveOutputBuffer() const override;
InputBuffer* const GetActiveInputBuffer() const override;
#pragma endregion
bool CursorIsDoubleWidth() const;
DWORD OutputMode;
WORD ResizingWindow; // > 0 if we should ignore WM_SIZE messages
short WheelDelta;
short HWheelDelta;
private:
std::unique_ptr<TextBuffer> _textBuffer;
public:
SCREEN_INFORMATION* Next;
BYTE WriteConsoleDbcsLeadByte[2];
BYTE FillOutDbcsLeadChar;
// non ownership pointer
ConversionAreaInfo* ConvScreenInfo;
UINT ScrollScale;
bool IsActiveScreenBuffer() const;
const Microsoft::Console::VirtualTerminal::StateMachine& GetStateMachine() const;
Microsoft::Console::VirtualTerminal::StateMachine& GetStateMachine();
void SetCursorInformation(const ULONG Size,
const bool Visible) noexcept;
void SetCursorColor(const unsigned int Color, const bool setMain = false) noexcept;
void SetCursorType(const CursorType Type, const bool setMain = false) noexcept;
void SetCursorDBMode(const bool DoubleCursor);
[[nodiscard]] NTSTATUS SetCursorPosition(const COORD Position, const bool TurnOn);
void MakeCursorVisible(const COORD CursorPosition, const bool updateBottom = true);
Microsoft::Console::Types::Viewport GetRelativeScrollMargins() const;
Microsoft::Console::Types::Viewport GetAbsoluteScrollMargins() const;
void SetScrollMargins(const Microsoft::Console::Types::Viewport margins);
bool AreMarginsSet() const noexcept;
bool IsCursorInMargins(const COORD cursorPosition) const noexcept;
Microsoft::Console::Types::Viewport GetScrollingRegion() const noexcept;
[[nodiscard]] NTSTATUS UseAlternateScreenBuffer();
void UseMainScreenBuffer();
SCREEN_INFORMATION& GetMainBuffer();
const SCREEN_INFORMATION& GetMainBuffer() const;
SCREEN_INFORMATION& GetActiveBuffer();
const SCREEN_INFORMATION& GetActiveBuffer() const;
void AddTabStop(const SHORT sColumn);
void ClearTabStops() noexcept;
void ClearTabStop(const SHORT sColumn) noexcept;
COORD GetForwardTab(const COORD cCurrCursorPos) const noexcept;
COORD GetReverseTab(const COORD cCurrCursorPos) const noexcept;
bool AreTabsSet() const noexcept;
void SetDefaultVtTabStops();
TextAttribute GetAttributes() const;
const TextAttribute* const GetPopupAttributes() const;
void SetAttributes(const TextAttribute& attributes);
void SetPopupAttributes(const TextAttribute& popupAttributes);
void SetDefaultAttributes(const TextAttribute& attributes,
const TextAttribute& popupAttributes);
[[nodiscard]] HRESULT VtEraseAll();
void SetTerminalConnection(_In_ Microsoft::Console::ITerminalOutputConnection* const pTtyConnection);
void UpdateBottom();
void MoveToBottom();
Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept;
FontInfo& GetCurrentFont() noexcept;
const FontInfo& GetCurrentFont() const noexcept;
FontInfoDesired& GetDesiredFont() noexcept;
const FontInfoDesired& GetDesiredFont() const noexcept;
void InitializeCursorRowAttributes();
private:
SCREEN_INFORMATION(_In_ Microsoft::Console::Interactivity::IWindowMetrics* pMetrics,
_In_ Microsoft::Console::Interactivity::IAccessibilityNotifier* pNotifier,
const TextAttribute popupAttributes,
const FontInfo fontInfo);
Microsoft::Console::Interactivity::IWindowMetrics* _pConsoleWindowMetrics;
Microsoft::Console::Interactivity::IAccessibilityNotifier* _pAccessibilityNotifier;
[[nodiscard]] HRESULT _AdjustScreenBufferHelper(const RECT* const prcClientNew,
const COORD coordBufferOld,
_Out_ COORD* const pcoordClientNewCharacters);
[[nodiscard]] HRESULT _AdjustScreenBuffer(const RECT* const prcClientNew);
void _CalculateViewportSize(const RECT* const prcClientArea, _Out_ COORD* const pcoordSize);
void _AdjustViewportSize(const RECT* const prcClientNew, const RECT* const prcClientOld, const COORD* const pcoordSize);
void _InternalSetViewportSize(const COORD* const pcoordSize, const bool fResizeFromTop, const bool fResizeFromLeft);
static void s_CalculateScrollbarVisibility(const RECT* const prcClientArea,
const COORD* const pcoordBufferSize,
const COORD* const pcoordFontSize,
_Out_ bool* const pfIsHorizontalVisible,
_Out_ bool* const pfIsVerticalVisible);
[[nodiscard]] NTSTATUS ResizeWithReflow(const COORD coordnewScreenSize);
[[nodiscard]] NTSTATUS ResizeTraditional(const COORD coordNewScreenSize);
[[nodiscard]] NTSTATUS _InitializeOutputStateMachine();
void _FreeOutputStateMachine();
[[nodiscard]] NTSTATUS _CreateAltBuffer(_Out_ SCREEN_INFORMATION** const ppsiNewScreenBuffer);
bool _IsAltBuffer() const;
bool _IsInPtyMode() const;
bool _IsInVTMode() const;
std::shared_ptr<Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
Microsoft::Console::Types::Viewport _scrollMargins; //The margins of the VT specified scroll region. Left and Right are currently unused, but could be in the future.
// Specifies which coordinates of the screen buffer are visible in the
// window client (the "viewport" into the buffer)
Microsoft::Console::Types::Viewport _viewport;
SCREEN_INFORMATION* _psiAlternateBuffer; // The VT "Alternate" screen buffer.
SCREEN_INFORMATION* _psiMainBuffer; // A pointer to the main buffer, if this is the alternate buffer.
RECT _rcAltSavedClientNew;
RECT _rcAltSavedClientOld;
bool _fAltWindowChanged;
std::list<short> _tabStops;
TextAttribute _PopupAttributes;
FontInfo _currentFont;
FontInfoDesired _desiredFont;
// Tracks the last virtual position the viewport was at. This is not
// affected by the user scrolling the viewport, only when API calls cause
// the viewport to move (SetBufferInfo, WriteConsole, etc)
short _virtualBottom;
ScreenBufferRenderTarget _renderTarget;
#ifdef UNIT_TESTING
friend class TextBufferIteratorTests;
friend class ScreenBufferTests;
friend class CommonState;
friend class ConptyOutputTests;
friend class TerminalCoreUnitTests::ConptyRoundtripTests;
#endif
};