public async Task <ConsoleKeyInfo> ReadKeyAsync(bool intercept, CancellationToken cancellationToken) { await s_readKeyHandle.WaitAsync(cancellationToken); // I tried to replace this library with a call to `stty -echo`, but unfortunately // the library also sets up allowing backspace to trigger `Console.KeyAvailable`. InputEcho.Disable(); try { while (!await WaitForKeyAvailableAsync(cancellationToken)) { ; } } finally { InputEcho.Enable(); s_readKeyHandle.Release(); } await s_stdInHandle.WaitAsync(cancellationToken); try { return(System.Console.ReadKey(intercept)); } finally { s_stdInHandle.Release(); } }
private static async Task WaitForKeyAvailableAsync(CancellationToken cancellationToken) { InputEcho.Disable(); try { while (!Console.KeyAvailable) { await Task.Delay(50, cancellationToken); } } finally { InputEcho.Enable(); } }
public ConsoleKeyInfo ReadKey(bool intercept, CancellationToken cancellationToken) { s_readKeyHandle.Wait(cancellationToken); // On Unix platforms System.Console.ReadKey has an internal lock on stdin. Because // of this, if a ReadKey call is pending in one thread and in another thread // Console.CursorLeft is called, both threads block until a key is pressed. // To work around this we wait for a key to be pressed before actually calling Console.ReadKey. // However, any pressed keys during this time will be echoed to the console. To get around // this we use the UnixConsoleEcho package to disable echo prior to waiting. if (Utils.IsPS6) { InputEcho.Disable(); } try { // The WaitForKeyAvailable delegate switches between a long delay between waits and // a short timeout depending on how recently a key has been pressed. This allows us // to let the CPU enter low power mode without compromising responsiveness. while (!WaitForKeyAvailable(cancellationToken)) { ; } } finally { if (Utils.IsPS6) { InputEcho.Disable(); } s_readKeyHandle.Release(); } // A key has been pressed, so aquire a lock on our internal stdin handle. This is done // so any of our calls to cursor position API's do not release ReadKey. s_stdInHandle.Wait(cancellationToken); try { return(System.Console.ReadKey(intercept)); } finally { s_stdInHandle.Release(); } }