File Coverage

blib/lib/Term/ReadKey.pm
Criterion Covered Total %
statement 6 85 7.0
branch 0 66 0.0
condition 0 42 0.0
subroutine 2 7 28.5
pod 4 5 80.0
total 12 205 5.8


line stmt bran cond sub pod time code
1             package Term::ReadKey;
2              
3             =head1 NAME
4              
5             Term::ReadKey - A perl module for simple terminal control
6              
7             =head1 SYNOPSIS
8              
9             use Term::ReadKey;
10             ReadMode 4; # Turn off controls keys
11             while (not defined ($key = ReadKey(-1))) {
12             # No key yet
13             }
14             print "Get key $key\n";
15             ReadMode 0; # Reset tty mode before exiting
16              
17             =head1 DESCRIPTION
18              
19             Term::ReadKey is a compiled perl module dedicated to providing simple
20             control over terminal driver modes (cbreak, raw, cooked, etc.,) support for
21             non-blocking reads, if the architecture allows, and some generalized handy
22             functions for working with terminals. One of the main goals is to have the
23             functions as portable as possible, so you can just plug in "use
24             Term::ReadKey" on any architecture and have a good likelihood of it working.
25              
26             Version 2.30.01:
27             Added handling of arrows, page up/down, home/end, insert/delete keys
28             under Win32. These keys emit xterm-compatible sequences.
29             Works with Term::ReadLine::Perl.
30              
31             =over 4
32              
33             =item ReadMode MODE [, Filehandle]
34              
35             Takes an integer argument or a string synonym (case insensitive), which
36             can currently be one of the following values:
37              
38             INT SYNONYM DESCRIPTION
39              
40             0 'restore' Restore original settings.
41              
42             1 'normal' Change to what is commonly the default mode,
43             echo on, buffered, signals enabled, Xon/Xoff
44             possibly enabled, and 8-bit mode possibly disabled.
45              
46             2 'noecho' Same as 1, just with echo off. Nice for
47             reading passwords.
48              
49             3 'cbreak' Echo off, unbuffered, signals enabled, Xon/Xoff
50             possibly enabled, and 8-bit mode possibly enabled.
51              
52             4 'raw' Echo off, unbuffered, signals disabled, Xon/Xoff
53             disabled, and 8-bit mode possibly disabled.
54              
55             5 'ultra-raw' Echo off, unbuffered, signals disabled, Xon/Xoff
56             disabled, 8-bit mode enabled if parity permits,
57             and CR to CR/LF translation turned off.
58              
59              
60             These functions are automatically applied to the STDIN handle if no
61             other handle is supplied. Modes 0 and 5 have some special properties
62             worth mentioning: not only will mode 0 restore original settings, but it
63             cause the next ReadMode call to save a new set of default settings. Mode
64             5 is similar to mode 4, except no CR/LF translation is performed, and if
65             possible, parity will be disabled (only if not being used by the terminal,
66             however. It is no different from mode 4 under Windows.)
67              
68             If you just need to read a key at a time, then modes 3 or 4 are probably
69             sufficient. Mode 4 is a tad more flexible, but needs a bit more work to
70             control. If you use ReadMode 3, then you should install a SIGINT or END
71             handler to reset the terminal (via ReadMode 0) if the user aborts the
72             program via C<^C>. (For any mode, an END handler consisting of "ReadMode 0"
73             is actually a good idea.)
74              
75             If you are executing another program that may be changing the terminal mode,
76             you will either want to say
77              
78             ReadMode 1; # same as ReadMode 'normal'
79             system('someprogram');
80             ReadMode 1;
81              
82             which resets the settings after the program has run, or:
83              
84             $somemode=1;
85             ReadMode 0; # same as ReadMode 'restore'
86             system('someprogram');
87             ReadMode 1;
88              
89             which records any changes the program may have made, before resetting the
90             mode.
91              
92             =item ReadKey MODE [, Filehandle]
93              
94             Takes an integer argument, which can currently be one of the following
95             values:
96              
97             0 Perform a normal read using getc
98             -1 Perform a non-blocked read
99             >0 Perform a timed read
100              
101             If the filehandle is not supplied, it will default to STDIN. If there is
102             nothing waiting in the buffer during a non-blocked read, then undef will be
103             returned. In most situations, you will probably want to use C.
104              
105             I that if the OS does not provide any known mechanism for non-blocking
106             reads, then a C can die with a fatal error. This will hopefully
107             not be common.
108              
109             If MODE is greater then zero, then ReadKey will use it as a timeout value in
110             seconds (fractional seconds are allowed), and won't return C until
111             that time expires.
112              
113             I, again, that some OS's may not support this timeout behaviour.
114              
115             If MODE is less then zero, then this is treated as a timeout
116             of zero, and thus will return immediately if no character is waiting. A MODE
117             of zero, however, will act like a normal getc.
118              
119             I, there are currently some limitations with this call under Windows.
120             It may be possible that non-blocking reads will fail when reading repeating
121             keys from more then one console.
122              
123              
124             =item ReadLine MODE [, Filehandle]
125              
126             Takes an integer argument, which can currently be one of the following
127             values:
128              
129             0 Perform a normal read using scalar()
130             -1 Perform a non-blocked read
131             >0 Perform a timed read
132              
133             If there is nothing waiting in the buffer during a non-blocked read, then
134             undef will be returned.
135              
136             I, that if the OS does not provide any known mechanism for
137             non-blocking reads, then a C can die with a fatal
138             error. This will hopefully not be common.
139              
140             I that a non-blocking test is only performed for the first character
141             in the line, not the entire line. This call will probably B do what
142             you assume, especially with C MODE values higher then 1. For
143             example, pressing Space and then Backspace would appear to leave you
144             where you started, but any timeouts would now be suspended.
145              
146             B.
147              
148             =item GetTerminalSize [Filehandle]
149              
150             Returns either an empty array if this operation is unsupported, or a four
151             element array containing: the width of the terminal in characters, the
152             height of the terminal in character, the width in pixels, and the height in
153             pixels. (The pixel size will only be valid in some environments.)
154              
155             I, under Windows, this function must be called with an B
156             filehandle, such as C, or a handle opened to C.
157              
158             =item SetTerminalSize WIDTH,HEIGHT,XPIX,YPIX [, Filehandle]
159              
160             Return -1 on failure, 0 otherwise.
161              
162             I that this terminal size is only for B value, and
163             changing the size via this mechanism will B change the size of
164             the screen. For example, XTerm uses a call like this when
165             it resizes the screen. If any of the new measurements vary from the old, the
166             OS will probably send a SIGWINCH signal to anything reading that tty or pty.
167              
168             B.
169              
170             =item GetSpeeds [, Filehandle]
171              
172             Returns either an empty array if the operation is unsupported, or a two
173             value array containing the terminal in and out speeds, in B. E.g,
174             an in speed of 9600 baud and an out speed of 4800 baud would be returned as
175             (9600,4800). Note that currently the in and out speeds will always be
176             identical in some OS's.
177              
178             B.
179              
180             =item GetControlChars [, Filehandle]
181              
182             Returns an array containing key/value pairs suitable for a hash. The pairs
183             consist of a key, the name of the control character/signal, and the value
184             of that character, as a single character.
185              
186             B.
187              
188             Each key will be an entry from the following list:
189              
190             DISCARD
191             DSUSPEND
192             EOF
193             EOL
194             EOL2
195             ERASE
196             ERASEWORD
197             INTERRUPT
198             KILL
199             MIN
200             QUIT
201             QUOTENEXT
202             REPRINT
203             START
204             STATUS
205             STOP
206             SUSPEND
207             SWITCH
208             TIME
209              
210             Thus, the following will always return the current interrupt character,
211             regardless of platform.
212              
213             %keys = GetControlChars;
214             $int = $keys{INTERRUPT};
215              
216             =item SetControlChars [, Filehandle]
217              
218             Takes an array containing key/value pairs, as a hash will produce. The pairs
219             should consist of a key that is the name of a legal control
220             character/signal, and the value should be either a single character, or a
221             number in the range 0-255. SetControlChars will die with a runtime error if
222             an invalid character name is passed or there is an error changing the
223             settings. The list of valid names is easily available via
224              
225             %cchars = GetControlChars();
226             @cnames = keys %cchars;
227              
228             B.
229              
230             =back
231              
232             =head1 AUTHOR
233              
234             Kenneth Albanowski
235              
236             Currently maintained by Jonathan Stowe
237              
238             =head1 SUPPORT
239              
240             The code is maintained at
241              
242             https://github.com/jonathanstowe/TermReadKey
243              
244             Please feel free to fork and suggest patches.
245              
246              
247             =head1 LICENSE
248              
249             Prior to the 2.31 release the license statement was:
250              
251             Copyright (C) 1994-1999 Kenneth Albanowski.
252             2001-2005 Jonathan Stowe and others
253              
254             Unlimited distribution and/or modification is allowed as long as this
255             copyright notice remains intact.
256              
257             And was only stated in the README file.
258              
259             Because I believe the original author's intent was to be more open than the
260             other commonly used licenses I would like to leave that in place. However if
261             you or your lawyers require something with some more words you can optionally
262             choose to license this under the standard Perl license:
263              
264             This module is free software; you can redistribute it and/or modify it
265             under the terms of the Artistic License. For details, see the full
266             text of the license in the file "Artistic" that should have been provided
267             with the version of perl you are using.
268              
269             This program is distributed in the hope that it will be useful, but
270             without any warranty; without even the implied warranty of merchantability
271             or fitness for a particular purpose.
272              
273              
274             =cut
275              
276 2     2   18806 use vars qw($VERSION);
  2         5  
  2         271  
