#!/usr/bin/perl -w
# keys.pl 1.0.0, 13-jul-2005
# petar marinov, http:/geocities.com/h2428, this is public domain

use strict;
$| = 1;
my $got = '';
while (1) {
  # wait for a sequence to begin
  $got = getone() while (ord($got) == 0);
  # process a sequence ($got already holds the first character)
  while (ord($got) != 0) {
    exit(0) if ($got eq 'x');
    printf("\\x%02x", ord($got));
    $got = getone();
  }
  print "\n";
}
exit(0);

BEGIN {
  use POSIX qw(:termios_h);
  use Fcntl;

  my ($term, $oterm, $echo, $noecho);
  $term = POSIX::Termios->new();
  $term->getattr(fileno(STDIN));
  $oterm = $term->getlflag();

  # puts console in a raw mode -- permits non-blocking reading
  sub raw {
    my $flags = 0;
    $term->setlflag($oterm & ~(ECHO | ECHOK | ICANON));
    $term->setcc(VTIME, 1);
    $term->setattr(fileno(STDIN), TCSANOW);
    fcntl(STDIN, F_GETFL, $flags)
      or die "Couldn't get flags for HANDLE : $!\n";
    $flags |= O_NONBLOCK;
    fcntl(STDIN, F_SETFL, $flags)
      or die "Couldn't set flags for HANDLE: $!\n";
  }

  # restores console to original mode
  sub cooked {
    print "restore console mode\n";
    $term->setlflag($oterm);
    $term->setcc(VTIME, 0);
    $term->setattr(fileno(STDIN), TCSANOW);
  }

  # reads character or times out
  sub getone {
    my $key = ' ';
    my ($rv, $rin, $win, $ein);
    my ($nfound, $timeleft, $rout, $wout, $eout);

    $rin = $win = $ein = '';
    vec($rin, fileno(STDIN), 1) = 1;
    $ein = $rin | $win;
    ($nfound,$timeleft) =
      select($rout=$rin, $wout=$win, $eout=$ein, 0.10);
    return chr(0) if $nfound == 0;
    $rv = sysread(STDIN, $key, 1);
    return chr(0) if (!defined($rv));
    return $key;
  }

  raw();
  print "press 'x' to exit\n";
}

END {
  cooked() 
}

