Cancelling Console.ReadKey() using code, not in-program

1.3k Views Asked by At

So let's use this code:

Console.ReadKey(true);
//Cancel the ReadKey prompt
Console.WriteLine("ReadKey was cancelled.");

Upon running the program, the only thing that should happen is that the output ReadKey was cancelled. should appear. How can I achieve this? Is it even possible?

Thanks in advance.

3

There are 3 best solutions below

2
Kayla On

You can't cancel ReadKey, unless you abort the thread. (Force closing the program.)

I check if a key is available using the Console.KeyAvailable property before calling ReadKey.

0
Jim On

The only way I can see you could do this is using System.Windows.Forms.SendKeys.Send(), however this doesn't work 'out of the box' for a console app because they don't manage windows messages, if you try it you'll see the exception. There could be a way to implement this yourself using windows API's.

0
Flydog57 On

Nearly 10 years later, how about doing it async? You still need to do it on another thread if you want to make it cancelable, but...

If you want a fully cancelable async version, here goes:

public static async Task<char?> ReadConsoleCharAsync(CancellationToken cancellationToken, bool intercept = false)
{
    // if there is a key available, return it without waiting
    //  (or dispatching work to the thread queue)
    if (Console.KeyAvailable)
    {
        var read = Console.ReadKey(intercept);
        return read.KeyChar;
    }

    // otherwise
    var result = await Task.Run<char?>(async () =>
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            await Task.Delay(100);
            if (Console.KeyAvailable)
            {
                var read = Console.ReadKey(intercept);
                return read.KeyChar;
            }
        }
        cancellationToken.ThrowIfCancellationRequested();
        return null;
    }, cancellationToken);
    return result;
}

I return a char, but you could return the full ConsoleKeyInfo if you wanted.

If you want a non-cancellable async version, it's a bit simpler:

public static async Task<char> ReadConsoleCharAsync(bool intercept = false)
{
    // if there is a key available, return it without waiting
    //  (or dispatching work to the thread queue)
    if (Console.KeyAvailable)
    {
        var read = Console.ReadKey(intercept);
        return read.KeyChar;
    }

    // otherwise
    var result = await Task.Run<char>(async () =>
    {
        while (!Console.KeyAvailable)
        {
            await Task.Delay(100);
        }

        var read = Console.ReadKey(intercept);
        return read.KeyChar;
        
    });
    return result;
}

In both cases, I check to see if there's a character to read before doing anything else. If there is one, I return it. If not, I dispatch work to the threadpool using Task.Run. I need to return a char? in the cancellable case; I need to return something when it gets cancelled (so it's a null)