开发者

Perl Term::ReadKey don't wait for newline

开发者 https://www.devze.com 2023-01-03 12:22 出处:网络
In a perl script, I\'m trying to accept input without blocking and without echoing the characters entered (The script is producing output and I want to have \'hotkeys\' to alter its behaviour).

In a perl script, I'm trying to accept input without blocking and without echoing the characters entered (The script is producing output and I want to have 'hotkeys' to alter its behaviour).

I got a开发者_StackOverflows far as using

use Term::ReadKey;
ReadMode( "cbreak", STDIN );
if($input = ReadKey($pause_time, STDIN)){
    #process input
}

But once the user types anything then the script stops until a newline is entered. I'd like the input to be processed per-character, without waiting for a newline.


Here is a small program that does what I think you desire:

#!/usr/bin/perl

use strict;
use warnings;

use Term::ReadKey;

ReadMode 4;
END { ReadMode 0 }

print <<EOS;
q to quit
b to print in binary
o to print in octal
d to print in decimal
x to print in hexadecimal
EOS

my $control = "d";
my $i       = 0;
while (1) {
    #use "if" if you want to have a buffer of commands
    #that will be processed one per second  
    while (defined (my $key = ReadKey(-1))) {
        exit 0          if $key eq 'q';
        $control = $key if $key =~ /^[bodx]$/;
    }
    printf "%$control\n", $i++;
    sleep 1;
}


I was going to leave this as a comment to your own 'answer' but decided I needed more room.

cbreak is equivalent to raw mode except in that cbreak doesn't intercept control sequences like ctrl-c, ctrl-z etc. They both collect characters one at a time. The difference in behavior between the two modes isn't the source of your problem. If Chas's solution does something like what you intended, then the problem more likely has to do with whatever you redacted in your #process input line. I've commented already that your original script works fine if I fill it with something rudimentary so I can see that it's working. For example, a minor touch-up:

use strict;
use warnings;
use Term::ReadKey;

my ($char, $input, $pause_time);
ReadMode("cbreak");

# Collect all characters typed into $input
# and quit when '#' is typed.

$input = '';
while ($char = ReadKey($pause_time)) {
    last if $char eq '#';
    $input .= $char;
}

print "$input\n";

There's no need for me to hit 'enter' at the end of this, and doing so won't do anything (apart from throwing a carriage return into $input and weirding up the string).

0

精彩评论

暂无评论...
验证码 换一张
取 消