| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Term::InKey; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | # Ariel Brosh (R.I.P), November 2001, for Raz Information Systems | 
| 4 |  |  |  |  |  |  | # Now manitained by Oded S. Resnik Raz Information Systems | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | require Exporter; | 
| 7 | 1 |  |  | 1 |  | 1406 | use strict qw(vars subs); | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 40 |  | 
| 8 | 1 |  |  | 1 |  | 5 | use vars qw(@ISA @EXPORT $VERSION $WIN32CONSOLE $BAD_CLS $BAD_RKEY $TER_CLS); | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 3529 |  | 
| 9 |  |  |  |  |  |  | @ISA = qw(Exporter); | 
| 10 |  |  |  |  |  |  | @EXPORT = qw(ReadKey Clear ReadPassword); | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | $VERSION = '1.04'; | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | sub WinSetConsole { | 
| 15 | 0 | 0 |  | 0 | 0 | 0 | return $WIN32CONSOLE if $WIN32CONSOLE; | 
| 16 | 0 |  |  |  |  | 0 | require Win32::Console; | 
| 17 | 0 |  |  |  |  | 0 | import Win32::Console; | 
| 18 |  |  |  |  |  |  | { | 
| 19 | 0 |  |  |  |  | 0 | local *STDERR; | 
|  | 0 |  |  |  |  | 0 |  | 
| 20 | 0 |  |  |  |  | 0 | open STDERR, ">/dev/null"; | 
| 21 | 0 |  |  |  |  | 0 | $WIN32CONSOLE = Win32::Console-> | 
| 22 |  |  |  |  |  |  | new(Win32::Console->STD_INPUT_HANDLE); | 
| 23 |  |  |  |  |  |  | } | 
| 24 | 0 |  |  |  |  | 0 | return $WIN32CONSOLE; | 
| 25 |  |  |  |  |  |  | } | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | sub WinReadKey { | 
| 28 | 0 |  |  | 0 | 0 | 0 | my $y; | 
| 29 | 0 |  |  |  |  | 0 | eval { | 
| 30 | 0 | 0 |  |  |  | 0 | if(&WinSetConsole) | 
| 31 |  |  |  |  |  |  | { | 
| 32 | 0 |  | 0 |  |  | 0 | my $mode = $WIN32CONSOLE->Mode || die $^E; | 
| 33 | 0 |  |  |  |  | 0 | my $newmode = $mode; | 
| 34 | 0 |  |  |  |  | 0 | $newmode &= ~(&ENABLE_LINE_INPUT | &ENABLE_ECHO_INPUT); | 
| 35 | 0 | 0 |  |  |  | 0 | $WIN32CONSOLE->Mode($newmode) || die $^E; | 
| 36 | 0 | 0 |  |  |  | 0 | $WIN32CONSOLE->Flush || die $^E; | 
| 37 |  |  |  |  |  |  |  | 
| 38 | 0 |  |  |  |  | 0 | $y = $WIN32CONSOLE->InputChar(1); | 
| 39 | 0 | 0 |  |  |  | 0 | $WIN32CONSOLE->Flush || die $^E; | 
| 40 | 0 | 0 |  |  |  | 0 | $WIN32CONSOLE->Mode($mode) || die $^E; | 
| 41 | 0 | 0 |  |  |  | 0 | die $^E unless defined($y); | 
| 42 |  |  |  |  |  |  | } | 
| 43 |  |  |  |  |  |  | }; | 
| 44 | 0 | 0 |  |  |  | 0 | die "Not implemented on $^O: $@" if $@; | 
| 45 | 0 |  |  |  |  | 0 | $y; | 
| 46 |  |  |  |  |  |  | } | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | sub BadReadKey { | 
| 49 | 0 | 0 |  | 0 | 0 | 0 | if ($^O !~ /Win32/i) { | 
| 50 | 0 |  |  |  |  | 0 | $BAD_RKEY =1; | 
| 51 | 0 |  |  |  |  | 0 | system "stty raw -echo"; | 
| 52 | 0 |  |  |  |  | 0 | my $ch = getc; | 
| 53 | 0 |  |  |  |  | 0 | system "stty -raw echo"; | 
| 54 | 0 |  |  |  |  | 0 | $ch; | 
| 55 |  |  |  |  |  |  | } | 
| 56 |  |  |  |  |  |  | } | 
| 57 |  |  |  |  |  |  |  | 
| 58 |  |  |  |  |  |  | sub ReadKey { | 
| 59 | 73 | 50 |  | 73 | 0 | 501 | if ($^O =~ /Win32/i) { | 
| 60 | 0 |  |  |  |  | 0 | return &WinReadKey; | 
| 61 |  |  |  |  |  |  | }; | 
| 62 |  |  |  |  |  |  |  | 
| 63 | 73 |  |  |  |  | 86 | my $save; | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 73 | 50 |  |  |  | 166 | &BadReadKey if $BAD_RKEY; | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 73 |  |  |  |  | 123 | eval { | 
| 68 | 73 |  |  |  |  | 1565 | require POSIX; | 
| 69 | 73 |  |  |  |  | 8692 | import POSIX; | 
| 70 |  |  |  |  |  |  |  | 
| 71 | 73 |  |  |  |  | 223519 | $save = new POSIX::Termios; | 
| 72 |  |  |  |  |  |  | }; | 
| 73 | 73 | 50 |  |  |  | 244 | return &BadReadKey if $@; | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 73 |  |  |  |  | 556 | $save->getattr(0); | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 73 |  |  |  |  | 293 | my $x = new POSIX::Termios; | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 73 |  |  |  |  | 288 | $x->getattr(0); | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 73 |  |  |  |  | 101 | my %flags; | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 73 |  |  |  |  | 190 | &getit($x, \%flags); | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | # +raw | 
| 86 |  |  |  |  |  |  | { | 
| 87 | 73 |  |  |  |  | 116 | $flags{'i'} &= ~(&IGNBRK|&BRKINT|&PARMRK|&ISTRIP | 
|  | 73 |  |  |  |  | 524 |  | 
| 88 |  |  |  |  |  |  | |&INLCR|&IGNCR|&ICRNL|&IXON); | 
| 89 | 73 |  |  |  |  | 131 | $flags{'o'} &= ~&OPOST; | 
| 90 | 73 |  |  |  |  | 330 | $flags{'l'} &= ~(&ECHO|&ECHONL|&ICANON|&ISIG|&IEXTEN); | 
| 91 | 73 |  |  |  |  | 160 | $flags{'c'} &= ~(&CSIZE|&PARENB); | 
| 92 | 73 |  |  |  |  | 135 | $flags{'c'} |= &CS8; | 
| 93 |  |  |  |  |  |  | } | 
| 94 | 73 |  |  |  |  | 172 | &setit($x, \%flags); | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 73 |  |  |  |  | 466 | $x->setattr(0); | 
| 97 |  |  |  |  |  |  |  | 
| 98 | 73 |  |  |  |  | 255 | my $ch = getc; | 
| 99 |  |  |  |  |  |  |  | 
| 100 | 73 |  |  |  |  | 400 | $save->setattr(0); | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 73 |  |  |  |  | 331 | $ch; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | sub getit { | 
| 106 | 73 |  |  | 73 | 0 | 121 | my ($x, $flags) = @_; | 
| 107 | 73 |  |  |  |  | 163 | foreach (qw(i o c l)) { | 
| 108 | 292 |  |  |  |  | 855 | my $meth = $x->can("get${_}flag"); | 
| 109 | 292 |  |  |  |  | 1075 | $flags->{$_} = &$meth($x); | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | sub setit { | 
| 114 | 73 |  |  | 73 | 0 | 108 | my ($x, $flags) = @_; | 
| 115 | 73 |  |  |  |  | 125 | foreach (qw(i o c l)) { | 
| 116 | 292 |  |  |  |  | 782 | my $meth = $x->can("set${_}flag"); | 
| 117 | 292 |  |  |  |  | 795 | &$meth($x, $flags->{$_}); | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | sub WinClear { | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 0 | 0 |  | 0 | 0 | 0 | &BadClear if $BAD_CLS; | 
| 124 |  |  |  |  |  |  |  | 
| 125 | 0 |  |  |  |  | 0 | eval { | 
| 126 | 0 | 0 |  |  |  | 0 | if(&WinSetConsole) | 
| 127 |  |  |  |  |  |  | { | 
| 128 | 0 |  |  |  |  | 0 | local *STDERR; | 
| 129 | 0 |  |  |  |  | 0 | open STDERR, ">/dev/null"; | 
| 130 | 0 | 0 |  |  |  | 0 | $WIN32CONSOLE->Cls || die $^E; | 
| 131 | 0 |  |  |  |  | 0 | $WIN32CONSOLE->Display; | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  | else { | 
| 134 | 0 |  |  |  |  | 0 | &BadClear; | 
| 135 |  |  |  |  |  |  | }; | 
| 136 |  |  |  |  |  |  | }; | 
| 137 | 0 | 0 |  |  |  | 0 | &BadClear if $@; | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | sub BadClear { | 
| 142 | 0 |  |  | 0 | 0 | 0 | $BAD_CLS = 1; | 
| 143 | 0 | 0 | 0 |  |  | 0 | if ($^O =~ /Win/i || $^O =~ /Dos/i) { | 
| 144 | 0 |  |  |  |  | 0 | system "cls"; | 
| 145 | 0 |  |  |  |  | 0 | return; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 0 |  |  |  |  | 0 | system "clear"; | 
| 149 |  |  |  |  |  |  | } | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | sub Clear { | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 1 | 50 |  | 1 | 0 | 135 | &BadClear if $BAD_CLS; | 
| 154 |  |  |  |  |  |  |  | 
| 155 | 1 | 50 | 33 |  |  | 14 | if ($^O =~ /Win32/i || $^O =~ /Dos/i) { | 
| 156 | 0 |  |  |  |  | 0 | &WinClear; | 
| 157 | 0 |  |  |  |  | 0 | return; | 
| 158 |  |  |  |  |  |  | } | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 1 | 50 |  |  |  | 4 | unless ($TER_CLS) { | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 1 |  |  |  |  | 2 | my $speed = 9600; | 
| 164 |  |  |  |  |  |  |  | 
| 165 | 1 |  |  |  |  | 4 | eval { | 
| 166 | 1 |  |  |  |  | 6 | require POSIX; | 
| 167 | 1 |  |  |  |  | 25 | import POSIX; | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 1 |  |  |  |  | 3040 | my $x = new POSIX::Termios; | 
| 170 | 1 |  |  |  |  | 10 | POSIX::Termios::getattr($x, 0); | 
| 171 | 1 |  |  |  |  | 7 | $speed = $x->getospeed; | 
| 172 |  |  |  |  |  |  | }; | 
| 173 |  |  |  |  |  |  |  | 
| 174 | 1 |  |  |  |  | 2 | eval { | 
| 175 | 1 |  |  |  |  | 1255 | require Term::Cap; | 
| 176 | 1 |  | 50 |  |  | 3530 | my $emu = $ENV{'TERM'} || 'vt100'; | 
| 177 | 1 |  |  |  |  | 12 | my $term = Term::Cap->Tgetent({'TERM' => $emu, | 
| 178 |  |  |  |  |  |  | 'OSPEED' => $speed}); | 
| 179 | 1 |  |  |  |  | 13445 | $TER_CLS = $term->Tputs('cl'); | 
| 180 |  |  |  |  |  |  | }; | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  |  | 
| 183 | 1 | 50 |  |  |  | 114 | unless ($TER_CLS) { | 
| 184 | 0 |  |  |  |  | 0 | &BadClear; | 
| 185 | 0 |  |  |  |  | 0 | return; | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  |  | 
| 188 | 1 |  |  |  |  | 15 | my $desc = select; | 
| 189 | 1 |  |  |  |  | 7 | select STDOUT; | 
| 190 | 1 |  |  |  |  | 5 | my $pipe = $|; | 
| 191 | 1 |  |  |  |  | 7 | $| = 1; | 
| 192 | 1 |  |  |  |  | 32 | print $TER_CLS; | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 1 |  |  |  |  | 3 | $| = $pipe; | 
| 195 | 1 |  |  |  |  | 38 | select $desc; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | sub ReadPassword { | 
| 199 | 1 |  |  | 1 | 0 | 6 | my ($opt) = @_; | 
| 200 | 1 |  |  |  |  | 2 | my $bullet = "*"; | 
| 201 | 1 |  |  |  |  | 3 | my ($bs, $ws, $nl) = ("\b", " ", "\n"); | 
| 202 | 1 | 50 |  |  |  | 4 | if ($opt) { | 
| 203 | 1 | 50 |  |  |  | 4 | $bullet = $opt if length($opt) == 1; | 
| 204 | 1 | 50 |  |  |  | 3 | ($bs, $ws, $nl, $bullet) | 
| 205 |  |  |  |  |  |  | = () if ($opt =~ /-\d+/); | 
| 206 |  |  |  |  |  |  | } | 
| 207 | 1 |  |  |  |  | 4 | my $save = $|; | 
| 208 | 1 |  |  |  |  | 2 | $| = 1; | 
| 209 | 1 |  |  |  |  | 2 | my $pass = ''; | 
| 210 | 1 |  |  |  |  | 2 | for (;;) { | 
| 211 | 72 |  |  |  |  | 183 | my $ch = &ReadKey; | 
| 212 | 72 | 50 |  |  |  | 210 | if ($ch eq "\3") { | 
| 213 | 0 |  |  |  |  | 0 | $pass = ""; | 
| 214 | 0 |  |  |  |  | 0 | $ch = "\n"; | 
| 215 |  |  |  |  |  |  | } | 
| 216 | 72 | 100 |  |  |  | 239 | if ($ch =~ /[\r\n]/) { | 
| 217 | 1 |  |  |  |  | 3 | $| = $save; | 
| 218 | 1 | 50 |  |  |  | 48 | print $nl if $nl; | 
| 219 | 1 |  |  |  |  | 65 | return $pass; | 
| 220 |  |  |  |  |  |  | } | 
| 221 | 71 | 50 |  |  |  | 176 | if ($ch =~ /[\b\x7F]/) { | 
| 222 | 0 | 0 |  |  |  | 0 | next unless $pass; | 
| 223 | 0 |  |  |  |  | 0 | chop $pass; | 
| 224 | 0 | 0 |  |  |  | 0 | print "$bs$ws$bs" if $bs; | 
| 225 | 0 |  |  |  |  | 0 | next; | 
| 226 |  |  |  |  |  |  | } | 
| 227 | 71 | 50 |  |  |  | 146 | if ($ch eq "\025") { | 
| 228 | 0 |  |  |  |  | 0 | my $len = length($pass); | 
| 229 | 0 | 0 |  |  |  | 0 | if ($ws) { | 
| 230 | 0 |  |  |  |  | 0 | my $res =  ($bs x $len) . ($ws x $len) . | 
| 231 |  |  |  |  |  |  | ($bs x $len); | 
| 232 | 0 |  |  |  |  | 0 | print "$res"; | 
| 233 |  |  |  |  |  |  | } | 
| 234 | 0 |  |  |  |  | 0 | $pass = ''; | 
| 235 |  |  |  |  |  |  | } | 
| 236 | 71 | 50 |  |  |  | 170 | if (ord($ch) < 32) { | 
| 237 | 0 |  |  |  |  | 0 | print "\7"; | 
| 238 | 0 |  |  |  |  | 0 | next; | 
| 239 |  |  |  |  |  |  | } | 
| 240 | 71 |  |  |  |  | 93 | $pass .= $ch; | 
| 241 | 71 | 50 |  |  |  | 2447 | print $bullet if $bullet; | 
| 242 |  |  |  |  |  |  | } | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | 1; | 
| 247 |  |  |  |  |  |  | __END__ |