using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; namespace System { public static class AsyncConsole { /// private enum StdHandle { STD_INPUT_HANDLE = -10, STD_OUTPUT_HANDLE = -11, STD_ERROR_HANDLE = -12 } /// [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(int nStdHandle); /// [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CancelIoEx(IntPtr handle, IntPtr lpOverlapped); public static async Task 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 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 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 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); }); } } }