C# 如何使用标准输入流而不是Console.ReadKey

C# 如何使用标准输入流而不是Console.ReadKey,c#,console,C#,Console,如何使用Stream.Read()而不是Console.ReadKey() while(true) { var c=Console.In.Read(); 控制台写入线(“输入:+c”); } 但该值仅在输入整行时返回 我不想使用Console.ReadKey()来实现这个函数。因为这不利于测试 那么,如何通过流监控用户的密钥输入呢?或通过其他方式。(尽可能不使用接口时).NET Framework和.NET Core使用Win32函数ReadConsoleInput为Console.ReadK

如何使用Stream.Read()而不是Console.ReadKey()

while(true)
{
var c=Console.In.Read();
控制台写入线(“输入:+c”);
}
但该值仅在输入整行时返回

我不想使用Console.ReadKey()来实现这个函数。因为这不利于测试


那么,如何通过流监控用户的密钥输入呢?或通过其他方式。(尽可能不使用接口时)

.NET Framework和.NET Core使用Win32函数
ReadConsoleInput
Console.ReadKey()
供电,该函数一次从控制台缓冲区读取一位数据

相反,使用
Console.In
Console.OpenStandardInput()
调用Win32函数
GetStdHandle
,然后将句柄包装到私有类
\uu ConsoleStream
,该类内部使用
ReadFile
ReadConsole
Win32函数,具体取决于几件事情

默认情况下,控制台流配置有
ENABLE_ECHO_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);
}
这将为您提供一个流,允许您一次读取一个字符,即使尚未输入整行


请注意,这不会将每个字符打印到屏幕上。如果您仍然需要,您必须自己回显它。

.NET Framework和.NET Core使用Win32函数
ReadConsoleInput
启动
Console.ReadKey()
,它一次从控制台缓冲区读取一点数据

相反,使用
Console.In
Console.OpenStandardInput()
调用Win32函数
GetStdHandle
,然后将句柄包装到私有类
\uu ConsoleStream
,该类内部使用
ReadFile
ReadConsole
Win32函数,具体取决于几件事情

默认情况下,控制台流配置有
ENABLE_ECHO_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);
}
这将为您提供一个流,允许您一次读取一个字符,即使尚未输入整行


请注意,这不会将每个字符打印到屏幕上。如果您仍然希望这样做,您必须自己回显它。

我想问的是,它可能无法在某些用户的计算机上工作,因为我无法保证对控制台应用程序运行的环境进行精确控制。请尝试。不过,这些都是自Windows 2000以来的标准Windows功能,因此我不希望出现任何奇怪的不兼容。我想问的是,它可能无法在某些用户的计算机上工作,因为我无法保证对控制台应用程序运行的环境进行精确控制。请尝试。不过,这些都是自Windows 2000以来的标准Windows函数,所以我不希望出现任何奇怪的不兼容。