Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the S8C1T/S7C1T escape sequences #17945

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/cascadia/TerminalCore/Terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,10 @@ class Microsoft::Terminal::Core::Terminal final :
void SetWindowTitle(const std::wstring_view title) override;
CursorType GetUserDefaultCursorStyle() const noexcept override;
bool ResizeWindow(const til::CoordType width, const til::CoordType height) override;
void SetConsoleOutputCP(const unsigned int codepage) noexcept override;
unsigned int GetConsoleOutputCP() const noexcept override;
void SetCodePage(const unsigned int codepage) 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 SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
void SetWorkingDirectory(std::wstring_view uri) override;
Expand Down
19 changes: 15 additions & 4 deletions src/cascadia/TerminalCore/TerminalApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,25 @@ bool Terminal::ResizeWindow(const til::CoordType width, const til::CoordType hei
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;
}

Expand Down
45 changes: 25 additions & 20 deletions src/host/getset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1128,23 +1128,16 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
CATCH_RETURN();
}

[[nodiscard]] HRESULT DoSrvSetConsoleOutputCodePage(const unsigned int codepage)
void DoSrvSetConsoleOutputCodePage(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.OutputCP != codepage)
{
// Set new code page
gci.OutputCP = codepage;

SetConsoleCPInfo(TRUE);
}

return S_OK;
}

// Routine Description:
Expand All @@ -1157,13 +1150,32 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
{
try
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });
return DoSrvSetConsoleOutputCodePage(codepage);
// Return if it's not known as a valid codepage ID.
RETURN_HR_IF(E_INVALIDARG, !(IsValidCodePage(codepage)));
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();
}

void DoSrvSetConsoleInputCodePage(const unsigned int codepage)
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
// Do nothing if no change.
if (gci.CP != codepage)
{
// Set new code page
gci.CP = codepage;
SetConsoleCPInfo(FALSE);
}
}

// Routine Description:
// - Sets the codepage used for translating text when calling A versions of functions affecting the input buffer.
// Arguments:
Expand All @@ -1177,19 +1189,12 @@ void ApiRoutines::GetLargestConsoleWindowSizeImpl(const SCREEN_INFORMATION& cont
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
LockConsole();
auto Unlock = wil::scope_exit([&] { UnlockConsole(); });

// 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);
}

DoSrvSetConsoleInputCodePage(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.DefaultCP = codepage;
return S_OK;
}
CATCH_RETURN();
Expand Down
3 changes: 2 additions & 1 deletion src/host/getset.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ Revision History:
#include "../inc/conattrs.hpp"
class SCREEN_INFORMATION;

[[nodiscard]] HRESULT DoSrvSetConsoleOutputCodePage(const unsigned int codepage);
void DoSrvSetConsoleOutputCodePage(const unsigned int codepage);
void DoSrvSetConsoleInputCodePage(const unsigned int codepage);
2 changes: 2 additions & 0 deletions src/host/output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ using namespace Microsoft::Console::Interactivity;
// codepage by console.cpl or shell32. The default codepage is OEMCP.
gci.CP = gci.GetCodePage();
gci.OutputCP = gci.GetCodePage();
gci.DefaultCP = gci.GetCodePage();
gci.DefaultOutputCP = gci.GetCodePage();

gci.Flags |= CONSOLE_USE_PRIVATE_FLAGS;

Expand Down
42 changes: 35 additions & 7 deletions src/host/outputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,27 +221,55 @@ void ConhostInternalGetSet::ShowWindow(bool showOrHide)
}

// 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:
// - codepage - the new output codepage of the console.
// - codepage - the new code page of the console.
// Return Value:
// - <none>
void ConhostInternalGetSet::SetConsoleOutputCP(const unsigned int codepage)
void ConhostInternalGetSet::SetCodePage(const unsigned int codepage)
{
THROW_IF_FAILED(DoSrvSetConsoleOutputCodePage(codepage));
if (IsValidCodePage(codepage))
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why we should check this outside the two set functions? I think it may be safer if it was inside them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It just seemed a little more efficient, but that's not really important here. I've moved the checks back into the DoSrvSet* functions now.

DoSrvSetConsoleOutputCodePage(codepage);
DoSrvSetConsoleInputCodePage(codepage);
}
}

// Routine Description:
// - Reset the code pages to their default values.
// Arguments:
// - <none>
// Return Value:
// - <none>
void ConhostInternalGetSet::ResetCodePage()
{
const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
DoSrvSetConsoleOutputCodePage(gci.DefaultOutputCP);
DoSrvSetConsoleInputCodePage(gci.DefaultCP);
}

// Routine Description:
// - Gets the codepage used for translating text when calling A versions of functions affecting the output buffer.
// - Gets the code page used for translating text when calling A versions of output functions.
// Arguments:
// - <none>
// Return Value:
// - the outputCP of the console.
unsigned int ConhostInternalGetSet::GetConsoleOutputCP() const
// - the output code page of the console.
unsigned int ConhostInternalGetSet::GetOutputCodePage() const
{
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:
// - Copies the given content to the clipboard.
// Arguments:
Expand Down
6 changes: 4 additions & 2 deletions src/host/outputStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal::

bool ResizeWindow(const til::CoordType width, const til::CoordType height) override;

void SetConsoleOutputCP(const unsigned int codepage) override;
unsigned int GetConsoleOutputCP() const override;
void SetCodePage(const unsigned int codepage) override;
void ResetCodePage() override;
unsigned int GetOutputCodePage() const override;
unsigned int GetInputCodePage() const override;

void CopyToClipboard(const wil::zwstring_view content) override;
void SetTaskbarProgress(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TaskbarState state, const size_t progress) override;
Expand Down
3 changes: 3 additions & 0 deletions src/host/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ class CONSOLE_INFORMATION :
// the following fields are used for ansi-unicode translation
UINT CP = 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 LimitingProcessId = 0;
Expand Down
1 change: 1 addition & 0 deletions src/terminal/adapter/ITermDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch
virtual void LockingShiftRight(const VTInt gsetNumber) = 0; // LS1R, LS2R, LS3R
virtual void SingleShift(const VTInt gsetNumber) = 0; // SS2, SS3
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 SoftReset() = 0; // DECSTR
Expand Down
6 changes: 4 additions & 2 deletions src/terminal/adapter/ITerminalApi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ namespace Microsoft::Console::VirtualTerminal

virtual void ShowWindow(bool showOrHide) = 0;

virtual void SetConsoleOutputCP(const unsigned int codepage) = 0;
virtual unsigned int GetConsoleOutputCP() const = 0;
virtual void SetCodePage(const unsigned int codepage) = 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 SetTaskbarProgress(const DispatchTypes::TaskbarState state, const size_t progress) = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/adapter/InteractDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void InteractDispatch::WriteString(const std::wstring_view string)
{
if (!string.empty())
{
const auto codepage = _api.GetConsoleOutputCP();
const auto codepage = _api.GetOutputCodePage();
InputEventQueue keyEvents;
Comment on lines -65 to 66
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to mention that I noticed we're using the output code page here to generate input events, which seemed wrong to me. Was that intentional?

That codepage is only used if the UseNumpadEventsForClipboardInput feature is enabled (which doesn't appear to be the case), so I don't think it's breaking anything at the moment, but it's still worth fixing if it's incorrect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an excellent question. Personally I'm not sure, though I suspect that it was an oversight.

UseNumpadEvents... was a last minute "don't break Windows conhost users right before a big release" feature flag, which we should almost certainly just remove now... :)


for (const auto& wch : string)
Expand Down
Loading
Loading