bashscript para detectar a tecla de seta direita sendo pressionada

9

Por que isso sempre é detectado como verdadeiro, mesmo que o código da chave não seja a tecla de seta para a direita?

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
ConfusedStack
fonte
relacionada stackoverflow.com/questions/22842896/...
Ciro Santilli冠状病毒审查六四事件法轮功

Respostas:

16

Você (provavelmente) leu primeiro de dois + bytes. $keycodeno seu script seria ESC quando a tecla seta for pressionada.

As teclas de seta podem ser:

\x1b + some value

Ele sempre é avaliado como verdadeiro devido à falta de espaços na expressão condicional.

Edit: uma atualização sobre essa declaração.

Seu ifopera no status de saída do [comando. O [comando é equivalente a test. O fato de ser um comando é um fato muito importante. Como um comando, ele requer espaços entre argumentos. O [comando é ainda mais especial, pois requer ]como último argumento.

[ EXPRESSION ]

O comando sai com o status determinado por EXPRESSION. 1 ou 0, verdadeiro ou falso .

É não uma forma exótica de escrever parêntesis. Em outras palavras, não faz parte da ifsintaxe, como por exemplo em C:

if (x == 39)

De:

if [ "$keycode"=39 ]; then

você emite:

[ "$keycode"=39 ]

que se expande para

[ \x1b=39 ]

aqui \x1b=39é lido como um argumento. Quando testou [é dado um argumento, ele sai com false apenas se EXPRESSION for nulo - o que nunca será. Mesmo se $keycodeestivesse vazio, resultaria em =39(que não é nulo / vazio).

Outra maneira de ver é que você diz:

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

Leia estas perguntas e respostas para obter mais detalhes - assim como a discussão sobre [vs [[:

Nesse sentido, você também pode pesquisar os ticks anteriores `` vs $( )


Sequência de escape multibyte com teclas de seta:

Como mencionado na parte superior: Você (provavelmente) leu primeiro de dois + bytes. $keycodeno seu script seria ESC quando a tecla seta for pressionada.

As setas e outras teclas especiais resultam em sequências de escape a serem enviadas ao sistema. O byte ESC sinaliza que "aqui estão alguns bytes que devem ser interpretados de maneira diferente" . Quanto teclas de seta que seria o ASCII [seguido por ASCII A, B, Cou D.

Em outras palavras, você deve analisar três bytes ao lidar com as teclas de seta.

Você pode tentar algo na direção disso para verificar:

{   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

Produção:

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

Não tenho certeza de como isso é portátil, mas já brincamos com códigos como este para pegar as teclas de seta. Pressione qpara sair:

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

(Como nota secundária, você também (pretende) testar contra o decimal 39 - que se parece com uma mistura entre decimal e hexadecimal. O primeiro byte de uma sequência de escape é o valor ASCII ESC , que é decimal 27 e hexadecimal 0x1b, enquanto o decimal 39 é hexadecimal 0x27. )

user367890
fonte
2
O primeiro problema da pergunta é que não há espaços ao redor do =sinal no teste, portanto ele é analisado simplesmente como uma sequência não vazia e, portanto, é verdade. O fato de as teclas de seta terem vários bytes é um problema separado.
wurtel
2
Hmm, essa frase não tem muito contexto como está, eu li sobre isso porque pensei que era parte da explicação de sequências de vários bytes que eu já conhecia.
wurtel
2
@wurtel: Sim. Para vaga, eu acho. Descubra que, uma vez que uma explicação [é um comando interno, as pessoas entendem por que os espaços são importantes muito mais rapidamente. (Não é simplesmente uma maneira estranha de bash usar colchetes em vez de parênteses.) Tem que acabar agora. Atualize uma vez de volta.
precisa saber é