csotzing has asked for the wisdom of the Perl Monks concerning the following question:

Hi all-
I'm trying to figure out how to flush/clear STDIN for a text-menu based perl script. Below is part of the code for my menu pkg--it displays the menu, gets and handles user selections. handleResponse() calls the callback, which may take some time. BUT-if the user starts typing during the callback's processing, my menu will take it as the next input, and start acting funny. Any ideas on how I can clear STDIN so that I only get what's typed after the handleResponse returns? (Or maybe how I can close STDIN before handleResponse and reopen it after?)
# Name: showLoop # Desc: MainLoop for displaying text menu and handling input # In: loopMax - max number of looping # Out: None sub showLoop { my ($self,$loopMax) = (@_); my $loopNum = 0; while (1) { # clear screen clearScreen(); # display menu print "\n $self->{'title'}\n\n"; foreach my $item (@{$self->{"itemsRef"}}) { my $label = $item->getLabel(); print " $label\n"; } print "\n Select an option or quit [q]: "; # handle user response my $resp = $self->getResponse(); if ($resp =~ /^[qQ]$/) { last; } else { $self->handleResponse($resp); } $loopNum++; if ((defined $loopMax) && ($loopNum >= $loopMax)) { last; } # flush stdout and stdin autoflush STDOUT,1; # how to flush/empty stdin without blocking? # continue print "\n Return continues\n"; <STDIN>; } }


print(map(lc(chr),split(6,qw/99672682673683684689632658645641610607/)));

Replies are listed 'Best First'.
Re: Ignore STDIN during processing
by flounder99 (Friar) on Jun 18, 2002 at 15:02 UTC
    Try using Term::ReadKey It has a cleaner interface.
    use Term::ReadKey; use strict; while (1) { print "input some text: "; my $x = ReadLine(0); chomp $x; print "processing $x ...\n"; sleep 5; # try typing something while waiting ReadMode 4; # set to raw mode while (defined ReadKey(-1)) {}; # eats up keys in buffer ReadMode 0; # set to normal mode }

    --
    flounder

Re: Ignore STDIN during processing
by ariels (Curate) on Jun 18, 2002 at 13:20 UTC
    Here's A Way To Do It...
    #!/usr/local/bin/perl -w use strict; use Fcntl; print "Enter some text to lose...\n"; sleep 4; print "Losing...\n"; fcntl(STDIN, F_SETFL, O_NONBLOCK) or die "Couldn't set STDIN to non-blocking I/O: $!\n"; my $buf; 1 while (sysread(STDIN, $buf, 4096)); print "Reading...\n"; fcntl(STDIN, F_SETFL, 0) or die "Couldn't set STDIN to blocking I/O: $!\n"; print scalar <STDIN>;

    The code sleeps for 4 seconds, to let you type in some text. Then it loses that text, and reads in a line.

    You might also need something more: the above code deals with whole lines, so any incomplete lines typed before the 4 seconds are up will be kept. To get rid of those, try this (on UNIX):

    #!/usr/local/bin/perl -w use strict; use Fcntl; print "Enter some text to lose...\n"; sleep 4; print "Losing...\n"; system("/bin/stty raw"); die "stty failed\n" if $?; fcntl(STDIN, F_SETFL, O_NONBLOCK) or die "Couldn't set STDIN to non-blocking I/O: $!\n"; my $buf; print $buf while (sysread(STDIN, $buf, 4096)); print "Reading...\n"; system("/bin/stty cooked"); die "stty failed\n" if $?; fcntl(STDIN, F_SETFL, 0) or die "Couldn't set STDIN to blocking I/O: $!\n"; print scalar <STDIN>;

    Have "fun" (for the UN*Xish definition of "fun")...

      More Info--
      I need my perl to work on both Unix & Win... (I don't believe that Fcntl and Non-Blocking I/O work on Win) Is there a way to do this? ...or am I stuck to just implement the Fcntl for Unix, and to hell with the Win users?

      print(map(lc(chr),split(6,qw/99672682673683684689632658645641610607/)));