【发布时间】:2011-02-10 17:24:23
【问题描述】:
我正在尝试在 Perl 中制作交互式 shell 脚本。
我能找到的唯一用户输入如下:
$name = <STDIN>;
print STDOUT "Hello $name\n";
但在这种情况下,用户必须始终按 Enter 才能使更改生效。 如何让程序在按下按钮后立即继续?
【问题讨论】:
标签: perl user-input
我正在尝试在 Perl 中制作交互式 shell 脚本。
我能找到的唯一用户输入如下:
$name = <STDIN>;
print STDOUT "Hello $name\n";
但在这种情况下,用户必须始终按 Enter 才能使更改生效。 如何让程序在按下按钮后立即继续?
【问题讨论】:
标签: perl user-input
您可以使用Term::ReadKey 模块来检查按键。
【讨论】:
来自perlfaq8对How 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;
【讨论】: