15.6. Reading from the Keyboard

Problem

You want to read a single character from the keyboard. For instance, you've displayed a menu of one-character options, and you don't want to require the user to press Enter to make their selection.

Solution

Use the CPAN module Term::ReadKey to put the terminal into cbreak mode, read characters from STDIN, and then put the terminal back into its normal mode:

use Term::ReadKey;

ReadMode 'cbreak';
$key = ReadKey(0);
ReadMode 'normal';

Discussion

Term::ReadKey can put the terminal into many modes  - cbreak is just one of them. cbreak mode makes each character available to your program as it is typed (see Example 15.1 ). It also echoes the characters to the screen; see Recipe 15.10 for an example of a mode that does not echo.

Example 15.1: sascii

#!/usr/bin/perl -w
# 

sascii - Show ASCII values for keypresses

use Term::ReadKey;
ReadMode('cbreak');
print "Press keys to see their ASCII values.  Use Ctrl-C to quit.\n";

while (1) {
    $char = ReadKey(0);
    last unless defined $char;
    printf(" Decimal: %d\tHex: %x\n", ord($char), ord($char));
}

ReadMode('normal');

Using cbreak mode doesn't prevent the terminal's device driver from interpreting end-of-file and flow-control characters. If you want to be able to read a real Ctrl-C (which normally sends a SIGINT to your process) or a Ctrl-D (which indicates end-of-file under Unix), you want to use raw mode.

An argument of 0 to ReadKey indicates that we want a normal read using getc . If no input is available, the program will pause until there is some. We can also pass -1 to indicate a non-blocking read, or a number greater than 0 to indicate the number of seconds to wait for input to become available; fractional seconds are allowed. Non-blocking reads and timed-out reads return either undef when no input is available or a zero-length string on end of file.

Recent versions of Term::ReadKey also include limited support for non-Unix systems.

See Also

The getc and sysread functions in Chapter 3 of Programming Perl , and in perlfunc (1); the documentation for the Term::ReadKey module from CPAN; Recipe 15.8 ; Recipe 15.9