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 querying the DECSCUSR setting #17659

Merged
merged 3 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
111 changes: 55 additions & 56 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4259,6 +4259,9 @@ ITermDispatch::StringHandler AdaptDispatch::RequestSetting()
case VTID("s"):
_ReportDECSLRMSetting();
break;
case VTID(" q"):
_ReportDECSCUSRSetting();
break;
case VTID("\"q"):
_ReportDECSCASetting();
break;
Expand Down Expand Up @@ -4376,20 +4379,12 @@ void AdaptDispatch::_ReportSGRSetting() const
// - None
void AdaptDispatch::_ReportDECSTBMSetting()
{
using namespace std::string_view_literals;

// A valid response always starts with DCS 1 $ r.
fmt::basic_memory_buffer<wchar_t, 64> response;
response.append(L"\033P1$r"sv);

const auto page = _pages.ActivePage();
const auto [marginTop, marginBottom] = _GetVerticalMargins(page, false);
// A valid response always starts with DCS 1 $ r, the 'r' indicates this
// is a DECSTBM response, and ST ends the sequence.
// VT origin is at 1,1 so we need to add 1 to these margins.
fmt::format_to(std::back_inserter(response), FMT_COMPILE(L"{};{}"), marginTop + 1, marginBottom + 1);

// The 'r' indicates this is an DECSTBM response, and ST ends the sequence.
response.append(L"r\033\\"sv);
_api.ReturnResponse({ response.data(), response.size() });
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033P1$r{};{}r\033\\"), marginTop + 1, marginBottom + 1));
}

// Method Description:
Expand All @@ -4400,20 +4395,46 @@ void AdaptDispatch::_ReportDECSTBMSetting()
// - None
void AdaptDispatch::_ReportDECSLRMSetting()
{
using namespace std::string_view_literals;

// A valid response always starts with DCS 1 $ r.
fmt::basic_memory_buffer<wchar_t, 64> response;
response.append(L"\033P1$r"sv);

const auto pageWidth = _pages.ActivePage().Width();
const auto [marginLeft, marginRight] = _GetHorizontalMargins(pageWidth);
// A valid response always starts with DCS 1 $ r, the 's' indicates this
// is a DECSLRM response, and ST ends the sequence.
// VT origin is at 1,1 so we need to add 1 to these margins.
fmt::format_to(std::back_inserter(response), FMT_COMPILE(L"{};{}"), marginLeft + 1, marginRight + 1);
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033P1$r{};{}s\033\\"), marginLeft + 1, marginRight + 1));
}

// The 's' indicates this is an DECSLRM response, and ST ends the sequence.
response.append(L"s\033\\"sv);
_api.ReturnResponse({ response.data(), response.size() });
// Method Description:
// - Reports the DECSCUSR cursor style in response to a DECRQSS query.
// Arguments:
// - None
// Return Value:
// - None
void AdaptDispatch::_ReportDECSCUSRSetting() const
{
const auto& cursor = _pages.ActivePage().Cursor();
const auto blinking = cursor.IsBlinkingAllowed();
// A valid response always starts with DCS 1 $ r. This is followed by a
// number from 1 to 6 representing the cursor style. The ' q' indicates
// this is a DECSCUSR response, and ST ends the sequence.
switch (cursor.GetType())
{
case CursorType::FullBox:
_api.ReturnResponse(blinking ? L"\033P1$r1 q\033\\" : L"\033P1$r2 q\033\\");
break;
case CursorType::Underscore:
_api.ReturnResponse(blinking ? L"\033P1$r3 q\033\\" : L"\033P1$r4 q\033\\");
break;
case CursorType::VerticalBar:
_api.ReturnResponse(blinking ? L"\033P1$r5 q\033\\" : L"\033P1$r6 q\033\\");
break;
default:
// 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.
// That way, if an application later tries to restore the cursor with
// the returned value, it should be reset to its original state.
_api.ReturnResponse(L"\033P1$r0 q\033\\");
break;
}
}

// Method Description:
Expand All @@ -4424,18 +4445,11 @@ void AdaptDispatch::_ReportDECSLRMSetting()
// - None
void AdaptDispatch::_ReportDECSCASetting() const
{
using namespace std::string_view_literals;

// A valid response always starts with DCS 1 $ r.
fmt::basic_memory_buffer<wchar_t, 64> response;
response.append(L"\033P1$r"sv);

const auto& attr = _pages.ActivePage().Attributes();
response.append(attr.IsProtected() ? L"1"sv : L"0"sv);

// The '"q' indicates this is an DECSCA response, and ST ends the sequence.
response.append(L"\"q\033\\"sv);
_api.ReturnResponse({ response.data(), response.size() });
const auto isProtected = _pages.ActivePage().Attributes().IsProtected();
// A valid response always starts with DCS 1 $ r. This is followed by '1' if
// the protected attribute is set, or '0' if not. The '"q' indicates this is
// a DECSCA response, and ST ends the sequence.
_api.ReturnResponse(isProtected ? L"\033P1$r1\"q\033\\" : L"\033P1$r0\"q\033\\");
}

