【问题标题】:How can I get user input without waiting for enter in Perl?如何在不等待输入 Perl 的情况下获取用户输入?
【发布时间】:2011-02-10 17:24:23
【问题描述】:

我正在尝试在 Perl 中制作交互式 shell 脚本。

我能找到的唯一用户输入如下:

 $name = <STDIN>;
 print STDOUT "Hello $name\n";

但在这种情况下,用户必须始终按 Enter 才能使更改生效。 如何让程序在按下按钮后立即继续?

【问题讨论】:

    标签: perl user-input


    【解决方案1】:

    您可以使用Term::ReadKey 模块来检查按键。

    【讨论】:

      【解决方案2】:

      来自perlfaq8How do I read just one key without waiting for a return key? 的回复:


      控制输入缓冲非常依赖于系统。在许多系统上,您可以只使用 perlfunc 中的 getc 中所示的 stty 命令,但正如您所见,这已经让您陷入可移植性障碍。

      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";
      

      来自 CPAN 的 Term::ReadKey 模块提供了一个易于使用的界面,该界面应该比为每个键都输出到 stty 更有效。它甚至包括对 Windows 的有限支持。

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

      但是,使用该代码需要您有一个可用的 C 编译器,并且可以使用它来构建和安装 CPAN 模块。这是一个使用标准 POSIX 模块的解决方案,该模块已经在您的系统上(假设您的系统支持 POSIX)。

      use HotKey;
      $key = readkey();
      

      这里是 HotKey 模块,它隐藏了操作 POSIX termios 结构的有点神秘的调用。

      # 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;
      

      【讨论】:

      • 我能够使用第一种方法(加上第二种方法):打开 TTY,将其设置为字符中断,然后使用 sysread 仅抓取 1 个字符
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多