1#!/usr/bin/env perl 2# $XTermId: cursor.pl,v 1.8 2007/12/03 00:56:29 tom Exp $ 3# ----------------------------------------------------------------------------- 4# Copyright 2007 by Thomas E. Dickey 5# 6# All Rights Reserved 7# 8# Permission is hereby granted, free of charge, to any person obtaining a 9# copy of this software and associated documentation files (the 10# "Software"), to deal in the Software without restriction, including 11# without limitation the rights to use, copy, modify, merge, publish, 12# distribute, sublicense, and/or sell copies of the Software, and to 13# permit persons to whom the Software is furnished to do so, subject to 14# the following conditions: 15# 16# The above copyright notice and this permission notice shall be included 17# in all copies or substantial portions of the Software. 18# 19# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26# 27# Except as contained in this notice, the name(s) of the above copyright 28# holders shall not be used in advertising or otherwise to promote the 29# sale, use or other dealings in this Software without prior written 30# authorization. 31# ----------------------------------------------------------------------------- 32# Read a file (or pipe from a program) and move the cursor around the screen 33# in response to h,j,k,l commands so we can see the colors that affect the 34# cursor. Exit on 'q'. Do forward/backward paging to \E[J markers 35# in the data with n,p. Ignore other characters. 36# 37# Use this rather than, say, a curses program since it is much easier to 38# construct a particular screen using 'script' or echo commands than to 39# guarantee the same screen with curses' optimization. 40 41use strict; 42 43use Getopt::Std; 44use IO::Handle; 45 46our ( $opt_x ); 47our ( $row_max, $col_max ); 48our $old_stty; 49our $text_blob; 50our $text_1st; 51our $text_2nd; 52our $text_chop = qw/^\x1b\[H\x1b\[J/; 53our $text_mark = "\x1b[H\x1b[J"; 54 55sub get_screensize() { 56 my @reply = `resize -u`; 57 chomp @reply; 58 for my $n (0..$#reply) { 59 if ( $reply[$n] =~ /=/ ) { 60 my $value = $reply[$n]; 61 $value =~ s/^.*=//; 62 if ( $reply[$n] =~ /^COLUMNS.*/ ) { 63 $col_max = $value; 64 } else { 65 $row_max = $value; 66 } 67 } 68 } 69} 70 71sub end_cursor($) { 72 close TTY; 73 system "stty $old_stty"; 74 print $_[0]; 75 exit; 76} 77 78sub begin_cursor() { 79 open TTY, "+</dev/tty" or end_cursor("Cannot open /dev/tty\n"); 80 autoflush TTY 1; 81 $old_stty=`stty -g`; 82 system "stty raw -echo min 0 time 1"; 83} 84 85sub beep() { 86 printf "\007"; 87} 88 89sub get_char() { 90 my $reply; 91 do { 92 $reply=<TTY>; 93 # printf "get_char\r\n"; 94 } while (not defined $reply); 95 return $reply; 96} 97 98sub move_to($$) { 99 my $y = $_[0]; 100 my $x = $_[1]; 101 if ( $y < 0 ) { 102 $y = 0; 103 } elsif ( $x < 0 ) { 104 $x = 0; 105 } elsif ( $y >= $row_max ) { 106 $y -= 1; 107 } elsif ( $x >= $col_max ) { 108 $x -= 1; 109 } else { 110 printf "\x1b[%d;%dH", $y + 1, $x + 1; 111 } 112 return ( $y, $x ); 113} 114 115sub vxt_cursor() { 116 my $ch; 117 my $x = 0; 118 my $y = 0; 119 my @pages = split $text_chop, $text_blob; 120 my $page = 1; 121 122my_page: 123 move_to ($y, $x); 124 printf "%s", $text_mark . $pages[$page]; 125 move_to ($y, $x); 126my_loop: 127 for (;;) { 128 $ch = get_char(); 129 if ( $ch eq "q") { 130 last my_loop; 131 } elsif ( $ch eq "h" ) { 132 ($y, $x) = move_to($y, $x - 1); 133 } elsif ( $ch eq "j" ) { 134 ($y, $x) = move_to($y + 1, $x); 135 } elsif ( $ch eq "k" ) { 136 ($y, $x) = move_to($y - 1, $x); 137 } elsif ( $ch eq "l" ) { 138 ($y, $x) = move_to($y, $x + 1); 139 } elsif ( $ch eq "n" ) { 140 if ( $page < $#pages ) { 141 $page += 1; 142 goto my_page; 143 } else { 144 beep(); 145 } 146 } elsif ( $ch eq "p" ) { 147 if ( $page > 1 ) { 148 $page -= 1; 149 goto my_page; 150 } else { 151 beep(); 152 } 153 } else { 154 beep(); 155 # printf "got:%s\r\n", $ch; 156 } 157 } 158} 159 160sub load_text($) { 161 my $source = $_[0]; 162 my $text; 163 if ( defined($opt_x) ) { 164 $text = `$source`; 165 } else { 166 $text = `cat $source`; 167 } 168 $text =~ s/\n/\r\n/g; 169 if ( $text !~ $text_chop ) { 170 $text = $text_mark . $text; 171 } 172 $text_blob = $text_blob . $text; 173} 174 175&getopts('x') || die(); 176 177while ( $#ARGV >= 0 ) { 178 load_text ( shift @ARGV ); 179} 180 181get_screensize(); 182begin_cursor(); 183vxt_cursor(); 184end_cursor("Done\n"); 185