news.utdallas.edu!convex!convex!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!yale!gumby!destroyer!cs.ubc.ca!uw-beaver!fluke!dbc Wed Mar  3 13:09:26 CST 1993
Article: 1330 of comp.lang.perl
Xref: feenix.metronet.com comp.lang.perl:1330
Newsgroups: comp.lang.perl
Path: feenix.metronet.com!news.utdallas.edu!convex!convex!cs.utexas.edu!qt.cs.utexas.edu!yale.edu!yale!gumby!destroyer!cs.ubc.ca!uw-beaver!fluke!dbc
From: dbc@tc.fluke.COM (Dan Carson)
#Subject: Re: Testing input character if arrow or function key etc (DOS).
Message-ID: <1993Mar2.171637.21894@tc.fluke.COM>
Organization: John Fluke Mfg. Co., Inc., Everett, WA
References: <1493@alsys1.aecom.yu.edu>
Date: Tue, 2 Mar 1993 17:16:37 GMT
Lines: 90

In article <1493@alsys1.aecom.yu.edu> manaster@yu1.yu.edu (Chaim Manaster) writes:
>The question is in two parts:
>1) How do you get a single character returned from the keyboard
>without requiring a carriage return after the keypress? I have been
>directed to the perl FAQ, unfortunately, it is totaly moot on
>how to do this for MSDOS systems. I have tried simply using
>$key = getc; or $key = <STDIN>; which required a carriage return
>and didn't quite work as expected.
>
>2) Once you have the keypress stored in $key, how do you test
>to see if it was either an arrow key, HOME, END, PGUP, PGDN, a
>function key (F1-F12) or some other non-printable key? 
>i.e. $key == ???????
>
>Please be DOS specific as this is system dependent.
>
>I have tried something like:
>$key = <STDIN>;
>print oct($key);
>
>to see if that would give me a clue as to what value these keys
>returned to no avail. (I tried with chop($key) as well).
>
>Thank you very much for the help.
>
>Henry Manaster
>
>-- 
>***************************************************************************
>	Henry Manaster          *     EMail: manaster@yu1.yu.edu
>	Brooklyn, NY            *
>                                *
>	Disclaimer: The above is not necessarily MY opinion nor that 
>				of anyone else :-)  ????!
>****************************************************************************
> 

This should be added to the FAQ, I've answered this question in this group
several times.

Question 1:  To put the PC in "raw" mode, use ioctl with some magic numbers
gleaned from msdos.c (Perl source file) and Ralf Brown's interrupt list
(comes across the net every so often):

$old_ioctl = ioctl(STDIN,0,0);     # Gets device info
$old_ioctl &= 0xff;
ioctl(STDIN,1,$old_ioctl | 32);    # Writes it back, setting bit 5

Then to read a single character:

sysread(STDIN,$c,1);               # Read a single character

And to put the PC back to "cooked" mode:

ioctl(STDIN,1,$old_ioctl);         # Sets it back to cooked mode.


Question 2:  So now you have $c.  If ord($c) == 0, you have a two byte code,
which means you hit a special key.  Read another byte (sysread(STDIN,$c,1)),
and that value tells you what combination it was according to this table:

# PC 2-byte keycodes = ^@ + the following:

# HEX     KEYS
# ---     ----
# 0F      SHF TAB
# 10-19   ALT QWERTYUIOP
# 1E-26   ALT ASDFGHJKL
# 2C-32   ALT ZXCVBNM
# 3B-44   F1-F10
# 47-49   HOME,UP,PgUp
# 4B      LEFT
# 4D      RIGHT
# 4F-53   END,DOWN,PgDn,Ins,Del
# 54-5D   SHF F1-F10
# 5E-67   CTR F1-F10
# 68-71   ALT F1-F10
# 73-77   CTR LEFT,RIGHT,END,PgDn,HOME
# 78-83   ALT 1234567890-=
# 84      CTR PgUp

This is all trial and error I did a long time ago, I hope I'm reading the
file that worked.

Good luck-

dbc@tc.fluke.COM
Dan Carson
John Fluke Mfg.
Everett, WA