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

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

问题描述

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

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.

以下脚本适用于空字符串(用户只需按 Enter 键,而没有其他操作),以及正常的用户输入(用户输入字符并用 Enter 确认).

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).

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

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.

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

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

前两个时代(旧时代"),由于还提交了控制字符,我不得不翻倍/翻了三遍键盘输入.但是,注册 Escape 键后,输入缓冲区中什么都没有.

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.

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

How to fix the input cancellation issues related to pressing the Escape 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...

推荐答案

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

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

下面是代码,该代码修复了 ConsoleReadLine 函数.

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键时,如何修复Console输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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