// Method Description:
Expand All @@ -4446,17 +4460,11 @@ void AdaptDispatch::_ReportDECSCASetting() const
// - None
void AdaptDispatch::_ReportDECSACESetting() const
{
using namespace std::string_view_literals;

// A valid response always starts with DCS 1 $ r.
fmt::basic_memory_buffer<wchar_t, 64> response;
response.append(L"\033P1$r"sv);

response.append(_modes.test(Mode::RectangularChangeExtent) ? L"2"sv : L"1"sv);

// The '*x' indicates this is an DECSACE response, and ST ends the sequence.
response.append(L"*x\033\\"sv);
_api.ReturnResponse({ response.data(), response.size() });
const auto rectangularExtent = _modes.test(Mode::RectangularChangeExtent);
// A valid response always starts with DCS 1 $ r. This is followed by '2' if
// the extent is rectangular, or '1' if it's a stream. The '*x' indicates
// this is a DECSACE response, and ST ends the sequence.
_api.ReturnResponse(rectangularExtent ? L"\033P1$r2*x\033\\" : L"\033P1$r1*x\033\\");
}

// Method Description:
Expand All @@ -4467,8 +4475,6 @@ void AdaptDispatch::_ReportDECSACESetting() const
// - None
void AdaptDispatch::_ReportDECACSetting(const VTInt itemNumber) const
{
using namespace std::string_view_literals;

size_t fgIndex = 0;
size_t bgIndex = 0;
switch (static_cast<DispatchTypes::ColorItem>(itemNumber))
Expand All @@ -4485,16 +4491,9 @@ void AdaptDispatch::_ReportDECACSetting(const VTInt itemNumber) const
_api.ReturnResponse(L"\033P0$r\033\\");
return;
}

// A valid response always starts with DCS 1 $ r.
fmt::basic_memory_buffer<wchar_t, 64> response;
response.append(L"\033P1$r"sv);

fmt::format_to(std::back_inserter(response), FMT_COMPILE(L"{};{};{}"), itemNumber, fgIndex, bgIndex);

// The ',|' indicates this is a DECAC response, and ST ends the sequence.
response.append(L",|\033\\"sv);
_api.ReturnResponse({ response.data(), response.size() });
// A valid response always starts with DCS 1 $ r, the ',|' indicates this
// is a DECAC response, and ST ends the sequence.
_api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033P1$r{};{};{},|\033\\"), itemNumber, fgIndex, bgIndex));
}

// Routine Description:
Expand Down
1 change: 1 addition & 0 deletions src/terminal/adapter/adaptDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ namespace Microsoft::Console::VirtualTerminal
void _ReportSGRSetting() const;
void _ReportDECSTBMSetting();
void _ReportDECSLRMSetting();
void _ReportDECSCUSRSetting() const;
void _ReportDECSCASetting() const;
void _ReportDECSACESetting() const;
void _ReportDECACSetting(const VTInt itemNumber) const;
Expand Down
49 changes: 49 additions & 0 deletions src/terminal/adapter/ut_adapter/adapterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,55 @@ class AdapterTest
requestSetting(L"m");
_testGetSet->ValidateInputEvent(L"\033P1$r0;38:2::12:34:56;48:2::65:43:21;58:2::128:222:45m\033\\");

Log::Comment(L"Requesting DECSCUSR style (blinking block).");
_testGetSet->PrepData();
_testGetSet->_textBuffer->GetCursor().SetBlinkingAllowed(true);
_testGetSet->_textBuffer->GetCursor().SetType(CursorType::FullBox);
requestSetting(L" q");
_testGetSet->ValidateInputEvent(L"\033P1$r1 q\033\\");

Log::Comment(L"Requesting DECSCUSR style (steady block).");
_testGetSet->PrepData();
_testGetSet->_textBuffer->GetCursor().SetBlinkingAllowed(false);
_testGetSet->_textBuffer->GetCursor().SetType(CursorType::FullBox);
requestSetting(L" q");
_testGetSet->ValidateInputEvent(L"\033P1$r2 q\033\\");

Log::Comment(L"Requesting DECSCUSR style (blinking underline).");
_testGetSet->PrepData();
_testGetSet->_textBuffer->GetCursor().SetBlinkingAllowed(true);
_testGetSet->_textBuffer->GetCursor().SetType(CursorType::Underscore);
requestSetting(L" q");
_testGetSet->ValidateInputEvent(L"\033P1$r3 q\033\\");

Log::Comment(L"Requesting DECSCUSR style (steady underline).");
_testGetSet->PrepData();
_testGetSet->_textBuffer->GetCursor().SetBlinkingAllowed(false);
_testGetSet->_textBuffer->GetCursor().SetType(CursorType::Underscore);
requestSetting(L" q");
_testGetSet->ValidateInputEvent(L"\033P1$r4 q\033\\");

Log::Comment(L"Requesting DECSCUSR style (blinking bar).");
_testGetSet->PrepData();
_testGetSet->_textBuffer->GetCursor().SetBlinkingAllowed(true);
_testGetSet->_textBuffer->GetCursor().SetType(CursorType::VerticalBar);
requestSetting(L" q");
_testGetSet->ValidateInputEvent(L"\033P1$r5 q\033\\");

Log::Comment(L"Requesting DECSCUSR style (steady bar).");
_testGetSet->PrepData();
_testGetSet->_textBuffer->GetCursor().SetBlinkingAllowed(false);
_testGetSet->_textBuffer->GetCursor().SetType(CursorType::VerticalBar);
requestSetting(L" q");
_testGetSet->ValidateInputEvent(L"\033P1$r6 q\033\\");

Log::Comment(L"Requesting DECSCUSR style (non-standard).");
_testGetSet->PrepData();
_testGetSet->_textBuffer->GetCursor().SetBlinkingAllowed(true);
_testGetSet->_textBuffer->GetCursor().SetType(CursorType::Legacy);
requestSetting(L" q");
_testGetSet->ValidateInputEvent(L"\033P1$r0 q\033\\");

Log::Comment(L"Requesting DECSCA attributes (unprotected).");
_testGetSet->PrepData();
attribute = {};
Expand Down
Loading