bashscript 检测右箭头键被按下

bashscript 检测右箭头键被按下

为什么即使键码不是右箭头键,它总是检测为 true?

stty_state=`stty -g`
stty raw; stty -echo
keycode=`dd bs=1 count=1 2>/dev/null`
stty "$stty_state"  

echo $keycode

if [ "$keycode"=39 ]; then
echo "Right Arrow Key Pressed!"
fi

答案1

您(可能)首先读取两个以上字节。$keycode当按下箭头键时,您的脚本中将是 ESC。

箭头键可以是:

\x1b + some value

由于条件表达式中缺少空格,它的计算结果始终为 true。

编辑:对该声明的更新。

if对命令的退出状态进行操作[。该[命令相当于test.事实上,它是一个命令这是一个非常重要的事实。作为命令,它的参数之间需要空格。该[命令的更特殊之处在于它需要]作为最后一个参数。

[ EXPRESSION ]

命令退出,状态由 EXPRESSION 确定。 1 或 0,真的或者错误的

这是不是一种奇异的括号书写方式。换句话说就是不是语法的一部分,if例如在 C 中:

if (x == 39)

经过:

if [ "$keycode"=39 ]; then

你发出:

[ "$keycode"=39 ]

扩展到

[ \x1b=39 ]

这里\x1b=39读作争论。当test[被给予时参数以 false 退出除非EXPRESSION 为空——这是永远不会的。即使$keycode为空,也会导致=39(不为空/空)。

另一种看待它的方式是你说:

if 0 ; then # When _command_ exit with 0.
if 1 ; then # When _command_ exit with 1.

阅读这些问题和答案以了解更多详细信息 - 以及关于[vs 的讨论[[

在这方面,您还可以研究反​​引号`` vs$( )


带箭头键的多字节转义序列:

正如上面提到的:您(可能)首先读取两个以上字节。$keycode当按下箭头键时,您的脚本中将是 ESC。

箭头和其他特殊键会导致转义序列发送至系统。这ESC键字节信号表明“这里出现了一些应该以不同方式解释的字节”。至于箭头键,则为 ASCII[后跟 ASCII AB或。CD

换句话说,在处理箭头键时必须解析三个字节。

您可以尝试朝此方向进行检查:

{   stty_state=$(stty -g)
    stty raw isig -echo
    keycode=$(dd bs=8 conv=sync count=1)
    stty "$stty_state"
} </dev/tty 2>/dev/null
printf %s "$keycode" | xxd

屈服:

HEX        ASCII
1b 5b 41   .[A # Up arrow
1b 5b 42   .[B # Down arrow
1b 5b 43   .[C # Right arrow
1b 5b 44   .[D # Left arrow
 |  |  |
 |  |  +------ ASCII A, B, C and D
 |  +--------- ASCII [
 +------------ ASCII ESC

不确定这有多便携,但之前曾使用过这样的代码来捕获箭头键。按q退出:

while read -rsn1 ui; do
    case "$ui" in
    $'\x1b')    # Handle ESC sequence.
        # Flush read. We account for sequences for Fx keys as
        # well. 6 should suffice far more then enough.
        read -rsn1 -t 0.1 tmp
        if [[ "$tmp" == "[" ]]; then
            read -rsn1 -t 0.1 tmp
            case "$tmp" in
            "A") printf "Up\n";;
            "B") printf "Down\n";;
            "C") printf "Right\n";;
            "D") printf "Left\n";;
            esac
        fi
        # Flush "stdin" with 0.1  sec timeout.
        read -rsn5 -t 0.1
        ;;
    # Other one byte (char) cases. Here only quit.
    q) break;;
    esac
done

(作为一个小注意事项,您还(打算)针对十进制 39 进行测试 - 这看起来像是十进制和十六进制之间的混合。转义序列中的第一个字节是ASCII 值 ESC,即小数27 和十六进制0x1b, 而小数39 是十六进制0x27。)

相关内容