2013-05-08 34 views
0

如果不调用函数_end_win,是否有调用函数main的可能性?再次建立初始状态的安全方法。

#!/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

我不确定你在问什么。你可以把_end_win调出来,但我不认为这就是你的意思。 – Borodin 2013-05-08 09:20:36

+0

你究竟在努力完成什么?我可以想出几种方法来防止'_end_win'被永远调用(例如,当它等待用户输入时'kill -9'进程),但是,在不知道你的目的的情况下,不可能说出哪些可能与你有关。 – 2013-05-08 10:55:25

+0

我想知道,如果这是保存。 – 2013-05-08 11:14:59

回答

1

为确保在程序退出时终端复位,请将复位代码放入END区块。

END { 
    print "\n\r"; 
    Term::ReadKey::ReadMode 'restore'; 
} 

(我删除重新$|select ED输出文件句柄由于过程是无论如何退出线,所以他们要变得无关紧要。)

:例如,你可以用更换您 _end_win

当程序以“正常”方式终止时,例如调用exitdie或触击可执行代码的结尾,END块将始终运行。当进程由于接收信号而终止时它不会触发;它看起来像是直接处理ctrl-C字符,但您也可以考虑添加%SIG{INT}处理程序,以防有人向您发送kill -2

+0

我猜对了,如果函数和'END'块在模块中,这也可以工作。 – 2013-05-08 16:08:15

+0

@sid_com:是的,你是对的。 'END'块可以在任何一段加载的代码中。 – 2013-05-09 00:08:59