From 9c1436775e44c1a7090c41cd44624d5a39cb9828 Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Wed, 14 Aug 2024 04:35:47 +0200 Subject: [PATCH] Use a plain char array to pass connection input (#17710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `HSTRING` does not permit strings that aren't null-terminated. As such we'll simply use a plain char array which compiles down to a `UINT32` and `wchar_t*` pointer pair. Unfortunately, cppwinrt uses `char16_t` in place of `wchar_t`, and also offers no trivial conversion between `winrt::array_view` and `std::wstring_view` either. As such, most of this PR is about explicit type casting. Closes #17697 ## Validation Steps Performed * Patch the `DeviceAttributes` implementation in `adaptDispatch.cpp` to respond like this: ```cpp _api.ReturnResponse({L"ABCD", 3}); ``` * Open a WSL shell and execute this: ```sh printf "\e[c"; read ``` * Doesn't crash ✅ --- .../TerminalApp/DebugTapConnection.cpp | 14 +- src/cascadia/TerminalApp/DebugTapConnection.h | 6 +- src/cascadia/TerminalAzBridge/main.cpp | 2 +- .../TerminalConnection/AzureConnection.cpp | 9 +- .../TerminalConnection/AzureConnection.h | 3 +- .../TerminalConnection/ConptyConnection.cpp | 4 +- .../TerminalConnection/ConptyConnection.h | 2 +- .../TerminalConnection/EchoConnection.cpp | 3 +- .../TerminalConnection/EchoConnection.h | 2 +- .../ITerminalConnection.idl | 2 +- src/cascadia/TerminalControl/ControlCore.cpp | 4 +- .../PreviewConnection.cpp | 2 +- .../PreviewConnection.h | 2 +- .../UnitTests_Control/ControlCoreTests.cpp | 127 +++++++++--------- .../ControlInteractivityTests.cpp | 26 ++-- .../UnitTests_Control/MockConnection.h | 4 +- src/cascadia/inc/cppwinrt_utils.h | 12 ++ 17 files changed, 123 insertions(+), 101 deletions(-) diff --git a/src/cascadia/TerminalApp/DebugTapConnection.cpp b/src/cascadia/TerminalApp/DebugTapConnection.cpp index 25251bd9df..6d2ccc0b75 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.cpp +++ b/src/cascadia/TerminalApp/DebugTapConnection.cpp @@ -39,10 +39,10 @@ namespace winrt::Microsoft::TerminalApp::implementation _wrappedConnection.Start(); } - void WriteInput(const hstring& data) + void WriteInput(const winrt::array_view buffer) { - _pairedTap->_PrintInput(data); - _wrappedConnection.WriteInput(data); + _pairedTap->_PrintInput(winrt_array_to_wstring_view(buffer)); + _wrappedConnection.WriteInput(buffer); } void Resize(uint32_t rows, uint32_t columns) { _wrappedConnection.Resize(rows, columns); } void Close() { _wrappedConnection.Close(); } @@ -77,13 +77,13 @@ namespace winrt::Microsoft::TerminalApp::implementation _start.count_down(); } - void DebugTapConnection::WriteInput(const hstring& data) + void DebugTapConnection::WriteInput(const winrt::array_view buffer) { // If the user types into the tap side, forward it to the input side if (auto strongInput{ _inputSide.get() }) { auto inputAsTap{ winrt::get_self(strongInput) }; - inputAsTap->WriteInput(data); + inputAsTap->WriteInput(buffer); } } @@ -117,7 +117,7 @@ namespace winrt::Microsoft::TerminalApp::implementation return ConnectionState::Failed; } - void DebugTapConnection::_OutputHandler(const hstring str) + void DebugTapConnection::_OutputHandler(const std::wstring_view str) { auto output = til::visualize_control_codes(str); // To make the output easier to read, we introduce a line break whenever @@ -131,7 +131,7 @@ namespace winrt::Microsoft::TerminalApp::implementation } // Called by the DebugInputTapConnection to print user input - void DebugTapConnection::_PrintInput(const hstring& str) + void DebugTapConnection::_PrintInput(const std::wstring_view str) { auto clean{ til::visualize_control_codes(str) }; auto formatted{ wil::str_printf(L"\x1b[91m%ls\x1b[m", clean.data()) }; diff --git a/src/cascadia/TerminalApp/DebugTapConnection.h b/src/cascadia/TerminalApp/DebugTapConnection.h index 933270df13..70b607e82f 100644 --- a/src/cascadia/TerminalApp/DebugTapConnection.h +++ b/src/cascadia/TerminalApp/DebugTapConnection.h @@ -16,7 +16,7 @@ namespace winrt::Microsoft::TerminalApp::implementation void Initialize(const Windows::Foundation::Collections::ValueSet& /*settings*/){}; ~DebugTapConnection(); void Start(); - void WriteInput(const hstring& data); + void WriteInput(const winrt::array_view data); void Resize(uint32_t rows, uint32_t columns); void Close(); @@ -30,8 +30,8 @@ namespace winrt::Microsoft::TerminalApp::implementation til::typed_event StateChanged; private: - void _PrintInput(const hstring& data); - void _OutputHandler(const hstring str); + void _PrintInput(const std::wstring_view data); + void _OutputHandler(const std::wstring_view str); winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::TerminalOutput_revoker _outputRevoker; winrt::Microsoft::Terminal::TerminalConnection::ITerminalConnection::StateChanged_revoker _stateChangedRevoker; diff --git a/src/cascadia/TerminalAzBridge/main.cpp b/src/cascadia/TerminalAzBridge/main.cpp index c5515f7ff5..05e3e99b23 100644 --- a/src/cascadia/TerminalAzBridge/main.cpp +++ b/src/cascadia/TerminalAzBridge/main.cpp @@ -42,7 +42,7 @@ static ConnectionState RunConnectionToCompletion(const ITerminalConnection& conn auto input = reader.Read(); if (input) { - connection.WriteInput(*input); + connection.WriteInput(winrt_wstring_to_array_view(*input)); } } }).detach(); diff --git a/src/cascadia/TerminalConnection/AzureConnection.cpp b/src/cascadia/TerminalConnection/AzureConnection.cpp index 210f7cc06c..a0f4e0f926 100644 --- a/src/cascadia/TerminalConnection/AzureConnection.cpp +++ b/src/cascadia/TerminalConnection/AzureConnection.cpp @@ -186,7 +186,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation // - handles the different possible inputs in the different states // Arguments: // the user's input - void AzureConnection::WriteInput(const hstring& data) + void AzureConnection::WriteInput(const winrt::array_view buffer) + { + _writeInput(winrt_array_to_wstring_view(buffer)); + } + + void AzureConnection::_writeInput(const std::wstring_view data) { // We read input while connected AND connecting. if (!_isStateOneOf(ConnectionState::Connected, ConnectionState::Connecting)) @@ -804,7 +809,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation std::swap(_userInput, queuedUserInput); if (queuedUserInput.size() > 0) { - WriteInput(static_cast(queuedUserInput)); // send the user's queued up input back through + _writeInput(queuedUserInput); // send the user's queued up input back through } } diff --git a/src/cascadia/TerminalConnection/AzureConnection.h b/src/cascadia/TerminalConnection/AzureConnection.h index afb5d6e8b9..3b8a092692 100644 --- a/src/cascadia/TerminalConnection/AzureConnection.h +++ b/src/cascadia/TerminalConnection/AzureConnection.h @@ -22,7 +22,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation void Initialize(const Windows::Foundation::Collections::ValueSet& settings); void Start(); - void WriteInput(const hstring& data); + void WriteInput(const winrt::array_view buffer); void Resize(uint32_t rows, uint32_t columns); void Close(); @@ -66,6 +66,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation std::vector<::Microsoft::Terminal::Azure::Tenant> _tenantList; std::optional<::Microsoft::Terminal::Azure::Tenant> _currentTenant; + void _writeInput(const std::wstring_view str); void _WriteStringWithNewline(const std::wstring_view str); void _WriteCaughtExceptionRecord(); winrt::Windows::Data::Json::JsonObject _SendRequestReturningJson(std::wstring_view uri, const winrt::Windows::Web::Http::IHttpContent& content = nullptr, winrt::Windows::Web::Http::HttpMethod method = nullptr, const winrt::Windows::Foundation::Uri referer = nullptr); diff --git a/src/cascadia/TerminalConnection/ConptyConnection.cpp b/src/cascadia/TerminalConnection/ConptyConnection.cpp index 23a7e263b8..1cb7689c4c 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.cpp +++ b/src/cascadia/TerminalConnection/ConptyConnection.cpp @@ -473,8 +473,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation } CATCH_LOG() - void ConptyConnection::WriteInput(const hstring& data) + void ConptyConnection::WriteInput(const winrt::array_view buffer) { + const auto data = winrt_array_to_wstring_view(buffer); + if (!_isConnected()) { return; diff --git a/src/cascadia/TerminalConnection/ConptyConnection.h b/src/cascadia/TerminalConnection/ConptyConnection.h index 85f292baad..083005e70e 100644 --- a/src/cascadia/TerminalConnection/ConptyConnection.h +++ b/src/cascadia/TerminalConnection/ConptyConnection.h @@ -21,7 +21,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation static winrt::fire_and_forget final_release(std::unique_ptr connection); void Start(); - void WriteInput(const hstring& data); + void WriteInput(const winrt::array_view buffer); void Resize(uint32_t rows, uint32_t columns); void Close() noexcept; void ClearBuffer(); diff --git a/src/cascadia/TerminalConnection/EchoConnection.cpp b/src/cascadia/TerminalConnection/EchoConnection.cpp index 5ac052ad6a..ca28af28e5 100644 --- a/src/cascadia/TerminalConnection/EchoConnection.cpp +++ b/src/cascadia/TerminalConnection/EchoConnection.cpp @@ -15,8 +15,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation { } - void EchoConnection::WriteInput(const hstring& data) + void EchoConnection::WriteInput(const winrt::array_view buffer) { + const auto data = winrt_array_to_wstring_view(buffer); std::wstringstream prettyPrint; for (const auto& wch : data) { diff --git a/src/cascadia/TerminalConnection/EchoConnection.h b/src/cascadia/TerminalConnection/EchoConnection.h index cfdf4189db..92146a8771 100644 --- a/src/cascadia/TerminalConnection/EchoConnection.h +++ b/src/cascadia/TerminalConnection/EchoConnection.h @@ -12,7 +12,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation EchoConnection() noexcept; void Start() noexcept; - void WriteInput(const hstring& data); + void WriteInput(const winrt::array_view buffer); void Resize(uint32_t rows, uint32_t columns) noexcept; void Close() noexcept; diff --git a/src/cascadia/TerminalConnection/ITerminalConnection.idl b/src/cascadia/TerminalConnection/ITerminalConnection.idl index bae69c765f..275b57b2ac 100644 --- a/src/cascadia/TerminalConnection/ITerminalConnection.idl +++ b/src/cascadia/TerminalConnection/ITerminalConnection.idl @@ -20,7 +20,7 @@ namespace Microsoft.Terminal.TerminalConnection void Initialize(Windows.Foundation.Collections.ValueSet settings); void Start(); - void WriteInput(String data); + void WriteInput(Char[] data); void Resize(UInt32 rows, UInt32 columns); void Close(); diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp index 1b6f5ff7e7..06d6e0478e 100644 --- a/src/cascadia/TerminalControl/ControlCore.cpp +++ b/src/cascadia/TerminalControl/ControlCore.cpp @@ -438,7 +438,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation } else { - _connection.WriteInput(wstr); + _connection.WriteInput(winrt_wstring_to_array_view(wstr)); } } @@ -2487,7 +2487,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation { // _sendInputToConnection() asserts that we aren't in focus mode, // but window focus events are always fine to send. - _connection.WriteInput(*out); + _connection.WriteInput(winrt_wstring_to_array_view(*out)); } } diff --git a/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp b/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp index 6be3a1ddb1..aabfb6579c 100644 --- a/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp +++ b/src/cascadia/TerminalSettingsEditor/PreviewConnection.cpp @@ -39,7 +39,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { } - void PreviewConnection::WriteInput(const hstring& /*data*/) + void PreviewConnection::WriteInput(const winrt::array_view /*data*/) { } diff --git a/src/cascadia/TerminalSettingsEditor/PreviewConnection.h b/src/cascadia/TerminalSettingsEditor/PreviewConnection.h index 9c95377134..c988ff5156 100644 --- a/src/cascadia/TerminalSettingsEditor/PreviewConnection.h +++ b/src/cascadia/TerminalSettingsEditor/PreviewConnection.h @@ -23,7 +23,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation void Initialize(const Windows::Foundation::Collections::ValueSet& settings) noexcept; void Start() noexcept; - void WriteInput(const hstring& data); + void WriteInput(const winrt::array_view buffer); void Resize(uint32_t rows, uint32_t columns) noexcept; void Close() noexcept; diff --git a/src/cascadia/UnitTests_Control/ControlCoreTests.cpp b/src/cascadia/UnitTests_Control/ControlCoreTests.cpp index 2aaaed243f..8c76135d4e 100644 --- a/src/cascadia/UnitTests_Control/ControlCoreTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlCoreTests.cpp @@ -249,9 +249,9 @@ namespace ControlUnitTests L"(leaving the cursor afer 'Bar')"); for (auto i = 0; i < 40; ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } - conn->WriteInput(L"Bar"); + conn->WriteInput(winrt_wstring_to_array_view(L"Bar")); // We printed that 40 times, but the final \r\n bumped the view down one MORE row. Log::Comment(L"Check the buffer viewport before the clear"); @@ -286,9 +286,9 @@ namespace ControlUnitTests L"(leaving the cursor afer 'Bar')"); for (auto i = 0; i < 40; ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } - conn->WriteInput(L"Bar"); + conn->WriteInput(winrt_wstring_to_array_view(L"Bar")); // We printed that 40 times, but the final \r\n bumped the view down one MORE row. Log::Comment(L"Check the buffer viewport before the clear"); @@ -323,9 +323,9 @@ namespace ControlUnitTests L"(leaving the cursor afer 'Bar')"); for (auto i = 0; i < 40; ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } - conn->WriteInput(L"Bar"); + conn->WriteInput(winrt_wstring_to_array_view(L"Bar")); // We printed that 40 times, but the final \r\n bumped the view down one MORE row. Log::Comment(L"Check the buffer viewport before the clear"); @@ -358,25 +358,26 @@ namespace ControlUnitTests _standardInit(core); Log::Comment(L"Print some text"); - conn->WriteInput(L"This is some text \r\n"); - conn->WriteInput(L"with varying amounts \r\n"); - conn->WriteInput(L"of whitespace \r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"This is some text \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"with varying amounts \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"of whitespace \r\n")); Log::Comment(L"Check the buffer contents"); VERIFY_ARE_EQUAL(L"This is some text\r\nwith varying amounts\r\nof whitespace\r\n", core->ReadEntireBuffer()); } - void _writePrompt(const winrt::com_ptr& conn, const auto& path) + + static void _writePrompt(const winrt::com_ptr& conn, const std::wstring_view& path) { - conn->WriteInput(L"\x1b]133;D\x7"); - conn->WriteInput(L"\x1b]133;A\x7"); - conn->WriteInput(L"\x1b]9;9;"); - conn->WriteInput(path); - conn->WriteInput(L"\x7"); - conn->WriteInput(L"PWSH "); - conn->WriteInput(path); - conn->WriteInput(L"> "); - conn->WriteInput(L"\x1b]133;B\x7"); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;D\x7")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;A\x7")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]9;9;")); + conn->WriteInput(winrt_wstring_to_array_view(path)); + conn->WriteInput(winrt_wstring_to_array_view(L"\x7")); + conn->WriteInput(winrt_wstring_to_array_view(L"PWSH ")); + conn->WriteInput(winrt_wstring_to_array_view(path)); + conn->WriteInput(winrt_wstring_to_array_view(L"> ")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;B\x7")); } void ControlCoreTests::TestSelectCommandSimple() @@ -390,13 +391,13 @@ namespace ControlUnitTests Log::Comment(L"Print some text"); _writePrompt(conn, L"C:\\Windows"); - conn->WriteInput(L"Foo-bar"); - conn->WriteInput(L"\x1b]133;C\x7"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo-bar")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); - conn->WriteInput(L"\r\n"); - conn->WriteInput(L"This is some text \r\n"); - conn->WriteInput(L"with varying amounts \r\n"); - conn->WriteInput(L"of whitespace \r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"\r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"This is some text \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"with varying amounts \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"of whitespace \r\n")); _writePrompt(conn, L"C:\\Windows"); @@ -422,8 +423,8 @@ namespace ControlUnitTests } core->_terminal->ClearSelection(); - conn->WriteInput(L"Boo-far"); - conn->WriteInput(L"\x1b]133;C\x7"); + conn->WriteInput(winrt_wstring_to_array_view(L"Boo-far")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); VERIFY_IS_FALSE(core->HasSelection()); { @@ -473,13 +474,13 @@ namespace ControlUnitTests Log::Comment(L"Print some text"); _writePrompt(conn, L"C:\\Windows"); - conn->WriteInput(L"Foo-bar"); - conn->WriteInput(L"\x1b]133;C\x7"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo-bar")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); - conn->WriteInput(L"\r\n"); - conn->WriteInput(L"This is some text \r\n"); - conn->WriteInput(L"with varying amounts \r\n"); - conn->WriteInput(L"of whitespace \r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"\r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"This is some text \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"with varying amounts \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"of whitespace \r\n")); _writePrompt(conn, L"C:\\Windows"); @@ -515,13 +516,13 @@ namespace ControlUnitTests Log::Comment(L"Print some text"); _writePrompt(conn, L"C:\\Windows"); - conn->WriteInput(L"Foo-bar"); - conn->WriteInput(L"\x1b]133;C\x7"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo-bar")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); - conn->WriteInput(L"\r\n"); - conn->WriteInput(L"This is some text \r\n"); - conn->WriteInput(L"with varying amounts \r\n"); - conn->WriteInput(L"of whitespace \r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"\r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"This is some text \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"with varying amounts \r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"of whitespace \r\n")); _writePrompt(conn, L"C:\\Windows"); @@ -535,7 +536,7 @@ namespace ControlUnitTests } Log::Comment(L"Write 'Bar' to the command..."); - conn->WriteInput(L"Bar"); + conn->WriteInput(winrt_wstring_to_array_view(L"Bar")); { auto historyContext{ core->CommandHistory() }; // Bar shouldn't be in the history, it should be the current command @@ -544,9 +545,9 @@ namespace ControlUnitTests } Log::Comment(L"then delete it"); - conn->WriteInput(L"\b \b"); - conn->WriteInput(L"\b \b"); - conn->WriteInput(L"\b \b"); + conn->WriteInput(winrt_wstring_to_array_view(L"\b \b")); + conn->WriteInput(winrt_wstring_to_array_view(L"\b \b")); + conn->WriteInput(winrt_wstring_to_array_view(L"\b \b")); { auto historyContext{ core->CommandHistory() }; VERIFY_ARE_EQUAL(1u, historyContext.History().Size()); @@ -566,23 +567,23 @@ namespace ControlUnitTests Log::Comment(L"Print some text"); _writePrompt(conn, L"C:\\Windows"); // row 0 - conn->WriteInput(L"Foo-bar"); // row 0 - conn->WriteInput(L"\x1b]133;C\x7"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo-bar")); // row 0 + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); - conn->WriteInput(L"\r\n"); - conn->WriteInput(L"This is some text \r\n"); // row 1 - conn->WriteInput(L"with varying amounts \r\n"); // row 2 - conn->WriteInput(L"of whitespace \r\n"); // row 3 + conn->WriteInput(winrt_wstring_to_array_view(L"\r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"This is some text \r\n")); // row 1 + conn->WriteInput(winrt_wstring_to_array_view(L"with varying amounts \r\n")); // row 2 + conn->WriteInput(winrt_wstring_to_array_view(L"of whitespace \r\n")); // row 3 _writePrompt(conn, L"C:\\Windows"); // row 4 - conn->WriteInput(L"gci"); - conn->WriteInput(L"\x1b]133;C\x7"); - conn->WriteInput(L"\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"gci")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); + conn->WriteInput(winrt_wstring_to_array_view(L"\r\n")); // enough to scroll for (auto i = 0; i < 30; i++) // row 5-34 { - conn->WriteInput(L"-a--- 2/8/2024 9:47 README\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"-a--- 2/8/2024 9:47 README\r\n")); } _writePrompt(conn, L"C:\\Windows"); @@ -635,23 +636,23 @@ namespace ControlUnitTests Log::Comment(L"Print some text"); _writePrompt(conn, L"C:\\Windows"); // row 0 - conn->WriteInput(L"Foo-bar"); // row 0 - conn->WriteInput(L"\x1b]133;C\x7"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo-bar")); // row 0 + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); - conn->WriteInput(L"\r\n"); - conn->WriteInput(L"This is some text \r\n"); // row 1 - conn->WriteInput(L"with varying amounts \r\n"); // row 2 - conn->WriteInput(L"of whitespace \r\n"); // row 3 + conn->WriteInput(winrt_wstring_to_array_view(L"\r\n")); + conn->WriteInput(winrt_wstring_to_array_view(L"This is some text \r\n")); // row 1 + conn->WriteInput(winrt_wstring_to_array_view(L"with varying amounts \r\n")); // row 2 + conn->WriteInput(winrt_wstring_to_array_view(L"of whitespace \r\n")); // row 3 _writePrompt(conn, L"C:\\Windows"); // row 4 - conn->WriteInput(L"gci"); - conn->WriteInput(L"\x1b]133;C\x7"); - conn->WriteInput(L"\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"gci")); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b]133;C\x7")); + conn->WriteInput(winrt_wstring_to_array_view(L"\r\n")); // enough to scroll for (auto i = 0; i < 30; i++) // row 5-35 { - conn->WriteInput(L"-a--- 2/8/2024 9:47 README.md\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"-a--- 2/8/2024 9:47 README.md\r\n")); } _writePrompt(conn, L"C:\\Windows"); diff --git a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp index f95d9f0f16..9ef3edc4fe 100644 --- a/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp +++ b/src/cascadia/UnitTests_Control/ControlInteractivityTests.cpp @@ -230,7 +230,7 @@ namespace ControlUnitTests expectedBufferHeight++; } - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } // We printed that 40 times, but the final \r\n bumped the view down one MORE row. VERIFY_ARE_EQUAL(20, core->_terminal->GetViewport().Height()); @@ -398,7 +398,7 @@ namespace ControlUnitTests Log::Comment(L"Add some test to the terminal so we can scroll"); for (auto i = 0; i < 40; ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } // We printed that 40 times, but the final \r\n bumped the view down one MORE row. VERIFY_ARE_EQUAL(20, core->_terminal->GetViewport().Height()); @@ -475,7 +475,7 @@ namespace ControlUnitTests for (auto i = 0; i < 40; ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } // We printed that 40 times, but the final \r\n bumped the view down one MORE row. VERIFY_ARE_EQUAL(20, core->_terminal->GetViewport().Height()); @@ -534,7 +534,7 @@ namespace ControlUnitTests interactivity->MouseWheel(modifiers, delta, mousePos, state); // 2/5 VERIFY_ARE_EQUAL(21, core->ScrollOffset()); - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); VERIFY_ARE_EQUAL(22, core->ScrollOffset()); interactivity->MouseWheel(modifiers, delta, mousePos, state); // 1/5 VERIFY_ARE_EQUAL(22, core->ScrollOffset()); @@ -699,7 +699,7 @@ namespace ControlUnitTests expectedBufferHeight++; } - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } // We printed that 40 times, but the final \r\n bumped the view down one MORE row. VERIFY_ARE_EQUAL(20, core->_terminal->GetViewport().Height()); @@ -721,7 +721,7 @@ namespace ControlUnitTests } // Enable VT mouse event tracking - conn->WriteInput(L"\x1b[?1003;1006h"); + conn->WriteInput(winrt_wstring_to_array_view(L"\x1b[?1003;1006h")); // Mouse clicks in the inactive region (i.e. the top 10 rows in this case) should not register Log::Comment(L"Click on the terminal"); @@ -765,7 +765,7 @@ namespace ControlUnitTests // at the point where outputting more lines causes circular incrementing for (auto i = 0; i < settings->HistorySize() + core->ViewHeight(); ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } VERIFY_ARE_EQUAL(scrollbackLength, core->_terminal->GetScrollOffset()); @@ -811,7 +811,7 @@ namespace ControlUnitTests VERIFY_ARE_EQUAL(expectedAnchor, core->_terminal->GetSelectionEnd()); Log::Comment(L"Output a line of text"); - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); Log::Comment(L"Verify the location of the selection"); // The selection should now be 1 row lower @@ -829,7 +829,7 @@ namespace ControlUnitTests VERIFY_ARE_EQUAL(scrollbackLength - 1, core->_terminal->GetScrollOffset()); Log::Comment(L"Output a line of text"); - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); Log::Comment(L"Verify the location of the selection"); // The selection should now be 1 row lower @@ -875,7 +875,7 @@ namespace ControlUnitTests Log::Comment(L"Output a line ant move the mouse a little to update the selection, all at once"); // Same as above. The viewport has moved, so the mouse is still over the // same character, even though it's at a new offset. - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); expectedAnchor.y -= 1; VERIFY_ARE_EQUAL(scrollbackLength - 3, core->_terminal->GetScrollOffset()); interactivity->PointerMoved(leftMouseDown, @@ -900,7 +900,7 @@ namespace ControlUnitTests // Output enough text for the selection to get pushed off the buffer for (auto i = 0; i < settings->HistorySize() + core->ViewHeight(); ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } // Verify that the selection got reset VERIFY_IS_FALSE(core->HasSelection()); @@ -954,7 +954,7 @@ namespace ControlUnitTests // Output enough text for view to start scrolling for (auto i = 0; i < core->ViewHeight() * 2; ++i) { - conn->WriteInput(L"Foo\r\n"); + conn->WriteInput(winrt_wstring_to_array_view(L"Foo\r\n")); } // Start checking output @@ -1018,7 +1018,7 @@ namespace ControlUnitTests modifiers, cursorPosition0.to_core_point()); // Flush it out. - conn->WriteInput(L"sentinel"); + conn->WriteInput(winrt_wstring_to_array_view(L"sentinel")); VERIFY_ARE_EQUAL(0u, expectedOutput.size(), L"Validate we drained all the expected output"); // This is the part as mentioned in GH#12719 diff --git a/src/cascadia/UnitTests_Control/MockConnection.h b/src/cascadia/UnitTests_Control/MockConnection.h index abbed69095..90758a4ce3 100644 --- a/src/cascadia/UnitTests_Control/MockConnection.h +++ b/src/cascadia/UnitTests_Control/MockConnection.h @@ -16,9 +16,9 @@ namespace ControlUnitTests void Initialize(const winrt::Windows::Foundation::Collections::ValueSet& /*settings*/){}; void Start() noexcept {}; - void WriteInput(const winrt::hstring& data) + void WriteInput(const winrt::array_view data) { - TerminalOutput.raise(data); + TerminalOutput.raise(winrt_array_to_wstring_view(data)); } void Resize(uint32_t /*rows*/, uint32_t /*columns*/) noexcept {} void Close() noexcept {} diff --git a/src/cascadia/inc/cppwinrt_utils.h b/src/cascadia/inc/cppwinrt_utils.h index 0f35d6eefc..851156ef48 100644 --- a/src/cascadia/inc/cppwinrt_utils.h +++ b/src/cascadia/inc/cppwinrt_utils.h @@ -176,6 +176,18 @@ protected: { \ }; +inline winrt::array_view winrt_wstring_to_array_view(const std::wstring_view& str) +{ +#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1). + return winrt::array_view(reinterpret_cast(str.data()), gsl::narrow(str.size())); +} + +inline std::wstring_view winrt_array_to_wstring_view(const winrt::array_view& str) noexcept +{ +#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1). + return { reinterpret_cast(str.data()), str.size() }; +} + // This is a helper method for deserializing a SAFEARRAY of // COM objects and converting it to a vector that // owns the extracted COM objects