For some reason, in my simple menu program, weird things happen as a result of ReadKey()
#!/usr/local/bin/perl
use strict ;
use warnings ;
use English ;
use Term::ReadKey ;
my @available_choices = ('choice one', 'choice two', 'choice three') ;
my $array_size = scalar (@available_choices) ;
print "\nPlease make your selection from the options below:\n\n" ;
for (my $i=0, my $j=1 ; $i < $array_size ; $i++, $j++) {
print "$j) $available_choices[$i]\n" ;
}
my $key = undef ;
for (my $k=0; $k < 5; $k++) {
print "\nSelection :> " ;
$key = ReadKey();
if ((defined $key) && ($key =~ /[1-$array_size]/)) {
print "\nYou selected \"$available_choices[$key-1]\"\n" ;
last ;
}
else {
sleep 1 ;
}
}
So if you run this simple program and give 1, 2, or 3 as your selection it works as expected. If you enter anything else (to trigger the else block) the loop iterates like 3 or 4 times before ReadKey() accepts input, again. Best illustrated by this output (I entered xxx and then “Selection:>” printed 3 times before I was able to type yyy):
$ ./bar.pl
Please make your selection from the options below:
1) choice one
2) choice two
3) choice three
Selection :> xxx
Selection :>
Selection :>
Selection :>
Selection :> yyy
It’s because
ReadKeyreads a key. When you press x 3 times and then Enter, that’s 4 keys. In fact, even a correct selection (1 Enter) is 2 keys; you just don’t notice because your program exits immediately.This is less obvious because the default input mode buffers keystrokes until you press Enter. At that point,
ReadKeywill start to return each keystroke one at a time.The solution depends on the behavior you’re looking for. If you want to have to press Enter before acting on the input, then you can just read a line at a time (with the standard
<>operator). You don’t needTerm::ReadKeyat all.If you want to take action immediately after a keypress, you’ll need to use
Term::ReadKey‘sReadModefunction to change the input buffering. Don’t forget to addEND { ReadMode(0) }to restore the original mode when your program exits.