terminal/src/terminal/adapter/ITermDispatch.hpp
James Holderness 6742965bb8
Disable the acceptance of C1 control codes by default (#11690)
There are some code pages with "unmapped" code points in the C1 range,
which results in them being translated into Unicode C1 control codes,
even though that is not their intended use. To avoid having these
characters triggering unintentional escape sequences, this PR now
disables C1 controls by default.

Switching to ISO-2022 encoding will re-enable them, though, since that
is the most likely scenario in which they would be required. They can
also be explicitly enabled, even in UTF-8 mode, with the `DECAC1` escape
sequence.

What I've done is add a new mode to the `StateMachine` class that
controls whether C1 code points are interpreted as control characters or
not. When disabled, these code points are simply dropped from the
output, similar to the way a `NUL` is interpreted.

This isn't exactly the way they were handled in the v1 console (which I
think replaces them with the font _notdef_ glyph), but it matches the
XTerm behavior, which seems more appropriate considering this is in VT
mode. And it's worth noting that Windows Explorer seems to work the same
way.

As mentioned above, the mode can be enabled by designating the ISO-2022
coding system with a `DOCS` sequence, and it will be disabled again when
UTF-8 is designated. You can also enable it explicitly with a `DECAC1`
sequence (originally this was actually a DEC printer sequence, but it
doesn't seem unreasonable to use it in a terminal).

I've also extended the operations that save and restore "cursor state"
(e.g. `DECSC` and `DECRC`) to include the state of the C1 parser mode,
since it's closely tied to the code page and character sets which are
also saved there. Similarly, when a `DECSTR` sequence resets the code
page and character sets, I've now made it reset the C1 mode as well.

I should note that the new `StateMachine` mode is controlled via a
generic `SetParserMode` method (with a matching API in the `ConGetSet`
interface) to allow for easier addition of other modes in the future.
And I've reimplemented the existing ANSI/VT52 mode in terms of these
generic methods instead of it having to have its own separate APIs.

## Validation Steps Performed

Some of the unit tests for OSC sequences were using a C1 `0x9C` for the
string terminator, which doesn't work by default anymore. Since that's
not a good practice anyway, I thought it best to change those to a
standard 7-bit terminator. However, in tests that were explicitly
validating the C1 controls, I've just enabled the C1 parser mode at the
start of the tests in order to get them working again.

There were also some ANSI mode adapter tests that had to be updated to
account for the fact that it has now been reimplemented in terms of the
`SetParserMode` API.

I've added a new state machine test to validate the changes in behavior
when the C1 parser mode is enabled or disabled. And I've added an
adapter test to verify that the `DesignateCodingSystems` and
`AcceptC1Controls` methods toggle the C1 parser mode as expected.

I've manually verified the test cases in #10069 and #10310 to confirm
that they're no longer triggering control sequences by default.
Although, as I explained above, the C1 code points are completely
dropped from the output rather than displayed as _notdef_ glyphs. I
think this is a reasonable compromise though.

Closes #10069
Closes #10310
2021-11-17 23:40:31 +00:00

150 lines
8.1 KiB
C++

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
/*
Module Name:
- ITermDispatch.hpp
Abstract:
- This is the interface for all output state machine callbacks. When actions
occur, they will be dispatched to the methods on this interface which must
be implemented by a child class and passed into the state machine on
creation.
*/
#pragma once
#include "DispatchTypes.hpp"
#include "../buffer/out/LineRendition.hpp"
namespace Microsoft::Console::VirtualTerminal
{
class ITermDispatch;
};
class Microsoft::Console::VirtualTerminal::ITermDispatch
{
public:
using StringHandler = std::function<bool(const wchar_t)>;
#pragma warning(push)
#pragma warning(disable : 26432) // suppress rule of 5 violation on interface because tampering with this is fraught with peril
virtual ~ITermDispatch() = 0;
virtual void Execute(const wchar_t wchControl) = 0;
virtual void Print(const wchar_t wchPrintable) = 0;
virtual void PrintString(const std::wstring_view string) = 0;
virtual bool CursorUp(const size_t distance) = 0; // CUU
virtual bool CursorDown(const size_t distance) = 0; // CUD
virtual bool CursorForward(const size_t distance) = 0; // CUF
virtual bool CursorBackward(const size_t distance) = 0; // CUB, BS
virtual bool CursorNextLine(const size_t distance) = 0; // CNL
virtual bool CursorPrevLine(const size_t distance) = 0; // CPL
virtual bool CursorHorizontalPositionAbsolute(const size_t column) = 0; // HPA, CHA
virtual bool VerticalLinePositionAbsolute(const size_t line) = 0; // VPA
virtual bool HorizontalPositionRelative(const size_t distance) = 0; // HPR
virtual bool VerticalPositionRelative(const size_t distance) = 0; // VPR
virtual bool CursorPosition(const size_t line, const size_t column) = 0; // CUP, HVP
virtual bool CursorSaveState() = 0; // DECSC
virtual bool CursorRestoreState() = 0; // DECRC
virtual bool CursorVisibility(const bool isVisible) = 0; // DECTCEM
virtual bool InsertCharacter(const size_t count) = 0; // ICH
virtual bool DeleteCharacter(const size_t count) = 0; // DCH
virtual bool ScrollUp(const size_t distance) = 0; // SU
virtual bool ScrollDown(const size_t distance) = 0; // SD
virtual bool InsertLine(const size_t distance) = 0; // IL
virtual bool DeleteLine(const size_t distance) = 0; // DL
virtual bool SetColumns(const size_t columns) = 0; // DECCOLM
virtual bool SetCursorKeysMode(const bool applicationMode) = 0; // DECCKM
virtual bool SetKeypadMode(const bool applicationMode) = 0; // DECKPAM, DECKPNM
virtual bool EnableWin32InputMode(const bool win32InputMode) = 0; // win32-input-mode
virtual bool EnableCursorBlinking(const bool enable) = 0; // ATT610
virtual bool SetAnsiMode(const bool ansiMode) = 0; // DECANM
virtual bool SetScreenMode(const bool reverseMode) = 0; // DECSCNM
virtual bool SetOriginMode(const bool relativeMode) = 0; // DECOM
virtual bool SetAutoWrapMode(const bool wrapAtEOL) = 0; // DECAWM
virtual bool SetTopBottomScrollingMargins(const size_t topMargin, const size_t bottomMargin) = 0; // DECSTBM
virtual bool WarningBell() = 0; // BEL
virtual bool CarriageReturn() = 0; // CR
virtual bool LineFeed(const DispatchTypes::LineFeedType lineFeedType) = 0; // IND, NEL, LF, FF, VT
virtual bool ReverseLineFeed() = 0; // RI
virtual bool SetWindowTitle(std::wstring_view title) = 0; // OscWindowTitle
virtual bool UseAlternateScreenBuffer() = 0; // ASBSET
virtual bool UseMainScreenBuffer() = 0; // ASBRST
virtual bool HorizontalTabSet() = 0; // HTS
virtual bool ForwardTab(const size_t numTabs) = 0; // CHT, HT
virtual bool BackwardsTab(const size_t numTabs) = 0; // CBT
virtual bool TabClear(const DispatchTypes::TabClearType clearType) = 0; // TBC
virtual bool EnableDECCOLMSupport(const bool enabled) = 0; // ?40
virtual bool EnableVT200MouseMode(const bool enabled) = 0; // ?1000
virtual bool EnableUTF8ExtendedMouseMode(const bool enabled) = 0; // ?1005
virtual bool EnableSGRExtendedMouseMode(const bool enabled) = 0; // ?1006
virtual bool EnableButtonEventMouseMode(const bool enabled) = 0; // ?1002
virtual bool EnableAnyEventMouseMode(const bool enabled) = 0; // ?1003
virtual bool EnableAlternateScroll(const bool enabled) = 0; // ?1007
virtual bool EnableXtermBracketedPasteMode(const bool enabled) = 0; // ?2004
virtual bool SetColorTableEntry(const size_t tableIndex, const DWORD color) = 0; // OSCColorTable
virtual bool SetDefaultForeground(const DWORD color) = 0; // OSCDefaultForeground
virtual bool SetDefaultBackground(const DWORD color) = 0; // OSCDefaultBackground
virtual bool EraseInDisplay(const DispatchTypes::EraseType eraseType) = 0; // ED
virtual bool EraseInLine(const DispatchTypes::EraseType eraseType) = 0; // EL
virtual bool EraseCharacters(const size_t numChars) = 0; // ECH
virtual bool SetGraphicsRendition(const VTParameters options) = 0; // SGR
virtual bool SetLineRendition(const LineRendition rendition) = 0; // DECSWL, DECDWL, DECDHL
virtual bool PushGraphicsRendition(const VTParameters options) = 0; // XTPUSHSGR
virtual bool PopGraphicsRendition() = 0; // XTPOPSGR
virtual bool SetMode(const DispatchTypes::ModeParams param) = 0; // DECSET
virtual bool ResetMode(const DispatchTypes::ModeParams param) = 0; // DECRST
virtual bool DeviceStatusReport(const DispatchTypes::AnsiStatusType statusType) = 0; // DSR, DSR-OS, DSR-CPR
virtual bool DeviceAttributes() = 0; // DA1
virtual bool SecondaryDeviceAttributes() = 0; // DA2
virtual bool TertiaryDeviceAttributes() = 0; // DA3
virtual bool Vt52DeviceAttributes() = 0; // VT52 Identify
virtual bool RequestTerminalParameters(const DispatchTypes::ReportingPermission permission) = 0; // DECREQTPARM
virtual bool DesignateCodingSystem(const VTID codingSystem) = 0; // DOCS
virtual bool Designate94Charset(const size_t gsetNumber, const VTID charset) = 0; // SCS
virtual bool Designate96Charset(const size_t gsetNumber, const VTID charset) = 0; // SCS
virtual bool LockingShift(const size_t gsetNumber) = 0; // LS0, LS1, LS2, LS3
virtual bool LockingShiftRight(const size_t gsetNumber) = 0; // LS1R, LS2R, LS3R
virtual bool SingleShift(const size_t gsetNumber) = 0; // SS2, SS3
virtual bool AcceptC1Controls(const bool enabled) = 0; // DECAC1
virtual bool SoftReset() = 0; // DECSTR
virtual bool HardReset() = 0; // RIS
virtual bool ScreenAlignmentPattern() = 0; // DECALN
virtual bool SetCursorStyle(const DispatchTypes::CursorStyle cursorStyle) = 0; // DECSCUSR
virtual bool SetCursorColor(const COLORREF color) = 0; // OSCSetCursorColor, OSCResetCursorColor
virtual bool SetClipboard(std::wstring_view content) = 0; // OSCSetClipboard
// DTTERM_WindowManipulation
virtual bool WindowManipulation(const DispatchTypes::WindowManipulationType function,
const VTParameter parameter1,
const VTParameter parameter2) = 0;
virtual bool AddHyperlink(const std::wstring_view uri, const std::wstring_view params) = 0;
virtual bool EndHyperlink() = 0;
virtual bool DoConEmuAction(const std::wstring_view string) = 0;
virtual StringHandler DownloadDRCS(const size_t fontNumber,
const VTParameter startChar,
const DispatchTypes::DrcsEraseControl eraseControl,
const DispatchTypes::DrcsCellMatrix cellMatrix,
const DispatchTypes::DrcsFontSet fontSet,
const DispatchTypes::DrcsFontUsage fontUsage,
const VTParameter cellHeight,
const DispatchTypes::DrcsCharsetSize charsetSize) = 0; // DECDLD
virtual StringHandler RequestSetting() = 0; // DECRQSS
};
inline Microsoft::Console::VirtualTerminal::ITermDispatch::~ITermDispatch() {}
#pragma warning(pop)