diff --git a/src/terminal/adapter/InteractDispatch.cpp b/src/terminal/adapter/InteractDispatch.cpp index 09cc2c970c..8ed76b9d7c 100644 --- a/src/terminal/adapter/InteractDispatch.cpp +++ b/src/terminal/adapter/InteractDispatch.cpp @@ -62,15 +62,38 @@ void InteractDispatch::WriteString(const std::wstring_view string) { if (!string.empty()) { - const auto codepage = _api.GetOutputCodePage(); - InputEventQueue keyEvents; + const auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation(); +#pragma warning(suppress : 26429) // Symbol 'inputBuffer' is never tested for nullness, it can be marked as not_null (f.23). + const auto inputBuffer = gci.GetActiveInputBuffer(); - for (const auto& wch : string) + // The input *may* be keyboard input in which case we must call CharToKeyEvents. + // + // However, it could also be legitimate VT sequences (e.g. a bracketed paste sequence). + // If we called `InputBuffer::Write` with those, we would end up indirectly + // calling `TerminalInput::HandleKey` and "double encode" the sequence. + // The effect of this is noticeable with the German keyboard layout, for instance, + // where the [ key maps to AltGr+8, and we fail to map it back to [ later. + // + // It's worth noting that all of this is bad design in either case. + // The way it should work is that we write INPUT_RECORDs and Strings as-is into the + // InputBuffer, and only during retrieval they're converted into one or the other. + // This prevents any kinds of double-encoding issues. + if (inputBuffer->IsInVirtualTerminalInputMode()) { - CharToKeyEvents(wch, codepage, keyEvents); + inputBuffer->WriteString(string); } + else + { + const auto codepage = _api.GetOutputCodePage(); + InputEventQueue keyEvents; - WriteInput(keyEvents); + for (const auto& wch : string) + { + CharToKeyEvents(wch, codepage, keyEvents); + } + + inputBuffer->Write(keyEvents); + } } }