粘贴文本时出现Console.ReadKey意外行为-一次输入多个键
本文关键字:一次 输入 文本 Console 意外 ReadKey | 更新日期: 2023-09-27 18:24:13
调用Console.ReadKey()
,并在提示下对长度>1的任何剪贴板文本执行PASTE(编辑->粘贴)(假设为"Hello World!")。
我刚刚发现,出乎意料的是,在随后调用Console.ReadKey()时,却没有向用户显示提示!相反,粘贴文本中的后续字符将被读取。。。没有提示!
底线:要使用ReadKey,我需要确保(非常确定)下次调用ReadKey时,它确实会给用户一个提示。目前,这使得ReadKey无法用于此类关键场景
看起来没有任何方法可以禁用它,或者简单地清除输入但尚未读取的值。
在我的情况下,这给简单的控制台应用程序带来了严重的错误,我在那里循环寻找单词"R"代表"RUN",或者任何"E"代表"END"。由于在这个时候我会提示输入文件路径,因此对于已经使用过它的用户来说,在发生意外时粘贴文件路径是相当容易的。问题是(!!!),如果该文件路径包含'r',它将立即运行。
using System;
namespace Practise1
{
class Program
{
static void Main()
{
RunDialogue2();
}
public static void RunDialogue()
{
while (true) {
Console.WriteLine("Type 'R' to RUN, 'E' to END");
ConsoleKey key = Console.ReadKey().Key;
Console.WriteLine("'r'n");
switch (key) {
case ConsoleKey.R:
Console.WriteLine("RUN! ENGINES BLAST OFF!");
BlastOff();
break;
case ConsoleKey.E:
Console.WriteLine("FINISHED");
return;
default:
Console.WriteLine("INVALID ENTRY, TRY AGAIN");
// we *thought* this would pick up bad input, but not pasted text!
break;
}
}
}
public static void RunDialogue2()
{
while (true) {
Console.WriteLine("Type 'R' to RUN, 'E' to END");
ConsoleKey key = Console.ReadKey().Key;
Console.WriteLine("'r'n");
switch (key) {
case ConsoleKey.R:
Console.WriteLine("RUN! ENGINES BLAST OFF!");
Console.WriteLine("We blasted off at: " + DateTime.UtcNow);
//BlastOff();
break;
case ConsoleKey.E:
Console.WriteLine("FINISHED");
return;
default:
Console.WriteLine("INVALID ENTRY, TRY AGAIN");
// we *thought* this would pick up bad input, but not pasted text!
break;
}
}
}
}
}
如果你有"查理的!"在剪贴板中粘贴,这是输出。注意如何获得多个RUN!一切都是无意的。非常可怕的是,这有多糟糕,对我来说意味着我们永远不能依赖ReadKey作为一种可实现的输入方法,尤其是当我们认为我们正在验证输入时:
Type 'R' to RUN, 'E' to END
C
INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
h
INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
a
INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
r
RUN! ENGINES BLAST OFF!
We blasted off at: 7/21/2013 11:24:36 PM
Type 'R' to RUN, 'E' to END
l
INVALID ENTRY, TRY AGAIN
Type 'R' to RUN, 'E' to END
e
FINISHED
我知道一个解决方案是使用Console.ReadLine,但只需按一下键就可以立即进行交互的能力要快乐得多。这种奇怪的行为有什么办法吗?
像这样的东西将通过readkey消除常量读取:
public static void RunDialogue()
{
while (true)
{
Console.WriteLine("Type 'R' to RUN, 'E' to END");
ConsoleKey key = Console.ReadKey().Key;
Console.WriteLine("'r'n");
switch (key)
{
case ConsoleKey.R:
Console.WriteLine("RUN! ENGINES BLAST OFF!");
BlastOff();
break;
case ConsoleKey.E:
Console.WriteLine("FINISHED");
return;
default:
Console.WriteLine("INVALID ENTRY, TRY AGAIN");
// we *thought* this would pick up bad input, but not pasted text!
break;
}
Console.In.ReadToEnd();
}
}
虽然这将消除原始帖子中的直接问题,但一个更完整的解决方案是读取并忽略输入流的其余部分,而不将其返回到屏幕,这样的方法会起作用:
public static void RunDialogue()
{
while (true)
{
Console.WriteLine("Type 'R' to RUN, 'E' to END");
ConsoleKey key = Console.ReadKey().Key;
Console.WriteLine("'r'n");
switch (key)
{
case ConsoleKey.R:
Console.WriteLine("RUN! ENGINES BLAST OFF!");
BlastOff();
break;
case ConsoleKey.E:
Console.WriteLine("FINISHED");
return;
default:
Console.WriteLine("INVALID ENTRY, TRY AGAIN");
// we *thought* this would pick up bad input, but not pasted text!
break;
}
while (Console.KeyAvailable)
{
Console.ReadKey(true);
}
}
}
我很感谢@tinstaafl的回答,它通过检查Console.KeyAvailable
揭示了关键的解决方案。虽然我肯定并公平地将答案作为解决方案,但以下是最终解决方案,涵盖了您必须完全验证输入是否真的只有一个字符的场景。
public static ConsoleKey ReadKeySingle(bool intercept = false, ConsoleKey errorKey = ConsoleKey.Clear)
{
ConsoleKey key = Console.ReadKey(intercept).Key;
while (Console.KeyAvailable) {
Console.ReadKey(true);
key = errorKey;
}
return key;
}
然后像这样使用(单行更改):
public static void RunDialogue()
{
while (true) {
Console.WriteLine("Type 'R' to RUN, 'E' to END");
// KEY! Call ReadKeySingle instead
ConsoleKey key = ReadKeySingle(); // Console.ReadKey().Key; //!!!
Console.WriteLine("'r'n");
switch (key) {
case ConsoleKey.R:
Console.WriteLine("RUN! ENGINES BLAST OFF!");
Console.WriteLine("We blasted off at: " + DateTime.UtcNow);
// BlastOff();
break;
case ConsoleKey.E:
Console.WriteLine("FINISHED");
return;
default:
Console.WriteLine("INVALID ENTRY, TRY AGAIN");
// we *thought* this would pick up bad input, but not pasted text!
break;
}
}
}