From 3487a13be3478e940bce2108181893f0774f324e Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Thu, 14 Apr 2022 10:57:13 -0700 Subject: [PATCH] Respect cancellation in `ReadOneOrMoreKeys()` Because .NET's . `Console.ReadKey()` is uncancellable, when a hosting application cancels PSReadLine, it also has to send a key press to get `ReadKey` to return. In this case, we want to ignore the key press (and a user certainly would not be expecting it, as `ReadLine` has already been canceled). --- PSReadLine/ReadLine.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/PSReadLine/ReadLine.cs b/PSReadLine/ReadLine.cs index bc7bf21ac..2e8f21a2d 100644 --- a/PSReadLine/ReadLine.cs +++ b/PSReadLine/ReadLine.cs @@ -91,7 +91,7 @@ bool IPSConsoleReadLineMockableMethods.RunspaceIsRemote(Runspace runspace) return runspace?.ConnectionInfo != null; } - private void ReadOneOrMoreKeys() + private void ReadOneOrMoreKeys(CancellationToken cancellationToken) { _readkeyStopwatch.Restart(); while (_console.KeyAvailable) @@ -144,6 +144,14 @@ private void ReadOneOrMoreKeys() while (_charMap.KeyAvailable) { var key = PSKeyInfo.FromConsoleKeyInfo(_charMap.ReadKey()); + if (cancellationToken.IsCancellationRequested) + { + // If PSReadLine is running under a host that can cancel it, the + // cancellation will come at a time when ReadKey is stuck waiting for input. + // The next key press will be used to force it to return, and so we want to + // discard this key since we were already canceled. + continue; + } _lastNKeys.Enqueue(key); _queuedKeys.Enqueue(key); } @@ -160,7 +168,7 @@ private void ReadKeyThreadProc() break; var localCancellationToken = _singleton._cancelReadCancellationToken; - ReadOneOrMoreKeys(); + ReadOneOrMoreKeys(localCancellationToken); if (localCancellationToken.IsCancellationRequested) { continue;