如何从用户输入接受箭头键按下?

时间:2016-01-01 06:02:25

标签: batch-file

我正在制作RPG风格的游戏,而且我已经达到了制作HUD的程度。它运行的理想方式是:

DPS:18
护甲:9
打开库存
打开地牢门

如何按箭头键按下选择打开库存还是打开Dungeon门?这是我到目前为止的代码:

:HUD

set /p damage=DPS:

set /p armor= Armour:

set /p open=Open the Dungeon door! 

set /p inventory= Open Inventory!

1 个答案:

答案 0 :(得分:1)

这是一个涉及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) }
    }
}