使用PowerShell,我想在发生按键时读取按键的值,而无需用户按Enter键。例如,如果用户按下“1”,我希望PowerShell脚本在没有“输入”的情况下立即对选择做出反应。
我的研究已发现ReadKey,
$ input = $ Host.UI.RawUI.ReadKey('IncludeKeyDown');
但是ReadKey在字符串中返回的信息比我要求的要多得多:
72,H,0,真
虽然我可以从这个字符串解析按键,但我更喜欢更直接的选项。是否存在?
答案 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]
。
但这是一个糟糕的决定。这是一个警告。有些人可能知道如何正确使用它。
按键会让您按某些键
此外Key属性[console]::ReadKey
与$key = [console]::ReadKey()
if ($key.Key -eq 'D1') {
"Pressed 1"
}
相似。
datasource.online(false);
datasource.read();
datasource.online(true);
答案 2 :(得分:0)
我已经提取了输入和菜单系统的要点,并给出了一些示例菜单项。
模式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()
可能是您想要的。