The Idiot's Guide To Reading The Keyboard

Dirk Koopman djk at tobit.co.uk
Tue Feb 26 17:50:56 GMT 2008


David Cantrell wrote:
> I need to be able to make a particular method call asynchronously, and
> to call it very frequently - about a hundred times a second should be
> about right - and if possible read a character from STDIN and pass it to
> the method, without blocking.
> 
> The obvious solution is a select() loop, but I just can't wrap my head
> around four-arg select.  Tried it several times, read the man pages
> backwards and forwards, looked in the cookbook, can't do it.
> The next most obvious solution is POE.  But unfortunately its
> documentation still favours completeness over usefullness.  There's lots
> of stuff in there about reading lines of text from STDIN, or reading
> from a notwork socket, but try as I might I can't combine them to read a
> character if one is available.
> 
> So I did this ...
> 
> use Time::HiRes qw(setitimer ITIMER_REAL);
> use Term::ReadKey;
> 
> ... [stuff here to create an object $o] ...
> 
> setitimer(ITIMER_REAL, 1, 0.01); # after 1 sec, ALRM every 0.01 sec
> $SIG{ALRM} = sub {
>     ReadMode 'cbreak';
>     ReadMode 'noecho';
>     $o->deal_with_input(ReadKey(-1));
>     ReadMode 'normal';
> };
> 
> $o->loop_forever();
> 
> Banging my head against select() and POE took a good couple of hours
> last night, with nothing to show for it.  Reading perlfaq8 at lunchtime
> took about five minutes.
> 
> On IRC, Nicholas said that this was sick.  I'm not sure why he thinks
> that, but I'll take it as a compliment :-)
> 

I agree, use IO::Select.

This is a snippet from something else:-

# open the read select handler and add all the file handles
my $rd = IO::Select->new($udp, @tty);

# handle various signals
my $end = 0;
$SIG{HUP} = 'IGNORE';
$SIG{PIPE} = 'IGNORE';
$SIG{TERM} = $SIG{INT} = sub {         # don't ask OK!
                 my $sig = shift;
                 $end = 15 if $sig eq 'TERM';
                 $end = 2 if $sig eq 'INT';
                 $end ||= -4;
             } unless $DB::VERSION;

#
# the main loop
#
my @ready;
my $lasttime = 0;
while (!$end) {
     @ready = $rd->can_read(0.01);
     my $now = time;

     foreach my $fh (@ready) {
         my $buf;
         my $r = $fh->sysread($buf, 1024);
         if (defined $r) {
             if ($r == 0) {
                 warn("tty closed\n");
                 $end = -2;
                 last;
             } else {
	        handle_tty($fh, $buf);
             }
         } elsif ($! == EAGAIN || $! == EWOULDBLOCK || $! == EINPROGRESS) {
             next;
         } else {
             warn "error $! received\n";
             $end = -3;
             last;
         }
     }

#
# do some other stuff
#

}




More information about the london.pm mailing list