bashscript untuk mendeteksi tombol panah kanan sedang ditekan

9

Mengapa ini selalu terdeteksi sebagai benar, bahkan jika kode kunci itu bukan tombol panah kanan?

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
sumber
stackoverflow.com/questions/22842896/…
Ciro Santilli 冠状 病毒 审查 六四 六四 事件 事件

Jawaban:

16

Anda (kemungkinan) membaca pertama dari dua + byte. $keycodedalam skrip Anda akan menjadi ESC ketika tombol panah ditekan.

Tombol panah dapat:

\x1b + some value

Itu selalu bernilai true karena ruang yang hilang dalam ekspresi bersyarat.

Edit: pembaruan pada pernyataan itu.

Anda ifberoperasi pada status keluar dari [perintah. The [perintah setara dengan test. Fakta bahwa itu adalah perintah adalah fakta yang sangat penting. Sebagai perintah itu membutuhkan spasi di antara argumen. The [perintah khusus lebih lanjut dalam hal itu membutuhkan ]sebagai argumen terakhir.

[ EXPRESSION ]

Perintah keluar dengan status yang ditentukan oleh EXPRESSION. 1 atau 0, benar atau salah .

Ini bukan cara eksotis untuk menulis kurung. Dengan kata lain itu bukan bagian dari ifsintaksis seperti misalnya dalam C:

if (x == 39)

Oleh:

if [ "$keycode"=39 ]; then

Anda mengeluarkan:

[ "$keycode"=39 ]

yang diperluas ke

[ \x1b=39 ]

di sini \x1b=39dibaca sebagai satu argumen. Ketika testatau [diberikan satu argumen ia keluar dengan false hanya jika EXPRESSION adalah null - yang tidak akan pernah terjadi. Bahkan jika $keycodekosong, itu akan menghasilkan =39(yang bukan nol / kosong).

Cara lain untuk melihatnya adalah dengan mengatakan:

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

Baca pertanyaan dan jawaban ini untuk lebih jelasnya - serta diskusi tentang [vs [[:

Dalam hal ini, Anda juga dapat meneliti kembali ticks `` vs $( )


Urutan melarikan diri multibyte dengan tombol panah:

Seperti disebutkan di atas: Anda (kemungkinan) membaca pertama dari dua + byte. $keycodedalam skrip Anda akan menjadi ESC ketika tombol panah ditekan.

Panah dan kunci khusus lainnya menghasilkan urutan melarikan diri untuk dikirim ke sistem. The ESC byte sinyal bahwa "inilah beberapa byte yang harus ditafsirkan secara berbeda" . Adapun tombol panah yang akan menjadi ASCII yang [diikuti oleh ASCII A, B, Catau D.

Dengan kata lain Anda harus mengurai tiga byte saat berurusan dengan tombol panah.

Anda dapat mencoba sesuatu ke arah ini untuk memeriksa:

{   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

Menghasilkan:

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

Tidak yakin seberapa portabel ini, tetapi sebelumnya bermain-main dengan kode seperti ini untuk menangkap tombol panah. Tekan quntuk berhenti:

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

(Sebagai catatan kecil Anda juga (bermaksud untuk) menguji terhadap desimal 39 - yang terlihat seperti campuran antara desimal dan heksadesimal. Byte pertama dalam urutan melarikan diri adalah nilai ASCII ESC , yang desimal 27 dan heksadesimal 0x1b, sedangkan desimal 39 adalah heksadesimal 0x27. )

pengguna367890
sumber
2
Masalah pertama dalam pertanyaan adalah bahwa tidak ada ruang di sekitar =tanda dalam tes, jadi itu diurai hanya sebagai string yang tidak kosong dan karenanya benar. Fakta bahwa tombol panah adalah beberapa byte adalah masalah yang terpisah.
Wurtel
2
Hmm, kalimat itu tidak memiliki banyak konteks apa adanya, saya membacanya karena saya pikir itu adalah bagian dari penjelasan urutan multi-byte yang sudah saya tahu.
Wurtel
2
@wurtel: Ya. Untuk samar-samar saya kira. Temukan bahwa begitu satu penjelasan [adalah perintah bawaan, orang-orang memahami mengapa ruang menjadi penting lebih cepat. (Ini bukan sekadar cara aneh bash untuk menggunakan tanda kurung alih-alih tanda kurung.) Harus kehabisan sekarang. Perbarui sekali kembali.
user367890