File Coverage

blib/lib/Term/ReadPassword/Win32.pm
Criterion Covered Total %
statement 13 86 15.1
branch 0 40 0.0
condition 0 22 0.0
subroutine 5 9 55.5
pod 0 5 0.0
total 18 162 11.1


line stmt bran cond sub pod time code
1             package Term::ReadPassword::Win32;
2              
3 1     1   15404 use strict;
  1         1  
  1         33  
4 1     1   4 use warnings;
  1         1  
  1         26  
5              
6 1     1   4 use Exporter qw(import);
  1         4  
  1         30  
7              
8 1         778 use vars qw(
9             $SUPPRESS_NEWLINE $INPUT_LIMIT
10             $USE_STARS $STAR_STRING $UNSTAR_STRING
11 1     1   3 );
  1         1  
12              
13             our @EXPORT = qw(read_password);
14             our @EXPORT_OK = qw(ReadPasswd read_passwd);
15              
16             our $VERSION = '0.11_02';
17              
18             if ( IsWin32() ) {
19             eval('use Win32');
20             eval('use Win32::Console');
21             eval('use Win32API::File');
22             }
23             else {
24             eval('require Term::ReadPassword');
25             }
26              
27             # The maximum amount of data for the input buffer to hold
28             $INPUT_LIMIT = 1000;
29              
30             sub ReadPasswd {
31 0     0 0 0 read_password(@_);
32             }
33              
34             sub read_passwd {
35 0     0 0 0 read_password(@_);
36             }
37              
38             sub read_password {
39 0     0 0 0 my ( $prompt, $idle_limit, $interruptmode ) = @_;
40 0 0       0 $prompt = '' unless defined $prompt;
41 0 0       0 $idle_limit = 0 unless defined $idle_limit;
42 0 0       0 $interruptmode = 0 unless defined $interruptmode;
43              
44 0 0       0 if ( !IsWin32() ) {
45 0 0       0 my $interruptable = ( $interruptmode > 0 ) ? 1 : 0;
46              
47 0         0 $Term::ReadPassword::SUPPRESS_NEWLINE = $SUPPRESS_NEWLINE;
48 0         0 $Term::ReadPassword::INPUT_LIMIT = $INPUT_LIMIT;
49 0         0 $Term::ReadPassword::USE_STARS = $USE_STARS;
50 0         0 $Term::ReadPassword::STAR_STRING = $STAR_STRING;
51 0         0 $Term::ReadPassword::UNSTAR_STRING = $UNSTAR_STRING;
52              
53 0         0 return Term::ReadPassword::read_password( $prompt, $idle_limit,
54             $interruptable );
55             }
56              
57 0         0 $idle_limit *= 1000; # sec -> msec
58              
59 0         0 my $CONIN = Win32::Console->new( Win32::Console::STD_INPUT_HANDLE() );
60 0         0 my $CONOUT = Win32::Console->new( Win32::Console::STD_ERROR_HANDLE() );
61              
62             # make sure that input and output are not redirected
63 0         0 my $hStdin = $CONIN->{'handle'};
64 0         0 $CONIN->{'handle'} = Win32API::File::createFile( 'CONIN$', 'rw' );
65 0         0 my $hStderr = $CONOUT->{'handle'};
66 0         0 $CONOUT->{'handle'} = Win32API::File::createFile( 'CONOUT$', 'rw' );
67              
68 0         0 $CONOUT->Write($prompt);
69              
70 0         0 $CONIN->Flush();
71              
72 0         0 my $conmode = $CONIN->Mode();
73 0 0       0 if ( $interruptmode <= 1 ) {
74              
75             # disable the system for processing Ctrl+C
76 0         0 $CONIN->Mode( $conmode & ~Win32::Console::ENABLE_PROCESSED_INPUT() );
77             }
78              
79             # Optionally echo stars in place of password characters.
80 0 0 0     0 my $star_string = $USE_STARS ? ( $STAR_STRING || '*' ) : '';
81 0 0 0     0 my $unstar_string = $USE_STARS ? ( $UNSTAR_STRING || "\b \b" ) : '';
82              
83             # the input buffer
84 0         0 my $input = '';
85              
86 0         0 my $tick = Win32::GetTickCount();
87 0         0 my $tick2 = $tick;
88             keyin:
89 0         0 while (1) {
90 0         0 while ( $CONIN->GetEvents() == 0 ) {
91 0         0 Win32::Sleep(10);
92 0         0 $tick2 = Win32::GetTickCount();
93 0 0 0     0 if ( $idle_limit && ( DiffTick( $tick2, $tick ) > $idle_limit ) )
94             {
95              
96             # timeout
97 0         0 undef $input;
98 0         0 last keyin;
99             }
100             }
101 0         0 $tick = $tick2;
102              
103             # read console
104 0         0 my ( $evtype, $keydown, undef, $keycode, undef, $ch, undef )
105             = $CONIN->Input();
106              
107             # next if not a keydown event
108 0 0 0     0 next if ( $evtype != 1 || !$keydown );
109              
110 0 0       0 $ch = 0x7f if ( $keycode == 0x2e ); # Del
111 0 0       0 next if ( $ch == 0x00 ); # Special Keys
112 0         0 $ch &= 0xff; # for multibyte chars
113              
114 0 0 0     0 if ( $ch == 0x0d || $ch == 0x0a ) { # Enter
    0 0        
    0 0        
    0 0        
115             # end
116 0         0 last;
117             }
118             elsif ( $ch == 0x08 || $ch == 0x7f ) { # BS, Del
119 0 0       0 if ( length($input) > 0 ) {
120              
121             # delete the last char
122             #
123             # BUG: If the last char is multibyte character,
124             # this doesn't work well.
125 0         0 chop $input;
126              
127 0         0 $CONOUT->Write($unstar_string);
128             }
129             }
130             elsif ( $ch == 0x15 ) { # Ctrl+U
131 0         0 $CONOUT->Write( $unstar_string x length($input) );
132 0         0 $input = ''; # clear all
133             }
134             elsif (( $interruptmode > 0 )
135             && ( $ch == 0x1b || $ch == 0x03 ) )
136             { # Esc, Ctrl+C
137             # cancel
138 0         0 undef $input;
139 0         0 last;
140             }
141             else {
142             # normal chars
143 0         0 $input .= chr($ch);
144 0         0 $CONOUT->Write($star_string);
145             }
146 0 0       0 if ( length($input) > $INPUT_LIMIT ) {
147 0         0 $input = substr( $input, 0, $INPUT_LIMIT );
148             }
149             }
150              
151 0 0       0 $CONOUT->Write("\n") unless $SUPPRESS_NEWLINE;
152              
153             # restore console mode
154 0         0 $CONIN->Mode($conmode);
155              
156             # restore console handles
157 0         0 Win32API::File::CloseHandle( $CONIN->{'handle'} );
158 0         0 $CONIN->{'handle'} = $hStdin;
159 0         0 Win32API::File::CloseHandle( $CONOUT->{'handle'} );
160 0         0 $CONOUT->{'handle'} = $hStderr;
161              
162 0         0 $CONIN = undef;
163 0         0 close STDIN;
164 0         0 open STDIN, '+
165 0         0 return $input;
166             }
167              
168             sub DiffTick {
169 0     0 0 0 my ( $tick1, $tick2 ) = @_;
170 0         0 $tick1 &= 0xFFFFFFFF;
171 0         0 $tick2 &= 0xFFFFFFFF;
172              
173 0 0       0 if ( $tick1 >= $tick2 ) {
174 0         0 return $tick1 - $tick2;
175             }
176             else {
177 0         0 return 0xFFFFFFFF + 1 + $tick1 - $tick2;
178             }
179             }
180              
181             sub IsWin32 {
182 1     1 0 4 return ( $^O eq 'MSWin32' );
183             }
184              
185             1;
186              
187             __END__