Adam
Adam

Reputation: 632

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

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.

Upvotes: 0

Views: 1429

Answers (3)

Flydog57
Flydog57

Reputation: 7111

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)

Upvotes: 0

Jim
Jim

Reputation: 21

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.

Upvotes: 1

Kayla
Kayla

Reputation: 485

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.

Upvotes: 3

Related Questions