在PowerShell中读取单个按键

时间:2014-09-10 14:47:59

标签: powershell input

使用PowerShell,我想在发生按键时读取按键的值,而无需用户按Enter键。例如,如果用户按下“1”,我希望PowerShell脚本在没有“输入”的情况下立即对选择做出反应。

我的研究已发现ReadKey,

  

$ input = $ Host.UI.RawUI.ReadKey('IncludeKeyDown');

但是ReadKey在字符串中返回的信息比我要求的要多得多:

  

72,H,0,真

虽然我可以从这个字符串解析按键,但我更喜欢更直接的选项。是否存在?

4 个答案:

答案 0 :(得分:9)

也许你可以澄清一下 - 但是ReadKey返回一个KeyInfo对象而不是一个字符串。 KeyInfo包含VirtualKeyCode,Character,ControlKeyState和KeyDown成员 - 输出字符串中的所有字段。事实上,看起来PowerShell刚刚在输出示例中调用了.ToString()方法。您可能希望查看Character属性以查找所需的角色。请考虑以下示例,其中我按 1

$key = $Host.UI.RawUI.ReadKey()
if ($key.Character -eq '1') {
  "Pressed 1"
}

答案 1 :(得分:1)

关于$Host.UI.RawUI.ReadKey('IncludeKeyDown');的使用 Goyuix answer应标记为正确的答案。

我发现$Host.UI.RawUI.ReadKey相当长,想要使用[console]

但这是一个糟糕的决定。这是一个警告。有些人可能知道如何正确使用它。

