1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: terminal.c 921 2008-01-31 02:09:25Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2021 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
18 * Program: Display routines
25 #include "../estruct.h"
26 #include "../keydefs.h"
43 #define MARGIN 8 /* size of minimim margin and */
44 #define MROW 2 /* rows in menu */
47 /* any special properties of the current terminal */
48 unsigned term_capabilities
= (TT_EOLEXIST
| TT_SCROLLEXIST
| TT_INSCHAR
| TT_DELCHAR
);
57 return(term_capabilities
);
64 * terminfo-based terminal i/o and control routines
68 /* internal prototypes */
69 static int tinfomove(int, int);
70 static int tinfoeeol(void);
71 static int tinfoeeop(void);
72 static int tinfobeep(void);
73 static int tinforev(int);
74 static int tinfoeri(void);
75 static int tinfoopen(void);
76 static int tinfoterminalinfo(int);
77 static int tinfoclose(void);
78 static void setup_dflt_esc_seq(void);
79 static void tinfoinsert(UCS
);
80 static void tinfodelete(void);
83 extern int tputs(char *, int, int (*)(int));
84 extern char *tgoto(char *, int, int);
85 extern char *tigetstr (char *);
86 extern int setupterm(char *, int, int *);
87 extern int tigetnum(char *);
88 extern int tigetflag(char *);
91 ** Note: The tgoto calls should really be replaced by tparm calls for
92 ** modern terminfo. tgoto(s, x, y) == tparm(s, y, x).
95 int _tlines
, _tcolumns
;
96 char *_clearscreen
, *_moveto
, *_up
, *_down
, *_right
, *_left
,
97 *_setinverse
, *_clearinverse
,
98 *_setunderline
, *_clearunderline
,
99 *_setbold
, *_clearallattr
, /* there is no clear only bold! */
100 *_cleartoeoln
, *_cleartoeos
,
101 *_deleteline
, /* delete line */
102 *_insertline
, /* insert line */
103 *_scrollregion
, /* define a scrolling region, vt100 */
104 *_insertchar
, /* insert character, preferable to : */
105 *_startinsert
, /* set insert mode and, */
106 *_endinsert
, /* end insert mode */
107 *_deletechar
, /* delete character */
108 *_startdelete
, /* set delete mode and, */
109 *_enddelete
, /* end delete mode */
110 *_scrolldown
, /* scroll down */
111 *_scrollup
, /* scroll up */
112 *_termcap_init
, /* string to start termcap */
113 *_termcap_end
, /* string to end termcap */
114 *_op
, *_oc
, *_setaf
, *_setab
, *_setf
, *_setb
, *_scp
;
115 int _colors
, _pairs
, _bce
, _xhp
;
139 * Add default keypad sequences to the trie.
142 setup_dflt_esc_seq(void)
145 * this is sort of a hack [no kidding], but it allows us to use
146 * the function keys on pc's running telnet
150 * UW-NDC/UCS vt10[02] application mode.
152 kpinsert("\033OP", F1
, 1);
153 kpinsert("\033OQ", F2
, 1);
154 kpinsert("\033OR", F3
, 1);
155 kpinsert("\033OS", F4
, 1);
156 kpinsert("\033Op", F5
, 1);
157 kpinsert("\033Oq", F6
, 1);
158 kpinsert("\033Or", F7
, 1);
159 kpinsert("\033Os", F8
, 1);
160 kpinsert("\033Ot", F9
, 1);
161 kpinsert("\033Ou", F10
, 1);
162 kpinsert("\033Ov", F11
, 1);
163 kpinsert("\033Ow", F12
, 1);
166 * DEC vt100, ANSI and cursor key mode.
168 kpinsert("\033OA", KEY_UP
, 1);
169 kpinsert("\033OB", KEY_DOWN
, 1);
170 kpinsert("\033OC", KEY_RIGHT
, 1);
171 kpinsert("\033OD", KEY_LEFT
, 1);
174 * special keypad functions
176 kpinsert("\033[4J", KEY_PGUP
, 1);
177 kpinsert("\033[3J", KEY_PGDN
, 1);
178 kpinsert("\033[2J", KEY_HOME
, 1);
179 kpinsert("\033[N", KEY_END
, 1);
184 kpinsert("\033[5~", KEY_PGUP
, 1);
185 kpinsert("\033[6~", KEY_PGDN
, 1);
186 kpinsert("\033[1~", KEY_HOME
, 1);
187 kpinsert("\033[4~", KEY_END
, 1);
190 * konsole, XTerm (XFree 4.x.x) keyboard setting
192 kpinsert("\033[H", KEY_HOME
, 1);
193 kpinsert("\033[F", KEY_END
, 1);
196 * gnome-terminal 2.6.0, don't know why it
199 kpinsert("\033OH", KEY_HOME
, 1);
200 kpinsert("\033OF", KEY_END
, 1);
203 * "\033[2~" was common for KEY_HOME in a quick survey
204 * of terminals (though typically the Insert key).
205 * Teraterm 2.33 sends the following escape sequences,
206 * which is quite incompatible with everything
208 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
210 * The best thing to do would be to fix TeraTerm
211 * keymappings or to tweak terminfo.
217 kpinsert("\033[=a", F1
, 1);
218 kpinsert("\033[=b", F2
, 1);
219 kpinsert("\033[=c", F3
, 1);
220 kpinsert("\033[=d", F4
, 1);
221 kpinsert("\033[=e", F5
, 1);
222 kpinsert("\033[=f", F6
, 1);
223 kpinsert("\033[=g", F7
, 1);
224 kpinsert("\033[=h", F8
, 1);
225 kpinsert("\033[=i", F9
, 1);
226 kpinsert("\033[=j", F10
, 1);
227 kpinsert("\033[=k", F11
, 1);
228 kpinsert("\033[=l", F12
, 1);
231 * DEC vt100, ANSI and cursor key mode reset.
233 kpinsert("\033[A", KEY_UP
, 1);
234 kpinsert("\033[B", KEY_DOWN
, 1);
235 kpinsert("\033[C", KEY_RIGHT
, 1);
236 kpinsert("\033[D", KEY_LEFT
, 1);
241 kpinsert("\033A", KEY_UP
, 1);
242 kpinsert("\033B", KEY_DOWN
, 1);
243 kpinsert("\033C", KEY_RIGHT
, 1);
244 kpinsert("\033D", KEY_LEFT
, 1);
247 * DEC vt52 application keys, and some Zenith 19.
249 kpinsert("\033?r", KEY_DOWN
, 1);
250 kpinsert("\033?t", KEY_LEFT
, 1);
251 kpinsert("\033?v", KEY_RIGHT
, 1);
252 kpinsert("\033?x", KEY_UP
, 1);
255 * Some Ctrl-Arrow keys
257 kpinsert("\033[5A", CTRL_KEY_UP
, 1);
258 kpinsert("\033[5B", CTRL_KEY_DOWN
, 1);
259 kpinsert("\033[5C", CTRL_KEY_RIGHT
, 1);
260 kpinsert("\033[5D", CTRL_KEY_LEFT
, 1);
262 kpinsert("\033[1;5A", CTRL_KEY_UP
, 1);
263 kpinsert("\033[1;5B", CTRL_KEY_DOWN
, 1);
264 kpinsert("\033[1;5C", CTRL_KEY_RIGHT
, 1);
265 kpinsert("\033[1;5D", CTRL_KEY_LEFT
, 1);
268 * Map some shift+up/down/left/right to their shiftless counterparts
270 kpinsert("\033[1;2A", KEY_UP
, 1);
271 kpinsert("\033[1;2B", KEY_DOWN
, 1);
272 kpinsert("\033[1;2C", KEY_RIGHT
, 1);
273 kpinsert("\033[1;2D", KEY_LEFT
, 1);
274 kpinsert("\033[a", KEY_UP
, 1);
275 kpinsert("\033[b", KEY_DOWN
, 1);
276 kpinsert("\033[c", KEY_RIGHT
, 1);
277 kpinsert("\033[d", KEY_LEFT
, 1);
280 * Sun Console sequences.
282 kpinsert("\033[1", KEY_SWALLOW_Z
, 1);
283 kpinsert("\033[215", KEY_SWAL_UP
, 1);
284 kpinsert("\033[217", KEY_SWAL_LEFT
, 1);
285 kpinsert("\033[219", KEY_SWAL_RIGHT
, 1);
286 kpinsert("\033[221", KEY_SWAL_DOWN
, 1);
289 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
291 kpinsert("\033_", KEY_KERMIT
, 1);
294 * Fake a control character.
296 kpinsert("\033\033", KEY_DOUBLE_ESC
, 1);
301 tinfoterminalinfo(int termcap_wins
)
303 char *_ku
, *_kd
, *_kl
, *_kr
,
304 *_kppu
, *_kppd
, *_kphome
, *_kpend
, *_kpdel
,
305 *_kf1
, *_kf2
, *_kf3
, *_kf4
, *_kf5
, *_kf6
,
306 *_kf7
, *_kf8
, *_kf9
, *_kf10
, *_kf11
, *_kf12
;
311 * setupterm() automatically retrieves the value
312 * of the TERM variable.
315 ttnm
= getenv("TERM");
319 strncpy(term_name
, ttnm
, sizeof(term_name
));
320 term_name
[sizeof(term_name
)-1] = '\0';
321 setupterm ((char *) 0, 1, &err
);
322 if (err
!= 1) return(err
-2);
326 * setupterm() issues a message and exits, if the
327 * terminfo data base is gone or the term type is
328 * unknown, if arg2 is 0.
330 setupterm ((char *) 0, 1, (int *) 0);
333 _clearscreen
= tigetstr("clear");
334 _moveto
= tigetstr("cup");
335 _up
= tigetstr("cuu1");
336 _down
= tigetstr("cud1");
337 _right
= tigetstr("cuf1");
338 _left
= tigetstr("cub1");
339 _setinverse
= tigetstr("smso");
340 _clearinverse
= tigetstr("rmso");
341 _setunderline
= tigetstr("smul");
342 _clearunderline
= tigetstr("rmul");
343 _setbold
= tigetstr("bold");
344 _clearallattr
= tigetstr("sgr0");
345 _cleartoeoln
= tigetstr("el");
346 _cleartoeos
= tigetstr("ed");
347 _deletechar
= tigetstr("dch1");
348 _insertchar
= tigetstr("ich1");
349 _startinsert
= tigetstr("smir");
350 _endinsert
= tigetstr("rmir");
351 _deleteline
= tigetstr("dl1");
352 _insertline
= tigetstr("il1");
353 _scrollregion
= tigetstr("csr");
354 _scrolldown
= tigetstr("ind");
355 _scrollup
= tigetstr("ri");
356 _termcap_init
= tigetstr("smcup");
357 _termcap_end
= tigetstr("rmcup");
358 _startdelete
= tigetstr("smdc");
359 _enddelete
= tigetstr("rmdc");
360 _ku
= tigetstr("kcuu1");
361 _kd
= tigetstr("kcud1");
362 _kl
= tigetstr("kcub1");
363 _kr
= tigetstr("kcuf1");
364 _kppu
= tigetstr("kpp");
365 _kppd
= tigetstr("knp");
366 _kphome
= tigetstr("khome");
367 _kpend
= tigetstr("kend");
368 _kpdel
= tigetstr("kdch1");
369 _kf1
= tigetstr("kf1");
370 _kf2
= tigetstr("kf2");
371 _kf3
= tigetstr("kf3");
372 _kf4
= tigetstr("kf4");
373 _kf5
= tigetstr("kf5");
374 _kf6
= tigetstr("kf6");
375 _kf7
= tigetstr("kf7");
376 _kf8
= tigetstr("kf8");
377 _kf9
= tigetstr("kf9");
378 _kf10
= tigetstr("kf10");
379 _kf11
= tigetstr("kf11");
380 _kf12
= tigetstr("kf12");
382 _colors
= tigetnum("colors");
383 _pairs
= tigetnum("pairs");
384 _setaf
= tigetstr("setaf");
385 _setab
= tigetstr("setab");
386 _setf
= tigetstr("setf");
387 _setb
= tigetstr("setb");
388 _scp
= tigetstr("scp");
389 _op
= tigetstr("op");
390 _oc
= tigetstr("oc");
391 _bce
= tigetflag("bce");
392 _xhp
= tigetflag("xhp");
394 _tlines
= tigetnum("lines");
399 /* tigetnum failed, try $LINES */
400 er
= getenv("LINES");
401 if(er
&& (rr
= atoi(er
)) > 0)
405 _tcolumns
= tigetnum("cols");
410 /* tigetnum failed, try $COLUMNS */
411 ec
= getenv("COLUMNS");
412 if(ec
&& (cc
= atoi(ec
)) > 0)
417 * Add default keypad sequences to the trie.
418 * Since these come first, they will override any conflicting termcap
419 * or terminfo escape sequences defined below. An escape sequence is
420 * considered conflicting if one is a prefix of the other.
421 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
422 * escape sequences that don't work, because they conflict with default
423 * sequences defined here.
426 setup_dflt_esc_seq();
429 * add termcap/info escape sequences to the trie...
432 if(_ku
!= NULL
&& _kd
!= NULL
&& _kl
!= NULL
&& _kr
!= NULL
){
433 kpinsert(_ku
, KEY_UP
, termcap_wins
);
434 kpinsert(_kd
, KEY_DOWN
, termcap_wins
);
435 kpinsert(_kl
, KEY_LEFT
, termcap_wins
);
436 kpinsert(_kr
, KEY_RIGHT
, termcap_wins
);
439 if(_kppu
!= NULL
&& _kppd
!= NULL
){
440 kpinsert(_kppu
, KEY_PGUP
, termcap_wins
);
441 kpinsert(_kppd
, KEY_PGDN
, termcap_wins
);
444 kpinsert(_kphome
, KEY_HOME
, termcap_wins
);
445 kpinsert(_kpend
, KEY_END
, termcap_wins
);
446 kpinsert(_kpdel
, KEY_DEL
, termcap_wins
);
448 kpinsert(_kf1
, F1
, termcap_wins
);
449 kpinsert(_kf2
, F2
, termcap_wins
);
450 kpinsert(_kf3
, F3
, termcap_wins
);
451 kpinsert(_kf4
, F4
, termcap_wins
);
452 kpinsert(_kf5
, F5
, termcap_wins
);
453 kpinsert(_kf6
, F6
, termcap_wins
);
454 kpinsert(_kf7
, F7
, termcap_wins
);
455 kpinsert(_kf8
, F8
, termcap_wins
);
456 kpinsert(_kf9
, F9
, termcap_wins
);
457 kpinsert(_kf10
, F10
, termcap_wins
);
458 kpinsert(_kf11
, F11
, termcap_wins
);
459 kpinsert(_kf12
, F12
, termcap_wins
);
462 * Add default keypad sequences to the trie.
463 * Since these come after the termcap/terminfo escape sequences above,
464 * the termcap/info sequences will override any conflicting default
465 * escape sequences defined here.
466 * So, with TERMCAP_WINS, some of the default sequences will be missing.
467 * This means that you'd better get all of your termcap/terminfo entries
468 * correct if you define TERMCAP_WINS.
471 setup_dflt_esc_seq();
485 * determine the terminal's communication speed and decide
486 * if we need to do optimization ...
489 term_capabilities
|= TT_OPTIMIZE
;
496 ttgetwinsz(&row
, &col
);
497 term
.t_nrow
= (short) row
;
498 term
.t_ncol
= (short) col
;
500 if(_cleartoeoln
!= NULL
) /* able to use clear to EOL? */
501 term_capabilities
|= TT_EOLEXIST
;
503 term_capabilities
&= ~TT_EOLEXIST
;
505 if(_setinverse
!= NULL
)
506 term_capabilities
|= TT_REVEXIST
;
508 term_capabilities
&= ~TT_REVEXIST
;
510 if(_deletechar
== NULL
&& (_startdelete
== NULL
|| _enddelete
== NULL
))
511 term_capabilities
&= ~TT_DELCHAR
;
513 if(_insertchar
== NULL
&& (_startinsert
== NULL
|| _endinsert
== NULL
))
514 term_capabilities
&= ~TT_INSCHAR
;
516 if((_scrollregion
== NULL
|| _scrolldown
== NULL
|| _scrollup
== NULL
)
517 && (_deleteline
== NULL
|| _insertline
== NULL
))
518 term_capabilities
&= ~TT_SCROLLEXIST
;
520 if(_clearscreen
== NULL
|| _moveto
== NULL
|| _up
== NULL
){
522 puts("Incomplete terminfo entry\n");
529 if(_termcap_init
&& !Pmaster
) {
530 putpad(_termcap_init
); /* any init terminfo requires */
532 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0)) ;
536 * Initialize UW-modified NCSA telnet to use its functionkeys
538 if((gmode
& MDFKEY
) && Pmaster
== NULL
)
551 puts("\033[99l"); /* reset UW-NCSA telnet keys */
553 if(_termcap_end
) /* any clean up terminfo requires */
554 putpad(_termcap_end
);
565 * tinfoinsert - insert a character at the current character position.
566 * _insertchar takes precedence.
571 if(_insertchar
!= NULL
){
576 putpad(_startinsert
);
584 * tinfodelete - delete a character at the current character position.
589 if(_startdelete
== NULL
&& _enddelete
== NULL
)
592 putpad(_startdelete
);
600 * o_scrolldown() - open a line at the given row position.
601 * use either region scrolling or deleteline/insertline
602 * to open a new line.
605 o_scrolldown(int row
, int n
)
609 if(_scrollregion
!= NULL
){
610 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
612 for(i
= 0; i
< n
; i
++)
613 putpad((_scrollup
!= NULL
&& *_scrollup
!= '\0') ? _scrollup
: "\n" );
614 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
619 * this code causes a jiggly motion of the keymenu when scrolling
621 for(i
= 0; i
< n
; i
++){
622 tinfomove(term
.t_nrow
- (term
.t_mrow
+1), 0);
629 * this code causes a sweeping motion up and down the display
631 tinfomove(term
.t_nrow
- term
.t_mrow
- n
, 0);
632 for(i
= 0; i
< n
; i
++)
635 for(i
= 0; i
< n
; i
++)
646 * o_scrollup() - open a line at the given row position.
647 * use either region scrolling or deleteline/insertline
648 * to open a new line.
651 o_scrollup(int row
, int n
)
655 if(_scrollregion
!= NULL
){
656 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
657 /* setting scrolling region moves cursor to home */
658 tinfomove(term
.t_nrow
-(term
.t_mrow
+1), 0);
659 for(i
= 0;i
< n
; i
++)
660 putpad((_scrolldown
== NULL
|| _scrolldown
[0] == '\0') ? "\n"
662 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
666 for(i
= 0; i
< n
; i
++){
669 tinfomove(term
.t_nrow
- (term
.t_mrow
+1), 0);
675 for(i
= 0; i
< n
; i
++)
677 tinfomove(term
.t_nrow
- term
.t_mrow
- n
, 0);
678 for(i
= 0;i
< n
; i
++)
690 * o_insert - use terminfo to optimized character insert
691 * returns: true if it optimized output, false otherwise
696 if(term_capabilities
& TT_INSCHAR
){
698 return(1); /* no problems! */
701 return(0); /* can't do it. */
706 * o_delete - use terminfo to optimized character insert
707 * returns true if it optimized output, false otherwise
712 if(term_capabilities
& TT_DELCHAR
){
714 return(1); /* deleted, no problem! */
717 return(0); /* no dice. */
722 tinfomove(int row
, int col
)
724 putpad(tgoto(_moveto
, col
, row
));
734 int c
, starting_col
, starting_line
;
738 * If the terminal doesn't have back color erase, then we have to
739 * erase manually to preserve the background color.
741 if(pico_usingcolor() && (!_bce
|| !_cleartoeoln
)){
742 extern int ttcol
, ttrow
;
744 starting_col
= ttcol
;
745 starting_line
= ttrow
;
746 last_bg_color
= pico_get_last_bg_color();
747 pico_set_nbg_color();
748 for(c
= ttcol
; c
< term
.t_ncol
; c
++)
751 tinfomove(starting_line
, starting_col
);
753 pico_set_bg_color(last_bg_color
);
757 else if(_cleartoeoln
)
758 putpad(_cleartoeoln
);
768 int i
, starting_col
, starting_row
;
771 * If the terminal doesn't have back color erase, then we have to
772 * erase manually to preserve the background color.
774 if(pico_usingcolor() && (!_bce
|| !_cleartoeos
)){
775 extern int ttcol
, ttrow
;
777 starting_col
= ttcol
;
778 starting_row
= ttrow
;
779 tinfoeeol(); /* rest of this line */
780 for(i
= ttrow
+1; i
<= term
.t_nrow
; i
++){ /* the remaining lines */
785 tinfomove(starting_row
, starting_col
);
796 tinforev(int state
) /* change reverse video status */
797 { /* FALSE = normal video, TRUE = rev video */
810 if(_xhp
&& _clearinverse
)
811 putpad(_clearinverse
);
830 tputs(str
, 1, putchar
);
836 * termcap-based terminal i/o and control routines
840 /* internal prototypes */
841 static int tcapmove(int, int);
842 static int tcapeeol(void);
843 static int tcapeeop(void);
844 static int tcapbeep(void);
845 static int tcaprev(int);
846 static int tcaperi(void);
847 static int tcapopen(void);
848 static int tcapterminalinfo(int);
849 static int tcapclose(void);
850 static void setup_dflt_esc_seq(void);
851 static void tcapinsert(UCS
);
852 static void tcapdelete(void);
855 extern char *tgoto(char *, int, int);
858 * This number used to be 315. No doubt there was a reason for that but we
859 * don't know what it was. It's a bit of a hassle to make it dynamic, and most
860 * modern systems seem to be using terminfo, so we'll just change it to 800.
861 * We weren't stopping on overflow before, so we'll do that, too.
864 char tcapbuf
[TCAPSLEN
];
865 int _tlines
, _tcolumns
;
866 char *_clearscreen
, *_moveto
, *_up
, *_down
, *_right
, *_left
,
867 *_setinverse
, *_clearinverse
,
868 *_setunderline
, *_clearunderline
,
869 *_setbold
, *_clearallattr
, /* there is no clear only bold! */
870 *_cleartoeoln
, *_cleartoeos
,
871 *_deleteline
, /* delete line */
872 *_insertline
, /* insert line */
873 *_scrollregion
, /* define a scrolling region, vt100 */
874 *_insertchar
, /* insert character, preferable to : */
875 *_startinsert
, /* set insert mode and, */
876 *_endinsert
, /* end insert mode */
877 *_deletechar
, /* delete character */
878 *_startdelete
, /* set delete mode and, */
879 *_enddelete
, /* end delete mode */
880 *_scrolldown
, /* scroll down */
881 *_scrollup
, /* scroll up */
882 *_termcap_init
, /* string to start termcap */
883 *_termcap_end
, /* string to end termcap */
884 *_op
, *_oc
, *_setaf
, *_setab
, *_setf
, *_setb
, *_scp
;
885 int _colors
, _pairs
, _bce
, _xhp
;
909 * Add default keypad sequences to the trie.
912 setup_dflt_esc_seq(void)
915 * this is sort of a hack, but it allows us to use
916 * the function keys on pc's running telnet
920 * UW-NDC/UCS vt10[02] application mode.
922 kpinsert("\033OP", F1
, 1);
923 kpinsert("\033OQ", F2
, 1);
924 kpinsert("\033OR", F3
, 1);
925 kpinsert("\033OS", F4
, 1);
926 kpinsert("\033Op", F5
, 1);
927 kpinsert("\033Oq", F6
, 1);
928 kpinsert("\033Or", F7
, 1);
929 kpinsert("\033Os", F8
, 1);
930 kpinsert("\033Ot", F9
, 1);
931 kpinsert("\033Ou", F10
, 1);
932 kpinsert("\033Ov", F11
, 1);
933 kpinsert("\033Ow", F12
, 1);
936 * DEC vt100, ANSI and cursor key mode.
938 kpinsert("\033OA", KEY_UP
, 1);
939 kpinsert("\033OB", KEY_DOWN
, 1);
940 kpinsert("\033OC", KEY_RIGHT
, 1);
941 kpinsert("\033OD", KEY_LEFT
, 1);
944 * special keypad functions
946 kpinsert("\033[4J", KEY_PGUP
, 1);
947 kpinsert("\033[3J", KEY_PGDN
, 1);
948 kpinsert("\033[2J", KEY_HOME
, 1);
949 kpinsert("\033[N", KEY_END
, 1);
954 kpinsert("\033[5~", KEY_PGUP
, 1);
955 kpinsert("\033[6~", KEY_PGDN
, 1);
956 kpinsert("\033[1~", KEY_HOME
, 1);
957 kpinsert("\033[4~", KEY_END
, 1);
960 * konsole, XTerm (XFree 4.x.x) keyboard setting
962 kpinsert("\033[H", KEY_HOME
, 1);
963 kpinsert("\033[F", KEY_END
, 1);
966 * gnome-terminal 2.6.0, don't know why it
969 kpinsert("\033OH", KEY_HOME
, 1);
970 kpinsert("\033OF", KEY_END
, 1);
973 * "\033[2~" was common for KEY_HOME in a quick survey
974 * of terminals (though typically the Insert key).
975 * Teraterm 2.33 sends the following escape sequences,
976 * which is quite incompatible with everything
978 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
980 * The best thing to do would be to fix TeraTerm
981 * keymappings or to tweak terminfo.
987 kpinsert("\033[=a", F1
, 1);
988 kpinsert("\033[=b", F2
, 1);
989 kpinsert("\033[=c", F3
, 1);
990 kpinsert("\033[=d", F4
, 1);
991 kpinsert("\033[=e", F5
, 1);
992 kpinsert("\033[=f", F6
, 1);
993 kpinsert("\033[=g", F7
, 1);
994 kpinsert("\033[=h", F8
, 1);
995 kpinsert("\033[=i", F9
, 1);
996 kpinsert("\033[=j", F10
, 1);
997 kpinsert("\033[=k", F11
, 1);
998 kpinsert("\033[=l", F12
, 1);
1001 * DEC vt100, ANSI and cursor key mode reset.
1003 kpinsert("\033[A", KEY_UP
, 1);
1004 kpinsert("\033[B", KEY_DOWN
, 1);
1005 kpinsert("\033[C", KEY_RIGHT
, 1);
1006 kpinsert("\033[D", KEY_LEFT
, 1);
1011 kpinsert("\033A", KEY_UP
, 1);
1012 kpinsert("\033B", KEY_DOWN
, 1);
1013 kpinsert("\033C", KEY_RIGHT
, 1);
1014 kpinsert("\033D", KEY_LEFT
, 1);
1017 * DEC vt52 application keys, and some Zenith 19.
1019 kpinsert("\033?r", KEY_DOWN
, 1);
1020 kpinsert("\033?t", KEY_LEFT
, 1);
1021 kpinsert("\033?v", KEY_RIGHT
, 1);
1022 kpinsert("\033?x", KEY_UP
, 1);
1025 * Some Ctrl-Arrow keys
1027 kpinsert("\033[5A", CTRL_KEY_UP
, 1);
1028 kpinsert("\033[5B", CTRL_KEY_DOWN
, 1);
1029 kpinsert("\033[5C", CTRL_KEY_RIGHT
, 1);
1030 kpinsert("\033[5D", CTRL_KEY_LEFT
, 1);
1032 kpinsert("\033[1;5A", CTRL_KEY_UP
, 1);
1033 kpinsert("\033[1;5B", CTRL_KEY_DOWN
, 1);
1034 kpinsert("\033[1;5C", CTRL_KEY_RIGHT
, 1);
1035 kpinsert("\033[1;5D", CTRL_KEY_LEFT
, 1);
1038 * Map some shift+up/down/left/right to their shiftless counterparts
1040 kpinsert("\033[1;2A", KEY_UP
, 1);
1041 kpinsert("\033[1;2B", KEY_DOWN
, 1);
1042 kpinsert("\033[1;2C", KEY_RIGHT
, 1);
1043 kpinsert("\033[1;2D", KEY_LEFT
, 1);
1044 kpinsert("\033[a", KEY_UP
, 1);
1045 kpinsert("\033[b", KEY_DOWN
, 1);
1046 kpinsert("\033[c", KEY_RIGHT
, 1);
1047 kpinsert("\033[d", KEY_LEFT
, 1);
1050 * Sun Console sequences.
1052 kpinsert("\033[1", KEY_SWALLOW_Z
, 1);
1053 kpinsert("\033[215", KEY_SWAL_UP
, 1);
1054 kpinsert("\033[217", KEY_SWAL_LEFT
, 1);
1055 kpinsert("\033[219", KEY_SWAL_RIGHT
, 1);
1056 kpinsert("\033[221", KEY_SWAL_DOWN
, 1);
1059 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
1061 kpinsert("\033_", KEY_KERMIT
, 1);
1064 * Fake a control character.
1066 kpinsert("\033\033", KEY_DOUBLE_ESC
, 1);
1071 * Read termcap and set some global variables. Initialize input trie to
1072 * decode escape sequences.
1075 tcapterminalinfo(int termcap_wins
)
1077 char *p
, *tgetstr();
1082 char *_ku
, *_kd
, *_kl
, *_kr
,
1083 *_kppu
, *_kppd
, *_kphome
, *_kpend
, *_kpdel
,
1084 *_kf1
, *_kf2
, *_kf3
, *_kf4
, *_kf5
, *_kf6
,
1085 *_kf7
, *_kf8
, *_kf9
, *_kf10
, *_kf11
, *_kf12
;
1087 if (!(tv_stype
= getenv("TERM")) || !strncpy(term_name
, tv_stype
, sizeof(term_name
))){
1092 puts("Environment variable TERM not defined!");
1097 term_name
[sizeof(term_name
)-1] = '\0';
1099 if((err
= tgetent(tcbuf
, tv_stype
)) != 1){
1104 snprintf(err_str
, sizeof(err_str
), "Unknown terminal type %s!", tv_stype
);
1112 _clearscreen
= tgetstr("cl", &p
);
1113 _moveto
= tgetstr("cm", &p
);
1114 _up
= tgetstr("up", &p
);
1115 _down
= tgetstr("do", &p
);
1116 _right
= tgetstr("nd", &p
);
1117 _left
= tgetstr("bs", &p
);
1118 _setinverse
= tgetstr("so", &p
);
1119 _clearinverse
= tgetstr("se", &p
);
1120 _setunderline
= tgetstr("us", &p
);
1121 _clearunderline
= tgetstr("ue", &p
);
1122 _setbold
= tgetstr("md", &p
);
1123 _clearallattr
= tgetstr("me", &p
);
1124 _cleartoeoln
= tgetstr("ce", &p
);
1125 _cleartoeos
= tgetstr("cd", &p
);
1126 _deletechar
= tgetstr("dc", &p
);
1127 _insertchar
= tgetstr("ic", &p
);
1128 _startinsert
= tgetstr("im", &p
);
1129 _endinsert
= tgetstr("ei", &p
);
1130 _deleteline
= tgetstr("dl", &p
);
1131 _insertline
= tgetstr("al", &p
);
1132 _scrollregion
= tgetstr("cs", &p
);
1133 _scrolldown
= tgetstr("sf", &p
);
1134 _scrollup
= tgetstr("sr", &p
);
1135 _termcap_init
= tgetstr("ti", &p
);
1136 _termcap_end
= tgetstr("te", &p
);
1137 _startdelete
= tgetstr("dm", &p
);
1138 _enddelete
= tgetstr("ed", &p
);
1139 _ku
= tgetstr("ku", &p
);
1140 _kd
= tgetstr("kd", &p
);
1141 _kl
= tgetstr("kl", &p
);
1142 _kr
= tgetstr("kr", &p
);
1143 _kppu
= tgetstr("kP", &p
);
1144 _kppd
= tgetstr("kN", &p
);
1145 _kphome
= tgetstr("kh", &p
);
1146 _kpend
= tgetstr("kH", &p
);
1147 _kpdel
= tgetstr("kD", &p
);
1148 _kf1
= tgetstr("k1", &p
);
1149 _kf2
= tgetstr("k2", &p
);
1150 _kf3
= tgetstr("k3", &p
);
1151 _kf4
= tgetstr("k4", &p
);
1152 _kf5
= tgetstr("k5", &p
);
1153 _kf6
= tgetstr("k6", &p
);
1154 _kf7
= tgetstr("k7", &p
);
1155 _kf8
= tgetstr("k8", &p
);
1156 _kf9
= tgetstr("k9", &p
);
1157 if((_kf10
= tgetstr("k;", &p
)) == NULL
)
1158 _kf10
= tgetstr("k0", &p
);
1159 _kf11
= tgetstr("F1", &p
);
1160 _kf12
= tgetstr("F2", &p
);
1162 _colors
= tgetnum("Co");
1163 _pairs
= tgetnum("pa");
1164 _setaf
= tgetstr("AF", &p
);
1165 _setab
= tgetstr("AB", &p
);
1166 _setf
= tgetstr("Sf", &p
);
1167 _setb
= tgetstr("Sb", &p
);
1168 _scp
= tgetstr("sp", &p
);
1169 _op
= tgetstr("op", &p
);
1170 _oc
= tgetstr("oc", &p
);
1171 _bce
= tgetflag("ut");
1172 _xhp
= tgetflag("xs");
1174 if (p
>= &tcapbuf
[TCAPSLEN
]){
1175 puts("Terminal description too big!\n");
1182 _tlines
= tgetnum("li");
1187 /* tgetnum failed, try $LINES */
1188 er
= getenv("LINES");
1189 if(er
&& (rr
= atoi(er
)) > 0)
1193 _tcolumns
= tgetnum("co");
1194 if(_tcolumns
== -1){
1198 /* tgetnum failed, try $COLUMNS */
1199 ec
= getenv("COLUMNS");
1200 if(ec
&& (cc
= atoi(ec
)) > 0)
1205 * Add default keypad sequences to the trie.
1206 * Since these come first, they will override any conflicting termcap
1207 * or terminfo escape sequences defined below. An escape sequence is
1208 * considered conflicting if one is a prefix of the other.
1209 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
1210 * escape sequences that don't work, because they conflict with default
1211 * sequences defined here.
1214 setup_dflt_esc_seq();
1217 * add termcap/info escape sequences to the trie...
1220 if(_ku
!= NULL
&& _kd
!= NULL
&& _kl
!= NULL
&& _kr
!= NULL
){
1221 kpinsert(_ku
, KEY_UP
, termcap_wins
);
1222 kpinsert(_kd
, KEY_DOWN
, termcap_wins
);
1223 kpinsert(_kl
, KEY_LEFT
, termcap_wins
);
1224 kpinsert(_kr
, KEY_RIGHT
, termcap_wins
);
1227 if(_kppu
!= NULL
&& _kppd
!= NULL
){
1228 kpinsert(_kppu
, KEY_PGUP
, termcap_wins
);
1229 kpinsert(_kppd
, KEY_PGDN
, termcap_wins
);
1232 kpinsert(_kphome
, KEY_HOME
, termcap_wins
);
1233 kpinsert(_kpend
, KEY_END
, termcap_wins
);
1234 kpinsert(_kpdel
, KEY_DEL
, termcap_wins
);
1236 kpinsert(_kf1
, F1
, termcap_wins
);
1237 kpinsert(_kf2
, F2
, termcap_wins
);
1238 kpinsert(_kf3
, F3
, termcap_wins
);
1239 kpinsert(_kf4
, F4
, termcap_wins
);
1240 kpinsert(_kf5
, F5
, termcap_wins
);
1241 kpinsert(_kf6
, F6
, termcap_wins
);
1242 kpinsert(_kf7
, F7
, termcap_wins
);
1243 kpinsert(_kf8
, F8
, termcap_wins
);
1244 kpinsert(_kf9
, F9
, termcap_wins
);
1245 kpinsert(_kf10
, F10
, termcap_wins
);
1246 kpinsert(_kf11
, F11
, termcap_wins
);
1247 kpinsert(_kf12
, F12
, termcap_wins
);
1250 * Add default keypad sequences to the trie.
1251 * Since these come after the termcap/terminfo escape sequences above,
1252 * the termcap/info sequences will override any conflicting default
1253 * escape sequences defined here.
1254 * So, with TERMCAP_WINS, some of the default sequences will be missing.
1255 * This means that you'd better get all of your termcap/terminfo entries
1256 * correct if you define TERMCAP_WINS.
1259 setup_dflt_esc_seq();
1273 * determine the terminal's communication speed and decide
1274 * if we need to do optimization ...
1277 term_capabilities
|= TT_OPTIMIZE
;
1284 ttgetwinsz(&row
, &col
);
1285 term
.t_nrow
= (short) row
;
1286 term
.t_ncol
= (short) col
;
1288 if(_cleartoeoln
!= NULL
) /* able to use clear to EOL? */
1289 term_capabilities
|= TT_EOLEXIST
;
1291 term_capabilities
&= ~TT_EOLEXIST
;
1293 if(_setinverse
!= NULL
)
1294 term_capabilities
|= TT_REVEXIST
;
1296 term_capabilities
&= ~TT_REVEXIST
;
1298 if(_deletechar
== NULL
&& (_startdelete
== NULL
|| _enddelete
== NULL
))
1299 term_capabilities
&= ~TT_DELCHAR
;
1301 if(_insertchar
== NULL
&& (_startinsert
== NULL
|| _endinsert
== NULL
))
1302 term_capabilities
&= ~TT_INSCHAR
;
1304 if((_scrollregion
== NULL
|| _scrolldown
== NULL
|| _scrollup
== NULL
)
1305 && (_deleteline
== NULL
|| _insertline
== NULL
))
1306 term_capabilities
&= ~TT_SCROLLEXIST
;
1308 if(_clearscreen
== NULL
|| _moveto
== NULL
|| _up
== NULL
){
1309 if(Pmaster
== NULL
){
1310 puts("Incomplete termcap entry\n");
1317 if(_termcap_init
&& !Pmaster
) {
1318 putpad(_termcap_init
); /* any init termcap requires */
1320 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0)) ;
1324 * Initialize UW-modified NCSA telnet to use it's functionkeys
1326 if(gmode
&MDFKEY
&& Pmaster
== NULL
)
1329 /* return ignored */
1339 puts("\033[99l"); /* reset UW-NCSA telnet keys */
1341 if(_termcap_end
) /* any cleanup termcap requires */
1342 putpad(_termcap_end
);
1347 /* return ignored */
1354 * tcapinsert - insert a character at the current character position.
1355 * _insertchar takes precedence.
1360 if(_insertchar
!= NULL
){
1361 putpad(_insertchar
);
1365 putpad(_startinsert
);
1373 * tcapdelete - delete a character at the current character position.
1378 if(_startdelete
== NULL
&& _enddelete
== NULL
)
1379 putpad(_deletechar
);
1381 putpad(_startdelete
);
1382 putpad(_deletechar
);
1389 * o_scrolldown - open a line at the given row position.
1390 * use either region scrolling or deleteline/insertline
1391 * to open a new line.
1394 o_scrolldown(int row
, int n
)
1398 if(_scrollregion
!= NULL
){
1399 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
1401 for(i
= 0; i
< n
; i
++)
1402 putpad( (_scrollup
!= NULL
&& *_scrollup
!= '\0')
1403 ? _scrollup
: "\n" );
1404 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
1409 * this code causes a jiggly motion of the keymenu when scrolling
1411 for(i
= 0; i
< n
; i
++){
1412 tcapmove(term
.t_nrow
- (term
.t_mrow
+1), 0);
1413 putpad(_deleteline
);
1415 putpad(_insertline
);
1417 #ifdef NOWIGGLYLINES
1419 * this code causes a sweeping motion up and down the display
1421 tcapmove(term
.t_nrow
- term
.t_mrow
- n
, 0);
1422 for(i
= 0; i
< n
; i
++)
1423 putpad(_deleteline
);
1425 for(i
= 0; i
< n
; i
++)
1426 putpad(_insertline
);
1430 /* return ignored */
1436 * o_scrollup - open a line at the given row position.
1437 * use either region scrolling or deleteline/insertline
1438 * to open a new line.
1441 o_scrollup(int row
, int n
)
1445 if(_scrollregion
!= NULL
){
1446 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
1447 /* setting scrolling region moves cursor to home */
1448 tcapmove(term
.t_nrow
-(term
.t_mrow
+1), 0);
1449 for(i
= 0;i
< n
; i
++)
1450 putpad((_scrolldown
== NULL
|| _scrolldown
[0] == '\0')
1451 ? "\n" : _scrolldown
);
1452 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
1456 for(i
= 0; i
< n
; i
++){
1458 putpad(_deleteline
);
1459 tcapmove(term
.t_nrow
- (term
.t_mrow
+1), 0);
1460 putpad(_insertline
);
1462 #ifdef NOWIGGLYLINES
1463 /* see note above */
1465 for(i
= 0; i
< n
; i
++)
1466 putpad(_deleteline
);
1467 tcapmove(term
.t_nrow
- term
.t_mrow
- n
, 0);
1468 for(i
= 0;i
< n
; i
++)
1469 putpad(_insertline
);
1473 /* return ignored */
1479 * o_insert - use termcap info to optimized character insert
1480 * returns: true if it optimized output, false otherwise
1485 if(term_capabilities
& TT_INSCHAR
){
1487 return(1); /* no problems! */
1490 return(0); /* can't do it. */
1495 * o_delete - use termcap info to optimized character insert
1496 * returns true if it optimized output, false otherwise
1501 if(term_capabilities
& TT_DELCHAR
){
1503 return(1); /* deleted, no problem! */
1506 return(0); /* no dice. */
1511 tcapmove(int row
, int col
)
1513 putpad(tgoto(_moveto
, col
, row
));
1515 /* return ignored */
1523 int c
, starting_col
, starting_line
;
1524 char *last_bg_color
;
1527 * If the terminal doesn't have back color erase, then we have to
1528 * erase manually to preserve the background color.
1530 if(pico_usingcolor() && (!_bce
|| !_cleartoeoln
)){
1531 extern int ttcol
, ttrow
;
1533 starting_col
= ttcol
;
1534 starting_line
= ttrow
;
1535 last_bg_color
= pico_get_last_bg_color();
1536 pico_set_nbg_color();
1537 for(c
= ttcol
; c
< term
.t_ncol
; c
++)
1540 tcapmove(starting_line
, starting_col
);
1542 pico_set_bg_color(last_bg_color
);
1543 free(last_bg_color
);
1546 else if(_cleartoeoln
)
1547 putpad(_cleartoeoln
);
1549 /* return ignored */
1557 int i
, starting_col
, starting_row
;
1560 * If the terminal doesn't have back color erase, then we have to
1561 * erase manually to preserve the background color.
1563 if(pico_usingcolor() && (!_bce
|| !_cleartoeos
)){
1564 extern int ttcol
, ttrow
;
1566 starting_col
= ttcol
;
1567 starting_row
= ttrow
;
1568 tcapeeol(); /* rest of this line */
1569 for(i
= ttrow
+1; i
<= term
.t_nrow
; i
++){ /* the remaining lines */
1574 tcapmove(starting_row
, starting_col
);
1576 else if(_cleartoeos
)
1577 putpad(_cleartoeos
);
1579 /* return ignored */
1587 if(_xhp
&& _clearinverse
)
1588 putpad(_clearinverse
);
1595 tcaprev(int state
) /* change reverse video status */
1596 { /* FALSE = normal video, TRUE = reverse video */
1611 /* return ignored */
1619 tputs(str
, 1, putchar
);
1622 #else /* HARD_CODED_ANSI_TERMINAL */
1625 * ANSI-specific terminal i/o and control routines
1629 #define BEL 0x07 /* BEL character. */
1630 #define ESC 0x1B /* ESC character. */
1633 extern int ttflush();
1635 extern int ansimove(int, int);
1636 extern int ansieeol(void);
1637 extern int ansieeop(void);
1638 extern int ansibeep(void);
1639 extern int ansiparm(int);
1640 extern int ansiopen(void);
1641 extern int ansiterminalinfo(int);
1642 extern int ansirev(int);
1645 * Standard terminal interface dispatch table. Most of the fields point into
1648 #if defined(VAX) && !defined(__ALPHA)
1671 ansimove(int row
, int col
)
1698 ansirev(int state
) /* change reverse video state */
1699 { /* TRUE = reverse, FALSE = normal */
1700 static int PrevState
= 0;
1702 if(state
!= PrevState
) {
1706 ttputc(state
? '7': '0');
1726 ttputc((n
%10) + '0');
1731 ansiterminalinfo(int termcap_wins
)
1737 if ((cp
= getenv("TERM")) == NULL
) {
1738 puts("Shell variable TERM not defined!");
1741 if (strcmp(cp
, "vt100") != 0) {
1742 puts("Terminal type not 'vt100'!");
1746 /* revexist = TRUE; dead code? */
1756 #endif /* HARD_CODED_ANSI_TERMINAL */
1757 #else /* _WINDOWS */
1759 /* These are all just noops in Windows */
1768 * o_insert - optimize screen insert of char c
1778 * o_delete - optimized character deletion
1788 #endif /* _WINDOWS */