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-2014 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 tinfoopen(void);
75 static int tinfoterminalinfo(int);
76 static int tinfoclose(void);
77 static void setup_dflt_esc_seq(void);
78 static void tinfoinsert(UCS
);
79 static void tinfodelete(void);
82 extern int tputs(char *, int, int (*)(int));
83 extern char *tgoto(char *, int, int);
84 extern char *tigetstr ();
85 extern int setupterm(char *, int, int *);
86 extern int tigetnum(char *);
87 extern int tigetflag(char *);
90 ** Note: The tgoto calls should really be replaced by tparm calls for
91 ** modern terminfo. tgoto(s, x, y) == tparm(s, y, x).
94 int _tlines
, _tcolumns
;
95 char *_clearscreen
, *_moveto
, *_up
, *_down
, *_right
, *_left
,
96 *_setinverse
, *_clearinverse
,
97 *_setunderline
, *_clearunderline
,
98 *_setbold
, *_clearallattr
, /* there is no clear only bold! */
99 *_cleartoeoln
, *_cleartoeos
,
100 *_deleteline
, /* delete line */
101 *_insertline
, /* insert line */
102 *_scrollregion
, /* define a scrolling region, vt100 */
103 *_insertchar
, /* insert character, preferable to : */
104 *_startinsert
, /* set insert mode and, */
105 *_endinsert
, /* end insert mode */
106 *_deletechar
, /* delete character */
107 *_startdelete
, /* set delete mode and, */
108 *_enddelete
, /* end delete mode */
109 *_scrolldown
, /* scroll down */
110 *_scrollup
, /* scroll up */
111 *_termcap_init
, /* string to start termcap */
112 *_termcap_end
, /* string to end termcap */
113 *_op
, *_oc
, *_setaf
, *_setab
, *_setf
, *_setb
, *_scp
;
114 int _colors
, _pairs
, _bce
;
137 * Add default keypad sequences to the trie.
140 setup_dflt_esc_seq(void)
143 * this is sort of a hack [no kidding], but it allows us to use
144 * the function keys on pc's running telnet
148 * UW-NDC/UCS vt10[02] application mode.
150 kpinsert("\033OP", F1
, 1);
151 kpinsert("\033OQ", F2
, 1);
152 kpinsert("\033OR", F3
, 1);
153 kpinsert("\033OS", F4
, 1);
154 kpinsert("\033Op", F5
, 1);
155 kpinsert("\033Oq", F6
, 1);
156 kpinsert("\033Or", F7
, 1);
157 kpinsert("\033Os", F8
, 1);
158 kpinsert("\033Ot", F9
, 1);
159 kpinsert("\033Ou", F10
, 1);
160 kpinsert("\033Ov", F11
, 1);
161 kpinsert("\033Ow", F12
, 1);
164 * DEC vt100, ANSI and cursor key mode.
166 kpinsert("\033OA", KEY_UP
, 1);
167 kpinsert("\033OB", KEY_DOWN
, 1);
168 kpinsert("\033OC", KEY_RIGHT
, 1);
169 kpinsert("\033OD", KEY_LEFT
, 1);
172 * special keypad functions
174 kpinsert("\033[4J", KEY_PGUP
, 1);
175 kpinsert("\033[3J", KEY_PGDN
, 1);
176 kpinsert("\033[2J", KEY_HOME
, 1);
177 kpinsert("\033[N", KEY_END
, 1);
182 kpinsert("\033[5~", KEY_PGUP
, 1);
183 kpinsert("\033[6~", KEY_PGDN
, 1);
184 kpinsert("\033[1~", KEY_HOME
, 1);
185 kpinsert("\033[4~", KEY_END
, 1);
188 * konsole, XTerm (XFree 4.x.x) keyboard setting
190 kpinsert("\033[H", KEY_HOME
, 1);
191 kpinsert("\033[F", KEY_END
, 1);
194 * gnome-terminal 2.6.0, don't know why it
197 kpinsert("\033OH", KEY_HOME
, 1);
198 kpinsert("\033OF", KEY_END
, 1);
201 * "\033[2~" was common for KEY_HOME in a quick survey
202 * of terminals (though typically the Insert key).
203 * Teraterm 2.33 sends the following escape sequences,
204 * which is quite incompatible with everything
206 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
208 * The best thing to do would be to fix TeraTerm
209 * keymappings or to tweak terminfo.
215 kpinsert("\033[=a", F1
, 1);
216 kpinsert("\033[=b", F2
, 1);
217 kpinsert("\033[=c", F3
, 1);
218 kpinsert("\033[=d", F4
, 1);
219 kpinsert("\033[=e", F5
, 1);
220 kpinsert("\033[=f", F6
, 1);
221 kpinsert("\033[=g", F7
, 1);
222 kpinsert("\033[=h", F8
, 1);
223 kpinsert("\033[=i", F9
, 1);
224 kpinsert("\033[=j", F10
, 1);
225 kpinsert("\033[=k", F11
, 1);
226 kpinsert("\033[=l", F12
, 1);
229 * DEC vt100, ANSI and cursor key mode reset.
231 kpinsert("\033[A", KEY_UP
, 1);
232 kpinsert("\033[B", KEY_DOWN
, 1);
233 kpinsert("\033[C", KEY_RIGHT
, 1);
234 kpinsert("\033[D", KEY_LEFT
, 1);
239 kpinsert("\033A", KEY_UP
, 1);
240 kpinsert("\033B", KEY_DOWN
, 1);
241 kpinsert("\033C", KEY_RIGHT
, 1);
242 kpinsert("\033D", KEY_LEFT
, 1);
245 * DEC vt52 application keys, and some Zenith 19.
247 kpinsert("\033?r", KEY_DOWN
, 1);
248 kpinsert("\033?t", KEY_LEFT
, 1);
249 kpinsert("\033?v", KEY_RIGHT
, 1);
250 kpinsert("\033?x", KEY_UP
, 1);
253 * Some Ctrl-Arrow keys
255 kpinsert("\033[5A", CTRL_KEY_UP
, 1);
256 kpinsert("\033[5B", CTRL_KEY_DOWN
, 1);
257 kpinsert("\033[5C", CTRL_KEY_RIGHT
, 1);
258 kpinsert("\033[5D", CTRL_KEY_LEFT
, 1);
260 kpinsert("\033[1;5A", CTRL_KEY_UP
, 1);
261 kpinsert("\033[1;5B", CTRL_KEY_DOWN
, 1);
262 kpinsert("\033[1;5C", CTRL_KEY_RIGHT
, 1);
263 kpinsert("\033[1;5D", CTRL_KEY_LEFT
, 1);
266 * Map some shift+up/down/left/right to their shiftless counterparts
268 kpinsert("\033[1;2A", KEY_UP
, 1);
269 kpinsert("\033[1;2B", KEY_DOWN
, 1);
270 kpinsert("\033[1;2C", KEY_RIGHT
, 1);
271 kpinsert("\033[1;2D", KEY_LEFT
, 1);
272 kpinsert("\033[a", KEY_UP
, 1);
273 kpinsert("\033[b", KEY_DOWN
, 1);
274 kpinsert("\033[c", KEY_RIGHT
, 1);
275 kpinsert("\033[d", KEY_LEFT
, 1);
278 * Sun Console sequences.
280 kpinsert("\033[1", KEY_SWALLOW_Z
, 1);
281 kpinsert("\033[215", KEY_SWAL_UP
, 1);
282 kpinsert("\033[217", KEY_SWAL_LEFT
, 1);
283 kpinsert("\033[219", KEY_SWAL_RIGHT
, 1);
284 kpinsert("\033[221", KEY_SWAL_DOWN
, 1);
287 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
289 kpinsert("\033_", KEY_KERMIT
, 1);
292 * Fake a control character.
294 kpinsert("\033\033", KEY_DOUBLE_ESC
, 1);
299 tinfoterminalinfo(int termcap_wins
)
301 char *_ku
, *_kd
, *_kl
, *_kr
,
302 *_kppu
, *_kppd
, *_kphome
, *_kpend
, *_kpdel
,
303 *_kf1
, *_kf2
, *_kf3
, *_kf4
, *_kf5
, *_kf6
,
304 *_kf7
, *_kf8
, *_kf9
, *_kf10
, *_kf11
, *_kf12
;
309 * setupterm() automatically retrieves the value
310 * of the TERM variable.
313 ttnm
= getenv("TERM");
317 strncpy(term_name
, ttnm
, sizeof(term_name
));
318 term_name
[sizeof(term_name
)-1] = '\0';
319 setupterm ((char *) 0, 1, &err
);
320 if (err
!= 1) return(err
-2);
324 * setupterm() issues a message and exits, if the
325 * terminfo data base is gone or the term type is
326 * unknown, if arg2 is 0.
328 setupterm ((char *) 0, 1, (int *) 0);
331 _clearscreen
= tigetstr("clear");
332 _moveto
= tigetstr("cup");
333 _up
= tigetstr("cuu1");
334 _down
= tigetstr("cud1");
335 _right
= tigetstr("cuf1");
336 _left
= tigetstr("cub1");
337 _setinverse
= tigetstr("smso");
338 _clearinverse
= tigetstr("rmso");
339 _setunderline
= tigetstr("smul");
340 _clearunderline
= tigetstr("rmul");
341 _setbold
= tigetstr("bold");
342 _clearallattr
= tigetstr("sgr0");
343 _cleartoeoln
= tigetstr("el");
344 _cleartoeos
= tigetstr("ed");
345 _deletechar
= tigetstr("dch1");
346 _insertchar
= tigetstr("ich1");
347 _startinsert
= tigetstr("smir");
348 _endinsert
= tigetstr("rmir");
349 _deleteline
= tigetstr("dl1");
350 _insertline
= tigetstr("il1");
351 _scrollregion
= tigetstr("csr");
352 _scrolldown
= tigetstr("ind");
353 _scrollup
= tigetstr("ri");
354 _termcap_init
= tigetstr("smcup");
355 _termcap_end
= tigetstr("rmcup");
356 _startdelete
= tigetstr("smdc");
357 _enddelete
= tigetstr("rmdc");
358 _ku
= tigetstr("kcuu1");
359 _kd
= tigetstr("kcud1");
360 _kl
= tigetstr("kcub1");
361 _kr
= tigetstr("kcuf1");
362 _kppu
= tigetstr("kpp");
363 _kppd
= tigetstr("knp");
364 _kphome
= tigetstr("khome");
365 _kpend
= tigetstr("kend");
366 _kpdel
= tigetstr("kdch1");
367 _kf1
= tigetstr("kf1");
368 _kf2
= tigetstr("kf2");
369 _kf3
= tigetstr("kf3");
370 _kf4
= tigetstr("kf4");
371 _kf5
= tigetstr("kf5");
372 _kf6
= tigetstr("kf6");
373 _kf7
= tigetstr("kf7");
374 _kf8
= tigetstr("kf8");
375 _kf9
= tigetstr("kf9");
376 _kf10
= tigetstr("kf10");
377 _kf11
= tigetstr("kf11");
378 _kf12
= tigetstr("kf12");
380 _colors
= tigetnum("colors");
381 _pairs
= tigetnum("pairs");
382 _setaf
= tigetstr("setaf");
383 _setab
= tigetstr("setab");
384 _setf
= tigetstr("setf");
385 _setb
= tigetstr("setb");
386 _scp
= tigetstr("scp");
387 _op
= tigetstr("op");
388 _oc
= tigetstr("oc");
389 _bce
= tigetflag("bce");
391 _tlines
= tigetnum("lines");
396 /* tigetnum failed, try $LINES */
397 er
= getenv("LINES");
398 if(er
&& (rr
= atoi(er
)) > 0)
402 _tcolumns
= tigetnum("cols");
407 /* tigetnum failed, try $COLUMNS */
408 ec
= getenv("COLUMNS");
409 if(ec
&& (cc
= atoi(ec
)) > 0)
414 * Add default keypad sequences to the trie.
415 * Since these come first, they will override any conflicting termcap
416 * or terminfo escape sequences defined below. An escape sequence is
417 * considered conflicting if one is a prefix of the other.
418 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
419 * escape sequences that don't work, because they conflict with default
420 * sequences defined here.
423 setup_dflt_esc_seq();
426 * add termcap/info escape sequences to the trie...
429 if(_ku
!= NULL
&& _kd
!= NULL
&& _kl
!= NULL
&& _kr
!= NULL
){
430 kpinsert(_ku
, KEY_UP
, termcap_wins
);
431 kpinsert(_kd
, KEY_DOWN
, termcap_wins
);
432 kpinsert(_kl
, KEY_LEFT
, termcap_wins
);
433 kpinsert(_kr
, KEY_RIGHT
, termcap_wins
);
436 if(_kppu
!= NULL
&& _kppd
!= NULL
){
437 kpinsert(_kppu
, KEY_PGUP
, termcap_wins
);
438 kpinsert(_kppd
, KEY_PGDN
, termcap_wins
);
441 kpinsert(_kphome
, KEY_HOME
, termcap_wins
);
442 kpinsert(_kpend
, KEY_END
, termcap_wins
);
443 kpinsert(_kpdel
, KEY_DEL
, termcap_wins
);
445 kpinsert(_kf1
, F1
, termcap_wins
);
446 kpinsert(_kf2
, F2
, termcap_wins
);
447 kpinsert(_kf3
, F3
, termcap_wins
);
448 kpinsert(_kf4
, F4
, termcap_wins
);
449 kpinsert(_kf5
, F5
, termcap_wins
);
450 kpinsert(_kf6
, F6
, termcap_wins
);
451 kpinsert(_kf7
, F7
, termcap_wins
);
452 kpinsert(_kf8
, F8
, termcap_wins
);
453 kpinsert(_kf9
, F9
, termcap_wins
);
454 kpinsert(_kf10
, F10
, termcap_wins
);
455 kpinsert(_kf11
, F11
, termcap_wins
);
456 kpinsert(_kf12
, F12
, termcap_wins
);
459 * Add default keypad sequences to the trie.
460 * Since these come after the termcap/terminfo escape sequences above,
461 * the termcap/info sequences will override any conflicting default
462 * escape sequences defined here.
463 * So, with TERMCAP_WINS, some of the default sequences will be missing.
464 * This means that you'd better get all of your termcap/terminfo entries
465 * correct if you define TERMCAP_WINS.
468 setup_dflt_esc_seq();
482 * determine the terminal's communication speed and decide
483 * if we need to do optimization ...
486 term_capabilities
|= TT_OPTIMIZE
;
493 ttgetwinsz(&row
, &col
);
494 term
.t_nrow
= (short) row
;
495 term
.t_ncol
= (short) col
;
497 if(_cleartoeoln
!= NULL
) /* able to use clear to EOL? */
498 term_capabilities
|= TT_EOLEXIST
;
500 term_capabilities
&= ~TT_EOLEXIST
;
502 if(_setinverse
!= NULL
)
503 term_capabilities
|= TT_REVEXIST
;
505 term_capabilities
&= ~TT_REVEXIST
;
507 if(_deletechar
== NULL
&& (_startdelete
== NULL
|| _enddelete
== NULL
))
508 term_capabilities
&= ~TT_DELCHAR
;
510 if(_insertchar
== NULL
&& (_startinsert
== NULL
|| _endinsert
== NULL
))
511 term_capabilities
&= ~TT_INSCHAR
;
513 if((_scrollregion
== NULL
|| _scrolldown
== NULL
|| _scrollup
== NULL
)
514 && (_deleteline
== NULL
|| _insertline
== NULL
))
515 term_capabilities
&= ~TT_SCROLLEXIST
;
517 if(_clearscreen
== NULL
|| _moveto
== NULL
|| _up
== NULL
){
519 puts("Incomplete terminfo entry\n");
526 if(_termcap_init
&& !Pmaster
) {
527 putpad(_termcap_init
); /* any init terminfo requires */
529 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0)) ;
533 * Initialize UW-modified NCSA telnet to use its functionkeys
535 if((gmode
& MDFKEY
) && Pmaster
== NULL
)
548 puts("\033[99l"); /* reset UW-NCSA telnet keys */
550 if(_termcap_end
) /* any clean up terminfo requires */
551 putpad(_termcap_end
);
562 * tinfoinsert - insert a character at the current character position.
563 * _insertchar takes precedence.
568 if(_insertchar
!= NULL
){
573 putpad(_startinsert
);
581 * tinfodelete - delete a character at the current character position.
586 if(_startdelete
== NULL
&& _enddelete
== NULL
)
589 putpad(_startdelete
);
597 * o_scrolldown() - open a line at the given row position.
598 * use either region scrolling or deleteline/insertline
599 * to open a new line.
602 o_scrolldown(int row
, int n
)
606 if(_scrollregion
!= NULL
){
607 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
609 for(i
= 0; i
< n
; i
++)
610 putpad((_scrollup
!= NULL
&& *_scrollup
!= '\0') ? _scrollup
: "\n" );
611 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
616 * this code causes a jiggly motion of the keymenu when scrolling
618 for(i
= 0; i
< n
; i
++){
619 tinfomove(term
.t_nrow
- (term
.t_mrow
+1), 0);
626 * this code causes a sweeping motion up and down the display
628 tinfomove(term
.t_nrow
- term
.t_mrow
- n
, 0);
629 for(i
= 0; i
< n
; i
++)
632 for(i
= 0; i
< n
; i
++)
643 * o_scrollup() - open a line at the given row position.
644 * use either region scrolling or deleteline/insertline
645 * to open a new line.
648 o_scrollup(int row
, int n
)
652 if(_scrollregion
!= NULL
){
653 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
654 /* setting scrolling region moves cursor to home */
655 tinfomove(term
.t_nrow
-(term
.t_mrow
+1), 0);
656 for(i
= 0;i
< n
; i
++)
657 putpad((_scrolldown
== NULL
|| _scrolldown
[0] == '\0') ? "\n"
659 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
663 for(i
= 0; i
< n
; i
++){
666 tinfomove(term
.t_nrow
- (term
.t_mrow
+1), 0);
672 for(i
= 0; i
< n
; i
++)
674 tinfomove(term
.t_nrow
- term
.t_mrow
- n
, 0);
675 for(i
= 0;i
< n
; i
++)
687 * o_insert - use terminfo to optimized character insert
688 * returns: true if it optimized output, false otherwise
693 if(term_capabilities
& TT_INSCHAR
){
695 return(1); /* no problems! */
698 return(0); /* can't do it. */
703 * o_delete - use terminfo to optimized character insert
704 * returns true if it optimized output, false otherwise
709 if(term_capabilities
& TT_DELCHAR
){
711 return(1); /* deleted, no problem! */
714 return(0); /* no dice. */
719 tinfomove(int row
, int col
)
721 putpad(tgoto(_moveto
, col
, row
));
731 int c
, starting_col
, starting_line
;
735 * If the terminal doesn't have back color erase, then we have to
736 * erase manually to preserve the background color.
738 if(pico_usingcolor() && (!_bce
|| !_cleartoeoln
)){
739 extern int ttcol
, ttrow
;
741 starting_col
= ttcol
;
742 starting_line
= ttrow
;
743 last_bg_color
= pico_get_last_bg_color();
744 pico_set_nbg_color();
745 for(c
= ttcol
; c
< term
.t_ncol
; c
++)
748 tinfomove(starting_line
, starting_col
);
750 pico_set_bg_color(last_bg_color
);
754 else if(_cleartoeoln
)
755 putpad(_cleartoeoln
);
765 int i
, starting_col
, starting_row
;
768 * If the terminal doesn't have back color erase, then we have to
769 * erase manually to preserve the background color.
771 if(pico_usingcolor() && (!_bce
|| !_cleartoeos
)){
772 extern int ttcol
, ttrow
;
774 starting_col
= ttcol
;
775 starting_row
= ttrow
;
776 tinfoeeol(); /* rest of this line */
777 for(i
= ttrow
+1; i
<= term
.t_nrow
; i
++){ /* the remaining lines */
782 tinfomove(starting_row
, starting_col
);
793 tinforev(int state
) /* change reverse video status */
794 { /* FALSE = normal video, TRUE = rev video */
817 tputs(str
, 1, putchar
);
823 * termcap-based terminal i/o and control routines
827 /* internal prototypes */
828 static int tcapmove(int, int);
829 static int tcapeeol(void);
830 static int tcapeeop(void);
831 static int tcapbeep(void);
832 static int tcaprev(int);
833 static int tcapopen(void);
834 static int tcapterminalinfo(int);
835 static int tcapclose(void);
836 static void setup_dflt_esc_seq(void);
837 static void tcapinsert(UCS
);
838 static void tcapdelete(void);
841 extern char *tgoto(char *, int, int);
844 * This number used to be 315. No doubt there was a reason for that but we
845 * don't know what it was. It's a bit of a hassle to make it dynamic, and most
846 * modern systems seem to be using terminfo, so we'll just change it to 800.
847 * We weren't stopping on overflow before, so we'll do that, too.
850 char tcapbuf
[TCAPSLEN
];
851 int _tlines
, _tcolumns
;
852 char *_clearscreen
, *_moveto
, *_up
, *_down
, *_right
, *_left
,
853 *_setinverse
, *_clearinverse
,
854 *_setunderline
, *_clearunderline
,
855 *_setbold
, *_clearallattr
, /* there is no clear only bold! */
856 *_cleartoeoln
, *_cleartoeos
,
857 *_deleteline
, /* delete line */
858 *_insertline
, /* insert line */
859 *_scrollregion
, /* define a scrolling region, vt100 */
860 *_insertchar
, /* insert character, preferable to : */
861 *_startinsert
, /* set insert mode and, */
862 *_endinsert
, /* end insert mode */
863 *_deletechar
, /* delete character */
864 *_startdelete
, /* set delete mode and, */
865 *_enddelete
, /* end delete mode */
866 *_scrolldown
, /* scroll down */
867 *_scrollup
, /* scroll up */
868 *_termcap_init
, /* string to start termcap */
869 *_termcap_end
, /* string to end termcap */
870 *_op
, *_oc
, *_setaf
, *_setab
, *_setf
, *_setb
, *_scp
;
871 int _colors
, _pairs
, _bce
;
894 * Add default keypad sequences to the trie.
897 setup_dflt_esc_seq(void)
900 * this is sort of a hack, but it allows us to use
901 * the function keys on pc's running telnet
905 * UW-NDC/UCS vt10[02] application mode.
907 kpinsert("\033OP", F1
, 1);
908 kpinsert("\033OQ", F2
, 1);
909 kpinsert("\033OR", F3
, 1);
910 kpinsert("\033OS", F4
, 1);
911 kpinsert("\033Op", F5
, 1);
912 kpinsert("\033Oq", F6
, 1);
913 kpinsert("\033Or", F7
, 1);
914 kpinsert("\033Os", F8
, 1);
915 kpinsert("\033Ot", F9
, 1);
916 kpinsert("\033Ou", F10
, 1);
917 kpinsert("\033Ov", F11
, 1);
918 kpinsert("\033Ow", F12
, 1);
921 * DEC vt100, ANSI and cursor key mode.
923 kpinsert("\033OA", KEY_UP
, 1);
924 kpinsert("\033OB", KEY_DOWN
, 1);
925 kpinsert("\033OC", KEY_RIGHT
, 1);
926 kpinsert("\033OD", KEY_LEFT
, 1);
929 * special keypad functions
931 kpinsert("\033[4J", KEY_PGUP
, 1);
932 kpinsert("\033[3J", KEY_PGDN
, 1);
933 kpinsert("\033[2J", KEY_HOME
, 1);
934 kpinsert("\033[N", KEY_END
, 1);
939 kpinsert("\033[5~", KEY_PGUP
, 1);
940 kpinsert("\033[6~", KEY_PGDN
, 1);
941 kpinsert("\033[1~", KEY_HOME
, 1);
942 kpinsert("\033[4~", KEY_END
, 1);
945 * konsole, XTerm (XFree 4.x.x) keyboard setting
947 kpinsert("\033[H", KEY_HOME
, 1);
948 kpinsert("\033[F", KEY_END
, 1);
951 * gnome-terminal 2.6.0, don't know why it
954 kpinsert("\033OH", KEY_HOME
, 1);
955 kpinsert("\033OF", KEY_END
, 1);
958 * "\033[2~" was common for KEY_HOME in a quick survey
959 * of terminals (though typically the Insert key).
960 * Teraterm 2.33 sends the following escape sequences,
961 * which is quite incompatible with everything
963 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
965 * The best thing to do would be to fix TeraTerm
966 * keymappings or to tweak terminfo.
972 kpinsert("\033[=a", F1
, 1);
973 kpinsert("\033[=b", F2
, 1);
974 kpinsert("\033[=c", F3
, 1);
975 kpinsert("\033[=d", F4
, 1);
976 kpinsert("\033[=e", F5
, 1);
977 kpinsert("\033[=f", F6
, 1);
978 kpinsert("\033[=g", F7
, 1);
979 kpinsert("\033[=h", F8
, 1);
980 kpinsert("\033[=i", F9
, 1);
981 kpinsert("\033[=j", F10
, 1);
982 kpinsert("\033[=k", F11
, 1);
983 kpinsert("\033[=l", F12
, 1);
986 * DEC vt100, ANSI and cursor key mode reset.
988 kpinsert("\033[A", KEY_UP
, 1);
989 kpinsert("\033[B", KEY_DOWN
, 1);
990 kpinsert("\033[C", KEY_RIGHT
, 1);
991 kpinsert("\033[D", KEY_LEFT
, 1);
996 kpinsert("\033A", KEY_UP
, 1);
997 kpinsert("\033B", KEY_DOWN
, 1);
998 kpinsert("\033C", KEY_RIGHT
, 1);
999 kpinsert("\033D", KEY_LEFT
, 1);
1002 * DEC vt52 application keys, and some Zenith 19.
1004 kpinsert("\033?r", KEY_DOWN
, 1);
1005 kpinsert("\033?t", KEY_LEFT
, 1);
1006 kpinsert("\033?v", KEY_RIGHT
, 1);
1007 kpinsert("\033?x", KEY_UP
, 1);
1010 * Some Ctrl-Arrow keys
1012 kpinsert("\033[5A", CTRL_KEY_UP
, 1);
1013 kpinsert("\033[5B", CTRL_KEY_DOWN
, 1);
1014 kpinsert("\033[5C", CTRL_KEY_RIGHT
, 1);
1015 kpinsert("\033[5D", CTRL_KEY_LEFT
, 1);
1017 kpinsert("\033[1;5A", CTRL_KEY_UP
, 1);
1018 kpinsert("\033[1;5B", CTRL_KEY_DOWN
, 1);
1019 kpinsert("\033[1;5C", CTRL_KEY_RIGHT
, 1);
1020 kpinsert("\033[1;5D", CTRL_KEY_LEFT
, 1);
1023 * Map some shift+up/down/left/right to their shiftless counterparts
1025 kpinsert("\033[1;2A", KEY_UP
, 1);
1026 kpinsert("\033[1;2B", KEY_DOWN
, 1);
1027 kpinsert("\033[1;2C", KEY_RIGHT
, 1);
1028 kpinsert("\033[1;2D", KEY_LEFT
, 1);
1029 kpinsert("\033[a", KEY_UP
, 1);
1030 kpinsert("\033[b", KEY_DOWN
, 1);
1031 kpinsert("\033[c", KEY_RIGHT
, 1);
1032 kpinsert("\033[d", KEY_LEFT
, 1);
1035 * Sun Console sequences.
1037 kpinsert("\033[1", KEY_SWALLOW_Z
, 1);
1038 kpinsert("\033[215", KEY_SWAL_UP
, 1);
1039 kpinsert("\033[217", KEY_SWAL_LEFT
, 1);
1040 kpinsert("\033[219", KEY_SWAL_RIGHT
, 1);
1041 kpinsert("\033[221", KEY_SWAL_DOWN
, 1);
1044 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
1046 kpinsert("\033_", KEY_KERMIT
, 1);
1049 * Fake a control character.
1051 kpinsert("\033\033", KEY_DOUBLE_ESC
, 1);
1056 * Read termcap and set some global variables. Initialize input trie to
1057 * decode escape sequences.
1060 tcapterminalinfo(int termcap_wins
)
1062 char *p
, *tgetstr();
1067 char *_ku
, *_kd
, *_kl
, *_kr
,
1068 *_kppu
, *_kppd
, *_kphome
, *_kpend
, *_kpdel
,
1069 *_kf1
, *_kf2
, *_kf3
, *_kf4
, *_kf5
, *_kf6
,
1070 *_kf7
, *_kf8
, *_kf9
, *_kf10
, *_kf11
, *_kf12
;
1072 if (!(tv_stype
= getenv("TERM")) || !strncpy(term_name
, tv_stype
, sizeof(term_name
))){
1077 puts("Environment variable TERM not defined!");
1082 term_name
[sizeof(term_name
)-1] = '\0';
1084 if((err
= tgetent(tcbuf
, tv_stype
)) != 1){
1089 snprintf(err_str
, sizeof(err_str
), "Unknown terminal type %s!", tv_stype
);
1097 _clearscreen
= tgetstr("cl", &p
);
1098 _moveto
= tgetstr("cm", &p
);
1099 _up
= tgetstr("up", &p
);
1100 _down
= tgetstr("do", &p
);
1101 _right
= tgetstr("nd", &p
);
1102 _left
= tgetstr("bs", &p
);
1103 _setinverse
= tgetstr("so", &p
);
1104 _clearinverse
= tgetstr("se", &p
);
1105 _setunderline
= tgetstr("us", &p
);
1106 _clearunderline
= tgetstr("ue", &p
);
1107 _setbold
= tgetstr("md", &p
);
1108 _clearallattr
= tgetstr("me", &p
);
1109 _cleartoeoln
= tgetstr("ce", &p
);
1110 _cleartoeos
= tgetstr("cd", &p
);
1111 _deletechar
= tgetstr("dc", &p
);
1112 _insertchar
= tgetstr("ic", &p
);
1113 _startinsert
= tgetstr("im", &p
);
1114 _endinsert
= tgetstr("ei", &p
);
1115 _deleteline
= tgetstr("dl", &p
);
1116 _insertline
= tgetstr("al", &p
);
1117 _scrollregion
= tgetstr("cs", &p
);
1118 _scrolldown
= tgetstr("sf", &p
);
1119 _scrollup
= tgetstr("sr", &p
);
1120 _termcap_init
= tgetstr("ti", &p
);
1121 _termcap_end
= tgetstr("te", &p
);
1122 _startdelete
= tgetstr("dm", &p
);
1123 _enddelete
= tgetstr("ed", &p
);
1124 _ku
= tgetstr("ku", &p
);
1125 _kd
= tgetstr("kd", &p
);
1126 _kl
= tgetstr("kl", &p
);
1127 _kr
= tgetstr("kr", &p
);
1128 _kppu
= tgetstr("kP", &p
);
1129 _kppd
= tgetstr("kN", &p
);
1130 _kphome
= tgetstr("kh", &p
);
1131 _kpend
= tgetstr("kH", &p
);
1132 _kpdel
= tgetstr("kD", &p
);
1133 _kf1
= tgetstr("k1", &p
);
1134 _kf2
= tgetstr("k2", &p
);
1135 _kf3
= tgetstr("k3", &p
);
1136 _kf4
= tgetstr("k4", &p
);
1137 _kf5
= tgetstr("k5", &p
);
1138 _kf6
= tgetstr("k6", &p
);
1139 _kf7
= tgetstr("k7", &p
);
1140 _kf8
= tgetstr("k8", &p
);
1141 _kf9
= tgetstr("k9", &p
);
1142 if((_kf10
= tgetstr("k;", &p
)) == NULL
)
1143 _kf10
= tgetstr("k0", &p
);
1144 _kf11
= tgetstr("F1", &p
);
1145 _kf12
= tgetstr("F2", &p
);
1147 _colors
= tgetnum("Co");
1148 _pairs
= tgetnum("pa");
1149 _setaf
= tgetstr("AF", &p
);
1150 _setab
= tgetstr("AB", &p
);
1151 _setf
= tgetstr("Sf", &p
);
1152 _setb
= tgetstr("Sb", &p
);
1153 _scp
= tgetstr("sp", &p
);
1154 _op
= tgetstr("op", &p
);
1155 _oc
= tgetstr("oc", &p
);
1156 _bce
= tgetflag("ut");
1158 if (p
>= &tcapbuf
[TCAPSLEN
]){
1159 puts("Terminal description too big!\n");
1166 _tlines
= tgetnum("li");
1171 /* tgetnum failed, try $LINES */
1172 er
= getenv("LINES");
1173 if(er
&& (rr
= atoi(er
)) > 0)
1177 _tcolumns
= tgetnum("co");
1178 if(_tcolumns
== -1){
1182 /* tgetnum failed, try $COLUMNS */
1183 ec
= getenv("COLUMNS");
1184 if(ec
&& (cc
= atoi(ec
)) > 0)
1189 * Add default keypad sequences to the trie.
1190 * Since these come first, they will override any conflicting termcap
1191 * or terminfo escape sequences defined below. An escape sequence is
1192 * considered conflicting if one is a prefix of the other.
1193 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
1194 * escape sequences that don't work, because they conflict with default
1195 * sequences defined here.
1198 setup_dflt_esc_seq();
1201 * add termcap/info escape sequences to the trie...
1204 if(_ku
!= NULL
&& _kd
!= NULL
&& _kl
!= NULL
&& _kr
!= NULL
){
1205 kpinsert(_ku
, KEY_UP
, termcap_wins
);
1206 kpinsert(_kd
, KEY_DOWN
, termcap_wins
);
1207 kpinsert(_kl
, KEY_LEFT
, termcap_wins
);
1208 kpinsert(_kr
, KEY_RIGHT
, termcap_wins
);
1211 if(_kppu
!= NULL
&& _kppd
!= NULL
){
1212 kpinsert(_kppu
, KEY_PGUP
, termcap_wins
);
1213 kpinsert(_kppd
, KEY_PGDN
, termcap_wins
);
1216 kpinsert(_kphome
, KEY_HOME
, termcap_wins
);
1217 kpinsert(_kpend
, KEY_END
, termcap_wins
);
1218 kpinsert(_kpdel
, KEY_DEL
, termcap_wins
);
1220 kpinsert(_kf1
, F1
, termcap_wins
);
1221 kpinsert(_kf2
, F2
, termcap_wins
);
1222 kpinsert(_kf3
, F3
, termcap_wins
);
1223 kpinsert(_kf4
, F4
, termcap_wins
);
1224 kpinsert(_kf5
, F5
, termcap_wins
);
1225 kpinsert(_kf6
, F6
, termcap_wins
);
1226 kpinsert(_kf7
, F7
, termcap_wins
);
1227 kpinsert(_kf8
, F8
, termcap_wins
);
1228 kpinsert(_kf9
, F9
, termcap_wins
);
1229 kpinsert(_kf10
, F10
, termcap_wins
);
1230 kpinsert(_kf11
, F11
, termcap_wins
);
1231 kpinsert(_kf12
, F12
, termcap_wins
);
1234 * Add default keypad sequences to the trie.
1235 * Since these come after the termcap/terminfo escape sequences above,
1236 * the termcap/info sequences will override any conflicting default
1237 * escape sequences defined here.
1238 * So, with TERMCAP_WINS, some of the default sequences will be missing.
1239 * This means that you'd better get all of your termcap/terminfo entries
1240 * correct if you define TERMCAP_WINS.
1243 setup_dflt_esc_seq();
1257 * determine the terminal's communication speed and decide
1258 * if we need to do optimization ...
1261 term_capabilities
|= TT_OPTIMIZE
;
1268 ttgetwinsz(&row
, &col
);
1269 term
.t_nrow
= (short) row
;
1270 term
.t_ncol
= (short) col
;
1272 if(_cleartoeoln
!= NULL
) /* able to use clear to EOL? */
1273 term_capabilities
|= TT_EOLEXIST
;
1275 term_capabilities
&= ~TT_EOLEXIST
;
1277 if(_setinverse
!= NULL
)
1278 term_capabilities
|= TT_REVEXIST
;
1280 term_capabilities
&= ~TT_REVEXIST
;
1282 if(_deletechar
== NULL
&& (_startdelete
== NULL
|| _enddelete
== NULL
))
1283 term_capabilities
&= ~TT_DELCHAR
;
1285 if(_insertchar
== NULL
&& (_startinsert
== NULL
|| _endinsert
== NULL
))
1286 term_capabilities
&= ~TT_INSCHAR
;
1288 if((_scrollregion
== NULL
|| _scrolldown
== NULL
|| _scrollup
== NULL
)
1289 && (_deleteline
== NULL
|| _insertline
== NULL
))
1290 term_capabilities
&= ~TT_SCROLLEXIST
;
1292 if(_clearscreen
== NULL
|| _moveto
== NULL
|| _up
== NULL
){
1293 if(Pmaster
== NULL
){
1294 puts("Incomplete termcap entry\n");
1301 if(_termcap_init
&& !Pmaster
) {
1302 putpad(_termcap_init
); /* any init termcap requires */
1304 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0)) ;
1308 * Initialize UW-modified NCSA telnet to use it's functionkeys
1310 if(gmode
&MDFKEY
&& Pmaster
== NULL
)
1313 /* return ignored */
1323 puts("\033[99l"); /* reset UW-NCSA telnet keys */
1325 if(_termcap_end
) /* any cleanup termcap requires */
1326 putpad(_termcap_end
);
1331 /* return ignored */
1338 * tcapinsert - insert a character at the current character position.
1339 * _insertchar takes precedence.
1344 if(_insertchar
!= NULL
){
1345 putpad(_insertchar
);
1349 putpad(_startinsert
);
1357 * tcapdelete - delete a character at the current character position.
1362 if(_startdelete
== NULL
&& _enddelete
== NULL
)
1363 putpad(_deletechar
);
1365 putpad(_startdelete
);
1366 putpad(_deletechar
);
1373 * o_scrolldown - open a line at the given row position.
1374 * use either region scrolling or deleteline/insertline
1375 * to open a new line.
1378 o_scrolldown(int row
, int n
)
1382 if(_scrollregion
!= NULL
){
1383 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
1385 for(i
= 0; i
< n
; i
++)
1386 putpad( (_scrollup
!= NULL
&& *_scrollup
!= '\0')
1387 ? _scrollup
: "\n" );
1388 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
1393 * this code causes a jiggly motion of the keymenu when scrolling
1395 for(i
= 0; i
< n
; i
++){
1396 tcapmove(term
.t_nrow
- (term
.t_mrow
+1), 0);
1397 putpad(_deleteline
);
1399 putpad(_insertline
);
1401 #ifdef NOWIGGLYLINES
1403 * this code causes a sweeping motion up and down the display
1405 tcapmove(term
.t_nrow
- term
.t_mrow
- n
, 0);
1406 for(i
= 0; i
< n
; i
++)
1407 putpad(_deleteline
);
1409 for(i
= 0; i
< n
; i
++)
1410 putpad(_insertline
);
1414 /* return ignored */
1420 * o_scrollup - open a line at the given row position.
1421 * use either region scrolling or deleteline/insertline
1422 * to open a new line.
1425 o_scrollup(int row
, int n
)
1429 if(_scrollregion
!= NULL
){
1430 putpad(tgoto(_scrollregion
, term
.t_nrow
- (term
.t_mrow
+1), row
));
1431 /* setting scrolling region moves cursor to home */
1432 tcapmove(term
.t_nrow
-(term
.t_mrow
+1), 0);
1433 for(i
= 0;i
< n
; i
++)
1434 putpad((_scrolldown
== NULL
|| _scrolldown
[0] == '\0')
1435 ? "\n" : _scrolldown
);
1436 putpad(tgoto(_scrollregion
, term
.t_nrow
, 0));
1440 for(i
= 0; i
< n
; i
++){
1442 putpad(_deleteline
);
1443 tcapmove(term
.t_nrow
- (term
.t_mrow
+1), 0);
1444 putpad(_insertline
);
1446 #ifdef NOWIGGLYLINES
1447 /* see note above */
1449 for(i
= 0; i
< n
; i
++)
1450 putpad(_deleteline
);
1451 tcapmove(term
.t_nrow
- term
.t_mrow
- n
, 0);
1452 for(i
= 0;i
< n
; i
++)
1453 putpad(_insertline
);
1457 /* return ignored */
1463 * o_insert - use termcap info to optimized character insert
1464 * returns: true if it optimized output, false otherwise
1469 if(term_capabilities
& TT_INSCHAR
){
1471 return(1); /* no problems! */
1474 return(0); /* can't do it. */
1479 * o_delete - use termcap info to optimized character insert
1480 * returns true if it optimized output, false otherwise
1485 if(term_capabilities
& TT_DELCHAR
){
1487 return(1); /* deleted, no problem! */
1490 return(0); /* no dice. */
1495 tcapmove(int row
, int col
)
1497 putpad(tgoto(_moveto
, col
, row
));
1499 /* return ignored */
1507 int c
, starting_col
, starting_line
;
1508 char *last_bg_color
;
1511 * If the terminal doesn't have back color erase, then we have to
1512 * erase manually to preserve the background color.
1514 if(pico_usingcolor() && (!_bce
|| !_cleartoeoln
)){
1515 extern int ttcol
, ttrow
;
1517 starting_col
= ttcol
;
1518 starting_line
= ttrow
;
1519 last_bg_color
= pico_get_last_bg_color();
1520 pico_set_nbg_color();
1521 for(c
= ttcol
; c
< term
.t_ncol
; c
++)
1524 tcapmove(starting_line
, starting_col
);
1526 pico_set_bg_color(last_bg_color
);
1527 free(last_bg_color
);
1530 else if(_cleartoeoln
)
1531 putpad(_cleartoeoln
);
1533 /* return ignored */
1541 int i
, starting_col
, starting_row
;
1544 * If the terminal doesn't have back color erase, then we have to
1545 * erase manually to preserve the background color.
1547 if(pico_usingcolor() && (!_bce
|| !_cleartoeos
)){
1548 extern int ttcol
, ttrow
;
1550 starting_col
= ttcol
;
1551 starting_row
= ttrow
;
1552 tcapeeol(); /* rest of this line */
1553 for(i
= ttrow
+1; i
<= term
.t_nrow
; i
++){ /* the remaining lines */
1558 tcapmove(starting_row
, starting_col
);
1560 else if(_cleartoeos
)
1561 putpad(_cleartoeos
);
1563 /* return ignored */
1569 tcaprev(int state
) /* change reverse video status */
1570 { /* FALSE = normal video, TRUE = reverse video */
1585 /* return ignored */
1593 tputs(str
, 1, putchar
);
1596 #else /* HARD_CODED_ANSI_TERMINAL */
1599 * ANSI-specific terminal i/o and control routines
1603 #define BEL 0x07 /* BEL character. */
1604 #define ESC 0x1B /* ESC character. */
1607 extern int ttflush();
1609 extern int ansimove(int, int);
1610 extern int ansieeol(void);
1611 extern int ansieeop(void);
1612 extern int ansibeep(void);
1613 extern int ansiparm(int);
1614 extern int ansiopen(void);
1615 extern int ansiterminalinfo(int);
1616 extern int ansirev(int);
1619 * Standard terminal interface dispatch table. Most of the fields point into
1622 #if defined(VAX) && !defined(__ALPHA)
1645 ansimove(int row
, int col
)
1672 ansirev(int state
) /* change reverse video state */
1673 { /* TRUE = reverse, FALSE = normal */
1674 static int PrevState
= 0;
1676 if(state
!= PrevState
) {
1680 ttputc(state
? '7': '0');
1700 ttputc((n
%10) + '0');
1705 ansiterminalinfo(int termcap_wins
)
1711 if ((cp
= getenv("TERM")) == NULL
) {
1712 puts("Shell variable TERM not defined!");
1715 if (strcmp(cp
, "vt100") != 0) {
1716 puts("Terminal type not 'vt100'!");
1720 /* revexist = TRUE; dead code? */
1730 #endif /* HARD_CODED_ANSI_TERMINAL */
1731 #else /* _WINDOWS */
1733 /* These are all just noops in Windows */
1742 * o_insert - optimize screen insert of char c
1752 * o_delete - optimized character deletion
1762 #endif /* _WINDOWS */