OS Version: Debian GNU/Linux 8 (jessie) x86_64-linux-gnu
Tested .NET versions:
Summary
When using the Console.KeyAvailable property in order to implement non-blocking console input, the property is not being set to true when Backspace is pressed. The same code (see example) when being run on Windows works as intended.
Example
Here is a simple example which reproduces the issue on my machine:
ConsoleKeyInfo key = new ConsoleKeyInfo();
do
{
if (Console.KeyAvailable)
{
key = Console.ReadKey(true);
Console.WriteLine($"You pressed: {key.Key}");
}
System.Threading.Thread.Sleep(100);
} while (key.Key != ConsoleKey.Escape);
The following code, however, works as intended both on Linux and Windows (the difference that the IO is blocking here, which is unacceptable for my use case, sadly) - the Backspace key is being handled:
ConsoleKeyInfo key = new ConsoleKeyInfo();
do
{
key = Console.ReadKey(true);
Console.WriteLine($"You pressed: {key.Key}");
} while (key.Key != ConsoleKey.Escape);
I'm currently implementing a ncurses-like terminal GUI library, and I'm running my logic in a loop, so this issue is blocking me from implementing input handling for text input.
If any additional info is needed, I'll happily provide it. Thanks for creating such an awesome platform to develop on :wink:
Thanks @RaZeR-RBI. Any interest in debugging a bit? The more we understand the more likely a fix can happen sooner.
Cc @tmds
This is fixed by https://github.com/dotnet/corefx/pull/35621.
@RaZeR-RBI this isn't yet in a 3.0 preview release, but you can try using a daily build from https://github.com/dotnet/core-sdk/blob/master/README.md#installers-and-binaries
This is fixed by dotnet/corefx#35621.
@tmds, what was the issue and how did that fix it?
@tmds, what was the issue and how did that fix it?
Console.KeyAvailable doesn't return stdin is readable when the user presses backspace.
Before https://github.com/dotnet/corefx/pull/35621 we were in canonical mode while the user was pressing the key (during the Thread.Sleep). In canonical mode the backspace gets processed by the terminal.
This is fixed by dotnet/corefx#35621.
@RaZeR-RBI this isn't yet in a 3.0 preview release, but you can try using a daily build from https://github.com/dotnet/core-sdk/blob/master/README.md#installers-and-binaries
Downloaded the daily build, everything works now. Thanks!
In canonical mode the backspace gets processed by the terminal.
Got it. That's what I was missing.
For those who are looking for a workaround for the current version, here is a sample code (without error handling and other stuff, you should get the idea):
private struct pollfd
{
public int fd;
public short events;
public short revents;
};
private const int POLLIN = 0x0001;
private const int STDIN_FILENO = 0;
[DllImport("libc")]
private static extern int poll(ref pollfd fds, uint nfds, int timeout);
// call this at application start
public static void SetTerminalAttributes() =>
Process.Start("stty", "-echo -icanon min 1 time 0").WaitForExit();
// call this when needed
public static bool KeyAvailable()
{
var fd = new pollfd()
{
fd = STDIN_FILENO,
events = POLLIN
};
var result = poll(ref fd, 1, 0);
return result > 0;
}
It can also be used as a workaround for a related dotnet/corefx#25916 issue. Of course, this will mess up with children process echoing (I don't use them in my project, though), as stated here. And of course, don't forget to restore terminal settings at application exit :wink:
Thanks @tmds, and @RaZer-RBI for confirming.
Most helpful comment
Console.KeyAvailable doesn't return stdin is readable when the user presses backspace.
Before https://github.com/dotnet/corefx/pull/35621 we were in canonical mode while the user was pressing the key (during the Thread.Sleep). In canonical mode the backspace gets processed by the terminal.