277              
278             $VERSION = '2.33';
279              
280             require Exporter;
281             require AutoLoader;
282             require DynaLoader;
283 2     2   14 use Carp;
  2         4  
  2         2394  
284              
285             @ISA = qw(Exporter AutoLoader DynaLoader);
286              
287             # Items to export into callers namespace by default
288             # (move infrequently used names to @EXPORT_OK below)
289              
290             @EXPORT = qw(
291             ReadKey
292             ReadMode
293             ReadLine
294             GetTerminalSize
295             SetTerminalSize
296             GetSpeed
297             GetControlChars
298             SetControlChars
299             );
300              
301             @EXPORT_OK = qw();
302              
303             bootstrap Term::ReadKey;
304              
305             # Preloaded methods go here. Autoload methods go after __END__, and are
306             # processed by the autosplit program.
307              
308             # Should we use LINES and COLUMNS to try and get the terminal size?
309             # Change this to zero if you have systems where these are commonly
310             # set to erroneous values. (But if either are near zero, they won't be
311             # used anyhow.)
312              
313             $UseEnv = 1;
314              
315             $CurrentMode = 0;
316              
317             %modes = ( # lowercase is canonical
318             original => 0,
319             restore => 0,
320             normal => 1,
321             noecho => 2,
322             cbreak => 3,
323             raw => 4,
324             'ultra-raw' => 5
325             );
326              
327             sub ReadMode
328             {
329 0     0 1   my ($mode) = $modes{ lc $_[0] }; # lowercase is canonical
330 0 0         my ($fh) = normalizehandle( ( @_ > 1 ? $_[1] : \*STDIN ) );
331 0 0         if ( defined($mode) ) { $CurrentMode = $mode }
  0 0          
332 0           elsif ( $_[0] =~ /^\d/ ) { $CurrentMode = $_[0] }
333 0           else { croak("Unknown terminal mode `$_[0]'"); }
334 0           SetReadMode($CurrentMode, $fh);
335             }
336              
337             sub normalizehandle
338             {
339 0     0 0   my ($file) = @_;
340              
341             # print "Handle = $file\n";
342 0 0         if ( ref($file) ) { return $file; } # Reference is fine
  0            
343              
344             # if($file =~ /^\*/) { return $file; } # Type glob is good
345 0 0         if ( ref( \$file ) eq 'GLOB' ) { return $file; } # Glob is good
  0            
346              
347             # print "Caller = ",(caller(1))[0],"\n";
348 0           return \*{ ( ( caller(1) )[0] ) . "::$file" };
  0            
349             }
350              
351             sub GetTerminalSize
352             {
353 0 0   0 1   my ($file) = normalizehandle( ( @_ > 1 ? $_[1] : \*STDOUT ) );
354 0           my (@results) = ();
355 0           my (@fail);
356              
357 0 0         if ( &termsizeoptions() & 1 ) # VIO
    0          
    0          
    0          
358             {
359 0           @results = GetTermSizeVIO($file);
360 0           push( @fail, "VIOGetMode call" );
361             }
362             elsif ( &termsizeoptions() & 2 ) # GWINSZ
363             {
364 0           @results = GetTermSizeGWINSZ($file);
365 0           push( @fail, "TIOCGWINSZ ioctl" );
366             }
367             elsif ( &termsizeoptions() & 4 ) # GSIZE
368             {
369 0           @results = GetTermSizeGSIZE($file);
370 0           push( @fail, "TIOCGSIZE ioctl" );
371             }
372             elsif ( &termsizeoptions() & 8 ) # WIN32
373             {
374 0           @results = GetTermSizeWin32($file);
375 0           push( @fail, "Win32 GetConsoleScreenBufferInfo call" );
376             }
377             else
378             {
379 0           @results = ();
380             }
381              
382 0 0 0       if ( @results < 4 and $UseEnv )
383             {
384 0 0         my ($C) = defined( $ENV{COLUMNS} ) ? $ENV{COLUMNS} : 0;
385 0 0         my ($L) = defined( $ENV{LINES} ) ? $ENV{LINES} : 0;
386 0 0 0       if ( ( $C >= 2 ) and ( $L >= 2 ) )
387             {
388 0           @results = ( $C + 0, $L + 0, 0, 0 );
389             }
390 0           push( @fail, "COLUMNS and LINES environment variables" );
391             }
392              
393 0 0 0       if ( @results < 4 && $^O ne 'MSWin32')
394             {
395 0           my ($prog) = "resize";
396              
397             # Workaround for Solaris path silliness
398 0 0         if ( -f "/usr/openwin/bin/resize" ) {
399 0           $prog = "/usr/openwin/bin/resize";
400             }
401              
402 0           my ($resize) = scalar(`$prog 2>/dev/null`);
403 0 0 0       if (
      0        
404             defined $resize
405             and ( $resize =~ /COLUMNS\s*=\s*(\d+)/
406             or $resize =~ /setenv\s+COLUMNS\s+'?(\d+)/ )
407             )
408             {
409 0           $results[0] = $1;
410 0 0 0       if ( $resize =~ /LINES\s*=\s*(\d+)/
411             or $resize =~ /setenv\s+LINES\s+'?(\d+)/ )
412             {
413 0           $results[1] = $1;
414 0           @results[ 2, 3 ] = ( 0, 0 );
415             }
416             else
417             {
418 0           @results = ();
419             }
420             }
421             else
422             {
423 0           @results = ();
424             }
425 0           push( @fail, "resize program" );
426             }
427              
428 0 0 0       if ( @results < 4 && $^O ne 'MSWin32' )
429             {
430 0           my ($prog) = "stty size";
431              
432 0           my ($stty) = scalar(`$prog 2>/dev/null`);
433 0 0 0       if (
434             defined $stty
435             and ( $stty =~ /(\d+) (\d+)/ )
436             )
437             {
438 0           $results[0] = $2;
439 0           $results[1] = $1;
440 0           @results[ 2, 3 ] = ( 0, 0 );
441             }
442             else
443             {
444 0           @results = ();
445             }
446 0           push( @fail, "stty program" );
447             }
448              
449 0 0         if ( @results != 4 )
450             {
451 0           warn "Unable to get Terminal Size."
452             . join( "", map( " The $_ didn't work.", @fail ) );
453 0           return undef;
454             }
455              
456 0           @results;
457             }
458              
459             if ( &blockoptions() & 1 ) # Use nodelay
460             {
461             if ( &blockoptions() & 2 ) #poll
462             {
463             eval <<'DONE';
464             sub ReadKey {
465             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
466             if (defined $_[0] && $_[0] > 0) {
467             if ($_[0]) {
468             return undef if &pollfile($File,$_[0]) == 0;
469             }
470             }
471             if (defined $_[0] && $_[0] < 0) {
472             &setnodelay($File,1);
473             }
474             my ($value) = getc $File;
475             if (defined $_[0] && $_[0] < 0) {
476             &setnodelay($File,0);
477             }
478             $value;
479             }
480             sub ReadLine {
481             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
482              
483             if (defined $_[0] && $_[0] > 0) {
484             if ($_[0]) {
485             return undef if &pollfile($File,$_[0]) == 0;
486             }
487             }
488             if (defined $_[0] && $_[0] < 0) {
489             &setnodelay($File,1)
490             };
491             my ($value) = scalar(<$File>);
492             if ( defined $_[0] && $_[0]<0 ) {
493             &setnodelay($File,0)
494             };
495             $value;
496             }
497             DONE
498             }
499             elsif ( &blockoptions() & 4 ) #select
500             {
501 0 0 0 0 1   eval <<'DONE';
  0 0 0 0 1    
  0 0 0        
  0 0 0        
  0 0 0        
  0 0 0        
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
502             sub ReadKey {
503             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
504             if(defined $_[0] && $_[0]>0) {
505             if($_[0]) {return undef if &selectfile($File,$_[0])==0}
506             }
507             if(defined $_[0] && $_[0]<0) {&setnodelay($File,1);}
508             my($value) = getc $File;
509             if(defined $_[0] && $_[0]<0) {&setnodelay($File,0);}
510             $value;
511             }
512             sub ReadLine {
513             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
514             if(defined $_[0] && $_[0]>0) {
515             if($_[0]) {return undef if &selectfile($File,$_[0])==0}
516             }
517             if(defined $_[0] && $_[0]<0) {&setnodelay($File,1)};
518             my($value)=scalar(<$File>);
519             if(defined $_[0] && $_[0]<0) {&setnodelay($File,0)};
520             $value;
521             }
522             DONE
523             }
524             else
525             { #nothing
526             eval <<'DONE';
527             sub ReadKey {
528             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
529             if(defined $_[0] && $_[0]>0) {
530             # Nothing better seems to exist, so I just use time-of-day
531             # to timeout the read. This isn't very exact, though.
532             $starttime=time;
533             $endtime=$starttime+$_[0];
534             &setnodelay($File,1);
535             my($value)=undef;
536             while(time<$endtime) { # This won't catch wraparound!
537             $value = getc $File;
538             last if defined($value);
539             }
540             &setnodelay($File,0);
541             return $value;
542             }
543             if(defined $_[0] && $_[0]<0) {&setnodelay($File,1);}
544             my($value) = getc $File;
545             if(defined $_[0] && $_[0]<0) {&setnodelay($File,0);}
546             $value;
547             }
548             sub ReadLine {
549             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
550             if(defined $_[0] && $_[0]>0) {
551             # Nothing better seems to exist, so I just use time-of-day
552             # to timeout the read. This isn't very exact, though.
553             $starttime=time;
554             $endtime=$starttime+$_[0];
555             &setnodelay($File,1);
556             my($value)=undef;
557             while(time<$endtime) { # This won't catch wraparound!
558             $value = scalar(<$File>);
559             last if defined($value);
560             }
561             &setnodelay($File,0);
562             return $value;
563             }
564             if(defined $_[0] && $_[0]<0) {&setnodelay($File,1)};
565             my($value)=scalar(<$File>);
566             if(defined $_[0] && $_[0]<0) {&setnodelay($File,0)};
567             $value;
568             }
569             DONE
570             }
571             }
572             elsif ( &blockoptions() & 2 ) # Use poll
573             {
574             eval <<'DONE';
575             sub ReadKey {
576             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
577             if(defined $_[0] && $_[0] != 0) {
578             return undef if &pollfile($File,$_[0]) == 0
579             }
580             getc $File;
581             }
582             sub ReadLine {
583             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
584             if(defined $_[0] && $_[0]!=0) {
585             return undef if &pollfile($File,$_[0]) == 0;
586             }
587             scalar(<$File>);
588             }
589             DONE
590             }
591             elsif ( &blockoptions() & 4 ) # Use select
592             {
593             eval <<'DONE';
594             sub ReadKey {
595             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
596             if(defined $_[0] && $_[0] !=0 ) {
597             return undef if &selectfile($File,$_[0])==0
598             }
599             getc $File;
600             }
601             sub ReadLine {
602             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
603             if(defined $_[0] && $_[0] != 0) {
604             return undef if &selectfile($File,$_[0]) == 0;
605             }
606             scalar(<$File>);
607             }
608             DONE
609             }
610             elsif ( &blockoptions() & 8 ) # Use Win32
611             {
612             eval <<'DONE';
613             sub ReadKey {
614             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
615             if ($_[0] || $CurrentMode >= 3) {
616             Win32PeekChar($File, $_[0]);
617             } else {
618             getc $File;
619             }
620             #if ($_[0]!=0) {return undef if !Win32PeekChar($File, $_[0])};
621             #getc $File;
622             }
623             sub ReadLine {
624             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
625             #if ($_[0]!=0) {return undef if !Win32PeekChar($File, $_[0])};
626             #scalar(<$File>);
627             if($_[0])
628             {croak("Non-blocking ReadLine is not supported on this architecture")}
629             scalar(<$File>);
630             }
631             DONE
632             }
633             else
634             {
635             eval <<'DONE';
636             sub ReadKey {
637             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
638             if($_[0])
639             {croak("Non-blocking ReadKey is not supported on this architecture")}
640             getc $File;
641             }
642             sub ReadLine {
643             my($File) = normalizehandle((@_>1?$_[1]:\*STDIN));
644             if($_[0])
645             {croak("Non-blocking ReadLine is not supported on this architecture")}
646             scalar(<$File>);
647             }
648             DONE
649             }
650              
651             package Term::ReadKey; # return to package ReadKey so AutoSplit is happy
652             1;
653              
654             __END__;