如何修复C#中Console.ReadKey收到Escape键时的Console输出?

问题描述 投票:0回答:1

我想从一个以.NET Core 3.1为目标的C#控制台应用程序中读取用户输入的内容。逃生 键,当用户被提示输入时。

下面的脚本适用于空字符串(用户只需按下 进入 而不是其他),以及正常的用户输入(用户输入字符,并用 进入).

但是有一个问题。当用户取消输入(点击 逃生),下面的第一个字符是 Console.WriteLine 被压制,而 Console.Write 什么也不输出。观察表明,必须输出一个换行符才能恢复 Console.WriteLineConsole.Write 的预期行为。

另一个与此直接相关的问题是,当我注入一个额外的换行符时,在正常输入的情况下,我收到2个换行符,而在取消输入的情况下,我收到1个换行符。

using System;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApp1
{
    internal class Program
    {
        internal const ConsoleColor DefaultConsoleForegroundColor = ConsoleColor.Gray;
        internal const ConsoleColor DefaultConsoleInputForegroundColor = ConsoleColor.White;

        internal static readonly Regex WhitespaceRegex = new Regex(@"\s{2,}", RegexOptions.Compiled | RegexOptions.CultureInvariant);

        internal static readonly Encoding UTF8NoBomEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);

        private static void Main()
        {
            Console.InputEncoding = UTF8NoBomEncoding;
            Console.OutputEncoding = UTF8NoBomEncoding;
            Console.Title = @"ConsoleApp1";
            Console.TreatControlCAsInput = true;
            Console.Clear();
            Console.ResetColor();
            Console.ForegroundColor = DefaultConsoleForegroundColor;

            string firstName = ConsoleReadLine(message: @"Enter your first name: ", treatEmptyOrWhitespaceAsNull: true) ?? @"World";
            Console.WriteLine(@"Hello, {0}!", firstName);

            ConsoleReadKey(message: @"Press any key to exit...", hideInput: true, messageColor: DefaultConsoleInputForegroundColor);
        }

        internal static string ConsoleReadLine(string message = null, bool hideInput = false, bool treatEscapeAsCancel = true,
                                               bool trimInput = true, bool normalizeWhitespace = true,
                                               bool treatEmptyOrWhitespaceAsNull = false, bool addLineBreak = true,
                                               ConsoleColor messageColor = DefaultConsoleForegroundColor,
                                               ConsoleColor inputColor = DefaultConsoleInputForegroundColor)
        {
            string inputString;

            // Print optional message before the prompt (same line).
            Console.ForegroundColor = messageColor;
            if (!string.IsNullOrWhiteSpace(message))
                Console.Write(message);

            // Get input from user.
            Console.ForegroundColor = inputColor;
            StringBuilder inputBuilder = new StringBuilder();
            while (true)
            {
                ConsoleKeyInfo inputKey = Console.ReadKey(hideInput);
                if (inputKey.Key == ConsoleKey.Enter)
                {
                    inputString = inputBuilder.ToString();
                    break;
                }
                else if (treatEscapeAsCancel && inputKey.Key == ConsoleKey.Escape)
                {
                    inputString = null;
                    break;
                }
                else
                    inputBuilder.Append(inputKey.KeyChar);
            }

            // Optional input modifications.
            if (inputString != null)
            {
                if (trimInput)
                    inputString = inputString.Trim();
                if (normalizeWhitespace)
                    WhitespaceRegex.Replace(inputString, @" ");
                if (treatEmptyOrWhitespaceAsNull && string.IsNullOrWhiteSpace(inputString))
                    inputString = null;
            }

            // Reset foreground color.
            Console.ForegroundColor = DefaultConsoleForegroundColor;

            if (addLineBreak)
                Console.WriteLine();

            return inputString;
        }

        internal static ConsoleKeyInfo ConsoleReadKey(string message = null, bool hideInput = false, bool addLineBreak = true,
                                                      ConsoleColor messageColor = DefaultConsoleForegroundColor,
                                                      ConsoleColor inputColor = DefaultConsoleInputForegroundColor)
        {
            ConsoleKeyInfo key;

            // Print optional message before the prompt (same line).
            Console.ForegroundColor = messageColor;
            if (!string.IsNullOrWhiteSpace(message))
                Console.Write(message);

            // Get input from user.
            Console.ForegroundColor = inputColor;
            key = Console.ReadKey(hideInput);

            // Reset foreground color.
            Console.ForegroundColor = DefaultConsoleForegroundColor;

            if (addLineBreak)
                Console.WriteLine();

            return key;
        }
    }
}

早在几年前("旧时代"),由于控制字符也被提交,我不得不双倍读取键盘输入。然而,在输入缓冲区中,在输入字符之后没有任何东西。逃生 键被注册。

如何解决按下 逃生 键?


例1 (纠正)

Enter your first name: Test<Enter>
Hello, Test!
Press any key to exit...

例2 (错的)

Enter your first name: Test<Escape>
ello, World!
Press any key to exit...

例3 (纠正)

Enter your first name: <Enter>
Hello, World!
Press any key to exit...

例4 (错的)

Enter your first name: <Escape>
ello, World!
Press any key to exit...
c# input .net-core console-application
1个回答
0
投票

感谢@jscarle,解决方案是不允许Console.ReadKey打印字符,而是手动操作。

这里是代码,它修复了 ConsoleReadLine 职能。

while (true)
{
    ConsoleKeyInfo inputKey = Console.ReadKey(true);
    if (inputKey.Key == ConsoleKey.Enter)
    {
        inputString = inputBuilder.ToString();
        break;
    }
    else if (treatEscapeAsCancel && inputKey.Key == ConsoleKey.Escape)
    {
        inputString = null;
        break;
    }
    else
        inputBuilder.Append(inputKey.KeyChar);

    if (!hideInput)
        Console.Write(inputKey.KeyChar);
}
© www.soinside.com 2019 - 2024. All rights reserved.