diff --git a/src/host/inputBuffer.cpp b/src/host/inputBuffer.cpp index abdfed1961f..184670ffb1d 100644 --- a/src/host/inputBuffer.cpp +++ b/src/host/inputBuffer.cpp @@ -602,6 +602,27 @@ size_t InputBuffer::Write(const std::span& inEvents) } } +void InputBuffer::WriteString(const std::wstring_view& text) +try +{ + if (text.empty()) + { + return; + } + + const auto initiallyEmptyQueue = _storage.empty(); + + _writeString(text); + + if (initiallyEmptyQueue && !_storage.empty()) + { + ServiceLocator::LocateGlobals().hInputEvent.SetEvent(); + } + + WakeUpReadersWaitingForData(); +} +CATCH_LOG() + // This can be considered a "privileged" variant of Write() which allows FOCUS_EVENTs to generate focus VT sequences. // If we didn't do this, someone could write a FOCUS_EVENT_RECORD with WriteConsoleInput, exit without flushing the // input buffer and the next application will suddenly get a "\x1b[I" sequence in their input. See GH#13238. @@ -828,21 +849,7 @@ void InputBuffer::_HandleTerminalInputCallback(const TerminalInput::StringType& return; } - for (const auto& wch : text) - { - if (wch == UNICODE_NULL) - { - // Convert null byte back to input event with proper control state - const auto zeroKey = OneCoreSafeVkKeyScanW(0); - uint32_t ctrlState = 0; - WI_SetFlagIf(ctrlState, SHIFT_PRESSED, WI_IsFlagSet(zeroKey, 0x100)); - WI_SetFlagIf(ctrlState, LEFT_CTRL_PRESSED, WI_IsFlagSet(zeroKey, 0x200)); - WI_SetFlagIf(ctrlState, LEFT_ALT_PRESSED, WI_IsFlagSet(zeroKey, 0x400)); - _storage.push_back(SynthesizeKeyEvent(true, 1, LOBYTE(zeroKey), 0, wch, ctrlState)); - continue; - } - _storage.push_back(SynthesizeKeyEvent(true, 1, 0, 0, wch, 0)); - } + _writeString(text); if (!_vtInputShouldSuppress) { @@ -856,6 +863,25 @@ void InputBuffer::_HandleTerminalInputCallback(const TerminalInput::StringType& } } +void InputBuffer::_writeString(const std::wstring_view& text) +{ + for (const auto& wch : text) + { + if (wch == UNICODE_NULL) + { + // Convert null byte back to input event with proper control state + const auto zeroKey = OneCoreSafeVkKeyScanW(0); + uint32_t ctrlState = 0; + WI_SetFlagIf(ctrlState, SHIFT_PRESSED, WI_IsFlagSet(zeroKey, 0x100)); + WI_SetFlagIf(ctrlState, LEFT_CTRL_PRESSED, WI_IsFlagSet(zeroKey, 0x200)); + WI_SetFlagIf(ctrlState, LEFT_ALT_PRESSED, WI_IsFlagSet(zeroKey, 0x400)); + _storage.push_back(SynthesizeKeyEvent(true, 1, LOBYTE(zeroKey), 0, wch, ctrlState)); + continue; + } + _storage.push_back(SynthesizeKeyEvent(true, 1, 0, 0, wch, 0)); + } +} + TerminalInput& InputBuffer::GetTerminalInput() { return _termInput; diff --git a/src/host/inputBuffer.hpp b/src/host/inputBuffer.hpp index ec7cd75b082..019c6e628bd 100644 --- a/src/host/inputBuffer.hpp +++ b/src/host/inputBuffer.hpp @@ -58,6 +58,7 @@ class InputBuffer final : public ConsoleObjectHeader size_t Prepend(const std::span& inEvents); size_t Write(const INPUT_RECORD& inEvent); size_t Write(const std::span& inEvents); + void WriteString(const std::wstring_view& text); void WriteFocusEvent(bool focused) noexcept; bool WriteMouseEvent(til::point position, unsigned int button, short keyState, short wheelDelta); @@ -96,6 +97,7 @@ class InputBuffer final : public ConsoleObjectHeader void _WriteBuffer(const std::span& inRecords, _Out_ size_t& eventsWritten, _Out_ bool& setWaitEvent); bool _CoalesceEvent(const INPUT_RECORD& inEvent) noexcept; void _HandleTerminalInputCallback(const Microsoft::Console::VirtualTerminal::TerminalInput::StringType& text); + void _writeString(const std::wstring_view& text); #ifdef UNIT_TESTING friend class InputBufferTests; diff --git a/src/host/outputStream.cpp b/src/host/outputStream.cpp index a48e189f00d..24adc7a613f 100644 --- a/src/host/outputStream.cpp +++ b/src/host/outputStream.cpp @@ -33,24 +33,11 @@ ConhostInternalGetSet::ConhostInternalGetSet(_In_ IIoProvider& io) : // - void ConhostInternalGetSet::ReturnResponse(const std::wstring_view response) { - InputEventQueue inEvents; - - // generate a paired key down and key up event for every - // character to be sent into the console's input buffer - for (const auto& wch : response) - { - // This wasn't from a real keyboard, so we're leaving key/scan codes blank. - auto keyEvent = SynthesizeKeyEvent(true, 1, 0, 0, wch, 0); - inEvents.push_back(keyEvent); - keyEvent.Event.KeyEvent.bKeyDown = false; - inEvents.push_back(keyEvent); - } - // TODO GH#4954 During the input refactor we may want to add a "priority" input list // to make sure that "response" input is spooled directly into the application. // We switched this to an append (vs. a prepend) to fix GH#1637, a bug where two CPR // could collide with each other. - _io.GetActiveInputBuffer()->Write(inEvents); + _io.GetActiveInputBuffer()->WriteString(response); } // Routine Description: