in reply to Arrow Keys

A while back I rewrote a perl script which I took from a form where such a task was performed. I can't remember the details exactly but this seems to be the relevant code section:
while ( $_=getc(STDIN) ) { last if /[q\r\003\032]/;# break on q,Return,Ctrl-C,Ctrl-Z $Index-- if /[8A]/; # up $Index++ if /[2B]/; # down $Index=0 if /[9H1]/; # home $Index=$LineCount if /[3F4]/; # end }
It all takes place in a terminal which has been set to raw device (?):
$oldtty = `stty --save`; system('stty raw -echo');

Regards... Stefan

Replies are listed 'Best First'.
Re^2: Arrow Keys
by Anonymous Monk on May 27, 2009 at 18:28 UTC
    After cobbling some stuff together, I got this working. Hope it helps someone else. Bill
    #!/usr/bin/perl -w
    
    use strict;
    use warnings;
    
    use IO::Handle;
    
    eval {
        my $stdin = new IO::Handle;
           $stdin->fdopen( fileno( STDIN ), "r" ) || die "Cannot open STDIN";
    
        system "stty -icanon -isig -echo min 1 time 0";
    
        while ( my $char = $stdin->getc() ) {
            print "Up\n"     if ( ord( $char ) == 65 );  # up
            print "Down\n"   if ( ord( $char ) == 66 );  # down
            print "Right\n"  if ( ord( $char ) == 67 );  # right arrow
            print "Left\n"   if ( ord( $char ) == 68 );  # left arrow
            print "Return\n" if ( ord( $char ) == 10 );  # return key
            print "Delete\n" if ( ord( $char ) == 127 ); # delete key
            print "Esc\n"    if ( ord( $char ) == 27 );  # escape key
            print "Tab\n"    if ( ord( $char ) == 9 );   # tab key
            next             if ( ord( $char ) == 32 );  # skip on space key
            last             if ( $char =~ /q/ );        # break on q
            last             if ( $char =~ /\003/ );     # break on Ctrl-C
            last             if ( $char =~ /\032/ );     # break on Ctrl-Z
            print "ord: " . ord($char) . "\n";
        }
        system "stty icanon echo isig";
        exit(0);
    };
    
    if ( $@ ) {
        print "$@\n";
        system "stty icanon echo isig";
        exit(1);
    }
      heh... I posted the last bit of code, but wanted to mention that I have not found a good source for the escape codes (\###). Bill
        Ok...

        getc() is getting each 'character' at a time... when you do control keys and function keys, they appear to be made up of more than one character.

        So the script has to keep track of the sequence of characters to figure out what key was actually pressed.

        (Note, this works for xterm-color on OS X)

        Below is the new code:
        #!/usr/bin/perl -w
        
        use strict;
        use warnings;
        
        use IO::Handle;
        
        eval {
            my $stdin = new IO::Handle;
               $stdin->fdopen( fileno( STDIN ), "r" ) || die "Cannot open STDIN";
        
            system "stty -icanon -isig -echo min 1 time 0";
            my $escape;
            my $ctrl;
            my $function;
        
            while ( my $char = $stdin->getc() ) {
        
                if ( ord( $char ) == 27 ) {             # Escape character
                    $escape = 1;
                    print "ESC + ";
                    next;
                }
                if ( $escape && ord( $char ) == 91 ) {  # Control character
                    $ctrl = 1;
                    print "CTRL + ";
                    next;
                }
        
                if ( $escape && $ctrl && $function && ord( $char ) == 126 ) {
                    undef $escape;                      # Clean up after Fnctn key
                    undef $ctrl;
                    undef $function;
                    next;
                }
        
                if ( $escape && $ctrl && !$function ) {
                    print "Up\n"     if ( ord( $char ) == 65 );  # up
                    print "Down\n"   if ( ord( $char ) == 66 );  # down
                    print "Right\n"  if ( ord( $char ) == 67 );  # right arrow
                    print "Left\n"   if ( ord( $char ) == 68 );  # left arrow
                    if ( ord( $char ) == 49 ) {                  # Function character
                        $function = 1;
                        print "FCN + ";
                    } else {                                     # Clean up for arrow keys
                        undef $escape;
                        undef $ctrl;
                    }
                    next;
                }
        
                if ( $escape && $ctrl && $function ) {
                    print "F5\n"     if ( ord( $char ) == 53 ); # F5 key
                    print "F6\n"     if ( ord( $char ) == 55 ); # F6 key
                    print "F7\n"     if ( ord( $char ) == 56 ); # F7 key
                    print "F8\n"     if ( ord( $char ) == 57 ); # F8 key
                                                                # wait for clean up char
                    next;
                }
        
                if ( $escape && !$ctrl && !$function ) {
                    print "F1\n" if ( ord( $char ) == 80 );  # F1 key
                    print "F2\n" if ( ord( $char ) == 81 );  # F2 key
                    print "F3\n" if ( ord( $char ) == 82 );  # F3 key
                    print "F4\n" if ( ord( $char ) == 83 );  # F4 key
                    undef $escape;                           # Clean up
                    next;
                }
        
                print "Return\n" if ( ord( $char ) == 10 );  # return key
                print "Delete\n" if ( ord( $char ) == 127 ); # delete key
                print "Tab\n"    if ( ord( $char ) == 9 );   # tab key
                next             if ( ord( $char ) == 32 );  # skip on space key
                last             if ( $char =~ /q/ );        # break on q
                last             if ( $char =~ /\003/ );     # break on Ctrl-C
                last             if ( $char =~ /\032/ );     # break on Ctrl-Z
                print "ord: " . ord($char) . "\n";
            }
            system "stty icanon echo isig";
            exit(0);
        };
        
        if ( $@ ) {
            print "$@\n";
            system "stty icanon echo isig";
            exit(1);
        }
        
        Looking at: http://www.AsciiTable.com/
        it would appear my code is invalid... still looking.