From dea00fb3f91614f5f709151b70f8b3720e9d9edc Mon Sep 17 00:00:00 2001 From: James Holderness Date: Tue, 25 Jun 2024 21:27:03 +0100 Subject: [PATCH 1/2] Implement cell size and window pixel size queries. --- src/terminal/adapter/DispatchTypes.hpp | 2 ++ src/terminal/adapter/PageManager.cpp | 5 +++++ src/terminal/adapter/PageManager.hpp | 1 + src/terminal/adapter/SixelParser.hpp | 4 ++-- src/terminal/adapter/adaptDispatch.cpp | 22 ++++++++++++++++++---- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/terminal/adapter/DispatchTypes.hpp b/src/terminal/adapter/DispatchTypes.hpp index 7ba0132c07c..cb8adee0151 100644 --- a/src/terminal/adapter/DispatchTypes.hpp +++ b/src/terminal/adapter/DispatchTypes.hpp @@ -589,6 +589,8 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes IconifyWindow = 2, RefreshWindow = 7, ResizeWindowInCharacters = 8, + ReportTextSizeInPixels = 14, + ReportCharacterCellSize = 16, ReportTextSizeInCharacters = 18 }; diff --git a/src/terminal/adapter/PageManager.cpp b/src/terminal/adapter/PageManager.cpp index 284bee8530a..7c9862611cc 100644 --- a/src/terminal/adapter/PageManager.cpp +++ b/src/terminal/adapter/PageManager.cpp @@ -52,6 +52,11 @@ void Page::SetAttributes(const TextAttribute& attr, ITerminalApi* api) const } } +til::size Page::Size() const noexcept +{ + return { Width(), Height() }; +} + til::CoordType Page::Top() const noexcept { // If we ever support vertical window panning, the page top won't diff --git a/src/terminal/adapter/PageManager.hpp b/src/terminal/adapter/PageManager.hpp index 652c98b83ca..7b498e62abe 100644 --- a/src/terminal/adapter/PageManager.hpp +++ b/src/terminal/adapter/PageManager.hpp @@ -26,6 +26,7 @@ namespace Microsoft::Console::VirtualTerminal Cursor& Cursor() const noexcept; const TextAttribute& Attributes() const noexcept; void SetAttributes(const TextAttribute& attr, ITerminalApi* api = nullptr) const; + til::size Size() const noexcept; til::CoordType Top() const noexcept; til::CoordType Bottom() const noexcept; til::CoordType Width() const noexcept; diff --git a/src/terminal/adapter/SixelParser.hpp b/src/terminal/adapter/SixelParser.hpp index db62cd089fd..1966228d77f 100644 --- a/src/terminal/adapter/SixelParser.hpp +++ b/src/terminal/adapter/SixelParser.hpp @@ -28,8 +28,8 @@ namespace Microsoft::Console::VirtualTerminal public: static constexpr VTInt DefaultConformance = 9; - static til::size CellSizeForLevel(const VTInt conformanceLevel) noexcept; - static size_t MaxColorsForLevel(const VTInt conformanceLevel) noexcept; + static til::size CellSizeForLevel(const VTInt conformanceLevel = DefaultConformance) noexcept; + static size_t MaxColorsForLevel(const VTInt conformanceLevel = DefaultConformance) noexcept; SixelParser(AdaptDispatch& dispatcher, const StateMachine& stateMachine, const VTInt conformanceLevel = DefaultConformance) noexcept; void SoftReset(); diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 9b35e29f458..104b79c7132 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -3648,6 +3648,12 @@ bool AdaptDispatch::WindowManipulation(const DispatchTypes::WindowManipulationTy // Other Window Manipulation functions: // MSFT:13271098 - QueryViewport // MSFT:13271146 - QueryScreenSize + + const auto reportSize = [&](const auto size) { + const auto reportType = function - 10; + _api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033[{};{};{}t"), reportType, size.height, size.width)); + }; + switch (function) { case DispatchTypes::WindowManipulationType::DeIconifyWindow: @@ -3663,11 +3669,19 @@ bool AdaptDispatch::WindowManipulation(const DispatchTypes::WindowManipulationTy _api.ResizeWindow(parameter2.value_or(0), parameter1.value_or(0)); return true; case DispatchTypes::WindowManipulationType::ReportTextSizeInCharacters: - { - const auto page = _pages.VisiblePage(); - _api.ReturnResponse(fmt::format(FMT_COMPILE(L"\033[8;{};{}t"), page.Height(), page.Width())); + reportSize(_pages.VisiblePage().Size()); + return true; + case DispatchTypes::WindowManipulationType::ReportTextSizeInPixels: + // Prior to the existence of the character cell size query, Sixel applications + // that wanted to know the cell size would request the text area in pixels and + // divide that by the text area in characters. But for this to work, we need to + // return the virtual pixel size, as used in the Sixel graphics emulation, and + // not the physical pixel size (which should be of no concern to applications). + reportSize(_pages.VisiblePage().Size() * SixelParser::CellSizeForLevel()); + return true; + case DispatchTypes::WindowManipulationType::ReportCharacterCellSize: + reportSize(SixelParser::CellSizeForLevel()); return true; - } default: return false; } From 77b5373c6b576b28a52da1710387c9155307b605 Mon Sep 17 00:00:00 2001 From: James Holderness Date: Tue, 25 Jun 2024 21:52:19 +0100 Subject: [PATCH 2/2] Add unit tests. --- src/terminal/adapter/ut_adapter/adapterTest.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/terminal/adapter/ut_adapter/adapterTest.cpp b/src/terminal/adapter/ut_adapter/adapterTest.cpp index 44274d66a7d..da5a7c93cb2 100644 --- a/src/terminal/adapter/ut_adapter/adapterTest.cpp +++ b/src/terminal/adapter/ut_adapter/adapterTest.cpp @@ -3377,10 +3377,23 @@ class AdapterTest TEST_METHOD(WindowManipulationTypeTests) { + // Our pixel size reports are based on a virtual cell size of 10x20 pixels + // for compatibility with the VT240 and VT340 graphic terminals. + const auto cellSize = til::size{ 10, 20 }; + _testGetSet->PrepData(); - _pDispatch->WindowManipulation(DispatchTypes::WindowManipulationType::ReportTextSizeInCharacters, NULL, NULL); const auto [textBuffer, viewport, _] = _testGetSet->GetBufferAndViewport(); - const std::wstring expectedResponse = fmt::format(L"\033[8;{};{}t", viewport.height(), textBuffer.GetSize().Width()); + + _pDispatch->WindowManipulation(DispatchTypes::WindowManipulationType::ReportTextSizeInCharacters, NULL, NULL); + std::wstring expectedResponse = fmt::format(L"\033[8;{};{}t", viewport.height(), textBuffer.GetSize().Width()); + _testGetSet->ValidateInputEvent(expectedResponse.c_str()); + + _pDispatch->WindowManipulation(DispatchTypes::WindowManipulationType::ReportTextSizeInPixels, NULL, NULL); + expectedResponse = fmt::format(L"\033[4;{};{}t", viewport.height() * cellSize.height, textBuffer.GetSize().Width() * cellSize.width); + _testGetSet->ValidateInputEvent(expectedResponse.c_str()); + + _pDispatch->WindowManipulation(DispatchTypes::WindowManipulationType::ReportCharacterCellSize, NULL, NULL); + expectedResponse = fmt::format(L"\033[6;{};{}t", cellSize.height, cellSize.width); _testGetSet->ValidateInputEvent(expectedResponse.c_str()); }