粘贴文本时出现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,但只需按一下键就可以立即进行交互的能力要快乐得多。这种奇怪的行为有什么办法吗?

粘贴文本时出现Console.ReadKey意外行为-一次输入多个键

像这样的东西将通过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;
                }
            }
        }