bashscript pour détecter la pression de la flèche droite

9

Pourquoi est-ce toujours détecté comme vrai, même si le code de touche n'est pas la touche flèche droite?

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

Réponses:

16

Vous (probablement) lisez d'abord deux octets +. $keycodedans votre script serait ESC lorsque vous appuyez sur la touche fléchée.

Les touches fléchées peuvent être:

\x1b + some value

Il prend toujours la valeur true en raison des espaces manquants dans l'expression conditionnelle.

Edit: une mise à jour sur cette déclaration.

Votre iffonctionne sur l'état de sortie de la [commande. La [commande est équivalente à test. Le fait qu'il s'agisse d'une commande est un fait très important. En tant que commande, elle nécessite des espaces entre les arguments. La [commande est en outre spéciale en ce qu'elle requiert ]comme dernier argument.

[ EXPRESSION ]

La commande se termine avec le statut déterminé par EXPRESSION. 1 ou 0, vrai ou faux .

Ce n'est pas une façon exotique d'écrire des parenthèses. En d'autres termes, il ne fait pas partie de la ifsyntaxe comme par exemple en C:

if (x == 39)

Par:

if [ "$keycode"=39 ]; then

vous émettez:

[ "$keycode"=39 ]

qui s'étend à

[ \x1b=39 ]

ici \x1b=39est lu comme un argument. Lorsque testou [reçoit un argument, il ne se termine avec false que si EXPRESSION est null - ce qui ne le sera jamais. Même s'il $keycodeétait vide, il en résulterait =39(qui n'est pas nul / vide).

Une autre façon de voir les choses est de dire:

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

Lisez ces questions et réponses pour plus de détails - ainsi que la discussion sur [vs [[:

À cet égard, vous pouvez également rechercher des tiques arrière `` vs $( )


Séquence d'échappement multi-octets avec touches fléchées:

Comme mentionné en haut: vous lisez (probablement) le premier sur deux octets +. $keycodedans votre script serait ESC lorsque vous appuyez sur la touche fléchée.

Les flèches et autres touches spéciales entraînent l' envoi de séquences d'échappement au système. L' octet ESC signale que "voici quelques octets qui doivent être interprétés différemment" . En ce qui concerne les touches fléchées qui seraient ASCII [suivie par ASCII A, B, Cou D.

En d'autres termes, vous devez analyser trois octets lorsque vous utilisez les touches fléchées.

Vous pouvez essayer quelque chose dans ce sens pour vérifier:

{   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

Rendement:

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

Je ne sais pas à quel point c'est portable, mais j'ai déjà joué avec du code comme celui-ci pour attraper les touches fléchées. Appuyez qpour quitter:

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

(En tant que note mineure, vous avez également (l'intention de) tester la décimale 39 - qui ressemble à un mélange entre décimal et hexadécimal. Le premier octet d'une séquence d'échappement est la valeur ASCII ESC , qui est décimal 27 et hexadécimal 0x1b, tandis que la décimale 39 est hexadécimal 0x27. )

user367890
la source
2
Le premier problème de la question est qu'il n'y a pas d'espaces entourant le =signe dans le test, il est donc analysé simplement comme une chaîne non vide et est donc vrai. Le fait que les touches fléchées comportent plusieurs octets est un problème distinct.
wurtel
2
Hmm, cette phrase n'a pas beaucoup de contexte tel quel, je l'ai relu car je pensais que cela faisait partie de l'explication des séquences multi-octets que je connaissais déjà.
wurtel
2
@wurtel: Oui. Trop vague je suppose. Trouvez qu'une fois que l'on explique [est une commande intégrée, les gens comprennent plus rapidement pourquoi les espaces sont importants. (Ce n'est pas simplement une façon bizarre de bash d'utiliser des crochets au lieu de parenthèses.) Faut épuiser maintenant. Mettre à jour une fois de retour.
user367890