Casing arrow keys in bash

前端 未结 8 829
遥遥无期
遥遥无期 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:02

    Using eMPee584 answer I think I came up a good solution for you. Its output is much the same as user3229933 answer but will not be triggered by shift keys and will work in most terminals.

    It has UP DOWN LEFT RIGHT HOME and END Keys Press 'q' to quit Most of this is thanks to eMPee584

    you may need to change '-sn1' to '-sN1' if you get an error like illegal option n.

    #!/bin/bash
    
    while read -sn1 key # 1 char (not delimiter), silent
    do
    
      read -sn1 -t 0.0001 k1 # This grabs all three symbols 
      read -sn1 -t 0.0001 k2 # and puts them together
      read -sn1 -t 0.0001 k3 # so you can case their entire input.
    
       key+=${k1}${k2}${k3} 
    
      case "$key" in
        $'\e[A'|$'\e0A')  # up arrow
            ((cur > 1)) && ((cur--))
            echo up;;
    
        $'\e[D'|$'\e0D') # left arrow
            ((cur > 1)) && ((cur--))
            echo left;;
    
        $'\e[B'|$'\e0B')  # down arrow
            ((cur < $#-1)) && ((cur++))
            echo down;;
    
        $'\e[C'|$'\e0C')  # right arrow
            ((cur < $#-1)) && ((cur++))
            echo right;;
    
        $'\e[1~'|$'\e0H'|$'\e[H')  # home key:
            cur=0
            echo home;;
    
        $'\e[4~'|$'\e0F'|$'\e[F')  # end key:
            ((cur=$#-1))
            echo end;;
    
        q) # q: quit
            echo Bye!
            exit;;
    
       esac                  
    
    done
    
    0 讨论(0)
  • 2020-12-10 07:03
    # This will bind the arrow keys
    
    while true
    do
        read -r -sn1 t
        case $t in
            A) echo up ;;
            B) echo down ;;
            C) echo right ;;
            D) echo left ;;
        esac
    done
    
    0 讨论(0)
  • 2020-12-10 07:05

    You can read arrow keys as well as other keys without any unusual commands; you just need two read calls instead of one:

    escape_char=$(printf "\u1b")
    read -rsn1 mode # get 1 character
    if [[ $mode == $escape_char ]]; then
        read -rsn2 mode # read 2 more chars
    fi
    case $mode in
        'q') echo QUITTING ; exit ;;
        '[A') echo UP ;;
        '[B') echo DN ;;
        '[D') echo LEFT ;;
        '[C') echo RIGHT ;;
        *) >&2 echo 'ERR bad input'; return ;;
    esac
    
    0 讨论(0)
  • 2020-12-10 07:09

    You can use read -n 1 to read one character then use a case statement to choose an action to take based on the key.

    On problem is that arrow keys output more than one character and the sequence (and its length) varies from terminal to terminal.

    For example, on the terminal I'm using, the right arrow outputs ^[[C. You can see what sequence your terminal outputs by pressing Ctrl-V Right Arrow. The same is true for other cursor-control keys such as Page Up and End.

    I would recommend, instead, to use single-character keys like < and >. Handling them in your script will be much simpler.

    read -n 1 key
    
    case "$key" in
        '<') go_left;;
        '>') go_right;;
    esac
    
    0 讨论(0)
  • 2020-12-10 07:13

    As mentioned before, the cursor keys generate three bytes - and keys like home/end even generate four! A solution I saw somewhere was to let the initial one-char read() follow three subsequent one-char reads with a very short timeout. Most common key sequences can be shown like this f.e.:

    #!/bin/bash
    for term in vt100 linux screen xterm
      { echo "$term:"
        infocmp -L1 $term|egrep 'key_(left|right|up|down|home|end)'
      }
    

    Also, /etc/inputrc contains some of these with readline mappings.. So, answering original question, here's a snip from that bash menu i'm just hacking away at:

    while read -sN1 key # 1 char (not delimiter), silent
    do
      # catch multi-char special key sequences
      read -sN1 -t 0.0001 k1
      read -sN1 -t 0.0001 k2
      read -sN1 -t 0.0001 k3
      key+=${k1}${k2}${k3}
    
      case "$key" in
        i|j|$'\e[A'|$'\e0A'|$'\e[D'|$'\e0D')  # cursor up, left: previous item
          ((cur > 1)) && ((cur--));;
    
        k|l|$'\e[B'|$'\e0B'|$'\e[C'|$'\e0C')  # cursor down, right: next item
          ((cur < $#-1)) && ((cur++));;
    
        $'\e[1~'|$'\e0H'|$'\e[H')  # home: first item
          cur=0;;
    
        $'\e[4~'|$'\e0F'|$'\e[F')  # end: last item
          ((cur=$#-1));;
    
        ' ')  # space: mark/unmark item
          array_contains ${cur} "${sel[@]}" && \
          sel=($(array_remove $cur "${sel[@]}")) \
          || sel+=($cur);;
    
        q|'') # q, carriage return: quit
          echo "${sel[@]}" && return;;
      esac                  
    
      draw_menu $cur "${#sel[@]}" "${sel[@]}" "$@" >/dev/tty
      cursor_up $#
    done
    
    0 讨论(0)
  • 2020-12-10 07:13

    To extend JellicleCat's answer:

    #!/bin/bash
    escape_char=$(printf "\u1b")
    read -rsn1 mode # get 1 character
    if [[ $mode == $escape_char ]]; then
        read -rsn4 -t 0.001 mode # read 2 more chars
    fi
    case $mode in
        '') echo escape ;;
        '[a') echo UP ;;
        '[b') echo DOWN ;;
        '[d') echo LEFT ;;
        '[c') echo RIGHT ;;
        '[A') echo up ;;
        '[B') echo down ;;
        '[D') echo left ;;
        '[C') echo right ;;
        '[2~') echo insert ;;
        '[7~') echo home ;;
        '[7$') echo HOME ;;
        '[8~') echo end ;;
        '[8$') echo END ;;
        '[3~') echo delete ;;
        '[3$') echo DELETE ;;
        '[11~') echo F1 ;;
        '[12~') echo F2 ;;
        '[13~') echo F3 ;;
        '[14~') echo F4 ;;
        '[15~') echo F5 ;;
        '[16~') echo Fx ;;
        '[17~') echo F6 ;;
        '[18~') echo F7 ;;
        '[19~') echo F8 ;;
        '[20~') echo F9 ;;
        '[21~') echo F10 ;;
        '[22~') echo Fy ;;
        '[23~') echo F11 ;;
        '[24~') echo F12 ;;
        '') echo backspace ;;
        *) echo $mode;;
    esac
    
    0 讨论(0)
提交回复
热议问题