-
Notifications
You must be signed in to change notification settings - Fork 5k
Fix KeyAvailable and ReadKey() in ConsolePal.Windows. #104984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Tagging subscribers to this area: @dotnet/area-system-console |
cc @adamsitnik |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mawosoft big thanks for your contribution! Could you please add the missing comments?
In the meantime, I am going to buy a new battery for my numpad keyboard so I can test all scenarios manually.
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mawosoft big thanks for addressing my feedback! I bought the battery for my numeric keyboard and was able to test the fix.
I've used following app for testing:
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine($"Output encoding is: {Console.OutputEncoding}");
bool callKeyAvailableFirst = args.Length > 0;
if (callKeyAvailableFirst) Console.WriteLine("The app will call Console.KeyAvailable first.");
ConsoleKeyInfo info = default;
do
{
if (callKeyAvailableFirst)
{
while (!Console.KeyAvailable) ;
}
info = Console.ReadKey(intercept: true);
Console.WriteLine($"Got: key: {info.Key}, mod: {info.Modifiers}, char: {info.KeyChar}");
} while (info.Key != ConsoleKey.Escape);
I've built your fork and was running the app using corerun:
git clone https://github.com/mawosoft/runtime.git --branch fix-consolepal-windows fix-consolepal-windows
# skipped for brevity
D:\projects\forks\fix-consolepal-windows\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\corerun.exe .\bin\Release\net8.0\KeyTests.dll keyAvailable
Bug 1: Inconsistent logic between KeyAvailable and ReadKey
This affects input via an Alt plus numpad number sequence
Unfortunately, the opposite happens, because ReadKey() silently eats these keys in anticipation of a subsequent synthesized
I've tried the following combination: "Alt+NumPad1" and the outcome is the same (nothing gets printed). @mawosoft am I missing something?
However, on most keyboards, those keys exist twice - once on the numpad, and once on the arrow pad and control pad.
Do you mean the Home, PageUp and others?
I've tried the following combination: "Alt+PageUp" (not form the numpad) and with your fix the output gets printed, without it, it does not 👍
With the new version and for I didn't test it with this build, but I'm using almost the same code in a proprietary app, and there both automated and manual tests show the expected result.
Yep. I've listed them in the comments now: Insert, PageUp/Down, Home/End, arrow keys. |
@adamsitnik Afterthought: You probably know this already, but just in case... If you run this in some kind of terminal app, e.g. the terminal inside Visual Studio, you may get different results depending on how the terminal app translates those keys. |
I am using Windows Terminal on Windows 11 x64
I've tried that with no luck:
Is there any chance you could try it locally? Your PR is overall an improvement, but it would be great co clarify that before merging. Here you can find what is required to build dotnet/runtime: https://github.com/dotnet/runtime/blob/main/docs/workflow/requirements/windows-requirements.md git clone https://github.com/mawosoft/runtime.git --branch fix-consolepal-windows fix-consolepal-windows
cd fix-consolepal-windows
.\build.cmd -c Release -subset clr+libs+libs.tests This should produce .\artifacts\bin\testhost\net9.0-windows-Release-x64\shared\Microsoft.NETCore.App\9.0.0\corerun.exe $pathToTestApp.dll Corerun is going to use the local build of dotnet/runtime. If you apply some changes to .\dotnet.cmd build .\src\libraries\System.Console\System.Console.sln -c Release
May I ask how have you implemented automated tests for it? Have you just mocked the input for the |
Can you run this in a regular ConHost? I should note that I did all testing on Win10 x64. Not sure if Win11 could throw a wrench into things. Anyway, with Windows Terminal or any other you basically get kbd input --> translate to virtual terminal sequence -> send VT sequence -> read and interpret VT sequence -> synthesize kbd events, which may not match the original input at all.
Not before Wednesday. I guess we have to postpone it then, as you suggested initially.
No, I used the native SendInput (user32) to run through most possible key combos in Conhost. It's a custom impl, not AppDriver or something. It's a bit tricky to sync properly, and while automated, I only ran them locally, not in a CI environment. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you run this in a regular ConHost?
I did. It's the same. FWIW the following condition is true and false
is being returned, but there is no follow up event that this comment mentions:
runtime/src/libraries/System.Console/src/System/ConsolePal.Windows.cs
Lines 237 to 243 in 05240f1
// Possible Alt+NumPad unicode key sequence which surfaces by a subsequent | |
// Alt keyup event with uChar (see above). | |
ConsoleKey key = (ConsoleKey)keyCode; | |
if (key is >= ConsoleKey.NumPad0 and <= ConsoleKey.NumPad9) | |
{ | |
// Alt+Numpad keys (as received if NumLock is on). | |
return false; |
@mawosoft I've spent more time testing your code. It solves one of the two described problems and does not seem to introduce any new ones, so I believe it's worth merging now. If you find some free time and a way to fix the other issue, please send a follow up PR.
// Possible Alt+NumPad unicode key sequence which surfaces by a subsequent | ||
// Alt keyup event with uChar (see above). | ||
ConsoleKey key = (ConsoleKey)keyCode; | ||
if (key is >= ConsoleKey.NumPad0 and <= ConsoleKey.NumPad9) | ||
{ | ||
// Alt+Numpad keys (as received if NumLock is on). | ||
return false; | ||
} | ||
|
||
// If Numlock is off, the physical Numpad keys are received as navigation or | ||
// function keys. The EnhancedKey flag tells us whether these virtual keys | ||
// really originate from the numpad, or from the arrow pad / control pad. | ||
if ((keyState & ControlKeyState.EnhancedKey) == 0) | ||
{ | ||
// If the EnhancedKey flag is not set, the following virtual keys originate | ||
// from the numpad. | ||
if (key is ConsoleKey.Clear or ConsoleKey.Insert) | ||
{ | ||
// Skip Clear and Insert (usually mapped to Numpad 5 and 0). | ||
return false; | ||
} | ||
|
||
if (key is >= ConsoleKey.PageUp and <= ConsoleKey.DownArrow) | ||
{ | ||
// Skip PageUp/Down, End/Home, and arrow keys. | ||
return false; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the indentation is one level too deep. It's not worth starting the CI for this change, this can be fixed in a follow-up PR.
// Possible Alt+NumPad unicode key sequence which surfaces by a subsequent | |
// Alt keyup event with uChar (see above). | |
ConsoleKey key = (ConsoleKey)keyCode; | |
if (key is >= ConsoleKey.NumPad0 and <= ConsoleKey.NumPad9) | |
{ | |
// Alt+Numpad keys (as received if NumLock is on). | |
return false; | |
} | |
// If Numlock is off, the physical Numpad keys are received as navigation or | |
// function keys. The EnhancedKey flag tells us whether these virtual keys | |
// really originate from the numpad, or from the arrow pad / control pad. | |
if ((keyState & ControlKeyState.EnhancedKey) == 0) | |
{ | |
// If the EnhancedKey flag is not set, the following virtual keys originate | |
// from the numpad. | |
if (key is ConsoleKey.Clear or ConsoleKey.Insert) | |
{ | |
// Skip Clear and Insert (usually mapped to Numpad 5 and 0). | |
return false; | |
} | |
if (key is >= ConsoleKey.PageUp and <= ConsoleKey.DownArrow) | |
{ | |
// Skip PageUp/Down, End/Home, and arrow keys. | |
return false; | |
} | |
} | |
// Possible Alt+NumPad unicode key sequence which surfaces by a subsequent | |
// Alt keyup event with uChar (see above). | |
ConsoleKey key = (ConsoleKey)keyCode; | |
if (key is >= ConsoleKey.NumPad0 and <= ConsoleKey.NumPad9) | |
{ | |
// Alt+Numpad keys (as received if NumLock is on). | |
return false; | |
} | |
// If Numlock is off, the physical Numpad keys are received as navigation or | |
// function keys. The EnhancedKey flag tells us whether these virtual keys | |
// really originate from the numpad, or from the arrow pad / control pad. | |
if ((keyState & ControlKeyState.EnhancedKey) == 0) | |
{ | |
// If the EnhancedKey flag is not set, the following virtual keys originate | |
// from the numpad. | |
if (key is ConsoleKey.Clear or ConsoleKey.Insert) | |
{ | |
// Skip Clear and Insert (usually mapped to Numpad 5 and 0). | |
return false; | |
} | |
if (key is >= ConsoleKey.PageUp and <= ConsoleKey.DownArrow) | |
{ | |
// Skip PageUp/Down, End/Home, and arrow keys. | |
return false; | |
} | |
} |
@adamsitnik Thanks for the tests. If the follow-up event (the Alt keyup with the unicode char) doesn't appear, it indicates something driver-related. Is your numeric keyboard by any chance just a separate number block used in addition to the default keyboard? Do the Alt Numpad keys produce 'special' chars in other apps, e.g. in a plain old cmd.exe? An alternative would be to use the On-Screen Keyboard where you can enable the numpad section regardless of your physical keyboard layout. |
It is. To be exact it's Microsoft Sculpt Ergonomic Desktop
They don't.
I've tried that and the effect was the same. (to be exact I've enabled NumLock in the options, then started the app, pressed the right alt and then selected 1 from NumPad). |
@adamsitnik Well, its definitely some problem with your system/keyboard. I managed to run a test via CI that simulates pressing Alt+Numpad1: |
Contributes to #102425.