How do I detect a keyboard press?

Tom Armistead toma at swsrv1.cirr.com
Fri May 3 17:00:38 AEST 1991


In article <1991May2.125554.11557 at vaxa.strath.ac.uk> cadp35 at vaxa.strath.ac.uk writes:
>any of you wiz's know how I can detect a keyboard press in shell script??
>
>I want it for a script which will execute a certain option if I press the
>correct key.


Here is my shot at reading individual characters from the terminal from within
a shell script.  There are definately more 'elegant' solutions, but this was
done using ONLY sh (and it was actually fun!).

This works on System Vr3.2.  It most probally won't work on other Unix's
(System V is all I know...)? If you're system doesn't have the 'hd' command,
replace the line:

    key=`hd -n 1 -t|awk '{ printf "%s", $2; }'`

With:

    key=`rd`

And here is the C source for the rd command (rd.c). To compile it:
    $ cc -o rd rd.c
    
    main() { char ch; read(0,&ch,1); write(1,&ch,1); }

In summary, this is what I did.

I used the stty command to put the terminal in non-cononical mode (-icanon)
and then used the stty command to set the VTIME (time to wait for a character)
and VMIN (# of characters to read before returning to caller) so that a read
would wait forever for a single character (See the termio(7) man page).  Then
I used the hd (hex dump) command (or rd if you don't have hd) to read a
single character from the keyboard.  The shell read command wouldn't work,
because it reads until it see's a \n character.

I used stty -g, which prints out values from the 'termio' structure (in the
order that they appear in that structure).  I then used awk to modify the
needed elements in that structure to get a VMIN of 1 and a VTIME of 0.
I would of been able to use "stty eof '^a' eol '^@'" if ^@ evaluated to a hex
0 (eof and eol correspond to the VMIN and VTIME termio elements when in
-icanon mode).


Any questions?
Tom
-- 
Tom Armistead - Software Services - 2918 Dukeswood Dr. - Garland, Tx  75040
===========================================================================
toma at swsrv1.cirr.com                {egsner,letni,ozdaltx,void}!swsrv1!toma


############ Cut all above this line #########################################
#
# This source code is public domain.  Use it as YOU see fit.  If you want to
# send me money, the fridge is a little low on beer.  Or you could just send
# me beer (I drink Stroh's Lite)...
#
##############################################################################
#
# Save the current stty settings.
#
Orig_tty=`stty -g`

# Turn of Erase/Kill/INTR processing (enable single character read)
# This is the stty mode that will be used to read the character from the
# terminal.  If you don't want the pressed keys to be echo'd to the terminal,
# add '-echo' to this stty command.
#
stty -icanon -isig -brkint	# Tty mode to read character in.
Raw_tty=`stty -g`		# Save stty settings for the new mode.
stty $Orig_tty			# Restore original stty settings.

# Set single character read (the "1") and wait forever for the character (the
# "0")  These positions correspond to VMIN and VTIME in the termio structure
# (positions 4 and 5 in termio.c_cc[]).
#
Raw_tty=`echo $Raw_tty|awk -F: '{
	               printf "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s", \
                       $1,$2,$3,$4,$5,$6,$7,$8,"1","0",$11,$12 \
	               }'`



while [ "$leave" != yes ]
do
    echo
    echo "1   - Do the 1 thing."
    echo "2   - Do the 2 thing."
    echo "3   - Do the 3 thing."
    echo "4   - Do the 4 thing."
    echo "Q   - Quit"

    echo "\nSelect: \c"

    # Set up terminal to read read a single character
    #
    stty $Raw_tty

    # Read a single key from the terminal
    #
    key=`hd -n 1 -t|awk '{ printf "%s", $2; }'`

    # Restore original terminal settings
    #
    stty $Orig_tty

    # Figure out what to do with the pressed key?
    #
    case $key in
        1   )   echo "\n\nFirst thing."
                ;;
	2   )   echo "\n\nSecond thing."
                ;;
	3|4 )   echo "\n\nThree or Four."
                ;;
	q|Q )   echo "\n\nSo long..."
		leave=yes
                ;;
	*   )   echo "\n\n\007INVALID OPTION.\n"
                ;;
    esac
done #while

# The END.
-- 
Tom Armistead - Software Services - 2918 Dukeswood Dr. - Garland, Tx  75040
===========================================================================
toma at swsrv1.cirr.com                {egsner,letni,ozdaltx,void}!swsrv1!toma



More information about the Comp.unix.questions mailing list