bashscript do wykrycia naciśnięcia klawisza strzałki w prawo

9

Dlaczego to zawsze wykrywa jako prawdziwe, nawet jeśli kod klucza nie jest klawiszem ze strzałką w prawo?

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
źródło
powiązane stackoverflow.com/questions/22842896/…
Ciro Santilli 15 病毒 审查 六四 事件 法轮功

Odpowiedzi:

16

Najprawdopodobniej przeczytałeś pierwszy z dwóch + bajtów. $keycodew twoim skrypcie będzie ESC po naciśnięciu klawisza strzałki.

Klawisze strzałek mogą być:

\x1b + some value

Zawsze zwraca wartość true, ponieważ brakuje spacji w wyrażeniu warunkowym.

Edycja: aktualizacja tego oświadczenia.

Twój ifdziała na statusie wyjścia [polecenia. [Komenda jest równoważna test. Fakt, że jest to polecenie, jest bardzo ważnym faktem. Jako polecenie wymaga spacji między argumentami. [Komenda jest dodatkowo specjalny w to, że wymagają ]jako ostatni argument.

[ EXPRESSION ]

Polecenie kończy pracę ze statusem określonym przez WYRAŻENIE. 1 lub 0, prawda lub fałsz .

To nie jest egzotyczny sposób pisania nawiasów. Innymi słowy, nie jest to część ifskładni, jak na przykład w C:

if (x == 39)

Przez:

if [ "$keycode"=39 ]; then

wydajesz:

[ "$keycode"=39 ]

który rozwija się do

[ \x1b=39 ]

tutaj \x1b=39jest czytany jako jeden argument. Kiedy podano testlub [podano jeden argument, kończy się ono na fałsz tylko wtedy, gdy EXPRESSION ma wartość null - co nigdy nie będzie. Nawet jeśli $keycodebyłby pusty, spowodowałoby to =39(co nie jest zerowe / puste).

Innym sposobem spojrzenia na to jest powiedzenie:

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

Przeczytaj te pytania i odpowiedzi, aby uzyskać więcej informacji - a także dyskusję na temat [vs [[:

W tym względzie można również zbadać tyknięcia `` vs $( )


Wielobajtowa sekwencja ucieczki za pomocą klawiszy strzałek:

Jak wspomniano u góry: Najprawdopodobniej przeczytałeś pierwszy z dwóch + bajtów. $keycodew twoim skrypcie będzie ESC po naciśnięciu klawisza strzałki.

Strzałki i inne specjalne klawisze powodują wysłanie sekwencji ucieczki do systemu. W ESC bajt sygnały, że „tutaj jest kilka bajtów, które powinny być interpretowane w różny sposób” . Co do klawiszy strzałek, które byłyby ASCII [następnie ASCII A, B, Club D.

Innymi słowy, musisz parsować trzy bajty podczas obsługi klawiszy strzałek.

Możesz spróbować czegoś w tym kierunku, aby sprawdzić:

{   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

Wydajność:

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

Nie jestem pewien, jak przenośny, ale wcześniej bawiłem się takim kodem do łapania klawiszy strzałek. Naciśnij, qaby wyjść:

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

(Jako drobna uwaga, również (zamierzasz) przetestować dziesiętnie 39 - co wygląda jak połączenie dziesiętnego i szesnastkowego. Pierwszy bajt w sekwencji specjalnej to wartość ASCII ESC , która jest dziesiętna 27 i szesnastkowa 0x1b, podczas gdy dziesiętna 39 jest szesnastkowa 0x27. )

użytkownik367890
źródło
2
Pierwszym problemem w tym pytaniu jest to, że nie ma spacji otaczających =znak w teście, więc jest on parsowany po prostu jako niepusty ciąg i dlatego jest prawdziwy. Fakt, że klawisze strzałek są wieloma bajtami, stanowi osobny problem.
wurtel
2
Hmm, to zdanie nie ma takiego kontekstu, jaki jest, przeczytałem go, ponieważ myślałem, że to część wyjaśnienia sekwencji wielobajtowych, które już znałem.
wurtel
2
@wurtel: Tak. Chyba niejasne. Przekonaj się, że gdy jedno wyjaśnienie [jest wbudowanym poleceniem, ludzie szybko rozumieją, dlaczego spacje są ważne. (To nie jest po prostu dziwny sposób bash używać nawiasów zamiast nawiasów.) Musisz teraz skończyć. Zaktualizuj raz.
user367890