Search code examples
busyboxarrow-keysansi-escapeash

How do I prevent ANSI escape key sequences from spamming display during read in bash/ash script?


I'm attempting to make a script that handles arrow keys on a very limited system with busybox ash and very little else. No stty for example. I have something that mostly works but occasionally some ANSI escape sequences show up on the screen. This seems to happen most often when auto-key-repeat kicks in but also when more complex processing must be done before reading the next key. This is mostly good on on my laptop which is faster than my target system, but if I hold down the arrow keys occasionally one like ^[[B shows up on screen. How does it get past the silent reads?

I didn't explicitly handle HOME and END so ^[OH and ^[OF get through more often. This makes me think maybe they're leaking out during the timeout period, but I really don't know.

Anyhow, is there some trick with a pipe or subshell that might contain the escapees?

E=$(printf "\033")
NL='
'
# Works in bash, ash without stty but takes a sec for ESC key (not ESC sequence)
# But even with nothing but q key checks in the loop it still occasionally
# spams the screen with ^[[B etc if I hold arrow keys down for auto-repeat.
while true; do
  IFSBAK=$IFS ; IFS=
  read -rsn1 _KEY
  case "${_KEY}" in
    "${E}") _K=""; read -sn2 -t1 _K; _KEY="${E}${_K}";
      case "${_K}" in
    "[A"|"[B"|"[C"|"[D"|"") ;;
    "OP"|"OQ"|"OR"|"OS") ;;
    *) _K=""; read -n1 -t1 _K; _KEY="${_KEY}${_K}" ;;
      esac
  ;;  "") _KEY="NL"
  ;;
  esac
  IFS=$IFSBAK ; IFSBAK=

  case "$_KEY" in
    "${E}" | q )
      break;;
  esac
done

Solution

  • The question is

    How does it get past the silent reads?

    That's because the script is switching the terminal in/out of the modes used for the silent (no-echo) reads, and your keys are echoed by the shell when it is not expecting input. You can improve this by using stty to disable echo while the script is running (and restore echoing on exit).