.NET Framework и .NET Core используют функцию Win32 ReadConsoleInput
для питания Console.ReadKey()
, которая одновременно считывает бит данных из буфера консоли.
Напротив, использование Console.In
или Console.OpenStandardInput()
вызывает функцию Win32 GetStdHandle
, а затем оборачивает дескриптор в закрытый класс __ConsoleStream
, который внутренне использует функции ReadFile
или ReadConsole
Win32, в зависимости от на несколько вещей.
По умолчанию поток консоли настроен на ENABLE_ECHO_INPUT
, который отображает каждый введенный вами символ обратно на экран. Для этого необходимо установить ENABLE_LINE_INPUT
.
Документация для ENABLE_LINE_INPUT
гласит:
Функция ReadFile
или ReadConsole
возвращается только при чтении символа возврата каретки. Если этот режим отключен, функции возвращаются, когда доступны один или несколько символов.
Поэтому, если нам нужен поток, который использует ReadFile
или ReadConsole
, нам нужен дескриптор консоли с отключенными этими двумя флагами. Это можно сделать так:
static class Win32Console
{
public static Stream GetConsoleStreamWithImmediateInput()
{
var handle = GetStdHandle(STD_INPUT_HANDLE);
if (handle.IsInvalid) throw new Win32Exception();
try
{
if (!GetConsoleMode(handle, out var mode)) throw new Win32Exception();
mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
if (!SetConsoleMode(handle, mode)) throw new Win32Exception();
}
catch
{
handle.Close();
throw;
}
return new FileStream(handle, FileAccess.Read);
}
const int STD_INPUT_HANDLE = -10;
const int ENABLE_LINE_INPUT = 0x0002;
const int ENABLE_ECHO_INPUT = 0x0004;
[DllImport("Kernel32.dll", SetLastError = true)]
static extern SafeFileHandle GetStdHandle(int nStdHandle);
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetConsoleMode(SafeFileHandle hConsoleHandle, out int mode);
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetConsoleMode(SafeFileHandle hConsoleHandle, int mode);
}
Это даст вам поток, который позволит вам читать по одному символу за раз, даже если целая строка еще не введена.
Обратите внимание, что это не будет печатать каждый символ на экране. Если вы все еще хотите этого, вам придется повторить это самостоятельно.