3

I have a loop after setting stty -icanon time 0 min 0 to prevent read from blocking.

It works okay except it cant read the enter/return key.

Is there any way to read the enter key in this mode, or any other way my code could be written ?

Relevant Code

tput smcup
Draw
if [ -t 0 ]; then stty -icanon time 0 min 0; fi
count=0
keypress=''
while [ "$keypress" != "q" ]; do
        sleep 0.1
        (( count = count + 1 ))
        rows=$(tput lines)
        columns=$(tput cols)
        Draw
        read  keypress
        name=$name$keypress
        echo $name
        if [[ $oldcolumns != $columns || $oldrows != $rows ]];then
                Draw
                oldcolumns=$columns
                oldrows=$rows
        elif [[ $count -eq 1  ]]; then
#               Draw
                count=0
        fi
done

if [ -t 0 ]; then stty sane; fi
tput rmcup
#rm tail.tmp
echo "Thanks for using this script."
exit 0
Community
  • 1
  • 1
  • I think the problem is that `read` will return nothing if it receives just a newline. – tripleee Mar 26 '14 at 13:34
  • Thats what i was thinking, ive looked around and can only find [read] as a way of taking user input, do you know of any other functions or methods of reading key strokes ? –  Mar 26 '14 at 15:52

1 Answers1

2

You can do this with read by

  • unsetting IFS
  • not using any line delimiters
  • reading exactly 1 char at a time

.

IFS= read -t 0.01 -d '' -n1 keypress

For example, here we enter a, space, then return:

$ IFS= read -t 0.01 -s -d '' -n1 keypress ; echo "\"$keypress\""
"a"
$ IFS= read -t 0.01 -s -d '' -n1 keypress ; echo "\"$keypress\""
" "
$ IFS= read -t 0.01 -s -d '' -n1 keypress ; echo "\"$keypress\""
"
"
$ 

I added the -s flag in the above examples to suppress echoed input to read, so it doesn't confuse what is output. This is not necessary for the above to work.

Edit:

I hadn't appreciated that you effectively want non-blocking mode for your reads until I saw your comment. This is harder. The best I can figure out is to put a small (10msec) timeout in your read command. This has the unfortunate effect of a 10msec delay in your event loop, which may or may not be acceptable. For me, much smaller timeouts caused bash to behave badly, and a 0 timeout doesn't seem to work at all.

Community
  • 1
  • 1
Digital Trauma
  • 15,475
  • 3
  • 51
  • 83
  • Hi Thanks for the answer. Where in the code i posted would you place it ? If i put it within the loop where the read currently is, then it blocks until i input something. –  Mar 27 '14 at 09:00
  • @Jidder Sorry I hadn't appreciated that you need a non-blocking read. I made an edit which may or may not be useful to you. – Digital Trauma Mar 27 '14 at 14:42