2

我想在 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() 方法没有这个问题。

为什么?

4

1 回答 1

1

这是一个已知错误$Host.UI.RawUI.ReadKey 无缘无故获得额外的输入键

作为一种解决方法,您可以这样做(这不漂亮:))

$ki = $host.UI.RawUI.ReadKey("NoEcho, IncludeKeyUp")
$ki = $host.UI.RawUI.ReadKey("NoEcho, IncludeKeyUp")

$ki.Character会返回null,你仍然可以使用它[char]$ki.VirtualKeyCode

于 2020-11-06T09:19:54.867 回答