是否有可能在没有调用函数main
的情况下调用函数_end_win
?
#!/usr/bin/env perl
use warnings;
use strict;
use 5.10.0;
use Term::ReadKey;
use constant {
NEXT_getch => -1,
CONTROL_C => 0x03,
CONTROL_D => 0x04,
KEY_ENTER => 0x0d,
KEY_RIGHT => 0x1b5b43,
KEY_LEFT => 0x1b5b44,
};
say main();
sub main {
my $arg = {};
$arg->{handle_out} = *STDOUT;
_init_scr( $arg );
while ( 1 ) {
my $c = _getch( $arg );
if ( ! defined $c ) {
_end_win( $arg );
warn "EOT";
return;
}
next if $c == NEXT_getch;
given ( $c ) {
when ( $c >= 97 && $c <= 122 ) {
print chr $c;
$arg->{string} .= chr $c;
}
when ( $c == KEY_RIGHT ) {
print '>';
$arg->{string} .= '>';
}
when ( $c == KEY_LEFT ) {
print '<';
$arg->{string} .= '<';
}
when ( $c == CONTROL_D ) {
_end_win( $arg );
return;
}
when ( $c == CONTROL_C ) {
_end_win( $arg );
print STDERR "^C";
kill( 'INT', $$ );
return;
}
when ( $c == KEY_ENTER ) {
_end_win( $arg );
return $arg->{string};
}
}
}
}
sub _init_scr {
my ( $arg ) = @_;
$arg->{old_handle} = select( $arg->{handle_out} );
$arg->{backup_flush} = $|;
$| = 1;
Term::ReadKey::ReadMode 'ultra-raw';
}
sub _end_win {
my ( $arg ) = @_;
print "\n\r";
Term::ReadKey::ReadMode 'restore';
$| = $arg->{backup_flush};
select( $arg->{old_handle} );
}
sub _getch {
my ( $arg ) = @_;
my $c1 = ReadKey 0;
return if ! defined $c1;
if ( $c1 eq "\e" ) {
my $c2 = ReadKey 0.10;
if ( ! defined $c2 ) { return NEXT_getch; }
elsif ( $c2 eq 'C' ) { return KEY_RIGHT; }
elsif ( $c2 eq 'D' ) { return KEY_LEFT; }
elsif ( $c2 eq '[' ) {
my $c3 = ReadKey 0;
if ( $c3 eq 'C' ) { return KEY_RIGHT; }
elsif ( $c3 eq 'D' ) { return KEY_LEFT; }
else {
return NEXT_getch;
}
}
else {
return NEXT_getch;
}
}
else {
return ord $c1;
}
}
答案 0 :(得分:1)
要确保在程序退出时重置终端,请将重置代码放入END
块。例如,您可以将_end_win
子替换为:
END {
print "\n\r";
Term::ReadKey::ReadMode 'restore';
}
(我删除了重置$|
和select
ed输出文件句柄的行,因为无论如何退出流程,所以它们将变得无关紧要。)
当程序以“正常”方式终止时,END
块将始终运行,例如调用exit
或die
或命中可执行代码的末尾。由于接收到信号,当过程终止时,它不会触发;看起来您正在直接处理ctrl-C字符,但您可能还需要考虑添加%SIG{INT}
处理程序,以防有人向您发送kill -2
。