这是一个涉及 PowerShell 以解释批处理脚本中的箭头键按下的技巧。
@echo off
setlocal
set /P "=Hit an arrow key: "<NUL
:keyloop
call :getKey
if errorlevel 37 if not errorlevel 41 goto key%errorlevel%
goto keyloop
:key37
echo left
goto :EOF
:key38
echo up
goto :EOF
:key39
echo right
goto :EOF
:key40
echo down
goto :EOF
:getKey
powershell "exit($Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode)"
exit /b %errorlevel%
在反思下面 Klitos Kyriacou 的评论后,我想到最好让 PowerShell 在内部循环,直到关键代码成为有效值。否则,每次按键都会生成一个新的 PowerShell 实例,如果按下了一堆无效键,则会导致延迟。这是解决此问题的一个变体:
@echo off
setlocal
set "getKeyMacro=powershell -noprofile "^
while (-not (37..40).contains($x)) {^
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode^
}^
exit($x)^
""
set /P "=Hit an arrow key: "<NUL
%getKeyMacro%
if errorlevel 37 goto key%ERRORLEVEL%
rem // else user hit Ctrl-C. Exit gracefully.
echo Bye. & goto :EOF
:key37
echo left
goto :EOF
:key38
echo up
goto :EOF
:key39
echo right
goto :EOF
:key40
echo down
goto :EOF
这是一个缩写版本,它让 PowerShell 将键码转换为人类可读的左、上、右或下字符串。它对于在批处理脚本中触发条件逻辑可能没有那么有用,但可以随心所欲地使用它。
@echo off
setlocal
set "getKeyMacro=powershell -noprofile "^
while (-not (37..40).contains($x)) {^
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode^
}^
('left','up','right','down')[$x - 37]^
""
set /P "=Hit an arrow key: "<NUL
%getKeyMacro%
只是为了好玩,我编写了一个菜单选择脚本,让您使用箭头键进行选择。这也展示了一种制作 Batch + PowerShell 混合嵌合体的巧妙方法。
<# : Batch portion
@echo off & setlocal enabledelayedexpansion
set "menu[0]=Format C:"
set "menu[1]=Send spam to boss"
set "menu[2]=Truncate database *"
set "menu[3]=Randomize user password"
set "menu[4]=Download Dilbert"
set "menu[5]=Hack local AD"
set "selection=0"
set "max=5"
:menu
cls
echo === MENU ===
echo;
for /L %%I in (0,1,5) do (
if %%I equ !selection! (
echo --^> !menu[%%I]! ^<--
) else (
echo !menu[%%I]!
)
)
echo;
echo Use the arrow keys and Enter to select.
powershell -noprofile -executionpolicy remotesigned "iex ((gc '%~f0') -join \";\")"
goto :key%errorlevel%
:key13 (enter)
echo You chose !menu[%selection%]!.
goto :EOF
:key39 (right)
:key40 (down)
if %selection% lss %max% set /a selection += 1
goto menu
:key37 (left)
:key38 (up)
if %selection% gtr 0 set /a selection -= 1
goto menu
: PowerShell hybrid chimera #>
while (-not ((37..40 + 13) -contains $x)) {
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode
}
exit($x)
这是在 PowerShell 中保留菜单导航的另一个版本。这样做的一个好处是powershell 不会在每次更改菜单选择时重新生成,因此它会在较慢的计算机上响应更快。让 PowerShell 输出菜单还允许更改选择的背景颜色。
<# : Batch portion
@echo off & setlocal enabledelayedexpansion
set "menu[0]=Format C:"
set "menu[1]=Send spam to boss"
set "menu[2]=Truncate database *"
set "menu[3]=Randomize user password"
set "menu[4]=Download Dilbert"
set "menu[5]=Hack local AD"
set "default=0"
powershell -noprofile -executionpolicy remotesigned "iex ((gc '%~f0') -join \"`n\")"
echo You chose !menu[%ERRORLEVEL%]!.
goto :EOF
: end batch / begin PowerShell hybrid chimera #>
$menu = gci env: | ?{ $_.Name -match "^menu\[\d+\]$" } | %{ $_.Value }
[int]$selection = $env:default
$fg = $Host.UI.RawUI.ForegroundColor
$bg = $Host.UI.RawUI.BackgroundColor
function getKey {
while (-not ((37..40 + 13 + 48..53) -contains $x)) {
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode
}
$x
}
function menu {
cls
write-host " === MENU ===`n" -f $fg -b $bg
for ($i=0; $item = $menu[$i]; $i++) {
if ($i -eq $selection) {
write-host " > $item < " -f $bg -b yellow
} else {
write-host " $i`: $item" -f $fg -b $bg
}
}
write-host "`nChoose a number or use the arrow keys and Enter to select." -f $fg -b $bg
1
}
while (menu) {
[int]$key = getKey
switch ($key) {
37 {} # left or up
38 { if ($selection) { $selection-- }; break }
39 {} # right or down
40 { if ($selection -lt ($menu.length - 1)) { $selection++ }; break }
# number or enter
default { if ($key -gt 13) {$selection = $key - 48}; [void](menu); exit($selection) }
}
}