bashscript để phát hiện phím mũi tên phải được nhấn


9

Tại sao điều này luôn luôn phát hiện là đúng, ngay cả khi mã khóa không phải là phím mũi tên phải?

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

Câu trả lời:


16

Bạn (có khả năng) đọc đầu tiên trong số hai byte. $keycodetrong tập lệnh của bạn sẽ là ESC khi nhấn phím mũi tên.

Phím mũi tên có thể là:

\x1b + some value

Nó luôn luôn đánh giá là đúng vì thiếu khoảng trắng trong biểu thức điều kiện.

Chỉnh sửa: một bản cập nhật về tuyên bố đó.

ifHoạt động của bạn trên trạng thái thoát [lệnh. Các [lệnh tương đương với test. Thực tế đó là một lệnh là một thực tế rất quan trọng. Như một lệnh, nó yêu cầu khoảng trắng giữa các đối số. Các [lệnh là đặc biệt hơn nữa ở chỗ nó đòi hỏi ]như là đối số cuối cùng.

[ EXPRESSION ]

Lệnh thoát với trạng thái được xác định bởi EXPRESSION. 1 hoặc 0, đúng hay sai .

không phải là một cách kỳ lạ để viết ngoặc đơn. Nói cách khác, nó không phải là một phần của ifcú pháp như trong C:

if (x == 39)

Bởi:

if [ "$keycode"=39 ]; then

bạn phát hành:

[ "$keycode"=39 ]

mở rộng ra

[ \x1b=39 ]

ở đây \x1b=39được đọc như một đối số. Khi testhoặc [được đưa ra một đối số, nó sẽ thoát với false chỉ khi EXPRESSION là null - điều này sẽ không bao giờ xảy ra. Ngay cả khi $keycodetrống, nó sẽ dẫn đến =39(không phải là null / rỗng).

Một cách khác để xem xét nó là bạn nói:

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

Đọc những câu hỏi và câu trả lời này để biết thêm chi tiết - cũng như thảo luận về [vs [[:

Về vấn đề đó, bạn cũng có thể nghiên cứu lại các dấu tick `` vs. $( )


Trình tự thoát đa nhân với các phím mũi tên:

Như đã đề cập ở trên cùng: Bạn (có thể) đọc đầu tiên trong số hai byte. $keycodetrong tập lệnh của bạn sẽ là ESC khi nhấn phím mũi tên.

Mũi tên và các phím đặc biệt khác dẫn đến các chuỗi thoát được gửi đến hệ thống. Các tín hiệu byte ESC "ở đây có một số byte nên được hiểu khác nhau" . Đối với các phím mũi tên sẽ là ASCII [tiếp theo ASCII A, B, Choặc D.

Nói cách khác, bạn phải phân tích ba byte khi xử lý các phím mũi tên.

Bạn có thể thử một cái gì đó theo hướng này để kiểm tra:

{   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

Năng suất:

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

Không chắc chắn mức độ di động của nó, nhưng trước đó đã chơi xung quanh với mã như thế này để bắt các phím mũi tên. Nhấn qđể thoát:

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

(Là một phụ lưu ý bạn cũng (có ý định) kiểm tra đối với số thập phân 39 -. Mà trông giống như một mixup giữa số thập phân và thập lục phân byte đầu tiên trong một dãy thoát là giá trị ASCII ESC , đó là số thập phân 27 và thập lục phân 0x1b, trong khi số thập phân 39 là thập lục phân 0x27. )


2
Vấn đề đầu tiên trong câu hỏi là không có khoảng trắng xung quanh =dấu hiệu trong bài kiểm tra, do đó, nó được phân tích đơn giản dưới dạng một chuỗi không trống và do đó là đúng. Thực tế là các phím mũi tên là nhiều byte là một vấn đề riêng biệt.
wurtel

2
Hmm, câu đó không có nhiều ngữ cảnh như vậy, tôi đọc nó vì tôi nghĩ đó là một phần của lời giải thích về chuỗi nhiều byte mà tôi đã biết.
wurtel

2
@wurtel: Vâng. Để mơ hồ tôi đoán. Tìm thấy rằng một khi người ta giải thích [là một lệnh dựng sẵn, mọi người sẽ hiểu tại sao không gian lại quan trọng nhanh hơn nhiều. (Nó không chỉ đơn giản là một cách bash kỳ lạ để sử dụng dấu ngoặc thay vì dấu ngoặc đơn.) Phải chạy ra ngay bây giờ. Cập nhật một lần trở lại.
dùng367890
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.