我想在 PowerShell 7 中编写一个函数来等待用户按下某个键或组合键(例如 Alt+Ctrl+D)。我可以选择两个选项:.net 核心中的 Console.ReadKey() 方法和 PowerShell 中的 $host.UI.RawUI.ReadKey() 方法。
这两种方法我都测试过了。Console.ReadKey() 方法工作得很好,但是 $host.UI.RawUI.ReadKey() 方法有一个奇怪的行为:它会捕获一个没有真正按下的“Enter”键(键码:13)。
代码(在 .ps1 脚本文件中,用于测试方法):
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."
在 PowerShell 7 控制台中运行脚本后,在按下任何键之前,我得到:
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]
即使我在 while 循环之前调用$host.UI.RawUI.FlushInputBuffer()方法,或者在调用 ReadKey() 方法之前,仍然会出现这种奇怪的行为。
如果我使用 $host.UI.RawUI.ReadKey() 方法,此行为将破坏我的函数的工作,使其无法正确处理单个 Enter 键,并且在按下任何键之前它不能用于阻止,因为它会即使用户没有按下 Enter 键,也会捕获“Enter”键。
Console.ReadKey() 方法没有这个问题。
为什么?