runtime: Implement an async version of the blocking System.Console.ReadKey
In the PowerShell extension for Visual Studio Code, we have an async REPL loop where we’d love to be able to await Console.ReadKeyAsync()
rather than blocking on Console.ReadKey()
.
The current implementation is problematic because we need cancellation support. We have tried to work around the blocking ReadKey() call by using KeyAvailable() but there is a known issue with KeyAvailable() causing the characters to be echo’d to the screen on Linux which is not desirable when you’re asking for a user’s password.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 15
- Comments: 20 (6 by maintainers)
Commits related to this issue
- Make Debug.Print(string) behavior consistent with .NET Framework (#25036) * Debug.Print should call Debug.WriteLine - to behave similar to .NET Framework * temporarily disable tests - Waitin... — committed to Dotnet-GitSync-Bot/corefx by maryamariyan 5 years ago
- Make Debug.Print(string) behavior consistent with .NET Framework (#25036) * Debug.Print should call Debug.WriteLine - to behave similar to .NET Framework * temporarily disable tests - Waitin... — committed to dotnet/corefx by maryamariyan 5 years ago
Hi all, I wanted to revive this old thread with some context - especially since there was a ton of great work done in .NET Core 3.0 in the Console API space that have made our life a lot easier.
I work on PowerShell Editor Services which is the backend to the PowerShell extension for vscode.
We do a lot of weird things with the Console API in order to offer an “Integrated Console" experience in vscode. Here’s where we are at with the current Console APIs.
Good news!
In .NET Core 3.0, there was some incredible work done on the Console API which silently:
Context
Initially, that implementation’s sole purpose was to disable echo. However, recently we added support for PSReadLine which replaces the default PowerShell prompt with its own, and uses Console.ReadKey under the hood… or a delate that you can set via Reflection that PSReadLine will use instead of Console.ReadKey.
This is what we do. We have our “less than ideal” implementation as mentioned above.
What’s missing…
Because of this less than ideal implementation, imperfections show up… like how you can see the typing when you paste:
Having a proper ReadKeyAsync within .NET can help this experience greatly.
What would ReadKeyAsync look like?
Ideally, all we need is a
ReadKeyAsync
that has the same behavior ofReadKey
today, only it accepts aCancellationToken
.When that
CancellationToken
is canceled, theReadKeyAsync
is cancelled so that anotherReadKey
/ReadKeyAsync
can be run on another thread, for example, and not be blocked.Please let me know if there’s any additional context I can give! I’m happy to supply it.
This could go hand in hand with the new async main introduced in C# 7.1. Not knowing enough here but could this not be implimented using an i/o completion port or something similar (I know it would need to be different on linux)
Thanks.
Thanks, Tom.
I considered that, but have some concerns:
That said, if we did do the work to make our epoll/kqueues support more general-purpose, and validate that it has no negative impact on sockets, it could be used for positive gains elsewhere, e.g. using it to improve how we do waiting and cancellation in anonymous pipes, using it to aid FileStream when it’s wrapped around a SafeFileHandle for something other than a disk file, etc.
So, if you have the cycles to prototype it and prove it out, it’d be interesting to see the results.
In the actual code
KeyAvailable
isn’t called directly, but instead a separate method is called that pollsKeyAvailable
with a frequency determined by how recently a key was pressed. The actual wait happens in that method, not through the cancellation token. (I know you were trying to simplify the example, but that’s the important bit in this scenario).The very simplified version of the code that is running in a right click paste scenario would be sorta like this:
How would ReadKeyAsync be implemented? It wouldn’t just be blocking a different thread?