当 Console.ReadKey 在 C# 中收到 Escape 键时,如何修复控制台输出? [英] How to fix Console output when Console.ReadKey receives an Escape key in C#?

查看:22
本文介绍了当 Console.ReadKey 在 C# 中收到 Escape 键时,如何修复控制台输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从面向 .NET Core 3.1 的 C# 控制台应用程序读取用户输入.在某些情况下,当提示用户输入时,用户可以随时按Escape键选择取消输入和相关操作.

以下脚本适用于空字符串(用户只按 Enter 而没有别的)和普通用户输入(用户输入字符并用 Enter 确认).

但是有一个问题:当用户取消输入(点击Escape)时,后面的Console.WriteLine的第一个字符被抑制,而Console.Write 不输出任何内容.观察表明,必须输出换行符才能恢复 Console.WriteLineConsole.Write 预期行为.

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

使用系统;使用 System.Text;使用 System.Text.RegularExpressions;命名空间 ConsoleApp1{内部类程序{内部 const ConsoleColor DefaultConsoleForegroundColor = ConsoleColor.Gray;内部 const ConsoleColor DefaultConsoleInputForegroundColor = ConsoleColor.White;内部静态只读 Regex WhitespaceRegex = new Regex(@"s{2,}", RegexOptions.Compiled | RegexOptions.CultureInvariant);内部静态只读编码 UTF8NoBomEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);私有静态无效 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) ??@世界";Console.WriteLine(@"你好,{0}!", firstName);ConsoleReadKey(message: @"按任意键退出...", hideInput: true, messageColor: DefaultConsoleInputForegroundColor);}内部静态字符串 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){字符串输入字符串;//在提示前打印可选消息(同一行).Console.ForegroundColor = messageColor;if (!string.IsNullOrWhiteSpace(message))Console.Write(消息);//获取用户的输入.Console.ForegroundColor = inputColor;StringBuilder inputBuilder = new StringBuilder();而(真){ConsoleKeyInfo inputKey = Console.ReadKey(hideInput);if (inputKey.Key == ConsoleKey.Enter){inputString = inputBuilder.ToString();休息;}else if (treatEscapeAsCancel && inputKey.Key == ConsoleKey.Escape){输入字符串 = 空;休息;}别的inputBuilder.Append(inputKey.KeyChar);}//可选的输入修改.如果(输入字符串!= null){如果(修剪输入)inputString = inputString.Trim();如果(normalizeWhitespace)WhitespaceRegex.Replace(inputString, @" ");if (treatEmptyOrWhitespaceAsNull && string.IsNullOrWhiteSpace(inputString))输入字符串 = 空;}//重置前景色.Console.ForegroundColor = DefaultConsoleForegroundColor;if (addLineBreak)Console.WriteLine();返回输入字符串;}内部静态 ConsoleKeyInfo ConsoleReadKey(string message = null, bool hideInput = false, bool addLineBreak = true,ConsoleColor messageColor = DefaultConsoleForegroundColor,ConsoleColor inputColor = DefaultConsoleInputForegroundColor){ConsoleKeyInfo 键;//在提示前打印可选消息(同一行).Console.ForegroundColor = messageColor;if (!string.IsNullOrWhiteSpace(message))Console.Write(消息);//获取用户的输入.Console.ForegroundColor = inputColor;key = Console.ReadKey(hideInput);//重置前景色.Console.ForegroundColor = DefaultConsoleForegroundColor;if (addLineBreak)Console.WriteLine();返回键;}}}

回到几个时代(过去"),由于还提交了控制字符,我不得不双读/三读键盘输入.但是,Escape 键注册后,输入缓冲区中没有任何内容.

如何解决与按 Escape 键相关的输入取消问题?

<小时>

示例 1(正确)

输入你的名字:Test你好,测试!按任何一个键退出...

示例 2(错误)

输入您的名字:Test<Escape>你好,世界!按任何一个键退出...

示例 3(正确)

输入您的名字:你好,世界!按任何一个键退出...

示例 4(错误)

输入你的名字:你好,世界!按任何一个键退出...

解决方案

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

这是修复 ConsoleReadLine 函数的代码.

while (true){ConsoleKeyInfo inputKey = Console.ReadKey(true);if (inputKey.Key == ConsoleKey.Enter){inputString = inputBuilder.ToString();休息;}else if (treatEscapeAsCancel && inputKey.Key == ConsoleKey.Escape){输入字符串 = 空;休息;}别的inputBuilder.Append(inputKey.KeyChar);如果(!隐藏输入)Console.Write(inputKey.KeyChar);}

I want to read user inputs from a C# console application targeting .NET Core 3.1. In some situations, the user shall have the choice to cancel the input and the related operation by pressing the Escape key at any point of time when the user is prompted for input.

The following script works for empty strings (user just hit Enter and nothing else), and normal user input (user enters characters and confirms with Enter).

But there is a issue: When the user cancels the input (hits Escape), the first character of the following Console.WriteLine is suppressed, and Console.Write outputs nothing. Observations shows, that an line break must be outputted to restore Console.WriteLine and Console.Write expected behaviour.

Another issue directly related to this is that when I inject an additional line break, in the case of a normal input, I receive 2 line breaks, and in case of a canceled input, I receive 1 line break.

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;
        }
    }
}

Back a couple of ages ("the old days"), I had to double/triple read the keyboard input due to the control character was also submitted. However, there is nothing in the input buffer after the Escape key was registered.

How to fix the input cancellation issues related to pressing the Escape key?


Example 1 (correct)

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

Example 2 (wrong)

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

Example 3 (correct)

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

Example 4 (wrong)

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

解决方案

Thanks to @jscarle, the solution is to not allow Console.ReadKey to print characters, but do it manually.

Here is the code, that fixes the ConsoleReadLine function.

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);
}

这篇关于当 Console.ReadKey 在 C# 中收到 Escape 键时,如何修复控制台输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