using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace System
{
public static class AsyncConsole
{
/// <see href="https://docs.microsoft.com/en-us/windows/console/getstdhandle"/>
private enum StdHandle
{
STD_INPUT_HANDLE = -10,
STD_OUTPUT_HANDLE = -11,
STD_ERROR_HANDLE = -12
}
/// <see href="https://docs.microsoft.com/en-us/windows/console/getstdhandle"/>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);
/// <see href="https://docs.microsoft.com/en-us/windows/desktop/FileIO/cancelioex-func"/>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped);
public static async Task<ConsoleKeyInfo> ReadKey(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
using (RegisterReadCancel(cancellationToken))
{
return await Task.Run(() =>
{
try
{
return Console.ReadKey();
}
catch (InvalidOperationException inner)
{
throw new OperationCanceledException("Operation cancelled.", inner, cancellationToken);
}
}, cancellationToken);
}
}
public static async Task<ConsoleKeyInfo> ReadKey(bool intercept, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
using (RegisterReadCancel(cancellationToken))
{
return await Task.Run(() =>
{
try
{
return Console.ReadKey(intercept);
}
catch (InvalidOperationException inner)
{
throw new OperationCanceledException("Operation cancelled.", inner, cancellationToken);
}
}, cancellationToken);
}
}
public static async Task<string> ReadLine(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
using (RegisterReadCancel(cancellationToken))
{
return await Task.Run(() =>
{
try
{
return Console.ReadLine();
}
catch (InvalidOperationException inner)
{
throw new OperationCanceledException("Operation cancelled.", inner, cancellationToken);
}
}, cancellationToken);
}
}
public static async Task<int> Read(CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
using (RegisterReadCancel(cancellationToken))
{
return await Task.Run(() =>
{
try
{
return Console.Read();
}
catch (InvalidOperationException inner)
{
throw new OperationCanceledException("Operation cancelled.", inner, cancellationToken);
}
}, cancellationToken);
}
}
private static CancellationTokenRegistration RegisterReadCancel(CancellationToken cancellationToken)
{
return cancellationToken.Register(() =>
{
IntPtr handle = GetStdHandle((int)StdHandle.STD_INPUT_HANDLE);
CancelIoEx(handle, IntPtr.Zero);
});
}
}
}
Comments