bashscript para detectar a tecla de seta para a direita sendo pressionada

8

Por que isso sempre é verdade, mesmo que o código de acesso não esteja na 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
    
por ConfusedStack 15.01.2015 / 06:57

1 resposta

13

Você (provavelmente) lê primeiro dois bytes +. $keycode no seu script seria ESC quando a tecla de seta é 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 nessa declaração.

Seu if opera 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, requer espaços entre argumentos. O comando [ é ainda mais especial porque requer ] como último argumento.

[ EXPRESSION ]

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

Não é uma maneira exótica de escrever parênteses. Em outras palavras, não é parte da sintaxe if como, por exemplo, em C:

if (x == 39)

Por:

if [ "$keycode"=39 ]; then

você emite:

[ "$keycode"=39 ]

que se expande para

[ \x1b=39 ]

aqui \x1b=39 é lido como um argumento um . Quando test ou [ recebe o argumento um , ele sai com falso somente se EXPRESSION for nulo - o que nunca será. Mesmo se $keycode estivesse vazio, resultaria em =39 (que não é nulo / vazio).

Outra maneira de ver isso é 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 - bem como a discussão sobre [ vs [[ :

Nesse sentido, você também pode pesquisar carrapatos de volta '' vs $( )

Sequência de escape multibyte com teclas de seta:

Como mencionado no topo: Você (provavelmente) lê primeiro dois bytes +. $keycode no seu script seria ESC quando a tecla de seta é pressionada.

Seta e outras chaves especiais resultam em seqüências de escape a serem enviadas para o sistema. O ESC byte sinaliza que "aqui vem alguns bytes que devem ser interpretados de forma diferente" . Quanto às teclas de seta que seriam ASCII [ seguido por ASCII A , B , C ou D .

Em outras palavras, você precisa 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

Rendimento:

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á usei códigos como esse para capturar as teclas de seta. Pressione q para 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 menor, você também (pretende) testar contra o decimal 39 - que se parece com uma mistura entre decimal e hexadecimal. Primeiro byte em uma seqüência de escape é Valor ASCII ESC , que é decimal 27 e hexadecimal 0x1b , enquanto decimal 39 é hexadecimal 0x27 .)

    
por 15.01.2015 / 07:15