CC: | ruittenb [...] users.sourceforge.net |
Subject: | input is not received when it is available |
The problem can be reproduced with the attached program (reproduce.pl).
Run the program and press several function keys (e.g. F2/F3/F4/F5) in
quick succession. The application does not receive notification of all
of these keypresses: e.g. notification may stop when F2 and F3 have been
received. Only when another key is pressed (e.g. 'e') then will the keys
F4/F5/e arrive at the application.
The problem seems to be caused by the fact that the getc() function does
internal buffering, so that the select() call does not notice that there
is input ready to be processed. This seems to be a problem that occurs
on all Unices.
The problem can be solved by using sysread() instead of getc(). I have
attached a patch.
Subject: | Term-Screen-1.03.diff |
--- Screen-1.03.pm 2010-04-23 19:51:20.000000000 +0200
+++ Screen-1.03-sysread.pm 2010-04-23 19:52:38.000000000 +0200
@@ -6,7 +6,7 @@
use vars qw($VERSION);
-$VERSION = '1.03';
+$VERSION = '1.03-sysread';
=head1 NAME
@@ -441,11 +441,11 @@
sub getch
{
my $this = shift;
- my ( $c, $fn_flag ) = ( '', 0 );
+ my ( $c, $nc, $fn_flag ) = ( '', '', 0 );
my $partial_fn_str = '';
if ( $this->{IN} ) { $c = chop( $this->{IN} ); }
- else { $c = getc(STDIN); }
+ else { sysread( STDIN, $c, 1 ); }
$partial_fn_str = $c;
while ( exists( $this->{KEYS}{$partial_fn_str} ) )
@@ -460,7 +460,11 @@
else # wait for another key to see if were in FN yet
{
if ( $this->{IN} ) { $partial_fn_str .= chop( $this->{IN} ); }
- else { $partial_fn_str .= getc(); }
+ else
+ {
+ sysread(STDIN, $nc, 1);
+ $partial_fn_str .= $nc;
+ }
}
}
if ($fn_flag) # seemed like a fn key
@@ -552,8 +556,9 @@
sub flush_input
{
my $this = shift;
+ my $discard;
$this->{IN} = '';
- while ( $this->key_pressed() ) { getc(); }
+ while ( $this->key_pressed() ) { sysread(STDIN, $discard, 1); }
return $this;
}
Subject: | reproduce.pl |
#!/usr/bin/env perl
use Term::Screen;
$term = new Term::Screen();
$delay = 1;
$term->clrscr();
until ($key eq 'q')
{
print "Waiting for input.";
until (length($term->{IN}) || $term->key_pressed($delay))
{
# poll background jobs etc.
print ".";
}
$key = $term->getch();
print "\r\nReceived: $key. Hold on while I do stuff...\r\n";
sleep 1;
}