 
Use the POSIX termios interface.
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.
  #!/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;POSIX Programmer's Guide, by Donald Lewine; the documentation for the standard POSIX module, also in Chapter 32 of Programming Perl; Recipe 15.6; Recipe 15.9
 
Copyright © 2003 O'Reilly & Associates. All rights reserved.