List Info

Thread: The Idiot's Guide To Reading The Keyboard




The Idiot's Guide To Reading The Keyboard
country flaguser name
United Kingdom
2008-02-26 11:12:02
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 = 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 

-- 
David Cantrell | top google result for "internet beard
fetish club"

"IMO, the primary historical significance of Unix is
that it marks the
time in computer history where CPUs became so cheap that it
was possible
to build an operating system without adult
supervision."
                         -- Russ Holsclaw in a.f.c

Re: The Idiot's Guide To Reading The Keyboard
country flaguser name
United Kingdom
2008-02-26 11:50:56
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 = 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 = 'IGNORE';
$SIG = 'IGNORE';
$SIG = $SIG = 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 closedn");
                 $end = -2;
                 last;
             } else {
	        handle_tty($fh, $buf);
             }
         } elsif ($! == EAGAIN || $! == EWOULDBLOCK || $! ==
EINPROGRESS) {
             next;
         } else {
             warn "error $! receivedn";
             $end = -3;
             last;
         }
     }

#
# do some other stuff
#

}



[1-2]

about | contact  Other archives ( Real Estate discussion Medical topics )