按键会让您按某些键

  • 1 = D1
  • NumPad上的
  • 1 = NumPad1
  • a = A(仅限大写字母)
  • - = OemMinus(是啊

此外Key属性[console]::ReadKey$key = [console]::ReadKey() if ($key.Key -eq 'D1') { "Pressed 1" } 相似。

datasource.online(false);
datasource.read();
datasource.online(true);

答案 2 :(得分:0)

这肯定会做你想要的。

接受单个字符作为输入并具有验证性。

  • 我使用菜单系统使用PowerShell运行程序和实用程序。
  • 当我击中一个角色时,它会直接指向该选项并运行而无需按Enter键

我已经提取了输入和菜单系统的要点,并给出了一些示例菜单项。

请注意:有两种模式可以运行

模式1:使用读取主机,需要Enter,然后在ISE中运行。使用它进行故障排除/构建

模式2:使用ReadKey,无需输入,不在ISE中运行...您将需要在PowerShell命令行中运行它。下面的代码当前处于模式2。

注释/取消注释行以更改模式

##Formatting Variables
$fgc1 = 'cyan'
$fgc2 = 'white'
$indent = '  '

Function MainMenu {
    CLS
    Write-Host "###############"
    Write-Host "## Main Menu ##"
    Write-Host "###############"
    Write-Host -NoNewLine "$indent" "A " -ForegroundColor 'red'; Write-Host "== Options A" -ForegroundColor $fgc2
    Write-Host -NoNewLine "$indent" "B " -ForegroundColor 'red'; Write-Host "== Options B" -ForegroundColor $fgc2
    Write-Host -NoNewLine "$indent" "C " -ForegroundColor 'red'; Write-Host "== Options C" -ForegroundColor $fgc2
    Write-Host -NoNewLine "$indent" "D " -ForegroundColor 'red'; Write-Host "== Options D" -ForegroundColor $fgc2
    Write-Host -NoNewLine "$indent" "E " -ForegroundColor 'red'; Write-Host "== Options E" -ForegroundColor $fgc2
    Write-Host -NoNewLine "$indent" "F " -ForegroundColor 'red'; Write-Host "== Options F" -ForegroundColor $fgc2
    Write-Host -NoNewLine "$indent" "G " -ForegroundColor 'red'; Write-Host "== Options G" -ForegroundColor $fgc2
    Write-Host ""

    #This gives you a way to set the current function as a variable.  The Script: is there because the variable has to
    #be available OUTSIDE the function.  This way you can make it back to the menu that you came from as long as all 
    #of your menus are in functions!
    $Script:SourceMenu = $MyInvocation.MyCommand.Name

    # Mode 1#
    #Use this for troubleshooting so that you can stay in ISE
    # Uncomment the 2 lines below to use Read-Host.  This will necessitate an ENTER Key. BUT, it WILL work in ISE
    #$K = Read-Host - "Which option?"
    #MenuActions

    # Mode 2#
    #Uncomment the line below to use ReadKey.  This will NOT necessitate an ENTER Key. BUT, it ## will NOT work ## in ISE
    ReadKey
}

Function ReadKey {
    Write-Host "Please make your choice..."
    Write-Host ""
    Write-Host "Press Q to quit"
    $KeyPress = [System.Console]::ReadKey()

    #This gets the keypress to a common variable so that both modes work (Read-Host and KeyPress)
    $K = $KeyPress.Key

    #Jumps you down to the MenuActions function to take the keypress and "Switch" to it
    MenuActions
}

Function MenuActions {
    Switch ($K) {
        A {CLS;Write-Host "You Pressed A";Write-Host "Going to pause now... ";&pause}
        B {CLS;Write-Host "You pressed B";Write-Host "Going to pause now... ";&pause}
        C {CLS;Write-Host "You pressed C";Write-Host "Going to pause now... ";&pause}
        D {CLS;Write-Host "You pressed D";Write-Host "Going to pause now... ";&pause}
        E {CLS;Write-Host "You pressed E";Write-Host "Going to pause now... ";&pause}
        F {CLS;Write-Host "You pressed F";Write-Host "Going to pause now... ";&pause}
        G {CLS;Write-Host "You pressed G";Write-Host "Going to pause now... ";&pause}

        #This is a little strange of a process to exit out, but I like to use an existing mechanism to exit out
        #It sets the $SourceMenu to a process that will exit out.
        #I use this same process to jump to a different menu/sub-menu
        Q {$SourceMenu = "Exit-PSHostProcess";CLS;Write-Host "Exited Program"}
}
        #This next command will loop back to the menu you came from.  This, in essence, provides a validation that one of the 
        #"Switch ($X.key)" options were pressed.  This is also a good way to always find your way back to 
        #the menu you came from.  See "$Script:SourceMenu = $MyInvocation.MyCommand.Name" above.
        #
        #This is also the way that the Menu Item for Q exits out
    & $SourceMenu
}

# This runs the MainMenu function.  It has to be after all the functions so that they are defined before being called
MainMenu

整个过程的主要部分是:

$KeyPress = [System.Console]::ReadKey()

#This gets the keypress to a common variable so that both modes work (Read-Host and KeyPress)
$K = $KeyPress.Key
#
#Then do something with $K

接受两个按键的系统如何?

这里只是一点补充。既然我们在谈论单键...那么双键呢?好吧,这将正常工作。只需堆叠ReadKey命令并为每个命令分配变量,然后将它们组合起来即可:

Write-Host "Press the 2 character option you wish"
#Get KeyPress1 Variable
$KeyPress1 = [System.Console]::ReadKey()

#This gets the keypress to a common variable so that both modes work (Read-Host and KeyPress)
$K1 = $KeyPress1.Key

#Get KeyPress1 Variable
$KeyPress2 = [System.Console]::ReadKey()

#This gets the keypress to a common variable so that both modes work (Read-Host and KeyPress)
$K2 = $KeyPress2.Key

#This is just for troubleshooting to prove it works
CLS
Write-Host "This is the state of the variables right now"
Write-Host "Keypress1 is: $K1" -ForegroundColor Green
Write-Host "Keypress1 is: $K2" -ForegroundColor Green

$KEYS = "$K1"+"$K2"

Write-Host "The combined presses are: $KEYS" -ForegroundColor Red
pause

我希望提出问题或评论。

答案 3 :(得分:0)

似乎$Host.UI.RawUI.ReadKey()在VSCode控制台中不起作用。

这是我的ReadKey实现。

class DConsole {

    static [System.ConsoleKeyInfo]ReadKey() {
        return [DConsole]::ReadKey($true)
    }

    static [System.ConsoleKeyInfo]ReadKey([bool]$noEcho = $true) {
        $key = [System.Console]::ReadKey()
        if ($noEcho) {
            $cTop = [System.Console]::CursorTop
            [System.Console]::SetCursorPosition(0, $cTop)
        }
        return $key
    }
}

用法:

$key = [DConsole]::ReadKey()
# or
$key = [DConsole]::ReadKey($false)

欢迎进行任何改进。

回到问题,$key.KeyChar.ToString()可能是您想要的。