Skip to content

Commit

Permalink
Fix conpty rendering of control characters in the buffer (#16825)
Browse files Browse the repository at this point in the history
When using the legacy console APIs, it's possible to write arbitrary
codepoints into the buffer. If any of those codepoints are in the C0 or
C1 range, and the buffer contents are forwarded over conpty, they can
end up mistakenly interpreted as controls by the connected terminal.

This PR fixes that issue by converting any C0 and C1 codepoints in the
buffer into printable glyphs before forwarding them over conpty. I've
used the C0 glyphs from the DOS 437 codepage and just a `?` for the C1
codepoints, since that's what you would typically have seen in the v1
console with a raster font.

Although this doesn't address the main problem in #16410, it should at
least fix the rendering issues they're seeing when running their app in
Windows Terminal.

I've confirmed that the test case in #4363 now looks the same in Windows
Terminal as it does in conhost, and I've tested the Windows version of
the terminal game [Gorched], and confirmed that it now works correctly
in Window Terminal.

[Gorched]: https://github.com/zladovan/gorched

Closes #4363
Closes #6265

(cherry picked from commit 563b731)
Service-Card-Id: 92001661
Service-Version: 1.19
  • Loading branch information
j4james authored and DHowett committed Mar 8, 2024
1 parent 9acb15b commit 35cda31
Showing 1 changed file with 18 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/renderer/vt/paint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,25 @@ using namespace Microsoft::Console::Types;
_bufferLine.append(cluster.GetText());
totalWidth += cluster.GetColumns();
}

// If any of the values in the buffer are C0 or C1 controls, we need to
// convert them to printable codepoints, otherwise they'll end up being
// evaluated as control characters by the receiving terminal. We use the
// DOS 437 code page for the C0 controls and DEL, and just a `?` for the
// C1 controls, since that's what you would most likely have seen in the
// legacy v1 console with raster fonts.
const auto cchLine = _bufferLine.size();
std::for_each_n(_bufferLine.begin(), cchLine, [](auto& ch) {
static constexpr std::wstring_view C0Glyphs = L" ☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼";
if (ch < C0Glyphs.size())
{
ch = til::at(C0Glyphs, ch);
}
else if (ch >= L'\u007F' && ch < L'\u00A0')
{
ch = (ch == L'\u007F' ? L'' : L'?');
}
});

const auto spaceIndex = _bufferLine.find_last_not_of(L' ');
const auto foundNonspace = spaceIndex != decltype(_bufferLine)::npos;
Expand Down

0 comments on commit 35cda31

Please sign in to comment.