From 8a9af94095883bd5ea726ee64b6eec059d60810a Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Tue, 5 Dec 2023 02:53:55 +0100 Subject: [PATCH] Disable win32 input mode on exit (#16408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When ConPTY exits it should attempt to restore the state as it was before it started. This is particularly important for the win32 input mode sequences, as Linux shells don't know what to do with it. Related to #16343 ## Validation Steps Performed * Replace conhost with this * Launch a Win32 application inside WSL * Exit that application * Shell prompt doesn't get filled with win32 input mode sequences ✅ (cherry picked from commit 70e51ae28d305ff9cd7430984119648b9f0b04ef) Service-Card-Id: 91246943 Service-Version: 1.19 --- .../ConptyRoundtripTests.cpp | 2 +- src/renderer/vt/VtSequences.cpp | 19 ------------------- src/renderer/vt/invalidate.cpp | 8 ++++++++ src/renderer/vt/state.cpp | 6 ++++-- src/renderer/vt/vtrenderer.hpp | 5 ----- src/terminal/adapter/adaptDispatch.cpp | 10 ++++++++-- 6 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp b/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp index cf15e3ba191..f7948e5c59d 100644 --- a/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp +++ b/src/cascadia/UnitTests_TerminalCore/ConptyRoundtripTests.cpp @@ -1201,7 +1201,7 @@ void ConptyRoundtripTests::PassthroughHardReset() // Write a Hard Reset VT sequence to the host, it should come through to the Terminal // along with a DECSET sequence to re-enable win32 input and focus events. expectedOutput.push_back("\033c"); - expectedOutput.push_back("\033[?9001;1004h"); + expectedOutput.push_back("\033[?9001h\033[?1004h"); hostSm.ProcessString(L"\033c"); const auto termSecondView = term->GetViewport(); diff --git a/src/renderer/vt/VtSequences.cpp b/src/renderer/vt/VtSequences.cpp index 1b728aae500..612d3c06d06 100644 --- a/src/renderer/vt/VtSequences.cpp +++ b/src/renderer/vt/VtSequences.cpp @@ -476,25 +476,6 @@ using namespace Microsoft::Console::Render; return _Write(isReversed ? "\x1b[7m" : "\x1b[27m"); } -// Method Description: -// - Send a sequence to the connected terminal to request win32-input-mode from -// them. This will enable the connected terminal to send us full INPUT_RECORDs -// as input. If the terminal doesn't understand this sequence, it'll just -// ignore it. -// Arguments: -// - -// Return Value: -// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write. -[[nodiscard]] HRESULT VtEngine::_RequestWin32Input() noexcept -{ - return _Write("\x1b[?9001h"); -} - -[[nodiscard]] HRESULT VtEngine::_RequestFocusEventMode() noexcept -{ - return _Write("\x1b[?1004h"); -} - // Method Description: // - Send a sequence to the connected terminal to switch to the alternate or main screen buffer. // Arguments: diff --git a/src/renderer/vt/invalidate.cpp b/src/renderer/vt/invalidate.cpp index 7ef59bc03b0..8f80d3eb8ea 100644 --- a/src/renderer/vt/invalidate.cpp +++ b/src/renderer/vt/invalidate.cpp @@ -126,6 +126,14 @@ CATCH_RETURN(); // - S_OK [[nodiscard]] HRESULT VtEngine::PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept { + // This must be kept in sync with RequestWin32Input(). + // It ensures that we disable the modes that we requested on startup. + // Linux shells for instance don't understand the win32-input-mode 9001. + // + // This can be here, instead of being appended at the end of this final rendering pass, + // because these two states happen to have no influence on the caller's VT parsing. + std::ignore = _Write("\033[?9001l\033[?1004l"); + *pForcePaint = true; return S_OK; } diff --git a/src/renderer/vt/state.cpp b/src/renderer/vt/state.cpp index 8408ee3aeb6..df35691a361 100644 --- a/src/renderer/vt/state.cpp +++ b/src/renderer/vt/state.cpp @@ -525,11 +525,13 @@ void VtEngine::SetTerminalCursorTextPosition(const til::point cursor) noexcept // - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write. HRESULT VtEngine::RequestWin32Input() noexcept { + // On startup we request the modes we require for optimal functioning + // (namely win32 input mode and focus event mode). + // // It's important that any additional modes set here are also mirrored in // the AdaptDispatch::HardReset method, since that needs to re-enable them // in the connected terminal after passing through an RIS sequence. - RETURN_IF_FAILED(_RequestWin32Input()); - RETURN_IF_FAILED(_RequestFocusEventMode()); + RETURN_IF_FAILED(_Write("\033[?9001h\033[?1004h")); _Flush(); return S_OK; } diff --git a/src/renderer/vt/vtrenderer.hpp b/src/renderer/vt/vtrenderer.hpp index 15de6e0e760..094bebec385 100644 --- a/src/renderer/vt/vtrenderer.hpp +++ b/src/renderer/vt/vtrenderer.hpp @@ -80,8 +80,6 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT WriteTerminalUtf8(const std::string_view str) noexcept; [[nodiscard]] virtual HRESULT WriteTerminalW(const std::wstring_view str) noexcept = 0; void SetTerminalOwner(Microsoft::Console::VirtualTerminal::VtIo* const terminalOwner); - void BeginResizeRequest(); - void EndResizeRequest(); void SetResizeQuirk(const bool resizeQuirk); void SetPassthroughMode(const bool passthrough) noexcept; void SetLookingForDSRCallback(std::function pfnLooking) noexcept; @@ -208,11 +206,8 @@ namespace Microsoft::Console::Render [[nodiscard]] HRESULT _RequestCursor() noexcept; [[nodiscard]] HRESULT _ListenForDSR() noexcept; - [[nodiscard]] HRESULT _RequestWin32Input() noexcept; [[nodiscard]] HRESULT _SwitchScreenBuffer(const bool useAltBuffer) noexcept; - [[nodiscard]] HRESULT _RequestFocusEventMode() noexcept; - [[nodiscard]] virtual HRESULT _MoveCursor(const til::point coord) noexcept = 0; [[nodiscard]] HRESULT _RgbUpdateDrawingBrushes(const TextAttribute& textAttributes) noexcept; [[nodiscard]] HRESULT _16ColorUpdateDrawingBrushes(const TextAttribute& textAttributes) noexcept; diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 85582542980..31edacae21d 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -1917,7 +1917,13 @@ bool AdaptDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param, con return !_api.IsConsolePty(); case DispatchTypes::ModeParams::W32IM_Win32InputMode: _terminalInput.SetInputMode(TerminalInput::Mode::Win32, enable); - return !_PassThroughInputModes(); + // ConPTY requests the Win32InputMode on startup and disables it on shutdown. When nesting ConPTY inside + // ConPTY then this should not bubble up. Otherwise, when the inner ConPTY exits and the outer ConPTY + // passes the disable sequence up to the hosting terminal, we'd stop getting Win32InputMode entirely! + // It also makes more sense to not bubble it up, because this mode is specifically for INPUT_RECORD interop + // and thus entirely between a PTY's input records and its INPUT_RECORD-aware VT-aware console clients. + // Returning true here will mark this as being handled and avoid this. + return true; default: // If no functions to call, overall dispatch was a failure. return false; @@ -3097,7 +3103,7 @@ bool AdaptDispatch::HardReset() if (stateMachine.FlushToTerminal()) { auto& engine = stateMachine.Engine(); - engine.ActionPassThroughString(L"\033[?9001;1004h"); + engine.ActionPassThroughString(L"\033[?9001h\033[?1004h"); } } return true;