I've created a very simple function in a powershell module which should capture a keystroke if a key is pressed within a short time window.
function get-mycommand{
$count=0
$sleepTimer=2 #in milliseconds
while ($count -le 100)
{
if($host.UI.RawUI.KeyAvailable) {
$key = $host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
return $key.character
} else {
$count
Write-Host $count
Start-Sleep -m $sleepTimer
}
}
return "fail"
}
function test-get-command{
$myvalue = get-mycommand
Write-Host 'return ' $myvalue
}
This works fine so long as I press a key quickly. If I don't press a key then it will count up to some random number, usually less than 20, and then stop updating. It won't do anything until I press a key and it never times out. When I do press a key, even after several minutes it will return with the character. I never see the 'fail' message at all.
Using a longer timer interval doesn't change anything.I've tried a sleeptimer of 2, 20 & 200. They all behave the same.
CodePudding user response:
Unfortunately, $host.UI.RawUI.KeyAvailable
can have false positives in Windows PowerShell as well as in PowerShell (Core) up to at least v7.2.0-preview.9 (current as of this writing).
On Windows, it seemingly thinks a key is available even when there isn't, so that
$key = $host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
is executed, which indefinitely waits for an actual keypress.- In a regular console window this seems to happen after a few iterations at the latest.
- In Windows Terminal, it seems to happen consistently on the first iteration, so that your function produces no output at all.
GitHub issue #959 seems relevant, although it relates to the
PSReadLine
module.- While unloading the module (
Remove-Module PSReadLine
) - which you wouldn't want to do in a interactive session - does fix the problem in regular console windows, it doesn't help in Windows Terminal.
- While unloading the module (
Workaround:
Replace $host.UI.RawUI.KeyAvailable
with [Console]::KeyAvailable
Note that this limits use to consoles (terminals), but your original code wouldn't work in the obsolescent ISE anyway, because $host.UI.RawUI.KeyAvailable
there seemingly never reports a pending keypress.