mirror of
https://github.com/microsoft/terminal.git
synced 2026-04-13 01:31:09 +00:00
#4015 requires sweeping changes in order to allow a migration of our buffer coordinates from `int16_t` to `int32_t`. This commit reduces the size of future commits by using type inference wherever possible, dropping the need to manually adjust types throughout the project later. As an added bonus this commit standardizes the alignment of cv qualifiers to be always left of the type (e.g. `const T&` instead of `T const&`). The migration to type inference with `auto` was mostly done using JetBrains Resharper with some manual intervention and the standardization of cv qualifier alignment using clang-format 14. ## References This is preparation work for #4015. ## Validation Steps Performed * Tests pass ✅
88 lines
3.4 KiB
C++
88 lines
3.4 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
#include "ConsoleInputReader.h"
|
|
#include "unicode.hpp"
|
|
|
|
ConsoleInputReader::ConsoleInputReader(HANDLE handle) :
|
|
_handle(handle)
|
|
{
|
|
_buffer.resize(BufferSize);
|
|
_convertedString.reserve(BufferSize);
|
|
}
|
|
|
|
void ConsoleInputReader::SetWindowSizeChangedCallback(std::function<void()> callback)
|
|
{
|
|
_windowSizeChangedCallback = std::move(callback);
|
|
}
|
|
|
|
std::optional<std::wstring_view> ConsoleInputReader::Read()
|
|
{
|
|
DWORD readCount{ 0 };
|
|
|
|
_convertedString.clear();
|
|
while (_convertedString.empty())
|
|
{
|
|
_buffer.resize(BufferSize);
|
|
auto succeeded =
|
|
ReadConsoleInputW(_handle, _buffer.data(), gsl::narrow_cast<DWORD>(_buffer.size()), &readCount);
|
|
if (!succeeded)
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
|
|
_buffer.resize(readCount);
|
|
for (auto it = _buffer.begin(); it != _buffer.end(); ++it)
|
|
{
|
|
if (it->EventType == WINDOW_BUFFER_SIZE_EVENT && _windowSizeChangedCallback)
|
|
{
|
|
_windowSizeChangedCallback();
|
|
}
|
|
else if (it->EventType == KEY_EVENT)
|
|
{
|
|
const auto& keyEvent = it->Event.KeyEvent;
|
|
if (keyEvent.bKeyDown || (!keyEvent.bKeyDown && keyEvent.wVirtualKeyCode == VK_MENU))
|
|
{
|
|
// Got a high surrogate at the end of the buffer
|
|
if (IS_HIGH_SURROGATE(keyEvent.uChar.UnicodeChar))
|
|
{
|
|
_highSurrogate.emplace(keyEvent.uChar.UnicodeChar);
|
|
continue; // we've consumed it -- only dispatch it if we get a low
|
|
}
|
|
|
|
if (IS_LOW_SURROGATE(keyEvent.uChar.UnicodeChar))
|
|
{
|
|
// No matter what we do, we want to destructively consume the high surrogate
|
|
if (const auto oldHighSurrogate{ std::exchange(_highSurrogate, std::nullopt) })
|
|
{
|
|
_convertedString.push_back(*_highSurrogate);
|
|
}
|
|
else
|
|
{
|
|
// If we get a low without a high surrogate, we've done everything we can.
|
|
// This is an illegal state.
|
|
_convertedString.push_back(UNICODE_REPLACEMENT);
|
|
continue; // onto the next event
|
|
}
|
|
}
|
|
|
|
// (\0 with a scancode is probably a modifier key, not a VT input key)
|
|
if (keyEvent.uChar.UnicodeChar != L'\0' || keyEvent.wVirtualScanCode == 0)
|
|
{
|
|
if (_highSurrogate) // non-destructive: we don't want to set it to nullopt needlessly for every character
|
|
{
|
|
// If we get a high surrogate *here*, we didn't find a low surrogate.
|
|
// This state is also illegal.
|
|
_convertedString.push_back(UNICODE_REPLACEMENT);
|
|
_highSurrogate.reset();
|
|
}
|
|
_convertedString.push_back(keyEvent.uChar.UnicodeChar);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return _convertedString;
|
|
}
|