Using POSIX termios

Problem

You'd like to manipulate your terminal characteristics directly.

Solution

Use the POSIX termios interface.

Description

Think of everything you can do with the stty command - you can set everything from special characters to flow control and carriage-return mapping. The standard POSIX module provides direct access to the low-level terminal interface to implement stty-like capabilities in your program.

Example 15.2 finds what your tty's erase and kill characters are (probably backspace and Ctrl-U). Then it sets them back to their original values out of antiquity, # and @, and has you type something. It restores them when done.

Example 15.2: demo POSIX termios

#!/usr/bin/perl -w # demo POSIX termios use POSIX qw(:termios_h); $term = POSIX::Termios->new; $term->getattr(fileno(STDIN)); $erase = $term->getcc(VERASE); $kill = $term->getcc(VKILL);
printf "Erase is character %d, %s\n", $erase, uncontrol(chr($erase));
printf "Kill is character %d, %s\n", $kill, uncontrol(chr($kill)); $term->setcc(VERASE, ord('#')); $term->setcc(VKILL, ord('@')); $term->setattr(1, TCSANOW);
print("erase is #, kill is @; type something: "); $line = <STDIN>;
print "You typed: $line"; $term->setcc(VERASE, $erase); $term->setcc(VKILL, $kill); $term->setattr(1, TCSANOW); sub uncontrol { local $_ = shift; s/([\200-\377])/sprintf("M-%c",ord($1) & 0177)/eg; s/([\0-\37\177])/sprintf("^%c",ord($1) ^ 0100)/eg;
return $_;
}

Here's a module called HotKey that implements a readkey function in pure Perl. It doesn't provide any benefit over Term::ReadKey, but it shows POSIX termios in action:

# HotKey.pm package HotKey; @ISA = qw(Exporter); @EXPORT = qw(cbreak cooked readkey); use strict; use POSIX qw(:termios_h); my ($term, $oterm, $echo, $noecho, $fd_stdin); $fd_stdin = fileno(STDIN); $term = POSIX::Termios->new(); $term->getattr($fd_stdin); $oterm = $term->getlflag(); $echo = ECHO | ECHOK | ICANON; $noecho = $oterm & ~$echo; sub cbreak {
 $term->setlflag($noecho); # ok, so i don't want echo either $term->setcc(VTIME, 1); $term->setattr($fd_stdin, TCSANOW);
}
sub cooked {
 $term->setlflag($oterm); $term->setcc(VTIME, 0); $term->setattr($fd_stdin, TCSANOW);
}
sub readkey {
 my $key = ''; cbreak(); sysread(STDIN, $key, 1); cooked();
return $key;
}
END {
 cooked()
}
1;

See Also

POSIX Developer's Guide, by Donald Lewine; Anonymous (1991); the documentation for the standard POSIX module, also in of Perl Developing; ;