How can I get user input without waiting for enter in Perl?

后端 未结 2 764
被撕碎了的回忆
被撕碎了的回忆 2021-01-11 10:56

I am trying to make an interactive shell script in Perl.

The only user input I can find is the following:

 $name = ;
 print STDOUT \"Hel         


        
相关标签:
2条回答
  • 2021-01-11 11:21

    You can use the Term::ReadKey module to check for a keypress.

    0 讨论(0)
  • 2021-01-11 11:31

    From perlfaq8's answer to How do I read just one key without waiting for a return key? :


    Controlling input buffering is a remarkably system-dependent matter. On many systems, you can just use the stty command as shown in getc in perlfunc, but as you see, that's already getting you into portability snags.

    open(TTY, "+</dev/tty") or die "no tty: $!";
    system "stty  cbreak </dev/tty >/dev/tty 2>&1";
    $key = getc(TTY);       # perhaps this works
    # OR ELSE
    sysread(TTY, $key, 1);  # probably this does
    system "stty -cbreak </dev/tty >/dev/tty 2>&1";
    

    The Term::ReadKey module from CPAN offers an easy-to-use interface that should be more efficient than shelling out to stty for each key. It even includes limited support for Windows.

    use Term::ReadKey;
    ReadMode('cbreak');
    $key = ReadKey(0);
    ReadMode('normal');
    

    However, using the code requires that you have a working C compiler and can use it to build and install a CPAN module. Here's a solution using the standard POSIX module, which is already on your system (assuming your system supports POSIX).

    use HotKey;
    $key = readkey();
    

    And here's the HotKey module, which hides the somewhat mystifying calls to manipulate the POSIX termios structures.

    # HotKey.pm
    package HotKey;
    
    @ISA = qw(Exporter);
    @EXPORT = qw(cbreak cooked readkey);
    
    use strict;
    use POSIX qw(:termios_h);
    my ($term, $oterm, $echo, $noecho, $fd_stdin);
    
    $fd_stdin = fileno(STDIN);
    $term     = POSIX::Termios->new();
    $term->getattr($fd_stdin);
    $oterm     = $term->getlflag();
    
    $echo     = ECHO | ECHOK | ICANON;
    $noecho   = $oterm & ~$echo;
    
    sub cbreak {
        $term->setlflag($noecho);  # ok, so i don't want echo either
        $term->setcc(VTIME, 1);
        $term->setattr($fd_stdin, TCSANOW);
    }
    
    sub cooked {
        $term->setlflag($oterm);
        $term->setcc(VTIME, 0);
        $term->setattr($fd_stdin, TCSANOW);
    }
    
    sub readkey {
        my $key = '';
        cbreak();
        sysread(STDIN, $key, 1);
        cooked();
        return $key;
    }
    
    END { cooked() }
    
    1;
    
    0 讨论(0)
提交回复
热议问题