Listen for key press in .NET console app

后端 未结 9 1338
隐瞒了意图╮
隐瞒了意图╮ 2020-11-22 05:02

How can I continue to run my console application until a key press (like Esc is pressed?)

I\'m assuming its wrapped around a while loop. I don\'t like

9条回答
  •  孤街浪徒
    2020-11-22 05:35

    Addressing cases that some of the other answers don't handle well:

    • Responsive: direct execution of keypress handling code; avoids the vagaries of polling or blocking delays
    • Optionality: global keypress is opt-in; otherwise the app should exit normally
    • Separation of concerns: less invasive listening code; operates independently of normal console app code.

    Many of the solutions on this page involve polling Console.KeyAvailable or blocking on Console.ReadKey. While it's true that the .NET Console is not very cooperative here, you can use Task.Run to move towards a more modern Async mode of listening.

    The main issue to be aware of is that, by default, your console thread isn't set up for Async operation--meaning that, when you fall out of the bottom of your main function, instead of awaiting Async completions, your AppDoman and process will end. A proper way to address this would be to use Stephen Cleary's AsyncContext to establish full Async support in your single-threaded console program. But for simpler cases, like waiting for a keypress, installing a full trampoline may be overkill.

    The example below would be for a console program used in some kind of iterative batch file. In this case, when the program is done with its work, normally it should exit without requiring a keypress, and then we allow an optional key press to prevent the app from exiting. We can pause the cycle to examine things, possibly resuming, or use the pause as a known 'control point' at which to cleanly break out of the batch file.

    static void Main(String[] args)
    {
        Console.WriteLine("Press any key to prevent exit...");
        var tHold = Task.Run(() => Console.ReadKey(true));
    
        // ... do your console app activity ...
    
        if (tHold.IsCompleted)
        {
    #if false   // For the 'hold' state, you can simply halt forever...
            Console.WriteLine("Holding.");
            Thread.Sleep(Timeout.Infinite);
    #else                            // ...or allow continuing to exit
            while (Console.KeyAvailable)
                Console.ReadKey(true);     // flush/consume any extras
            Console.WriteLine("Holding. Press 'Esc' to exit.");
            while (Console.ReadKey(true).Key != ConsoleKey.Escape)
                ;
    #endif
        }
    }
    

提交回复
热议问题