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
)