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