I want to write a function in PowerShell 7 to wait the user to press a key or a key combination (such as Alt+Ctrl+D). There are two options I can choose: The Console.ReadKey() method in .net core, and $host.UI.RawUI.ReadKey() method in PowerShell.
I have tested these two methods. The Console.ReadKey() method works very well, but the $host.UI.RawUI.ReadKey() method has a strange behavior: It will capture a not-really-pressed "Enter" key (key code: 13).
The code (in a .ps1 script file, for testing the method):
using namespace System.Threading
using namespace System.Management.Automation.Host
Write-Host "Content before waiting keys."
Write-Host "Begin waiting keys..... Press 'Esc' to quit."
while($true)
{
while(-not $host.UI.RawUI.KeyAvailable)
{
Write-Host '.' -NoNewLine
[Thread]::Sleep(1000)
}
# No matter any combination of values of the ReadKeyOptions enum,
# the behavior of capturing not-really-pressed Enter key is the same.
$ki = $host.UI.RawUI.ReadKey("NoEcho, IncludeKeyUp")
Write-Host "[$($ki.ControlKeyState)]" -ForegroundColor Yellow
$altPressed = (($ki.ControlKeyState -band [ControlKeyStates]::LeftAltPressed) -gt 0) -or
(($ki.ControlKeyState -band [ControlKeyStates]::RightAltPressed) -gt 0)
$ctrlPressed = (($ki.ControlKeyState -band [ControlKeyStates]::LeftCtrlPressed) -gt 0) -or
(($ki.ControlKeyState -band [ControlKeyStates]::RightCtrlPressed) -gt 0)
$shiftPressed = (($ki.ControlKeyState -band [ControlKeyStates]::ShiftPressed) -gt 0)
$keyState = $ki.KeyDown ? "Down" : "UP"
Write-Host "`nGot a key:"
Write-Host "`tkey: $($ki.Character)" # Char
Write-Host "`tkey code: $($ki.VirtualKeyCode)" # int.
Write-Host "`tAlt: $altPressed"
Write-Host "`tCtrl: $ctrlPressed"
Write-Host "`tShift: $shiftPressed"
Write-Host "`tkey state: $keyState"
if($ki.VirtualKeyCode -eq 27)
{
break
}
}
Write-Host "`nContent after waiting keys."
After I run the script in PowerShell 7 console, before I pressed any key, I got:
Content before waiting keys.
Begin waiting keys..... Press 'Esc' to quit.
.[NumLockOn, EnhancedKey]
Got a key:
key:
key code: 13
Alt: False
Ctrl: False
Shift: False
key state: UP
...[NumLockOn]
Even I call the $host.UI.RawUI.FlushInputBuffer() method before the while loop, or before the calling of the ReadKey() method, this strange behavior will still occur.
If I use $host.UI.RawUI.ReadKey() method, this behavior will break the working of my function, make it cannot handle a single Enter key correctly, and it cannot be used to block until any key is pressed because it will capture an "Enter" key even though the user hasn't pressed the Enter key.
The Console.ReadKey() method hasn't this problem.
Why?