Casing arrow keys in bash

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

提交回复
热议问题