Console.ReadKey 在 C# 中收到 Escape 键时如何修复控制台输出?
How to fix Console output when Console.ReadKey receives an Escape key in C#?
我想从面向 .NET Core 3.1 的 C# 控制台应用程序读取用户输入。
在某些情况下,当提示用户输入时,用户可以选择通过按Escape键来取消输入和相关操作。
以下脚本适用于空字符串(用户只需按 Enter 即可)和普通用户输入(用户输入字符并使用 Enter[ 确认) =52=]).
但是有一个问题:当用户取消输入时(点击Escape),后面Console.WriteLine
的第一个字符被抑制,Console.Write
什么都不输出。观察表明,必须输出换行符才能恢复 Console.WriteLine
和 Console.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;
}
}
}
几年前 ("the old days"),由于还提交了控制字符,我不得不 double/triple 读取键盘输入。但是,在注册 Escape 键后,输入缓冲区中没有任何内容。
如何解决与按 Escape 键相关的输入取消问题?
示例 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打印字符,而是手动打印。
这是修复 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);
}
我想从面向 .NET Core 3.1 的 C# 控制台应用程序读取用户输入。 在某些情况下,当提示用户输入时,用户可以选择通过按Escape键来取消输入和相关操作。
以下脚本适用于空字符串(用户只需按 Enter 即可)和普通用户输入(用户输入字符并使用 Enter[ 确认) =52=]).
但是有一个问题:当用户取消输入时(点击Escape),后面Console.WriteLine
的第一个字符被抑制,Console.Write
什么都不输出。观察表明,必须输出换行符才能恢复 Console.WriteLine
和 Console.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;
}
}
}
几年前 ("the old days"),由于还提交了控制字符,我不得不 double/triple 读取键盘输入。但是,在注册 Escape 键后,输入缓冲区中没有任何内容。
如何解决与按 Escape 键相关的输入取消问题?
示例 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打印字符,而是手动打印。
这是修复 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);
}