perlfaq nodetype
faq_monk
<P>
Controlling input buffering is a remarkably system-dependent matter. If
most systems, you can just use the <STRONG>stty</STRONG> command as shown in
<U>getc</U>, but as you see, that's already getting you into portability snags.
<P>
<PRE> open(TTY, "+</dev/tty") or die "no tty: $!";
system "stty cbreak </dev/tty >/dev/tty 2>&1";
$key = getc(TTY); # perhaps this works
# OR ELSE
sysread(TTY, $key, 1); # probably this does
system "stty -cbreak </dev/tty >/dev/tty 2>&1";
</PRE>
<P>
The Term::ReadKey module from
<FONT SIZE=-1>CPAN</FONT> offers an easy-to-use interface that should be
more efficient than shelling out to <STRONG>stty</STRONG> for each key. It even includes limited support for Windows.
<P>
<PRE> use Term::ReadKey;
ReadMode('cbreak');
$key = ReadKey(0);
ReadMode('normal');
</PRE>
<P>
However, that requires that you have a working
<FONT SIZE=-1>C</FONT> compiler and can use it to build and install a
<FONT SIZE=-1>CPAN</FONT> module. Here's a solution using the standard
<FONT SIZE=-1>POSIX</FONT> module, which is already on your systems (assuming your system supports
<FONT SIZE=-1>POSIX).</FONT>
<P>
<PRE> use HotKey;
$key = readkey();
</PRE>
<P>
And here's the HotKey module, which hides the somewhat mystifying calls to manipulate the
<FONT SIZE=-1>POSIX</FONT> termios structures.
<P>
<PRE> # HotKey.pm
package HotKey;
</PRE>
<P>
<PRE> @ISA = qw(Exporter);
@EXPORT = qw(cbreak cooked readkey);
</PRE>
<P>
<PRE> use strict;
use POSIX qw(:termios_h);
my ($term, $oterm, $echo, $noecho, $fd_stdin);
</PRE>
<P>
<PRE> $fd_stdin = fileno(STDIN);
$term = POSIX::Termios->new();
$term->getattr($fd_stdin);
$oterm = $term->getlflag();
</PRE>
<P>
<PRE> $echo = ECHO | ECHOK | ICANON;
$noecho = $oterm & ~$echo;
</PRE>
<P>
<PRE> sub cbreak {
$term->setlflag($noecho); # ok, so i don't want echo either
$term->setcc(VTIME, 1);
$term->setattr($fd_stdin, TCSANOW);
}
</PRE>
<P>
<PRE> sub cooked {
$term->setlflag($oterm);
$term->setcc(VTIME, 0);
$term->setattr($fd_stdin, TCSANOW);
}
</PRE>
<P>
<PRE> sub readkey {
my $key = '';
cbreak();
sysread(STDIN, $key, 1);
cooked();
return $key;
}
</PRE>
<P>
<PRE> END { cooked() }
</PRE>
<P>
<PRE> 1;
</PRE>
<P>