1a5ae21e4Smrg#!/usr/bin/env perl
204b94745Smrg# $XTermId: xtra-scroll.pl,v 1.12 2021/09/03 18:34:50 tom Exp $
3a5ae21e4Smrg# -----------------------------------------------------------------------------
4a5ae21e4Smrg# this file is part of xterm
5a5ae21e4Smrg#
6a5ae21e4Smrg# Copyright 2021 by Thomas E. Dickey
7a5ae21e4Smrg#
8a5ae21e4Smrg#                         All Rights Reserved
9a5ae21e4Smrg#
10a5ae21e4Smrg# Permission is hereby granted, free of charge, to any person obtaining a
11a5ae21e4Smrg# copy of this software and associated documentation files (the
12a5ae21e4Smrg# "Software"), to deal in the Software without restriction, including
13a5ae21e4Smrg# without limitation the rights to use, copy, modify, merge, publish,
14a5ae21e4Smrg# distribute, sublicense, and/or sell copies of the Software, and to
15a5ae21e4Smrg# permit persons to whom the Software is furnished to do so, subject to
16a5ae21e4Smrg# the following conditions:
17a5ae21e4Smrg#
18a5ae21e4Smrg# The above copyright notice and this permission notice shall be included
19a5ae21e4Smrg# in all copies or substantial portions of the Software.
20a5ae21e4Smrg#
21a5ae21e4Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22a5ae21e4Smrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23a5ae21e4Smrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24a5ae21e4Smrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
25a5ae21e4Smrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26a5ae21e4Smrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27a5ae21e4Smrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28a5ae21e4Smrg#
29a5ae21e4Smrg# Except as contained in this notice, the name(s) of the above copyright
30a5ae21e4Smrg# holders shall not be used in advertising or otherwise to promote the
31a5ae21e4Smrg# sale, use or other dealings in this Software without prior written
32a5ae21e4Smrg# authorization.
33a5ae21e4Smrg# -----------------------------------------------------------------------------
34a5ae21e4Smrg# Interactively test screen-updates which can exercise the cdXtraScroll and
35a5ae21e4Smrg# tiXtraScroll features.
36a5ae21e4Smrg
37a5ae21e4Smrguse strict;
38a5ae21e4Smrguse warnings;
39a5ae21e4Smrg
40a5ae21e4Smrguse Getopt::Std;
41a5ae21e4Smrguse Term::ReadKey;
42a5ae21e4Smrguse I18N::Langinfo qw(langinfo CODESET);
43a5ae21e4Smrg
44a5ae21e4Smrg$! = 1;
45a5ae21e4Smrg
46a5ae21e4Smrgour $target = "";
47a5ae21e4Smrg
48a5ae21e4Smrgour $encoding = lc( langinfo( CODESET() ) );
49a5ae21e4Smrgour ($opt_8);
50a5ae21e4Smrg
51a5ae21e4Smrgour $dirty       = 1;    # nonzero if the screen should be painted
52a5ae21e4Smrgour $mode_margin = 0;    # nonzero if left/right margin mode enabled
53a5ae21e4Smrgour $mode_origin = 0;    # nonzero if origin-mode in effect
54a5ae21e4Smrgour $mode_screen = 0;    # nonzero if using alternate screen
55a5ae21e4Smrgour $pos_x       = 0;    # current cursor-Y, absolute
56a5ae21e4Smrgour $pos_y       = 0;    # current cursor-X, absolute
57a5ae21e4Smrgour $term_high;          # terminal's height
58a5ae21e4Smrgour $term_wide;          # terminal's width
59a5ae21e4Smrgour $CSI         = "\x1b[";
60a5ae21e4Smrgour $crlf        = "\r\n";
61a5ae21e4Smrgour $text_sample = "THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG ";
62a5ae21e4Smrgour $text_filler = "";
63a5ae21e4Smrgour %margins;
64a5ae21e4Smrg
65a5ae21e4Smrgsub raw() {
66a5ae21e4Smrg    ReadMode 'ultra-raw', 'STDIN';    # allow single-character inputs
67a5ae21e4Smrg}
68a5ae21e4Smrg
69a5ae21e4Smrgsub cooked() {
70a5ae21e4Smrg    ReadMode 'normal';
71a5ae21e4Smrg}
72a5ae21e4Smrg
73a5ae21e4Smrgsub utf8_sample() {
74a5ae21e4Smrg    my $text = "";
75a5ae21e4Smrg    for my $n ( 0 .. length($text_sample) ) {
76a5ae21e4Smrg        my $chr = substr( $text_sample, $n, 1 );
77a5ae21e4Smrg        if ( $chr eq " " ) {
78a5ae21e4Smrg            $chr = "  ";
79a5ae21e4Smrg        }
80a5ae21e4Smrg        elsif ( ord($chr) < 32 ) {
81a5ae21e4Smrg
82a5ae21e4Smrg            # leave control characters as-is
83a5ae21e4Smrg        }
84a5ae21e4Smrg        else {
85a5ae21e4Smrg            $chr = chr( 0xff00 + ord($chr) - 32 );
86a5ae21e4Smrg        }
87a5ae21e4Smrg        $text .= $chr;
88a5ae21e4Smrg    }
89a5ae21e4Smrg    return $text;
90a5ae21e4Smrg}
91a5ae21e4Smrg
92a5ae21e4Smrgsub next_x($) {
93a5ae21e4Smrg    my $value = shift;
94a5ae21e4Smrg    if ($mode_margin) {
95a5ae21e4Smrg        $value = $margins{R} if ( $value < $margins{R} );
96a5ae21e4Smrg        $value = $margins{L} if ( $value > $margins{L} );
97a5ae21e4Smrg    }
98a5ae21e4Smrg    else {
99a5ae21e4Smrg        $value = $value % $term_wide;
100a5ae21e4Smrg    }
101a5ae21e4Smrg    return $value;
102a5ae21e4Smrg}
103a5ae21e4Smrg
104a5ae21e4Smrgsub next_y($) {
105a5ae21e4Smrg    my $value = shift;
106a5ae21e4Smrg    if ($mode_origin) {
107a5ae21e4Smrg        $value = $margins{B} if ( $value < $margins{T} );
108a5ae21e4Smrg        $value = $margins{T} if ( $value > $margins{B} );
109a5ae21e4Smrg    }
110a5ae21e4Smrg    else {
111a5ae21e4Smrg        $value = $value % $term_high;
112a5ae21e4Smrg    }
113a5ae21e4Smrg    return $value;
114a5ae21e4Smrg}
115a5ae21e4Smrg
116a5ae21e4Smrgsub move() {
117a5ae21e4Smrg    my $y = $pos_y;
118a5ae21e4Smrg    if ($mode_origin) {
119a5ae21e4Smrg        my $min_y = ( $margins{T} >= 0 ) ? $margins{T} : 0;
120a5ae21e4Smrg        my $two_y = $min_y + 1;    # scrolling region is at least 2 lines
121a5ae21e4Smrg        my $max_y = ( $margins{B} >= $two_y ) ? $margins{B} : $two_y;
122a5ae21e4Smrg        $y = $max_y if ( $y > $max_y );
123a5ae21e4Smrg        $y -= $min_y;              # convert to relative ordinate
124a5ae21e4Smrg    }
125a5ae21e4Smrg    $y = 0 if ( $y < 0 );
126a5ae21e4Smrg    printf STDERR "%s%d;%dH", $CSI, 1 + $y, 1 + $pos_x;
127a5ae21e4Smrg}
128a5ae21e4Smrg
129a5ae21e4Smrgsub home() {
130a5ae21e4Smrg    printf STDERR "%sH", $CSI;
131a5ae21e4Smrg    $pos_x = 0;
132a5ae21e4Smrg    $pos_y = 0;
133a5ae21e4Smrg    &move;
134a5ae21e4Smrg}
135a5ae21e4Smrg
136a5ae21e4Smrgsub erase_display($) {
137a5ae21e4Smrg    my $mode = shift;
138a5ae21e4Smrg    printf STDERR "%s%sJ", $CSI, $mode;
139a5ae21e4Smrg}
140a5ae21e4Smrg
141a5ae21e4Smrgsub erase_line($) {
142a5ae21e4Smrg    my $mode = shift;
143a5ae21e4Smrg    printf STDERR "%s%sK", $CSI, $mode;
144a5ae21e4Smrg}
145a5ae21e4Smrg
146a5ae21e4Smrgsub toggle($) {
147a5ae21e4Smrg    my $value = shift;
148a5ae21e4Smrg    return ( $value == 0 ) ? 1 : 0;
149a5ae21e4Smrg}
150a5ae21e4Smrg
151a5ae21e4Smrg################################################################################
152a5ae21e4Smrg
153a5ae21e4Smrgsub set_margin_mode($) {
154a5ae21e4Smrg    my $mode = shift;
155a5ae21e4Smrg    printf STDERR "%s?69%s", $CSI, ( $mode == 0 ) ? "l" : "h";
156a5ae21e4Smrg    $mode_margin = $mode;
157a5ae21e4Smrg}
158a5ae21e4Smrg
159a5ae21e4Smrg################################################################################
160a5ae21e4Smrg
161a5ae21e4Smrgsub set_origin_mode($) {
162a5ae21e4Smrg    my $mode = shift;
163a5ae21e4Smrg    printf STDERR "%s?6%s", $CSI, ( $mode == 0 ) ? "l" : "h";
164a5ae21e4Smrg    $mode_origin = $mode;
165a5ae21e4Smrg}
166a5ae21e4Smrg
167a5ae21e4Smrg################################################################################
168a5ae21e4Smrg
169a5ae21e4Smrgsub set_screen_mode($) {
170a5ae21e4Smrg    my $mode = shift;
171a5ae21e4Smrg    printf STDERR "%s?1049%s", $CSI, ( $mode == 0 ) ? "l" : "h";
172a5ae21e4Smrg    $mode_screen = $mode;
173a5ae21e4Smrg}
174a5ae21e4Smrg
175a5ae21e4Smrg################################################################################
176a5ae21e4Smrg
177a5ae21e4Smrgsub do_tb_margins($$) {
178a5ae21e4Smrg    my $param_T = "";
179a5ae21e4Smrg    my $param_B = "";
180a5ae21e4Smrg    $param_T = sprintf( "%d", 1 + $margins{T} ) if ( $margins{T} >= 0 );
181a5ae21e4Smrg    $param_B = sprintf( "%d", 1 + $margins{B} )
182a5ae21e4Smrg      if ( $margins{B} > $margins{T} );
183a5ae21e4Smrg    printf STDERR "%s%s;%sr", $CSI, $param_T, $param_B;
184a5ae21e4Smrg    &move;
185a5ae21e4Smrg}
186a5ae21e4Smrg
187a5ae21e4Smrgsub undo_tb_margins() {
188a5ae21e4Smrg    &do_tb_margins( -1, -1 );
189a5ae21e4Smrg}
190a5ae21e4Smrg
191a5ae21e4Smrgsub redo_tb_margins() {
192a5ae21e4Smrg    &do_tb_margins( $margins{T}, $margins{B} );
193a5ae21e4Smrg}
194a5ae21e4Smrg
195a5ae21e4Smrgsub set_tb_margins($$) {
196a5ae21e4Smrg    my $reset = ( not defined $margins{T} or not defined $margins{B} ) ? 1 : 0;
197a5ae21e4Smrg    my $old_T = 1;
198a5ae21e4Smrg    my $old_B = $term_high;
199a5ae21e4Smrg    $old_T = $margins{T} if ( defined $margins{T} );
200a5ae21e4Smrg    $old_B = $margins{B} if ( defined $margins{B} );
201a5ae21e4Smrg    $margins{T} = shift;
202a5ae21e4Smrg    $margins{B} = shift;
203a5ae21e4Smrg    if ( $reset == 0 ) {
204a5ae21e4Smrg        $reset = 1 if ( $old_T != $margins{T} );
205a5ae21e4Smrg        $reset = 1 if ( $old_B != $margins{B} );
206a5ae21e4Smrg    }
207a5ae21e4Smrg    &redo_tb_margins if ( $reset == 1 );
208a5ae21e4Smrg}
209a5ae21e4Smrg
210a5ae21e4Smrg################################################################################
211a5ae21e4Smrg
212a5ae21e4Smrgsub do_lr_margins($$) {
213a5ae21e4Smrg    my $param_L = "";
214a5ae21e4Smrg    my $param_R = "";
215a5ae21e4Smrg    $param_L = sprintf( "%d", 1 + $margins{L} ) if ( $margins{L} >= 0 );
216a5ae21e4Smrg    $param_R = sprintf( "%d", 1 + $margins{R} )
217a5ae21e4Smrg      if ( $margins{R} > $margins{T} );
218a5ae21e4Smrg    printf STDERR "%s%s;%ss", $CSI, $param_L, $param_R;
219a5ae21e4Smrg    &move;
220a5ae21e4Smrg}
221a5ae21e4Smrg
222a5ae21e4Smrgsub undo_lr_margins() {
223a5ae21e4Smrg    &do_lr_margins( -1, -1 );
224a5ae21e4Smrg}
225a5ae21e4Smrg
226a5ae21e4Smrgsub redo_lr_margins() {
227a5ae21e4Smrg    &do_lr_margins( $margins{L}, $margins{R} );
228a5ae21e4Smrg}
229a5ae21e4Smrg
230a5ae21e4Smrgsub set_lr_margins($$) {
231a5ae21e4Smrg    my $reset = ( not defined $margins{L} or not defined $margins{R} ) ? 1 : 0;
232a5ae21e4Smrg    my $old_L = 1;
233a5ae21e4Smrg    my $old_R = $term_high;
234a5ae21e4Smrg    $old_L = $margins{L} if ( defined $margins{L} );
235a5ae21e4Smrg    $old_R = $margins{R} if ( defined $margins{R} );
236a5ae21e4Smrg    $margins{L} = shift;
237a5ae21e4Smrg    $margins{R} = shift;
238a5ae21e4Smrg    if ( $reset == 0 ) {
239a5ae21e4Smrg        $reset = 1 if ( $old_L != $margins{L} );
240a5ae21e4Smrg        $reset = 1 if ( $old_R != $margins{R} );
241a5ae21e4Smrg    }
242a5ae21e4Smrg    &redo_lr_margins if ( $reset == 1 );
243a5ae21e4Smrg}
244a5ae21e4Smrg
245a5ae21e4Smrg################################################################################
246a5ae21e4Smrg
247a5ae21e4Smrgsub has_tb_margins() {
248a5ae21e4Smrg    my $result = 0;
249a5ae21e4Smrg    $result = 1 if ( $margins{T} != 1 );
250a5ae21e4Smrg    $result = 1 if ( $margins{B} != $term_high );
251a5ae21e4Smrg    return $result;
252a5ae21e4Smrg}
253a5ae21e4Smrg
254a5ae21e4Smrgsub repaint($) {
255a5ae21e4Smrg    my $erase  = shift;
256a5ae21e4Smrg    my $save_x = $pos_x;
257a5ae21e4Smrg    my $save_y = $pos_y;
258a5ae21e4Smrg    $dirty = 0;
259a5ae21e4Smrg    if ($erase) {
260a5ae21e4Smrg        &home;
261a5ae21e4Smrg        &erase_display(2);
262a5ae21e4Smrg    }
263a5ae21e4Smrg    if ( $text_filler ne "" ) {
264a5ae21e4Smrg        if ( $mode_origin and &has_tb_margins ) {
265a5ae21e4Smrg            my @rows = split /$crlf/, $text_filler;
266a5ae21e4Smrg            for my $row ( 0 .. $#rows ) {
267a5ae21e4Smrg                next unless ( $row >= $margins{T} );
268a5ae21e4Smrg                next unless ( $row <= $margins{B} );
269a5ae21e4Smrg                printf STDERR "%s$crlf", $rows[$row];
270a5ae21e4Smrg            }
271a5ae21e4Smrg        }
272a5ae21e4Smrg        else {
273a5ae21e4Smrg            printf STDERR "%s$crlf", $text_filler;
274a5ae21e4Smrg        }
275a5ae21e4Smrg    }
276a5ae21e4Smrg    else {
277a5ae21e4Smrg        my $cells = 0;
278a5ae21e4Smrg        my $limit = $term_high * $term_wide;
279a5ae21e4Smrg        while ( $cells < $limit ) {
280a5ae21e4Smrg            my $sample = ( $encoding eq "utf-8" ) ? &utf8_sample : $text_sample;
281a5ae21e4Smrg            printf STDERR "%s", $sample;
282a5ae21e4Smrg            $cells += length($sample);
283a5ae21e4Smrg        }
284a5ae21e4Smrg    }
285a5ae21e4Smrg    $pos_x = $save_x;
286a5ae21e4Smrg    $pos_y = $save_y;
287a5ae21e4Smrg    &move;
288a5ae21e4Smrg}
289a5ae21e4Smrg
290a5ae21e4Smrgsub initialize() {
291a5ae21e4Smrg    if ( $encoding eq "utf-8" ) {
292a5ae21e4Smrg        binmode( STDOUT, ":utf8" );
293a5ae21e4Smrg        binmode( STDERR, ":utf8" );
294a5ae21e4Smrg    }
295a5ae21e4Smrg    if ($opt_8) {
296a5ae21e4Smrg        if ( $encoding eq "utf-8" ) {
297a5ae21e4Smrg            undef $opt_8;
298a5ae21e4Smrg            printf "...ignoring -8 option since locale uses %s\n", $encoding;
299a5ae21e4Smrg        }
300a5ae21e4Smrg        else {
301a5ae21e4Smrg            printf STDERR "\x1b G";
302a5ae21e4Smrg            $CSI = "\x9b";
303a5ae21e4Smrg        }
304a5ae21e4Smrg    }
305a5ae21e4Smrg
306a5ae21e4Smrg    &raw;
307a5ae21e4Smrg
308a5ae21e4Smrg    my @term_size = GetTerminalSize( \*STDERR );
309a5ae21e4Smrg    $term_wide = 80;
310a5ae21e4Smrg    $term_wide = $term_size[0] if ( $#term_size >= 0 );
311a5ae21e4Smrg    $term_wide = 80 if ( $term_wide <= 0 );
312a5ae21e4Smrg    $term_high = 24;
313a5ae21e4Smrg    $term_high = $term_size[1] if ( $#term_size >= 1 );
314a5ae21e4Smrg    $term_high = 24 if ( $term_high <= 0 );
315a5ae21e4Smrg
316a5ae21e4Smrg    &set_margin_mode(0);
317a5ae21e4Smrg    &set_origin_mode(0);
318a5ae21e4Smrg    &set_screen_mode(0);
319a5ae21e4Smrg
320a5ae21e4Smrg    &set_tb_margins( -1, -1 );
321a5ae21e4Smrg    &set_lr_margins( 1, $term_wide );
322a5ae21e4Smrg
323a5ae21e4Smrg    &home;
324a5ae21e4Smrg    &erase_display("2");
325a5ae21e4Smrg}
326a5ae21e4Smrg
327a5ae21e4Smrgsub cleanup() {
328a5ae21e4Smrg    &cooked;
329a5ae21e4Smrg
330a5ae21e4Smrg    printf STDERR "\x1b F" if ($opt_8);
331a5ae21e4Smrg
332a5ae21e4Smrg    &set_margin_mode(0);
333a5ae21e4Smrg    &set_origin_mode(0);
334a5ae21e4Smrg    &set_screen_mode(0);
335a5ae21e4Smrg
336a5ae21e4Smrg    &undo_tb_margins;
337a5ae21e4Smrg
338a5ae21e4Smrg    $pos_x = 1;
339a5ae21e4Smrg    $pos_y = $term_high - 2;
340a5ae21e4Smrg    &move;
341a5ae21e4Smrg    &erase_display("");
342a5ae21e4Smrg}
343a5ae21e4Smrg
344a5ae21e4Smrgsub beep() {
345a5ae21e4Smrg    printf STDERR "\a";
346a5ae21e4Smrg}
347a5ae21e4Smrg
348a5ae21e4Smrgsub main::HELP_MESSAGE() {
349a5ae21e4Smrg    printf STDERR <<EOF
350a5ae21e4SmrgUsage: $0 [options] [datafile]
351a5ae21e4SmrgOptions:
352a5ae21e4Smrg  -8      use 8-bit controls
353a5ae21e4SmrgEOF
354a5ae21e4Smrg      ;
355a5ae21e4Smrg    exit 1;
356a5ae21e4Smrg}
357a5ae21e4Smrg
358a5ae21e4Smrg$Getopt::Std::STANDARD_HELP_VERSION = 1;
359a5ae21e4Smrg&getopts('8') || &main::HELP_MESSAGE;
360a5ae21e4Smrg$#ARGV <= 0   || &main::HELP_MESSAGE;
361a5ae21e4Smrg
362a5ae21e4Smrg# provide for reading file containing text to repaint
363a5ae21e4Smrgif ( $#ARGV == 0 ) {
364a5ae21e4Smrg    if ( open( FP, $ARGV[0] ) ) {
365a5ae21e4Smrg        my @lines = <FP>;
366a5ae21e4Smrg        chomp @lines;
367a5ae21e4Smrg        close FP;
368a5ae21e4Smrg        $text_filler = join( $crlf, @lines );
369a5ae21e4Smrg    }
370a5ae21e4Smrg}
371a5ae21e4Smrg
372a5ae21e4Smrgprintf "encoding $encoding\n";
373a5ae21e4Smrg
374a5ae21e4Smrg&initialize();
375a5ae21e4Smrg
376a5ae21e4Smrgwhile (1) {
377a5ae21e4Smrg    my $cmd;
378a5ae21e4Smrg
379a5ae21e4Smrg    printf "\r\nCommand (? for help):" if ( $dirty != 0 );
380a5ae21e4Smrg    $cmd = ReadKey 0;
381a5ae21e4Smrg    if ( not $cmd ) {
382a5ae21e4Smrg        sleep 1;
383a5ae21e4Smrg    }
384a5ae21e4Smrg    elsif ( $cmd eq "?" ) {
385a5ae21e4Smrg        $dirty = 1;
386a5ae21e4Smrg        &home;
387a5ae21e4Smrg        &erase_display(2);
388a5ae21e4Smrg        printf $crlf
389a5ae21e4Smrg          . "General:"
390a5ae21e4Smrg          . $crlf
391a5ae21e4Smrg          . " ? (help),"
392a5ae21e4Smrg          . " q (quit)"
393a5ae21e4Smrg          . $crlf
394a5ae21e4Smrg          . "Clear:"
395a5ae21e4Smrg          . $crlf
396a5ae21e4Smrg          . " C (entire screen),"
397a5ae21e4Smrg          . " c (screen-below),"
398a5ae21e4Smrg          . " E (entire line),"
399a5ae21e4Smrg          . " e (line-right)"
400a5ae21e4Smrg          . $crlf . "Fill:"
401a5ae21e4Smrg          . $crlf
402a5ae21e4Smrg          . " @ (margin-box),"
403a5ae21e4Smrg          . " # (prompt-char)"
404a5ae21e4Smrg          . $crlf
405a5ae21e4Smrg          . "Move cursor:\r\n"
406a5ae21e4Smrg          . " h,j,k,l (vi-like),"
407a5ae21e4Smrg          . " H (to home)."
408a5ae21e4Smrg          . $crlf
409a5ae21e4Smrg          . "Set margin using current position:"
410a5ae21e4Smrg          . $crlf
411a5ae21e4Smrg          . " T (top),"
412a5ae21e4Smrg          . " B (bottom),"
413a5ae21e4Smrg          . " L (left),"
414a5ae21e4Smrg          . " R (right)"
415a5ae21e4Smrg          . $crlf
416a5ae21e4Smrg          . "Reset modes"
417a5ae21e4Smrg          . $crlf
418a5ae21e4Smrg          . " M (margins)"
419a5ae21e4Smrg          . $crlf
420a5ae21e4Smrg          . "Toggle modes"
421a5ae21e4Smrg          . $crlf
422a5ae21e4Smrg          . " A (alternate-screen),"
423a5ae21e4Smrg          . " O (origin-mode)"
424a5ae21e4Smrg          . " | (left/right-mode)"
425a5ae21e4Smrg          . $crlf
426a5ae21e4Smrg          . "Print sample:"
427a5ae21e4Smrg          . " form-feed (repaint)";
428a5ae21e4Smrg    }
429a5ae21e4Smrg    elsif ( $cmd eq "\033" ) {
430a5ae21e4Smrg
431a5ae21e4Smrg        # try to ignore special-keys
432a5ae21e4Smrg        my $count = 0;
433a5ae21e4Smrg        while (1) {
434a5ae21e4Smrg            $cmd = ReadKey 0;
435a5ae21e4Smrg            $count++;
436a5ae21e4Smrg            next if ( $count == 1 and $cmd eq "O" );
437a5ae21e4Smrg            next unless ( $cmd =~ /^[A-~]$/ );
438a5ae21e4Smrg            $cmd = ReadKey 0;
439a5ae21e4Smrg            last;
440a5ae21e4Smrg        }
441a5ae21e4Smrg    }
442a5ae21e4Smrg    elsif ( $cmd eq "q" ) {
443a5ae21e4Smrg        last;
444a5ae21e4Smrg    }
445a5ae21e4Smrg    elsif ( index( "CcEe@#hjklHMTBLRAO|\f", $cmd ) >= 0 ) {
446a5ae21e4Smrg        my $was_dirty = $dirty;
447a5ae21e4Smrg        &repaint(1) if ( $dirty != 0 );
448a5ae21e4Smrg        if ( $cmd eq "C" ) {
449a5ae21e4Smrg            &home;
450a5ae21e4Smrg            &erase_display("2");
451a5ae21e4Smrg        }
452a5ae21e4Smrg        elsif ( $cmd eq "c" ) {
453a5ae21e4Smrg            &erase_display("");
454a5ae21e4Smrg        }
455a5ae21e4Smrg        elsif ( $cmd eq "E" ) {
456a5ae21e4Smrg            &erase_line("2");
457a5ae21e4Smrg        }
458a5ae21e4Smrg        elsif ( $cmd eq "e" ) {
459a5ae21e4Smrg            &erase_line("");
460a5ae21e4Smrg        }
461a5ae21e4Smrg        elsif ( $cmd eq "@" ) {
462a5ae21e4Smrg
463a5ae21e4Smrg            # FIXME
464a5ae21e4Smrg        }
465a5ae21e4Smrg        elsif ( $cmd eq "#" ) {
466a5ae21e4Smrg            $text_sample = ReadKey 0;
467a5ae21e4Smrg            if ( $text_filler ne "" ) {
468a5ae21e4Smrg                my $save_filler = $text_filler;
469a5ae21e4Smrg                $text_filler =~ s/[^\d\s]/$text_sample/g;
470a5ae21e4Smrg                &repaint(0);
471a5ae21e4Smrg                $text_filler = $save_filler;
472a5ae21e4Smrg            }
473a5ae21e4Smrg            else {
474a5ae21e4Smrg                &repaint(0);
475a5ae21e4Smrg            }
476a5ae21e4Smrg        }
477a5ae21e4Smrg        elsif ( $cmd eq "h" ) {
478a5ae21e4Smrg            $pos_x = &next_x( $pos_x - 1 );
479a5ae21e4Smrg            &move;
480a5ae21e4Smrg        }
481a5ae21e4Smrg        elsif ( $cmd eq "j" ) {
482a5ae21e4Smrg            $pos_y = &next_y( $pos_y + 1 );
483a5ae21e4Smrg            &move;
484a5ae21e4Smrg        }
485a5ae21e4Smrg        elsif ( $cmd eq "k" ) {
486a5ae21e4Smrg            $pos_y = &next_y( $pos_y - 1 );
487a5ae21e4Smrg            &move;
488a5ae21e4Smrg        }
489a5ae21e4Smrg        elsif ( $cmd eq "l" ) {
490a5ae21e4Smrg            $pos_x = &next_x( $pos_x + 1 );
491a5ae21e4Smrg            &move;
492a5ae21e4Smrg        }
493a5ae21e4Smrg        elsif ( $cmd eq "H" ) {
494a5ae21e4Smrg            &home;
495a5ae21e4Smrg        }
496a5ae21e4Smrg        elsif ( $cmd eq "M" ) {
497a5ae21e4Smrg            &set_tb_margins( -1, -1 );
498a5ae21e4Smrg            &set_lr_margins( -1, -1 );
499a5ae21e4Smrg            &repaint(0);
500a5ae21e4Smrg        }
501a5ae21e4Smrg        elsif ( $cmd eq "T" ) {
502a5ae21e4Smrg            &set_tb_margins( $pos_y, $margins{B} );
503a5ae21e4Smrg        }
504a5ae21e4Smrg        elsif ( $cmd eq "B" ) {
505a5ae21e4Smrg            &set_tb_margins( $margins{T}, $pos_y );
506a5ae21e4Smrg        }
507a5ae21e4Smrg        elsif ( $cmd eq "L" ) {
508a5ae21e4Smrg            &set_lr_margins( $pos_x, $margins{R} );
509a5ae21e4Smrg        }
510a5ae21e4Smrg        elsif ( $cmd eq "R" ) {
511a5ae21e4Smrg            &set_lr_margins( $margins{L}, $pos_x );
512a5ae21e4Smrg        }
513a5ae21e4Smrg        elsif ( $cmd eq "A" ) {
514a5ae21e4Smrg            &set_screen_mode( &toggle($mode_screen) );
515a5ae21e4Smrg            &repaint(1);
516a5ae21e4Smrg        }
517a5ae21e4Smrg        elsif ( $cmd eq "O" ) {
518a5ae21e4Smrg            &set_origin_mode( &toggle($mode_origin) );
519a5ae21e4Smrg        }
520a5ae21e4Smrg        elsif ( $cmd eq "|" ) {
521a5ae21e4Smrg            &set_margin_mode( &toggle($mode_margin) );
522a5ae21e4Smrg        }
523a5ae21e4Smrg        elsif ( $cmd eq "\f" ) {
524a5ae21e4Smrg            &repaint(1) unless ($was_dirty);
525a5ae21e4Smrg        }
526a5ae21e4Smrg        else {
527a5ae21e4Smrg            &beep;
528a5ae21e4Smrg            $dirty = 2;
529a5ae21e4Smrg        }
530a5ae21e4Smrg    }
531a5ae21e4Smrg    else {
532a5ae21e4Smrg        &beep;
533a5ae21e4Smrg    }
534a5ae21e4Smrg}
535a5ae21e4Smrg
536a5ae21e4Smrg&cleanup;
537a5ae21e4Smrgprintf " ...quit\r\n";
538a5ae21e4Smrg
539a5ae21e4Smrg1;
540