Casing arrow keys in bash

前端 未结 8 830
遥遥无期
遥遥无期 2020-12-10 06:45

Is it possible to case arrow keys in a bash script to run a certain set of commands if the up/left arrow keys are pressed, and a certain set if the down/right arrow keys are

相关标签:
8条回答
  • 2020-12-10 07:15

    None of the above answers have worked for me! I had to grab bits and pieces from many answers in this thread, as well as other searches via google. It took me about an hour to concoct this.

    I am running Ubuntu 20.04 LTS and this works for me (although, it may not be perfect, as I had to 'hack' at it):

    waitkey() {
      local end=""
      local key=""
    
      echo
      echo "   Press ESC ... "
    
      while [ "$end" == "" ]; do
        read -rsn1 key
        case "$key" in
          $'\x1b')
            local k=""
            # I'm not sure why I have to do this if statement,
            # but without it, there are errors.  took forever
            # to figure out why 'read' would dump me outta the script
            if [ "$IFS" ]; then
              read -rsn1 -t 0.1 holder && k="$holder"
            else
              IFS=read -rsn1 -t 0.1 holder && k="$holder"
            fi 
    
            if [ "$k" == "[" ]; then
              read -rsn1 -t 0.1 holder && kk="$holder"
    
              ##############################
              # you put your arrow code here
              #
              # eg:
              #  case "$kk" in
              #    "A") echo "up arrow!" ;; # do something ...
              #  esac
              ##############################
            elif [ "$k" == "O" ]; then
              read -rsn1 -t 0.1 holder && kk="$holder"
    
              # I am honestly not knowing what this is for
            elif [ "$k" == "" ]; then
              end=1
            fi
        esac
      done
    }
    
    0 讨论(0)
  • 2020-12-10 07:26

    Not sure if this answer the question directly, but I think it's related - I was wandering where do those codes come from, and I finally found:

    • Linux Keycode Table (comptechdoc.org)

    It's a bit difficult to read at first; for left arrow, lookup "LEFT 4" in the "Key" column, and for the sequence that bash sees, look up the 5th ("keymap" - "normal") column, where it is written as "[D 1b 5b 44" - which are the three bytes (27, 91, 68) representing this key.

    Finding the thread How to read arrow keys on really old bash? - The UNIX and Linux Forums, inspired me to write a short one-liner which dumps the key codes of keys pressed. Basically, you press a key, then Enter (to trigger ending of read), and then use hexdump to output what read has saved (and finally hit Ctrl-C to exit the loop):

    $ while true; do read -p?; echo -n $REPLY | hexdump -C; done
    ?^[[D     
    00000000  1b 5b 44                                          |.[D| # left arrow
    00000003
    ?^[[C
    00000000  1b 5b 43                                          |.[C| # right arrow
    00000003
    ?^[[1;2D
    00000000  1b 5b 31 3b 32 44                                 |.[1;2D| # Shift+left arrow
    00000006
    ?^[[1;2C
    00000000  1b 5b 31 3b 32 43                                 |.[1;2C| # Shift+right arrow
    00000006
    ?^C
    

    So, while arrow keys require 3 bytes - Shift+arrow keys require 6! However, seemingly all these sequence start with 0x1b (27), so one could possibly check for this value for read -n1, before reading any more bytes; also 5b remains a second byte in multi-byte sequence for the "normal" and "shift/NUM-Lock" columns of the table above.


    Edit: much easier and proper way to scan for terminal codes of pressed keys in Linux is via showkey:

    $ showkey 
    Couldn't get a file descriptor referring to the console
    
    $ showkey -h
    showkey version 1.15
    
    usage: showkey [options...]
    
    valid options are:
    
        -h --help   display this help text
        -a --ascii  display the decimal/octal/hex values of the keys
        -s --scancodes  display only the raw scan-codes
        -k --keycodes   display only the interpreted keycodes (default)
    
    $ sudo showkey -a
    
    Press any keys - Ctrl-D will terminate this program
    
    ^[[A     27 0033 0x1b
             91 0133 0x5b
             65 0101 0x41
    ^[[B     27 0033 0x1b
             91 0133 0x5b
             66 0102 0x42
    ^[[A     27 0033 0x1b
             91 0133 0x5b
             65 0101 0x41
    ^[[D     27 0033 0x1b
             91 0133 0x5b
             68 0104 0x44
    ^[[C     27 0033 0x1b
             91 0133 0x5b
             67 0103 0x43
    ^C       3 0003 0x03
    ^M       13 0015 0x0d
    ^D       4 0004 0x04
    
    0 讨论(0)
提交回复
热议问题