mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-11 04:38:24 -06:00
Add support for the S8C1T/S7C1T escape sequences (#17945)
This PR adds support for the `S8C1T` and `S7C1T` commands, which enable an application to choose whether the terminal should use C1 controls when sending key sequences and query responses. This also updates the `DOCS` command to set both the input and output code pages. So when switched to ISO2022 mode, the C1 controls will be transmitted as 8-bit, which is what legacy systems would be expecting. ## Detailed Description of the Pull Request / Additional comments While adding the input code page support, I also reworked the way we handle the code page reset in `RIS`. In the original implementation we saved the active code page when the `DOCS` sequence was first used, and that would become the default value for a reset. With this PR I'm now saving the code pages whenever `SetConsoleCP` or `SetConsoleOutputCP` is called, so those APIs now control what the default values will be. This feels more consistent than the previous approach. And this is how WSL sets its initial code page to UTF-8. ## Validation Steps Performed I've added a couple of unit tests that check one of each applicable C1 control in the key sequences and query reports. I also built myself a code page aware telnet client so I could log into WSL in 8-bit mode, and confirmed that the C1 transmissions are working as expected in vttest. Closes #17931 Tests added/passed
This commit is contained in:
parent
b715008de3
commit
aa256ad5c9
@ -139,8 +139,10 @@ public:
|
|||||||
void SetWindowTitle(const std::wstring_view title) override;
|
void SetWindowTitle(const std::wstring_view title) override;
|
||||||
CursorType GetUserDefaultCursorStyle() const noexcept override;
|
CursorType GetUserDefaultCursorStyle() const noexcept override;
|
||||||
bool ResizeWindow(const til::CoordType width, const til::CoordType height) override;
|
bool ResizeWindow(const til::CoordType width, const til::CoordType height) override;
|
||||||
void SetConsoleOutputCP(const unsigned int codepage) noexcept override;
|
void SetCodePage(const unsigned int codepage) noexcept override;
|
||||||
unsigned int GetConsoleOutputCP() const noexcept override;
|
void ResetCodePage() noexcept override;
|
||||||
|
unsigned int GetOutputCodePage() const noexcept override;
|
||||||
|
unsigned int GetInputCodePage() const noexcept override;
|
||||||
void CopyToClipboard(wil::zwstring_view content) override;
|
void CopyToClipboard(wil::zwstring_view content) override;
|
||||||
void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
|
void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
|
||||||
void SetWorkingDirectory(std::wstring_view uri) override;
|
void SetWorkingDirectory(std::wstring_view uri) override;
|
||||||
|
|||||||
@ -116,14 +116,25 @@ bool Terminal::ResizeWindow(const til::CoordType width, const til::CoordType hei
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::SetConsoleOutputCP(const unsigned int /*codepage*/) noexcept
|
void Terminal::SetCodePage(const unsigned int /*codepage*/) noexcept
|
||||||
{
|
{
|
||||||
// TODO: This will be needed to support 8-bit charsets and DOCS sequences.
|
// Code pages are dealt with in ConHost, so this isn't needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Terminal::GetConsoleOutputCP() const noexcept
|
void Terminal::ResetCodePage() noexcept
|
||||||
{
|
{
|
||||||
// TODO: See SetConsoleOutputCP above.
|
// There is nothing to reset, since the code page never changes.
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Terminal::GetOutputCodePage() const noexcept
|
||||||
|
{
|
||||||
|
// See above. The code page is always UTF-8.
|
||||||
|
return CP_UTF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Terminal::GetInputCodePage() const noexcept
|
||||||
|
{
|
||||||
|
// See above. The code page is always UTF-8.
|
||||||
return CP_UTF8;
|
return CP_UTF8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1140,7 +1140,6 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
|
|||||||
{
|
{
|
||||||
// Set new code page
|
// Set new code page
|
||||||
gci.OutputCP = codepage;
|
gci.OutputCP = codepage;
|
||||||
|
|
||||||
SetConsoleCPInfo(TRUE);
|
SetConsoleCPInfo(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1157,13 +1156,36 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
LockConsole();
|
LockConsole();
|
||||||
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
|
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
|
||||||
return DoSrvSetConsoleOutputCodePage(codepage);
|
RETURN_IF_FAILED(DoSrvSetConsoleOutputCodePage(codepage));
|
||||||
|
// Setting the code page via the API also updates the default value.
|
||||||
|
// This is how the initial code page is set to UTF-8 in a WSL shell.
|
||||||
|
gci.DefaultOutputCP = codepage;
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
CATCH_RETURN();
|
CATCH_RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] HRESULT DoSrvSetConsoleInputCodePage(const unsigned int codepage)
|
||||||
|
{
|
||||||
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
|
||||||
|
// Return if it's not known as a valid codepage ID.
|
||||||
|
RETURN_HR_IF(E_INVALIDARG, !(IsValidCodePage(codepage)));
|
||||||
|
|
||||||
|
// Do nothing if no change.
|
||||||
|
if (gci.CP != codepage)
|
||||||
|
{
|
||||||
|
// Set new code page
|
||||||
|
gci.CP = codepage;
|
||||||
|
SetConsoleCPInfo(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
// - Sets the codepage used for translating text when calling A versions of functions affecting the input buffer.
|
// - Sets the codepage used for translating text when calling A versions of functions affecting the input buffer.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
@ -1177,19 +1199,10 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
|
|||||||
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
LockConsole();
|
LockConsole();
|
||||||
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
|
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
|
||||||
|
RETURN_IF_FAILED(DoSrvSetConsoleInputCodePage(codepage));
|
||||||
// Return if it's not known as a valid codepage ID.
|
// Setting the code page via the API also updates the default value.
|
||||||
RETURN_HR_IF(E_INVALIDARG, !(IsValidCodePage(codepage)));
|
// This is how the initial code page is set to UTF-8 in a WSL shell.
|
||||||
|
gci.DefaultCP = codepage;
|
||||||
// Do nothing if no change.
|
|
||||||
if (gci.CP != codepage)
|
|
||||||
{
|
|
||||||
// Set new code page
|
|
||||||
gci.CP = codepage;
|
|
||||||
|
|
||||||
SetConsoleCPInfo(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
CATCH_RETURN();
|
CATCH_RETURN();
|
||||||
|
|||||||
@ -19,3 +19,4 @@ Revision History:
|
|||||||
class SCREEN_INFORMATION;
|
class SCREEN_INFORMATION;
|
||||||
|
|
||||||
[[nodiscard]] HRESULT DoSrvSetConsoleOutputCodePage(const unsigned int codepage);
|
[[nodiscard]] HRESULT DoSrvSetConsoleOutputCodePage(const unsigned int codepage);
|
||||||
|
[[nodiscard]] HRESULT DoSrvSetConsoleInputCodePage(const unsigned int codepage);
|
||||||
|
|||||||
@ -35,6 +35,8 @@ using namespace Microsoft::Console::Interactivity;
|
|||||||
// codepage by console.cpl or shell32. The default codepage is OEMCP.
|
// codepage by console.cpl or shell32. The default codepage is OEMCP.
|
||||||
gci.CP = gci.GetCodePage();
|
gci.CP = gci.GetCodePage();
|
||||||
gci.OutputCP = gci.GetCodePage();
|
gci.OutputCP = gci.GetCodePage();
|
||||||
|
gci.DefaultCP = gci.GetCodePage();
|
||||||
|
gci.DefaultOutputCP = gci.GetCodePage();
|
||||||
|
|
||||||
gci.Flags |= CONSOLE_USE_PRIVATE_FLAGS;
|
gci.Flags |= CONSOLE_USE_PRIVATE_FLAGS;
|
||||||
|
|
||||||
|
|||||||
@ -221,27 +221,52 @@ void ConhostInternalGetSet::ShowWindow(bool showOrHide)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
// - Connects the SetConsoleOutputCP API call directly into our Driver Message servicing call inside Conhost.exe
|
// - Set the code page used for translating text when calling A versions of I/O functions.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - codepage - the new output codepage of the console.
|
// - codepage - the new code page of the console.
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - <none>
|
// - <none>
|
||||||
void ConhostInternalGetSet::SetConsoleOutputCP(const unsigned int codepage)
|
void ConhostInternalGetSet::SetCodePage(const unsigned int codepage)
|
||||||
{
|
{
|
||||||
THROW_IF_FAILED(DoSrvSetConsoleOutputCodePage(codepage));
|
LOG_IF_FAILED(DoSrvSetConsoleOutputCodePage(codepage));
|
||||||
|
LOG_IF_FAILED(DoSrvSetConsoleInputCodePage(codepage));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
// - Gets the codepage used for translating text when calling A versions of functions affecting the output buffer.
|
// - Reset the code pages to their default values.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// - <none>
|
// - <none>
|
||||||
// Return Value:
|
// Return Value:
|
||||||
// - the outputCP of the console.
|
// - <none>
|
||||||
unsigned int ConhostInternalGetSet::GetConsoleOutputCP() const
|
void ConhostInternalGetSet::ResetCodePage()
|
||||||
|
{
|
||||||
|
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
|
||||||
|
LOG_IF_FAILED(DoSrvSetConsoleOutputCodePage(gci.DefaultOutputCP));
|
||||||
|
LOG_IF_FAILED(DoSrvSetConsoleInputCodePage(gci.DefaultCP));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Routine Description:
|
||||||
|
// - Gets the code page used for translating text when calling A versions of output functions.
|
||||||
|
// Arguments:
|
||||||
|
// - <none>
|
||||||
|
// Return Value:
|
||||||
|
// - the output code page of the console.
|
||||||
|
unsigned int ConhostInternalGetSet::GetOutputCodePage() const
|
||||||
{
|
{
|
||||||
return ServiceLocator::LocateGlobals().getConsoleInformation().OutputCP;
|
return ServiceLocator::LocateGlobals().getConsoleInformation().OutputCP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Routine Description:
|
||||||
|
// - Gets the code page used for translating text when calling A versions of input functions.
|
||||||
|
// Arguments:
|
||||||
|
// - <none>
|
||||||
|
// Return Value:
|
||||||
|
// - the input code page of the console.
|
||||||
|
unsigned int ConhostInternalGetSet::GetInputCodePage() const
|
||||||
|
{
|
||||||
|
return ServiceLocator::LocateGlobals().getConsoleInformation().CP;
|
||||||
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
// - Copies the given content to the clipboard.
|
// - Copies the given content to the clipboard.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
|||||||
@ -53,8 +53,10 @@ public:
|
|||||||
|
|
||||||
bool ResizeWindow(const til::CoordType width, const til::CoordType height) override;
|
bool ResizeWindow(const til::CoordType width, const til::CoordType height) override;
|
||||||
|
|
||||||
void SetConsoleOutputCP(const unsigned int codepage) override;
|
void SetCodePage(const unsigned int codepage) override;
|
||||||
unsigned int GetConsoleOutputCP() const override;
|
void ResetCodePage() override;
|
||||||
|
unsigned int GetOutputCodePage() const override;
|
||||||
|
unsigned int GetInputCodePage() const override;
|
||||||
|
|
||||||
void CopyToClipboard(const wil::zwstring_view content) override;
|
void CopyToClipboard(const wil::zwstring_view content) override;
|
||||||
void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
|
void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
|
||||||
|
|||||||
@ -90,6 +90,9 @@ public:
|
|||||||
// the following fields are used for ansi-unicode translation
|
// the following fields are used for ansi-unicode translation
|
||||||
UINT CP = 0;
|
UINT CP = 0;
|
||||||
UINT OutputCP = 0;
|
UINT OutputCP = 0;
|
||||||
|
// the VT RIS sequence uses these default values to reset the code pages
|
||||||
|
UINT DefaultCP = 0;
|
||||||
|
UINT DefaultOutputCP = 0;
|
||||||
|
|
||||||
ULONG CtrlFlags = 0; // indicates outstanding ctrl requests
|
ULONG CtrlFlags = 0; // indicates outstanding ctrl requests
|
||||||
ULONG LimitingProcessId = 0;
|
ULONG LimitingProcessId = 0;
|
||||||
|
|||||||
@ -122,6 +122,7 @@ public:
|
|||||||
virtual void LockingShiftRight(const VTInt gsetNumber) = 0; // LS1R, LS2R, LS3R
|
virtual void LockingShiftRight(const VTInt gsetNumber) = 0; // LS1R, LS2R, LS3R
|
||||||
virtual void SingleShift(const VTInt gsetNumber) = 0; // SS2, SS3
|
virtual void SingleShift(const VTInt gsetNumber) = 0; // SS2, SS3
|
||||||
virtual void AcceptC1Controls(const bool enabled) = 0; // DECAC1
|
virtual void AcceptC1Controls(const bool enabled) = 0; // DECAC1
|
||||||
|
virtual void SendC1Controls(const bool enabled) = 0; // S8C1T, S7C1T
|
||||||
virtual void AnnounceCodeStructure(const VTInt ansiLevel) = 0; // ACS
|
virtual void AnnounceCodeStructure(const VTInt ansiLevel) = 0; // ACS
|
||||||
|
|
||||||
virtual void SoftReset() = 0; // DECSTR
|
virtual void SoftReset() = 0; // DECSTR
|
||||||
|
|||||||
@ -72,8 +72,10 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
|
|
||||||
virtual void ShowWindow(bool showOrHide) = 0;
|
virtual void ShowWindow(bool showOrHide) = 0;
|
||||||
|
|
||||||
virtual void SetConsoleOutputCP(const unsigned int codepage) = 0;
|
virtual void SetCodePage(const unsigned int codepage) = 0;
|
||||||
virtual unsigned int GetConsoleOutputCP() const = 0;
|
virtual void ResetCodePage() = 0;
|
||||||
|
virtual unsigned int GetOutputCodePage() const = 0;
|
||||||
|
virtual unsigned int GetInputCodePage() const = 0;
|
||||||
|
|
||||||
virtual void CopyToClipboard(const wil::zwstring_view content) = 0;
|
virtual void CopyToClipboard(const wil::zwstring_view content) = 0;
|
||||||
virtual void SetTaskbarProgress(const DispatchTypes::TaskbarState state, const size_t progress) = 0;
|
virtual void SetTaskbarProgress(const DispatchTypes::TaskbarState state, const size_t progress) = 0;
|
||||||
|
|||||||
@ -62,7 +62,7 @@ void InteractDispatch::WriteString(const std::wstring_view string)
|
|||||||
{
|
{
|
||||||
if (!string.empty())
|
if (!string.empty())
|
||||||
{
|
{
|
||||||
const auto codepage = _api.GetConsoleOutputCP();
|
const auto codepage = _api.GetOutputCodePage();
|
||||||
InputEventQueue keyEvents;
|
InputEventQueue keyEvents;
|
||||||
|
|
||||||
for (const auto& wch : string)
|
for (const auto& wch : string)
|
||||||
|
|||||||
@ -1243,7 +1243,7 @@ void AdaptDispatch::FillRectangularArea(const VTParameter ch, const VTInt top, c
|
|||||||
const auto charValue = ch.value_or(0) == 0 ? 32 : ch.value();
|
const auto charValue = ch.value_or(0) == 0 ? 32 : ch.value();
|
||||||
const auto glChar = (charValue >= 32 && charValue <= 126);
|
const auto glChar = (charValue >= 32 && charValue <= 126);
|
||||||
const auto grChar = (charValue >= 160 && charValue <= 255);
|
const auto grChar = (charValue >= 160 && charValue <= 255);
|
||||||
const auto unicodeChar = (charValue >= 256 && charValue <= 65535 && _api.GetConsoleOutputCP() == CP_UTF8);
|
const auto unicodeChar = (charValue >= 256 && charValue <= 65535 && _api.GetOutputCodePage() == CP_UTF8);
|
||||||
if (glChar || grChar || unicodeChar)
|
if (glChar || grChar || unicodeChar)
|
||||||
{
|
{
|
||||||
const auto fillChar = _termOutput.TranslateKey(gsl::narrow_cast<wchar_t>(charValue));
|
const auto fillChar = _termOutput.TranslateKey(gsl::narrow_cast<wchar_t>(charValue));
|
||||||
@ -1377,8 +1377,7 @@ void AdaptDispatch::RequestChecksumRectangularArea(const VTInt id, const VTInt p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto response = wil::str_printf<std::wstring>(L"\033P%d!~%04X\033\\", id, checksum);
|
_ReturnDcsResponse(wil::str_printf<std::wstring>(L"%d!~%04X", id, checksum));
|
||||||
_api.ReturnResponse(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -1484,7 +1483,7 @@ void AdaptDispatch::DeviceAttributes()
|
|||||||
// 32 = Text macros
|
// 32 = Text macros
|
||||||
// 42 = ISO Latin-2 character set
|
// 42 = ISO Latin-2 character set
|
||||||
|
|
||||||
_api.ReturnResponse(L"\x1b[?61;4;6;7;14;21;22;23;24;28;32;42c");
|
_ReturnCsiResponse(L"?61;4;6;7;14;21;22;23;24;28;32;42c");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -1496,7 +1495,7 @@ void AdaptDispatch::DeviceAttributes()
|
|||||||
// - <none>
|
// - <none>
|
||||||
void AdaptDispatch::SecondaryDeviceAttributes()
|
void AdaptDispatch::SecondaryDeviceAttributes()
|
||||||
{
|
{
|
||||||
_api.ReturnResponse(L"\x1b[>0;10;1c");
|
_ReturnCsiResponse(L">0;10;1c");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -1506,7 +1505,7 @@ void AdaptDispatch::SecondaryDeviceAttributes()
|
|||||||
// - <none>
|
// - <none>
|
||||||
void AdaptDispatch::TertiaryDeviceAttributes()
|
void AdaptDispatch::TertiaryDeviceAttributes()
|
||||||
{
|
{
|
||||||
_api.ReturnResponse(L"\x1bP!|00000000\x1b\\");
|
_ReturnDcsResponse(L"!|00000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -1544,10 +1543,10 @@ void AdaptDispatch::RequestTerminalParameters(const DispatchTypes::ReportingPerm
|
|||||||
switch (permission)
|
switch (permission)
|
||||||
{
|
{
|
||||||
case DispatchTypes::ReportingPermission::Unsolicited:
|
case DispatchTypes::ReportingPermission::Unsolicited:
|
||||||
_api.ReturnResponse(L"\x1b[2;1;1;128;128;1;0x");
|
_ReturnCsiResponse(L"2;1;1;128;128;1;0x");
|
||||||
break;
|
break;
|
||||||
case DispatchTypes::ReportingPermission::Solicited:
|
case DispatchTypes::ReportingPermission::Solicited:
|
||||||
_api.ReturnResponse(L"\x1b[3;1;1;128;128;1;0x");
|
_ReturnCsiResponse(L"3;1;1;128;128;1;0x");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1562,7 +1561,7 @@ void AdaptDispatch::RequestTerminalParameters(const DispatchTypes::ReportingPerm
|
|||||||
// - <none>
|
// - <none>
|
||||||
void AdaptDispatch::_DeviceStatusReport(const wchar_t* parameters) const
|
void AdaptDispatch::_DeviceStatusReport(const wchar_t* parameters) const
|
||||||
{
|
{
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033[{}n"), parameters));
|
_ReturnCsiResponse(fmt::format(FMT_COMPILE(L"{}n"), parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -1598,14 +1597,12 @@ void AdaptDispatch::_CursorPositionReport(const bool extendedReport)
|
|||||||
{
|
{
|
||||||
// An extended report also includes the page number.
|
// An extended report also includes the page number.
|
||||||
const auto pageNumber = page.Number();
|
const auto pageNumber = page.Number();
|
||||||
const auto response = wil::str_printf<std::wstring>(L"\x1b[?%d;%d;%dR", cursorPosition.y, cursorPosition.x, pageNumber);
|
_ReturnCsiResponse(wil::str_printf<std::wstring>(L"?%d;%d;%dR", cursorPosition.y, cursorPosition.x, pageNumber));
|
||||||
_api.ReturnResponse(response);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The standard report only returns the cursor position.
|
// The standard report only returns the cursor position.
|
||||||
const auto response = wil::str_printf<std::wstring>(L"\x1b[%d;%dR", cursorPosition.y, cursorPosition.x);
|
_ReturnCsiResponse(wil::str_printf<std::wstring>(L"%d;%dR", cursorPosition.y, cursorPosition.x));
|
||||||
_api.ReturnResponse(response);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1619,8 +1616,7 @@ void AdaptDispatch::_MacroSpaceReport() const
|
|||||||
{
|
{
|
||||||
const auto spaceInBytes = _macroBuffer ? _macroBuffer->GetSpaceAvailable() : MacroBuffer::MAX_SPACE;
|
const auto spaceInBytes = _macroBuffer ? _macroBuffer->GetSpaceAvailable() : MacroBuffer::MAX_SPACE;
|
||||||
// The available space is measured in blocks of 16 bytes, so we need to divide by 16.
|
// The available space is measured in blocks of 16 bytes, so we need to divide by 16.
|
||||||
const auto response = wil::str_printf<std::wstring>(L"\x1b[%zu*{", spaceInBytes / 16);
|
_ReturnCsiResponse(wil::str_printf<std::wstring>(L"%zu*{", spaceInBytes / 16));
|
||||||
_api.ReturnResponse(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -1633,8 +1629,7 @@ void AdaptDispatch::_MacroChecksumReport(const VTParameter id) const
|
|||||||
{
|
{
|
||||||
const auto requestId = id.value_or(0);
|
const auto requestId = id.value_or(0);
|
||||||
const auto checksum = _macroBuffer ? _macroBuffer->CalculateChecksum() : 0;
|
const auto checksum = _macroBuffer ? _macroBuffer->CalculateChecksum() : 0;
|
||||||
const auto response = wil::str_printf<std::wstring>(L"\033P%d!~%04X\033\\", requestId, checksum);
|
_ReturnDcsResponse(wil::str_printf<std::wstring>(L"%d!~%04X", requestId, checksum));
|
||||||
_api.ReturnResponse(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -1732,7 +1727,7 @@ void AdaptDispatch::RequestDisplayedExtent()
|
|||||||
const auto height = page.Viewport().height();
|
const auto height = page.Viewport().height();
|
||||||
const auto left = page.XPanOffset() + 1;
|
const auto left = page.XPanOffset() + 1;
|
||||||
const auto top = page.YPanOffset() + 1;
|
const auto top = page.YPanOffset() + 1;
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033[{};{};{};{};{}\"w"), height, width, left, top, page.Number()));
|
_ReturnCsiResponse(fmt::format(FMT_COMPILE(L"{};{};{};{};{}\"w"), height, width, left, top, page.Number()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -2068,7 +2063,7 @@ void AdaptDispatch::RequestMode(const DispatchTypes::ModeParams param)
|
|||||||
prefix = L"?";
|
prefix = L"?";
|
||||||
}
|
}
|
||||||
|
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\x1b[{}{};{}$y"), prefix, mode, state));
|
_ReturnCsiResponse(fmt::format(FMT_COMPILE(L"{}{};{}$y"), prefix, mode, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
// - DECKPAM, DECKPNM - Sets the keypad input mode to either Application mode or Numeric mode (true, false respectively)
|
// - DECKPAM, DECKPNM - Sets the keypad input mode to either Application mode or Numeric mode (true, false respectively)
|
||||||
@ -2785,22 +2780,15 @@ void AdaptDispatch::_InitTabStopsForWidth(const VTInt width)
|
|||||||
// - codingSystem - The coding system that will be selected.
|
// - codingSystem - The coding system that will be selected.
|
||||||
void AdaptDispatch::DesignateCodingSystem(const VTID codingSystem)
|
void AdaptDispatch::DesignateCodingSystem(const VTID codingSystem)
|
||||||
{
|
{
|
||||||
// If we haven't previously saved the initial code page, do so now.
|
|
||||||
// This will be used to restore the code page in response to a reset.
|
|
||||||
if (!_initialCodePage.has_value())
|
|
||||||
{
|
|
||||||
_initialCodePage = _api.GetConsoleOutputCP();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (codingSystem)
|
switch (codingSystem)
|
||||||
{
|
{
|
||||||
case DispatchTypes::CodingSystem::ISO2022:
|
case DispatchTypes::CodingSystem::ISO2022:
|
||||||
_api.SetConsoleOutputCP(28591);
|
_api.SetCodePage(28591);
|
||||||
AcceptC1Controls(true);
|
AcceptC1Controls(true);
|
||||||
_termOutput.EnableGrTranslation(true);
|
_termOutput.EnableGrTranslation(true);
|
||||||
break;
|
break;
|
||||||
case DispatchTypes::CodingSystem::UTF8:
|
case DispatchTypes::CodingSystem::UTF8:
|
||||||
_api.SetConsoleOutputCP(CP_UTF8);
|
_api.SetCodePage(CP_UTF8);
|
||||||
AcceptC1Controls(false);
|
AcceptC1Controls(false);
|
||||||
_termOutput.EnableGrTranslation(false);
|
_termOutput.EnableGrTranslation(false);
|
||||||
break;
|
break;
|
||||||
@ -2871,6 +2859,24 @@ void AdaptDispatch::AcceptC1Controls(const bool enabled)
|
|||||||
_api.GetStateMachine().SetParserMode(StateMachine::Mode::AcceptC1, enabled);
|
_api.GetStateMachine().SetParserMode(StateMachine::Mode::AcceptC1, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Routine Description:
|
||||||
|
// S8C1T/S7C1T - Enable or disable the sending of C1 controls in key sequences
|
||||||
|
// and query responses. When this is enabled, C1 controls are sent as a single
|
||||||
|
// codepoint. When disabled, they're sent as a two character escape sequence.
|
||||||
|
//Arguments:
|
||||||
|
// - enabled - true to send C1 controls, false to send escape sequences.
|
||||||
|
void AdaptDispatch::SendC1Controls(const bool enabled)
|
||||||
|
{
|
||||||
|
// If this is an attempt to enable C1 controls, the input code page must be
|
||||||
|
// one of the DOCS choices (UTF-8 or ISO-8859-1), otherwise there's a risk
|
||||||
|
// that those controls won't have a valid encoding.
|
||||||
|
const auto codepage = _api.GetInputCodePage();
|
||||||
|
if (enabled == false || codepage == CP_UTF8 || codepage == 28591)
|
||||||
|
{
|
||||||
|
_terminalInput.SetInputMode(TerminalInput::Mode::SendC1, enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Routine Description:
|
//Routine Description:
|
||||||
// ACS - Announces the ANSI conformance level for subsequent data exchange.
|
// ACS - Announces the ANSI conformance level for subsequent data exchange.
|
||||||
// This requires certain character sets to be mapped into the terminal's
|
// This requires certain character sets to be mapped into the terminal's
|
||||||
@ -3003,13 +3009,11 @@ void AdaptDispatch::HardReset()
|
|||||||
|
|
||||||
// Completely reset the TerminalOutput state.
|
// Completely reset the TerminalOutput state.
|
||||||
_termOutput = {};
|
_termOutput = {};
|
||||||
if (_initialCodePage.has_value())
|
// Reset the code page to the default value.
|
||||||
{
|
_api.ResetCodePage();
|
||||||
// Restore initial code page if previously changed by a DOCS sequence.
|
// Disable parsing and sending of C1 control codes.
|
||||||
_api.SetConsoleOutputCP(_initialCodePage.value());
|
|
||||||
}
|
|
||||||
// Disable parsing of C1 control codes.
|
|
||||||
AcceptC1Controls(false);
|
AcceptC1Controls(false);
|
||||||
|
SendC1Controls(false);
|
||||||
|
|
||||||
// Sets the SGR state to normal - this must be done before EraseInDisplay
|
// Sets the SGR state to normal - this must be done before EraseInDisplay
|
||||||
// to ensure that it clears with the default background color.
|
// to ensure that it clears with the default background color.
|
||||||
@ -3276,7 +3280,7 @@ void AdaptDispatch::RequestColorTableEntry(const size_t tableIndex)
|
|||||||
{
|
{
|
||||||
const til::color c{ color };
|
const til::color c{ color };
|
||||||
// Scale values up to match xterm's 16-bit color report format.
|
// Scale values up to match xterm's 16-bit color report format.
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033]4;{};rgb:{:04x}/{:04x}/{:04x}\033\\"), tableIndex, c.r * 0x0101, c.g * 0x0101, c.b * 0x0101));
|
_ReturnOscResponse(fmt::format(FMT_COMPILE(L"4;{};rgb:{:04x}/{:04x}/{:04x}"), tableIndex, c.r * 0x0101, c.g * 0x0101, c.b * 0x0101));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3321,7 +3325,7 @@ void AdaptDispatch::RequestXtermColorResource(const size_t resource)
|
|||||||
{
|
{
|
||||||
const til::color c{ color };
|
const til::color c{ color };
|
||||||
// Scale values up to match xterm's 16-bit color report format.
|
// Scale values up to match xterm's 16-bit color report format.
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033]{};rgb:{:04x}/{:04x}/{:04x}\033\\"), resource, c.r * 0x0101, c.g * 0x0101, c.b * 0x0101));
|
_ReturnOscResponse(fmt::format(FMT_COMPILE(L"{};rgb:{:04x}/{:04x}/{:04x}"), resource, c.r * 0x0101, c.g * 0x0101, c.b * 0x0101));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3377,7 +3381,7 @@ void AdaptDispatch::WindowManipulation(const DispatchTypes::WindowManipulationTy
|
|||||||
|
|
||||||
const auto reportSize = [&](const auto size) {
|
const auto reportSize = [&](const auto size) {
|
||||||
const auto reportType = function - 10;
|
const auto reportType = function - 10;
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033[{};{};{}t"), reportType, size.height, size.width));
|
_ReturnCsiResponse(fmt::format(FMT_COMPILE(L"{};{};{}t"), reportType, size.height, size.width));
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (function)
|
switch (function)
|
||||||
@ -3844,7 +3848,7 @@ void AdaptDispatch::RequestUserPreferenceCharset()
|
|||||||
{
|
{
|
||||||
const auto size = _termOutput.GetUserPreferenceCharsetSize();
|
const auto size = _termOutput.GetUserPreferenceCharsetSize();
|
||||||
const auto id = _termOutput.GetUserPreferenceCharsetId();
|
const auto id = _termOutput.GetUserPreferenceCharsetId();
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033P{}!u{}\033\\"), (size == 96 ? 1 : 0), id));
|
_ReturnDcsResponse(fmt::format(FMT_COMPILE(L"{}!u{}"), (size == 96 ? 1 : 0), id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -3976,9 +3980,9 @@ void AdaptDispatch::_ReportColorTable(const DispatchTypes::ColorModel colorModel
|
|||||||
{
|
{
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
// A valid response always starts with DCS 2 $ s.
|
// A valid response always starts with 2 $ s.
|
||||||
fmt::basic_memory_buffer<wchar_t, TextColor::TABLE_SIZE * 18> response;
|
fmt::basic_memory_buffer<wchar_t, TextColor::TABLE_SIZE * 18> response;
|
||||||
response.append(L"\033P2$s"sv);
|
response.append(L"2$s"sv);
|
||||||
|
|
||||||
const auto modelNumber = static_cast<int>(colorModel);
|
const auto modelNumber = static_cast<int>(colorModel);
|
||||||
for (size_t colorNumber = 0; colorNumber < TextColor::TABLE_SIZE; colorNumber++)
|
for (size_t colorNumber = 0; colorNumber < TextColor::TABLE_SIZE; colorNumber++)
|
||||||
@ -4003,9 +4007,7 @@ void AdaptDispatch::_ReportColorTable(const DispatchTypes::ColorModel colorModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An ST ends the sequence.
|
_ReturnDcsResponse({ response.data(), response.size() });
|
||||||
response.append(L"\033\\"sv);
|
|
||||||
_api.ReturnResponse({ response.data(), response.size() });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4108,7 +4110,7 @@ ITermDispatch::StringHandler AdaptDispatch::RequestSetting()
|
|||||||
_ReportDECACSetting(VTParameter{ parameter });
|
_ReportDECACSetting(VTParameter{ parameter });
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_api.ReturnResponse(L"\033P0$r\033\\");
|
_ReturnDcsResponse(L"0$r");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -4147,10 +4149,10 @@ void AdaptDispatch::_ReportSGRSetting() const
|
|||||||
{
|
{
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
// A valid response always starts with DCS 1 $ r.
|
// A valid response always starts with 1 $ r.
|
||||||
// Then the '0' parameter is to reset the SGR attributes to the defaults.
|
// Then the '0' parameter is to reset the SGR attributes to the defaults.
|
||||||
fmt::basic_memory_buffer<wchar_t, 64> response;
|
fmt::basic_memory_buffer<wchar_t, 64> response;
|
||||||
response.append(L"\033P1$r0"sv);
|
response.append(L"1$r0"sv);
|
||||||
|
|
||||||
const auto& attr = _pages.ActivePage().Attributes();
|
const auto& attr = _pages.ActivePage().Attributes();
|
||||||
const auto ulStyle = attr.GetUnderlineStyle();
|
const auto ulStyle = attr.GetUnderlineStyle();
|
||||||
@ -4202,9 +4204,9 @@ void AdaptDispatch::_ReportSGRSetting() const
|
|||||||
addColor(40, attr.GetBackground());
|
addColor(40, attr.GetBackground());
|
||||||
addColor(50, attr.GetUnderlineColor());
|
addColor(50, attr.GetUnderlineColor());
|
||||||
|
|
||||||
// The 'm' indicates this is an SGR response, and ST ends the sequence.
|
// The 'm' indicates this is an SGR response.
|
||||||
response.append(L"m\033\\"sv);
|
response.append(L"m"sv);
|
||||||
_api.ReturnResponse({ response.data(), response.size() });
|
_ReturnDcsResponse({ response.data(), response.size() });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4217,10 +4219,9 @@ void AdaptDispatch::_ReportDECSTBMSetting()
|
|||||||
{
|
{
|
||||||
const auto page = _pages.ActivePage();
|
const auto page = _pages.ActivePage();
|
||||||
const auto [marginTop, marginBottom] = _GetVerticalMargins(page, false);
|
const auto [marginTop, marginBottom] = _GetVerticalMargins(page, false);
|
||||||
// A valid response always starts with DCS 1 $ r, the 'r' indicates this
|
// A valid response always starts with 1 $ r and the final 'r' indicates this is a DECSTBM response.
|
||||||
// is a DECSTBM response, and ST ends the sequence.
|
|
||||||
// VT origin is at 1,1 so we need to add 1 to these margins.
|
// VT origin is at 1,1 so we need to add 1 to these margins.
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033P1$r{};{}r\033\\"), marginTop + 1, marginBottom + 1));
|
_ReturnDcsResponse(fmt::format(FMT_COMPILE(L"1$r{};{}r"), marginTop + 1, marginBottom + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4233,10 +4234,9 @@ void AdaptDispatch::_ReportDECSLRMSetting()
|
|||||||
{
|
{
|
||||||
const auto pageWidth = _pages.ActivePage().Width();
|
const auto pageWidth = _pages.ActivePage().Width();
|
||||||
const auto [marginLeft, marginRight] = _GetHorizontalMargins(pageWidth);
|
const auto [marginLeft, marginRight] = _GetHorizontalMargins(pageWidth);
|
||||||
// A valid response always starts with DCS 1 $ r, the 's' indicates this
|
// A valid response always starts with 1 $ r and the 's' indicates this is a DECSLRM response.
|
||||||
// is a DECSLRM response, and ST ends the sequence.
|
|
||||||
// VT origin is at 1,1 so we need to add 1 to these margins.
|
// VT origin is at 1,1 so we need to add 1 to these margins.
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033P1$r{};{}s\033\\"), marginLeft + 1, marginRight + 1));
|
_ReturnDcsResponse(fmt::format(FMT_COMPILE(L"1$r{};{}s"), marginLeft + 1, marginRight + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4249,26 +4249,26 @@ void AdaptDispatch::_ReportDECSCUSRSetting() const
|
|||||||
{
|
{
|
||||||
const auto& cursor = _pages.ActivePage().Cursor();
|
const auto& cursor = _pages.ActivePage().Cursor();
|
||||||
const auto blinking = cursor.IsBlinkingAllowed();
|
const auto blinking = cursor.IsBlinkingAllowed();
|
||||||
// A valid response always starts with DCS 1 $ r. This is followed by a
|
// A valid response always starts with 1 $ r. This is followed by a
|
||||||
// number from 1 to 6 representing the cursor style. The ' q' indicates
|
// number from 1 to 6 representing the cursor style. The ' q' indicates
|
||||||
// this is a DECSCUSR response, and ST ends the sequence.
|
// this is a DECSCUSR response.
|
||||||
switch (cursor.GetType())
|
switch (cursor.GetType())
|
||||||
{
|
{
|
||||||
case CursorType::FullBox:
|
case CursorType::FullBox:
|
||||||
_api.ReturnResponse(blinking ? L"\033P1$r1 q\033\\" : L"\033P1$r2 q\033\\");
|
_ReturnDcsResponse(blinking ? L"1$r1 q" : L"1$r2 q");
|
||||||
break;
|
break;
|
||||||
case CursorType::Underscore:
|
case CursorType::Underscore:
|
||||||
_api.ReturnResponse(blinking ? L"\033P1$r3 q\033\\" : L"\033P1$r4 q\033\\");
|
_ReturnDcsResponse(blinking ? L"1$r3 q" : L"1$r4 q");
|
||||||
break;
|
break;
|
||||||
case CursorType::VerticalBar:
|
case CursorType::VerticalBar:
|
||||||
_api.ReturnResponse(blinking ? L"\033P1$r5 q\033\\" : L"\033P1$r6 q\033\\");
|
_ReturnDcsResponse(blinking ? L"1$r5 q" : L"1$r6 q");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// If we have a non-standard style, this is likely because it's the
|
// If we have a non-standard style, this is likely because it's the
|
||||||
// user's chosen default style, so we report a default value of 0.
|
// user's chosen default style, so we report a default value of 0.
|
||||||
// That way, if an application later tries to restore the cursor with
|
// That way, if an application later tries to restore the cursor with
|
||||||
// the returned value, it should be reset to its original state.
|
// the returned value, it should be reset to its original state.
|
||||||
_api.ReturnResponse(L"\033P1$r0 q\033\\");
|
_ReturnDcsResponse(L"1$r0 q");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4282,10 +4282,10 @@ void AdaptDispatch::_ReportDECSCUSRSetting() const
|
|||||||
void AdaptDispatch::_ReportDECSCASetting() const
|
void AdaptDispatch::_ReportDECSCASetting() const
|
||||||
{
|
{
|
||||||
const auto isProtected = _pages.ActivePage().Attributes().IsProtected();
|
const auto isProtected = _pages.ActivePage().Attributes().IsProtected();
|
||||||
// A valid response always starts with DCS 1 $ r. This is followed by '1' if
|
// A valid response always starts with 1 $ r. This is followed by '1' if the
|
||||||
// the protected attribute is set, or '0' if not. The '"q' indicates this is
|
// protected attribute is set, or '0' if not. The '"q' indicates this is a
|
||||||
// a DECSCA response, and ST ends the sequence.
|
// DECSCA response.
|
||||||
_api.ReturnResponse(isProtected ? L"\033P1$r1\"q\033\\" : L"\033P1$r0\"q\033\\");
|
_ReturnDcsResponse(isProtected ? L"1$r1\"q" : L"1$r0\"q");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4297,10 +4297,10 @@ void AdaptDispatch::_ReportDECSCASetting() const
|
|||||||
void AdaptDispatch::_ReportDECSACESetting() const
|
void AdaptDispatch::_ReportDECSACESetting() const
|
||||||
{
|
{
|
||||||
const auto rectangularExtent = _modes.test(Mode::RectangularChangeExtent);
|
const auto rectangularExtent = _modes.test(Mode::RectangularChangeExtent);
|
||||||
// A valid response always starts with DCS 1 $ r. This is followed by '2' if
|
// A valid response always starts with 1 $ r. This is followed by '2' if
|
||||||
// the extent is rectangular, or '1' if it's a stream. The '*x' indicates
|
// the extent is rectangular, or '1' if it's a stream. The '*x' indicates
|
||||||
// this is a DECSACE response, and ST ends the sequence.
|
// this is a DECSACE response.
|
||||||
_api.ReturnResponse(rectangularExtent ? L"\033P1$r2*x\033\\" : L"\033P1$r1*x\033\\");
|
_ReturnDcsResponse(rectangularExtent ? L"1$r2*x" : L"1$r1*x");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4324,12 +4324,11 @@ void AdaptDispatch::_ReportDECACSetting(const VTInt itemNumber) const
|
|||||||
bgIndex = _renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground);
|
bgIndex = _renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_api.ReturnResponse(L"\033P0$r\033\\");
|
_ReturnDcsResponse(L"0$r");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// A valid response always starts with DCS 1 $ r, the ',|' indicates this
|
// A valid response always starts with 1 $ r and the ',|' indicates this is a DECAC response.
|
||||||
// is a DECAC response, and ST ends the sequence.
|
_ReturnDcsResponse(fmt::format(FMT_COMPILE(L"1$r{};{};{},|"), itemNumber, fgIndex, bgIndex));
|
||||||
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033P1$r{};{};{},|\033\\"), itemNumber, fgIndex, bgIndex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
@ -4442,9 +4441,9 @@ void AdaptDispatch::_ReportCursorInformation()
|
|||||||
const auto charset2 = _termOutput.GetCharsetId(2);
|
const auto charset2 = _termOutput.GetCharsetId(2);
|
||||||
const auto charset3 = _termOutput.GetCharsetId(3);
|
const auto charset3 = _termOutput.GetCharsetId(3);
|
||||||
|
|
||||||
// A valid response always starts with DCS 1 $ u and ends with ST.
|
// A valid response always starts with 1 $ u.
|
||||||
const auto response = fmt::format(
|
const auto response = fmt::format(
|
||||||
FMT_COMPILE(L"\033P1$u{};{};{};{};{};{};{};{};{};{}{}{}{}\033\\"),
|
FMT_COMPILE(L"1$u{};{};{};{};{};{};{};{};{};{}{}{}{}"),
|
||||||
cursorPosition.y,
|
cursorPosition.y,
|
||||||
cursorPosition.x,
|
cursorPosition.x,
|
||||||
page.Number(),
|
page.Number(),
|
||||||
@ -4458,7 +4457,7 @@ void AdaptDispatch::_ReportCursorInformation()
|
|||||||
charset1,
|
charset1,
|
||||||
charset2,
|
charset2,
|
||||||
charset3);
|
charset3);
|
||||||
_api.ReturnResponse({ response.data(), response.size() });
|
_ReturnDcsResponse({ response.data(), response.size() });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4623,9 +4622,9 @@ void AdaptDispatch::_ReportTabStops()
|
|||||||
|
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
// A valid response always starts with DCS 2 $ u.
|
// A valid response always starts with 2 $ u.
|
||||||
fmt::basic_memory_buffer<wchar_t, 64> response;
|
fmt::basic_memory_buffer<wchar_t, 64> response;
|
||||||
response.append(L"\033P2$u"sv);
|
response.append(L"2$u"sv);
|
||||||
|
|
||||||
auto need_separator = false;
|
auto need_separator = false;
|
||||||
for (auto column = 0; column < width; column++)
|
for (auto column = 0; column < width; column++)
|
||||||
@ -4638,9 +4637,7 @@ void AdaptDispatch::_ReportTabStops()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An ST ends the sequence.
|
_ReturnDcsResponse({ response.data(), response.size() });
|
||||||
response.append(L"\033\\"sv);
|
|
||||||
_api.ReturnResponse({ response.data(), response.size() });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method Description:
|
// Method Description:
|
||||||
@ -4685,6 +4682,26 @@ ITermDispatch::StringHandler AdaptDispatch::_RestoreTabStops()
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdaptDispatch::_ReturnCsiResponse(const std::wstring_view response) const
|
||||||
|
{
|
||||||
|
const auto csi = _terminalInput.GetInputMode(TerminalInput::Mode::SendC1) ? L"\x9B" : L"\x1B[";
|
||||||
|
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"{}{}"), csi, response));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdaptDispatch::_ReturnDcsResponse(const std::wstring_view response) const
|
||||||
|
{
|
||||||
|
const auto dcs = _terminalInput.GetInputMode(TerminalInput::Mode::SendC1) ? L"\x90" : L"\x1BP";
|
||||||
|
const auto st = _terminalInput.GetInputMode(TerminalInput::Mode::SendC1) ? L"\x9C" : L"\x1B\\";
|
||||||
|
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"{}{}{}"), dcs, response, st));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdaptDispatch::_ReturnOscResponse(const std::wstring_view response) const
|
||||||
|
{
|
||||||
|
const auto osc = _terminalInput.GetInputMode(TerminalInput::Mode::SendC1) ? L"\x9D" : L"\x1B]";
|
||||||
|
const auto st = _terminalInput.GetInputMode(TerminalInput::Mode::SendC1) ? L"\x9C" : L"\x1B\\";
|
||||||
|
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"{}{}{}"), osc, response, st));
|
||||||
|
}
|
||||||
|
|
||||||
// Routine Description:
|
// Routine Description:
|
||||||
// - DECPS - Plays a sequence of musical notes.
|
// - DECPS - Plays a sequence of musical notes.
|
||||||
// Arguments:
|
// Arguments:
|
||||||
|
|||||||
@ -121,6 +121,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
void LockingShiftRight(const VTInt gsetNumber) override; // LS1R, LS2R, LS3R
|
void LockingShiftRight(const VTInt gsetNumber) override; // LS1R, LS2R, LS3R
|
||||||
void SingleShift(const VTInt gsetNumber) noexcept override; // SS2, SS3
|
void SingleShift(const VTInt gsetNumber) noexcept override; // SS2, SS3
|
||||||
void AcceptC1Controls(const bool enabled) override; // DECAC1
|
void AcceptC1Controls(const bool enabled) override; // DECAC1
|
||||||
|
void SendC1Controls(const bool enabled) override; // S8C1T, S7C1T
|
||||||
void AnnounceCodeStructure(const VTInt ansiLevel) override; // ACS
|
void AnnounceCodeStructure(const VTInt ansiLevel) override; // ACS
|
||||||
void SoftReset() override; // DECSTR
|
void SoftReset() override; // DECSTR
|
||||||
void HardReset() override; // RIS
|
void HardReset() override; // RIS
|
||||||
@ -289,6 +290,10 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
void _ReportTabStops();
|
void _ReportTabStops();
|
||||||
StringHandler _RestoreTabStops();
|
StringHandler _RestoreTabStops();
|
||||||
|
|
||||||
|
void _ReturnCsiResponse(const std::wstring_view response) const;
|
||||||
|
void _ReturnDcsResponse(const std::wstring_view response) const;
|
||||||
|
void _ReturnOscResponse(const std::wstring_view response) const;
|
||||||
|
|
||||||
std::vector<uint8_t> _tabStopColumns;
|
std::vector<uint8_t> _tabStopColumns;
|
||||||
bool _initDefaultTabStops = true;
|
bool _initDefaultTabStops = true;
|
||||||
|
|
||||||
@ -302,7 +307,6 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
std::shared_ptr<SixelParser> _sixelParser;
|
std::shared_ptr<SixelParser> _sixelParser;
|
||||||
std::unique_ptr<FontBuffer> _fontBuffer;
|
std::unique_ptr<FontBuffer> _fontBuffer;
|
||||||
std::shared_ptr<MacroBuffer> _macroBuffer;
|
std::shared_ptr<MacroBuffer> _macroBuffer;
|
||||||
std::optional<unsigned int> _initialCodePage;
|
|
||||||
|
|
||||||
// We have two instances of the saved cursor state, because we need
|
// We have two instances of the saved cursor state, because we need
|
||||||
// one for the main buffer (at index 0), and another for the alt buffer
|
// one for the main buffer (at index 0), and another for the alt buffer
|
||||||
|
|||||||
@ -115,6 +115,7 @@ public:
|
|||||||
void LockingShiftRight(const VTInt /*gsetNumber*/) override {} // LS1R, LS2R, LS3R
|
void LockingShiftRight(const VTInt /*gsetNumber*/) override {} // LS1R, LS2R, LS3R
|
||||||
void SingleShift(const VTInt /*gsetNumber*/) override {} // SS2, SS3
|
void SingleShift(const VTInt /*gsetNumber*/) override {} // SS2, SS3
|
||||||
void AcceptC1Controls(const bool /*enabled*/) override {} // DECAC1
|
void AcceptC1Controls(const bool /*enabled*/) override {} // DECAC1
|
||||||
|
void SendC1Controls(const bool /*enabled*/) override {} // S8C1T, S7C1T
|
||||||
void AnnounceCodeStructure(const VTInt /*ansiLevel*/) override {} // ACS
|
void AnnounceCodeStructure(const VTInt /*ansiLevel*/) override {} // ACS
|
||||||
|
|
||||||
void SoftReset() override {} // DECSTR
|
void SoftReset() override {} // DECSTR
|
||||||
|
|||||||
@ -158,17 +158,28 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetConsoleOutputCP(const unsigned int codepage) override
|
void SetCodePage(const unsigned int codepage) override
|
||||||
{
|
{
|
||||||
Log::Comment(L"SetConsoleOutputCP MOCK called...");
|
Log::Comment(L"SetCodePage MOCK called...");
|
||||||
THROW_HR_IF(E_FAIL, !_setConsoleOutputCPResult);
|
THROW_HR_IF(E_FAIL, !_setCodePageResult);
|
||||||
VERIFY_ARE_EQUAL(_expectedOutputCP, codepage);
|
VERIFY_ARE_EQUAL(_expectedCodePage, codepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int GetConsoleOutputCP() const override
|
void ResetCodePage() override
|
||||||
{
|
{
|
||||||
Log::Comment(L"GetConsoleOutputCP MOCK called...");
|
Log::Comment(L"ResetCodePage MOCK called...");
|
||||||
return _expectedOutputCP;
|
}
|
||||||
|
|
||||||
|
unsigned int GetOutputCodePage() const override
|
||||||
|
{
|
||||||
|
Log::Comment(L"GetOutputCodePage MOCK called...");
|
||||||
|
return _expectedCodePage;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetInputCodePage() const override
|
||||||
|
{
|
||||||
|
Log::Comment(L"GetInputCodePage MOCK called...");
|
||||||
|
return _expectedCodePage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyToClipboard(const wil::zwstring_view /*content*/)
|
void CopyToClipboard(const wil::zwstring_view /*content*/)
|
||||||
@ -367,7 +378,7 @@ public:
|
|||||||
til::point _expectedCursorPos;
|
til::point _expectedCursorPos;
|
||||||
|
|
||||||
TextAttribute _expectedAttribute = {};
|
TextAttribute _expectedAttribute = {};
|
||||||
unsigned int _expectedOutputCP = 0;
|
unsigned int _expectedCodePage = 0;
|
||||||
bool _isPty = false;
|
bool _isPty = false;
|
||||||
|
|
||||||
bool _returnResponseResult = false;
|
bool _returnResponseResult = false;
|
||||||
@ -376,8 +387,7 @@ public:
|
|||||||
|
|
||||||
bool _setWindowTitleResult = false;
|
bool _setWindowTitleResult = false;
|
||||||
std::wstring_view _expectedWindowTitle{};
|
std::wstring_view _expectedWindowTitle{};
|
||||||
bool _setConsoleOutputCPResult = false;
|
bool _setCodePageResult = false;
|
||||||
bool _getConsoleOutputCPResult = false;
|
|
||||||
bool _expectedShowWindow = false;
|
bool _expectedShowWindow = false;
|
||||||
|
|
||||||
std::wstring _expectedMenuJson{};
|
std::wstring _expectedMenuJson{};
|
||||||
@ -3529,15 +3539,15 @@ public:
|
|||||||
|
|
||||||
Log::Comment(L"3. Designate ISO-2022 coding system");
|
Log::Comment(L"3. Designate ISO-2022 coding system");
|
||||||
// Code page should be set to ISO-8859-1 and C1 parsing enabled
|
// Code page should be set to ISO-8859-1 and C1 parsing enabled
|
||||||
_testGetSet->_setConsoleOutputCPResult = true;
|
_testGetSet->_setCodePageResult = true;
|
||||||
_testGetSet->_expectedOutputCP = 28591;
|
_testGetSet->_expectedCodePage = 28591;
|
||||||
_pDispatch->DesignateCodingSystem(DispatchTypes::CodingSystem::ISO2022);
|
_pDispatch->DesignateCodingSystem(DispatchTypes::CodingSystem::ISO2022);
|
||||||
VERIFY_IS_TRUE(_stateMachine->GetParserMode(StateMachine::Mode::AcceptC1));
|
VERIFY_IS_TRUE(_stateMachine->GetParserMode(StateMachine::Mode::AcceptC1));
|
||||||
|
|
||||||
Log::Comment(L"4. Designate UTF-8 coding system");
|
Log::Comment(L"4. Designate UTF-8 coding system");
|
||||||
// Code page should be set to UTF-8 and C1 parsing disabled
|
// Code page should be set to UTF-8 and C1 parsing disabled
|
||||||
_testGetSet->_setConsoleOutputCPResult = true;
|
_testGetSet->_setCodePageResult = true;
|
||||||
_testGetSet->_expectedOutputCP = CP_UTF8;
|
_testGetSet->_expectedCodePage = CP_UTF8;
|
||||||
_pDispatch->DesignateCodingSystem(DispatchTypes::CodingSystem::UTF8);
|
_pDispatch->DesignateCodingSystem(DispatchTypes::CodingSystem::UTF8);
|
||||||
VERIFY_IS_FALSE(_stateMachine->GetParserMode(StateMachine::Mode::AcceptC1));
|
VERIFY_IS_FALSE(_stateMachine->GetParserMode(StateMachine::Mode::AcceptC1));
|
||||||
}
|
}
|
||||||
@ -3962,6 +3972,39 @@ public:
|
|||||||
_pDispatch->PagePositionAbsolute(1);
|
_pDispatch->PagePositionAbsolute(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(SendC1ControlTest)
|
||||||
|
{
|
||||||
|
const auto S7C1T = L"\033 F";
|
||||||
|
const auto S8C1T = L"\033 G";
|
||||||
|
|
||||||
|
_testGetSet->PrepData();
|
||||||
|
_testGetSet->_expectedCodePage = CP_UTF8;
|
||||||
|
|
||||||
|
Log::Comment(L"Generating reports with C1 control sequences");
|
||||||
|
_stateMachine->ProcessString(S8C1T);
|
||||||
|
|
||||||
|
_pDispatch->SecondaryDeviceAttributes();
|
||||||
|
_testGetSet->ValidateInputEvent(L"\x9b>0;10;1c");
|
||||||
|
|
||||||
|
_pDispatch->TertiaryDeviceAttributes();
|
||||||
|
_testGetSet->ValidateInputEvent(L"\x90!|00000000\x9c");
|
||||||
|
|
||||||
|
_pDispatch->RequestColorTableEntry(0);
|
||||||
|
_testGetSet->ValidateInputEvent(L"\x9d\x34;0;rgb:0c0c/0c0c/0c0c\x9c");
|
||||||
|
|
||||||
|
Log::Comment(L"Generating reports with 7-bit escape sequence");
|
||||||
|
_stateMachine->ProcessString(S7C1T);
|
||||||
|
|
||||||
|
_pDispatch->SecondaryDeviceAttributes();
|
||||||
|
_testGetSet->ValidateInputEvent(L"\x1b[>0;10;1c");
|
||||||
|
|
||||||
|
_pDispatch->TertiaryDeviceAttributes();
|
||||||
|
_testGetSet->ValidateInputEvent(L"\x1bP!|00000000\x1b\\");
|
||||||
|
|
||||||
|
_pDispatch->RequestColorTableEntry(0);
|
||||||
|
_testGetSet->ValidateInputEvent(L"\x1b]4;0;rgb:0c0c/0c0c/0c0c\x1b\\");
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TerminalInput _terminalInput;
|
TerminalInput _terminalInput;
|
||||||
std::unique_ptr<TestGetSet> _testGetSet;
|
std::unique_ptr<TestGetSet> _testGetSet;
|
||||||
|
|||||||
@ -36,6 +36,7 @@ public:
|
|||||||
TEST_METHOD(CtrlNumTest);
|
TEST_METHOD(CtrlNumTest);
|
||||||
TEST_METHOD(BackarrowKeyModeTest);
|
TEST_METHOD(BackarrowKeyModeTest);
|
||||||
TEST_METHOD(AutoRepeatModeTest);
|
TEST_METHOD(AutoRepeatModeTest);
|
||||||
|
TEST_METHOD(SendC1ControlTest);
|
||||||
|
|
||||||
wchar_t GetModifierChar(const bool fShift, const bool fAlt, const bool fCtrl)
|
wchar_t GetModifierChar(const bool fShift, const bool fAlt, const bool fCtrl)
|
||||||
{
|
{
|
||||||
@ -790,3 +791,20 @@ void InputTest::AutoRepeatModeTest()
|
|||||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"A"), input.HandleKey(down));
|
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput(L"A"), input.HandleKey(down));
|
||||||
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput({}), input.HandleKey(up));
|
VERIFY_ARE_EQUAL(TerminalInput::MakeOutput({}), input.HandleKey(up));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputTest::SendC1ControlTest()
|
||||||
|
{
|
||||||
|
TerminalInput input;
|
||||||
|
|
||||||
|
Log::Comment(L"Sending keys with C1 control sequences");
|
||||||
|
input.SetInputMode(TerminalInput::Mode::SendC1, true);
|
||||||
|
|
||||||
|
TestKey(TerminalInput::MakeOutput(L"\x9bH"), input, 0, VK_HOME);
|
||||||
|
TestKey(TerminalInput::MakeOutput(L"\x8fP"), input, 0, VK_F1);
|
||||||
|
|
||||||
|
Log::Comment(L"Sending keys with 7-bit escape sequence");
|
||||||
|
input.SetInputMode(TerminalInput::Mode::SendC1, false);
|
||||||
|
|
||||||
|
TestKey(TerminalInput::MakeOutput(L"\x1b[H"), input, 0, VK_HOME);
|
||||||
|
TestKey(TerminalInput::MakeOutput(L"\x1bOP"), input, 0, VK_F1);
|
||||||
|
}
|
||||||
|
|||||||
@ -53,7 +53,7 @@ void TerminalInput::SetInputMode(const Mode mode, const bool enabled) noexcept
|
|||||||
|
|
||||||
// If we've changed one of the modes that alter the VT input sequences,
|
// If we've changed one of the modes that alter the VT input sequences,
|
||||||
// we'll need to regenerate our keyboard map.
|
// we'll need to regenerate our keyboard map.
|
||||||
static constexpr auto keyMapModes = til::enumset<Mode>{ Mode::LineFeed, Mode::Ansi, Mode::Keypad, Mode::CursorKey, Mode::BackarrowKey };
|
static constexpr auto keyMapModes = til::enumset<Mode>{ Mode::LineFeed, Mode::Ansi, Mode::Keypad, Mode::CursorKey, Mode::BackarrowKey, Mode::SendC1 };
|
||||||
if (keyMapModes.test(mode))
|
if (keyMapModes.test(mode))
|
||||||
{
|
{
|
||||||
_initKeyboardMap();
|
_initKeyboardMap();
|
||||||
@ -353,6 +353,19 @@ try
|
|||||||
|
|
||||||
_keyMap.clear();
|
_keyMap.clear();
|
||||||
|
|
||||||
|
// The CSI and SS3 introducers are C1 control codes, which can either be
|
||||||
|
// sent as a single codepoint, or as a two character escape sequence.
|
||||||
|
if (_inputMode.test(Mode::SendC1))
|
||||||
|
{
|
||||||
|
_csi = L"\x9B";
|
||||||
|
_ss3 = L"\x8F";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_csi = L"\x1B[";
|
||||||
|
_ss3 = L"\x1BO";
|
||||||
|
}
|
||||||
|
|
||||||
// PAUSE doesn't have a VT mapping, but traditionally we've mapped it to ^Z,
|
// PAUSE doesn't have a VT mapping, but traditionally we've mapped it to ^Z,
|
||||||
// regardless of modifiers.
|
// regardless of modifiers.
|
||||||
defineKeyWithUnusedModifiers(VK_PAUSE, L"\x1A"s);
|
defineKeyWithUnusedModifiers(VK_PAUSE, L"\x1A"s);
|
||||||
|
|||||||
@ -33,6 +33,7 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
CursorKey,
|
CursorKey,
|
||||||
BackarrowKey,
|
BackarrowKey,
|
||||||
Win32,
|
Win32,
|
||||||
|
SendC1,
|
||||||
|
|
||||||
Utf8MouseEncoding,
|
Utf8MouseEncoding,
|
||||||
SgrMouseEncoding,
|
SgrMouseEncoding,
|
||||||
@ -80,10 +81,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
til::enumset<Mode> _inputMode{ Mode::Ansi, Mode::AutoRepeat, Mode::AlternateScroll };
|
til::enumset<Mode> _inputMode{ Mode::Ansi, Mode::AutoRepeat, Mode::AlternateScroll };
|
||||||
bool _forceDisableWin32InputMode{ false };
|
bool _forceDisableWin32InputMode{ false };
|
||||||
|
|
||||||
// In the future, if we add support for "8-bit" input mode, these prefixes
|
const wchar_t* _csi = L"\x1B[";
|
||||||
// will sometimes be replaced with equivalent C1 control characters.
|
const wchar_t* _ss3 = L"\x1BO";
|
||||||
static constexpr auto _csi = L"\x1B[";
|
|
||||||
static constexpr auto _ss3 = L"\x1BO";
|
|
||||||
|
|
||||||
void _initKeyboardMap() noexcept;
|
void _initKeyboardMap() noexcept;
|
||||||
DWORD _trackControlKeyState(const KEY_EVENT_RECORD& key);
|
DWORD _trackControlKeyState(const KEY_EVENT_RECORD& key);
|
||||||
@ -108,9 +107,9 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region MouseInput
|
#pragma region MouseInput
|
||||||
[[nodiscard]] static OutputType _GenerateDefaultSequence(til::point position, unsigned int button, bool isHover, short modifierKeyState, short delta);
|
[[nodiscard]] OutputType _GenerateDefaultSequence(til::point position, unsigned int button, bool isHover, short modifierKeyState, short delta);
|
||||||
[[nodiscard]] static OutputType _GenerateUtf8Sequence(til::point position, unsigned int button, bool isHover, short modifierKeyState, short delta);
|
[[nodiscard]] OutputType _GenerateUtf8Sequence(til::point position, unsigned int button, bool isHover, short modifierKeyState, short delta);
|
||||||
[[nodiscard]] static OutputType _GenerateSGRSequence(til::point position, unsigned int button, bool isDown, bool isHover, short modifierKeyState, short delta);
|
[[nodiscard]] OutputType _GenerateSGRSequence(til::point position, unsigned int button, bool isDown, bool isHover, short modifierKeyState, short delta);
|
||||||
|
|
||||||
[[nodiscard]] OutputType _makeAlternateScrollOutput(short delta) const;
|
[[nodiscard]] OutputType _makeAlternateScrollOutput(short delta) const;
|
||||||
|
|
||||||
|
|||||||
@ -256,6 +256,12 @@ bool OutputStateMachineEngine::ActionEscDispatch(const VTID id)
|
|||||||
case EscActionCodes::DECAC1_AcceptC1Controls:
|
case EscActionCodes::DECAC1_AcceptC1Controls:
|
||||||
_dispatch->AcceptC1Controls(true);
|
_dispatch->AcceptC1Controls(true);
|
||||||
break;
|
break;
|
||||||
|
case EscActionCodes::S7C1T_Send7bitC1Controls:
|
||||||
|
_dispatch->SendC1Controls(false);
|
||||||
|
break;
|
||||||
|
case EscActionCodes::S8C1T_Send8bitC1Controls:
|
||||||
|
_dispatch->SendC1Controls(true);
|
||||||
|
break;
|
||||||
case EscActionCodes::ACS_AnsiLevel1:
|
case EscActionCodes::ACS_AnsiLevel1:
|
||||||
_dispatch->AnnounceCodeStructure(1);
|
_dispatch->AnnounceCodeStructure(1);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -77,6 +77,8 @@ namespace Microsoft::Console::VirtualTerminal
|
|||||||
LS2R_LockingShift = VTID("}"),
|
LS2R_LockingShift = VTID("}"),
|
||||||
LS3R_LockingShift = VTID("|"),
|
LS3R_LockingShift = VTID("|"),
|
||||||
DECAC1_AcceptC1Controls = VTID(" 7"),
|
DECAC1_AcceptC1Controls = VTID(" 7"),
|
||||||
|
S7C1T_Send7bitC1Controls = VTID(" F"),
|
||||||
|
S8C1T_Send8bitC1Controls = VTID(" G"),
|
||||||
ACS_AnsiLevel1 = VTID(" L"),
|
ACS_AnsiLevel1 = VTID(" L"),
|
||||||
ACS_AnsiLevel2 = VTID(" M"),
|
ACS_AnsiLevel2 = VTID(" M"),
|
||||||
ACS_AnsiLevel3 = VTID(" N"),
|
ACS_AnsiLevel3 = VTID(" N"),
|
||||||
|
|||||||
@ -25,6 +25,9 @@ StateMachine::StateMachine(std::unique_ptr<IStateMachineEngine> engine, const bo
|
|||||||
_oscString{},
|
_oscString{},
|
||||||
_cachedSequence{ std::nullopt }
|
_cachedSequence{ std::nullopt }
|
||||||
{
|
{
|
||||||
|
// The state machine must always accept C1 controls for the input engine,
|
||||||
|
// otherwise it won't work when the ConPTY terminal has S8C1T enabled.
|
||||||
|
_parserMode.set(Mode::AcceptC1, _isEngineForInput);
|
||||||
_ActionClear();
|
_ActionClear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user