screen.c revision 170259
1/* $FreeBSD: head/contrib/less/screen.c 170259 2007-06-04 01:43:11Z delphij $ */ 2/* 3 * Copyright (C) 1984-2007 Mark Nudelman 4 * 5 * You may distribute under the terms of either the GNU General Public 6 * License or the Less License, as specified in the README file. 7 * 8 * For more information about less, or for information on how to 9 * contact the author, see the README file. 10 */ 11 12 13/* 14 * Routines which deal with the characteristics of the terminal. 15 * Uses termcap to be as terminal-independent as possible. 16 */ 17 18#include "less.h" 19#include "cmd.h" 20 21#if MSDOS_COMPILER 22#include "pckeys.h" 23#if MSDOS_COMPILER==MSOFTC 24#include <graph.h> 25#else 26#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 27#include <conio.h> 28#if MSDOS_COMPILER==DJGPPC 29#include <pc.h> 30extern int fd0; 31#endif 32#else 33#if MSDOS_COMPILER==WIN32C 34#include <windows.h> 35#endif 36#endif 37#endif 38#include <time.h> 39 40#else 41 42#if HAVE_SYS_IOCTL_H 43#include <sys/ioctl.h> 44#endif 45 46#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 47#include <termios.h> 48#else 49#if HAVE_TERMIO_H 50#include <termio.h> 51#else 52#if HAVE_SGSTAT_H 53#include <sgstat.h> 54#else 55#include <sgtty.h> 56#endif 57#endif 58#endif 59 60#if HAVE_TERMCAP_H 61#include <termcap.h> 62#endif 63#ifdef _OSK 64#include <signal.h> 65#endif 66#if OS2 67#include <sys/signal.h> 68#include "pckeys.h" 69#endif 70#if HAVE_SYS_STREAM_H 71#include <sys/stream.h> 72#endif 73#if HAVE_SYS_PTEM_H 74#include <sys/ptem.h> 75#endif 76 77#endif /* MSDOS_COMPILER */ 78 79/* 80 * Check for broken termios package that forces you to manually 81 * set the line discipline. 82 */ 83#ifdef __ultrix__ 84#define MUST_SET_LINE_DISCIPLINE 1 85#else 86#define MUST_SET_LINE_DISCIPLINE 0 87#endif 88 89#if OS2 90#define DEFAULT_TERM "ansi" 91static char *windowid; 92#else 93#define DEFAULT_TERM "unknown" 94#endif 95 96#if MSDOS_COMPILER==MSOFTC 97static int videopages; 98static long msec_loops; 99static int flash_created = 0; 100#define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } 101#endif 102 103#if MSDOS_COMPILER==BORLANDC 104static unsigned short *whitescreen; 105static int flash_created = 0; 106#endif 107#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 108#define _settextposition(y,x) gotoxy(x,y) 109#define _clearscreen(m) clrscr() 110#define _outtext(s) cputs(s) 111#define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } 112extern int sc_height; 113#endif 114 115#if MSDOS_COMPILER==WIN32C 116struct keyRecord 117{ 118 int ascii; 119 int scan; 120} currentKey; 121 122static int keyCount = 0; 123static WORD curr_attr; 124static int pending_scancode = 0; 125static WORD *whitescreen; 126 127static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */ 128static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */ 129HANDLE con_out = INVALID_HANDLE_VALUE; /* current console */ 130 131extern int quitting; 132static void win32_init_term(); 133static void win32_deinit_term(); 134 135#define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) 136#define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) 137#define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) 138#define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ 139 if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ 140 error("SETCOLORS failed"); } 141#endif 142 143#if MSDOS_COMPILER 144public int nm_fg_color; /* Color of normal text */ 145public int nm_bg_color; 146public int bo_fg_color; /* Color of bold text */ 147public int bo_bg_color; 148public int ul_fg_color; /* Color of underlined text */ 149public int ul_bg_color; 150public int so_fg_color; /* Color of standout text */ 151public int so_bg_color; 152public int bl_fg_color; /* Color of blinking text */ 153public int bl_bg_color; 154static int sy_fg_color; /* Color of system text (before less) */ 155static int sy_bg_color; 156 157#else 158 159/* 160 * Strings passed to tputs() to do various terminal functions. 161 */ 162static char 163 *sc_pad, /* Pad string */ 164 *sc_home, /* Cursor home */ 165 *sc_addline, /* Add line, scroll down following lines */ 166 *sc_lower_left, /* Cursor to last line, first column */ 167 *sc_return, /* Cursor to beginning of current line */ 168 *sc_move, /* General cursor positioning */ 169 *sc_clear, /* Clear screen */ 170 *sc_eol_clear, /* Clear to end of line */ 171 *sc_eos_clear, /* Clear to end of screen */ 172 *sc_s_in, /* Enter standout (highlighted) mode */ 173 *sc_s_out, /* Exit standout mode */ 174 *sc_u_in, /* Enter underline mode */ 175 *sc_u_out, /* Exit underline mode */ 176 *sc_b_in, /* Enter bold mode */ 177 *sc_b_out, /* Exit bold mode */ 178 *sc_bl_in, /* Enter blink mode */ 179 *sc_bl_out, /* Exit blink mode */ 180 *sc_visual_bell, /* Visual bell (flash screen) sequence */ 181 *sc_backspace, /* Backspace cursor */ 182 *sc_s_keypad, /* Start keypad mode */ 183 *sc_e_keypad, /* End keypad mode */ 184 *sc_init, /* Startup terminal initialization */ 185 *sc_deinit; /* Exit terminal de-initialization */ 186#endif 187 188static int init_done = 0; 189 190public int auto_wrap; /* Terminal does \r\n when write past margin */ 191public int ignaw; /* Terminal ignores \n immediately after wrap */ 192public int erase_char; /* The user's erase char */ 193public int erase2_char; /* The user's other erase char */ 194public int kill_char; /* The user's line-kill char */ 195public int werase_char; /* The user's word-erase char */ 196public int sc_width, sc_height; /* Height & width of screen */ 197public int bo_s_width, bo_e_width; /* Printing width of boldface seq */ 198public int ul_s_width, ul_e_width; /* Printing width of underline seq */ 199public int so_s_width, so_e_width; /* Printing width of standout seq */ 200public int bl_s_width, bl_e_width; /* Printing width of blink seq */ 201public int above_mem, below_mem; /* Memory retained above/below screen */ 202public int can_goto_line; /* Can move cursor to any line */ 203public int clear_bg; /* Clear fills with background color */ 204public int missing_cap = 0; /* Some capability is missing */ 205 206static int attrmode = AT_NORMAL; 207extern int binattr; 208 209#if !MSDOS_COMPILER 210static char *cheaper(); 211static void tmodes(); 212#endif 213 214/* 215 * These two variables are sometimes defined in, 216 * and needed by, the termcap library. 217 */ 218#if MUST_DEFINE_OSPEED 219extern short ospeed; /* Terminal output baud rate */ 220extern char PC; /* Pad character */ 221#endif 222#ifdef _OSK 223short ospeed; 224char PC_, *UP, *BC; 225#endif 226 227extern int quiet; /* If VERY_QUIET, use visual bell for bell */ 228extern int no_back_scroll; 229extern int swindow; 230extern int no_init; 231extern int quit_at_eof; 232extern int less_is_more; 233extern int no_keypad; 234extern int sigs; 235extern int wscroll; 236extern int screen_trashed; 237extern int tty; 238extern int top_scroll; 239extern int oldbot; 240#if HILITE_SEARCH 241extern int hilite_search; 242#endif 243 244extern char *tgetstr(); 245extern char *tgoto(); 246 247 248/* 249 * Change terminal to "raw mode", or restore to "normal" mode. 250 * "Raw mode" means 251 * 1. An outstanding read will complete on receipt of a single keystroke. 252 * 2. Input is not echoed. 253 * 3. On output, \n is mapped to \r\n. 254 * 4. \t is NOT expanded into spaces. 255 * 5. Signal-causing characters such as ctrl-C (interrupt), 256 * etc. are NOT disabled. 257 * It doesn't matter whether an input \n is mapped to \r, or vice versa. 258 */ 259 public void 260raw_mode(on) 261 int on; 262{ 263 static int curr_on = 0; 264 265 if (on == curr_on) 266 return; 267 erase2_char = '\b'; /* in case OS doesn't know about erase2 */ 268#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 269 { 270 struct termios s; 271 static struct termios save_term; 272 static int saved_term = 0; 273 274 if (on) 275 { 276 /* 277 * Get terminal modes. 278 */ 279 tcgetattr(tty, &s); 280 281 /* 282 * Save modes and set certain variables dependent on modes. 283 */ 284 if (!saved_term) 285 { 286 save_term = s; 287 saved_term = 1; 288 } 289#if HAVE_OSPEED 290 switch (cfgetospeed(&s)) 291 { 292#ifdef B0 293 case B0: ospeed = 0; break; 294#endif 295#ifdef B50 296 case B50: ospeed = 1; break; 297#endif 298#ifdef B75 299 case B75: ospeed = 2; break; 300#endif 301#ifdef B110 302 case B110: ospeed = 3; break; 303#endif 304#ifdef B134 305 case B134: ospeed = 4; break; 306#endif 307#ifdef B150 308 case B150: ospeed = 5; break; 309#endif 310#ifdef B200 311 case B200: ospeed = 6; break; 312#endif 313#ifdef B300 314 case B300: ospeed = 7; break; 315#endif 316#ifdef B600 317 case B600: ospeed = 8; break; 318#endif 319#ifdef B1200 320 case B1200: ospeed = 9; break; 321#endif 322#ifdef B1800 323 case B1800: ospeed = 10; break; 324#endif 325#ifdef B2400 326 case B2400: ospeed = 11; break; 327#endif 328#ifdef B4800 329 case B4800: ospeed = 12; break; 330#endif 331#ifdef B9600 332 case B9600: ospeed = 13; break; 333#endif 334#ifdef EXTA 335 case EXTA: ospeed = 14; break; 336#endif 337#ifdef EXTB 338 case EXTB: ospeed = 15; break; 339#endif 340#ifdef B57600 341 case B57600: ospeed = 16; break; 342#endif 343#ifdef B115200 344 case B115200: ospeed = 17; break; 345#endif 346 default: ; 347 } 348#endif 349 erase_char = s.c_cc[VERASE]; 350#ifdef VERASE2 351 erase2_char = s.c_cc[VERASE2]; 352#endif 353 kill_char = s.c_cc[VKILL]; 354#ifdef VWERASE 355 werase_char = s.c_cc[VWERASE]; 356#else 357 werase_char = CONTROL('W'); 358#endif 359 360 /* 361 * Set the modes to the way we want them. 362 */ 363 s.c_lflag &= ~(0 364#ifdef ICANON 365 | ICANON 366#endif 367#ifdef ECHO 368 | ECHO 369#endif 370#ifdef ECHOE 371 | ECHOE 372#endif 373#ifdef ECHOK 374 | ECHOK 375#endif 376#if ECHONL 377 | ECHONL 378#endif 379 ); 380 381 s.c_oflag |= (0 382#ifdef OXTABS 383 | OXTABS 384#else 385#ifdef TAB3 386 | TAB3 387#else 388#ifdef XTABS 389 | XTABS 390#endif 391#endif 392#endif 393#ifdef OPOST 394 | OPOST 395#endif 396#ifdef ONLCR 397 | ONLCR 398#endif 399 ); 400 401 s.c_oflag &= ~(0 402#ifdef ONOEOT 403 | ONOEOT 404#endif 405#ifdef OCRNL 406 | OCRNL 407#endif 408#ifdef ONOCR 409 | ONOCR 410#endif 411#ifdef ONLRET 412 | ONLRET 413#endif 414 ); 415 s.c_cc[VMIN] = 1; 416 s.c_cc[VTIME] = 0; 417#ifdef VLNEXT 418 s.c_cc[VLNEXT] = 0; 419#endif 420#ifdef VDSUSP 421 s.c_cc[VDSUSP] = 0; 422#endif 423#if MUST_SET_LINE_DISCIPLINE 424 /* 425 * System's termios is broken; need to explicitly 426 * request TERMIODISC line discipline. 427 */ 428 s.c_line = TERMIODISC; 429#endif 430 } else 431 { 432 /* 433 * Restore saved modes. 434 */ 435 s = save_term; 436 } 437#if HAVE_FSYNC 438 fsync(tty); 439#endif 440 tcsetattr(tty, TCSADRAIN, &s); 441#if MUST_SET_LINE_DISCIPLINE 442 if (!on) 443 { 444 /* 445 * Broken termios *ignores* any line discipline 446 * except TERMIODISC. A different old line discipline 447 * is therefore not restored, yet. Restore the old 448 * line discipline by hand. 449 */ 450 ioctl(tty, TIOCSETD, &save_term.c_line); 451 } 452#endif 453 } 454#else 455#ifdef TCGETA 456 { 457 struct termio s; 458 static struct termio save_term; 459 static int saved_term = 0; 460 461 if (on) 462 { 463 /* 464 * Get terminal modes. 465 */ 466 ioctl(tty, TCGETA, &s); 467 468 /* 469 * Save modes and set certain variables dependent on modes. 470 */ 471 if (!saved_term) 472 { 473 save_term = s; 474 saved_term = 1; 475 } 476#if HAVE_OSPEED 477 ospeed = s.c_cflag & CBAUD; 478#endif 479 erase_char = s.c_cc[VERASE]; 480 kill_char = s.c_cc[VKILL]; 481#ifdef VWERASE 482 werase_char = s.c_cc[VWERASE]; 483#else 484 werase_char = CONTROL('W'); 485#endif 486 487 /* 488 * Set the modes to the way we want them. 489 */ 490 s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); 491 s.c_oflag |= (OPOST|ONLCR|TAB3); 492 s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); 493 s.c_cc[VMIN] = 1; 494 s.c_cc[VTIME] = 0; 495 } else 496 { 497 /* 498 * Restore saved modes. 499 */ 500 s = save_term; 501 } 502 ioctl(tty, TCSETAW, &s); 503 } 504#else 505#ifdef TIOCGETP 506 { 507 struct sgttyb s; 508 static struct sgttyb save_term; 509 static int saved_term = 0; 510 511 if (on) 512 { 513 /* 514 * Get terminal modes. 515 */ 516 ioctl(tty, TIOCGETP, &s); 517 518 /* 519 * Save modes and set certain variables dependent on modes. 520 */ 521 if (!saved_term) 522 { 523 save_term = s; 524 saved_term = 1; 525 } 526#if HAVE_OSPEED 527 ospeed = s.sg_ospeed; 528#endif 529 erase_char = s.sg_erase; 530 kill_char = s.sg_kill; 531 werase_char = CONTROL('W'); 532 533 /* 534 * Set the modes to the way we want them. 535 */ 536 s.sg_flags |= CBREAK; 537 s.sg_flags &= ~(ECHO|XTABS); 538 } else 539 { 540 /* 541 * Restore saved modes. 542 */ 543 s = save_term; 544 } 545 ioctl(tty, TIOCSETN, &s); 546 } 547#else 548#ifdef _OSK 549 { 550 struct sgbuf s; 551 static struct sgbuf save_term; 552 static int saved_term = 0; 553 554 if (on) 555 { 556 /* 557 * Get terminal modes. 558 */ 559 _gs_opt(tty, &s); 560 561 /* 562 * Save modes and set certain variables dependent on modes. 563 */ 564 if (!saved_term) 565 { 566 save_term = s; 567 saved_term = 1; 568 } 569 erase_char = s.sg_bspch; 570 kill_char = s.sg_dlnch; 571 werase_char = CONTROL('W'); 572 573 /* 574 * Set the modes to the way we want them. 575 */ 576 s.sg_echo = 0; 577 s.sg_eofch = 0; 578 s.sg_pause = 0; 579 s.sg_psch = 0; 580 } else 581 { 582 /* 583 * Restore saved modes. 584 */ 585 s = save_term; 586 } 587 _ss_opt(tty, &s); 588 } 589#else 590 /* MS-DOS, Windows, or OS2 */ 591#if OS2 592 /* OS2 */ 593 LSIGNAL(SIGINT, SIG_IGN); 594#endif 595 erase_char = '\b'; 596#if MSDOS_COMPILER==DJGPPC 597 kill_char = CONTROL('U'); 598 /* 599 * So that when we shell out or run another program, its 600 * stdin is in cooked mode. We do not switch stdin to binary 601 * mode if fd0 is zero, since that means we were called before 602 * tty was reopened in open_getchr, in which case we would be 603 * changing the original stdin device outside less. 604 */ 605 if (fd0 != 0) 606 setmode(0, on ? O_BINARY : O_TEXT); 607#else 608 kill_char = ESC; 609#endif 610 werase_char = CONTROL('W'); 611#endif 612#endif 613#endif 614#endif 615 curr_on = on; 616} 617 618#if !MSDOS_COMPILER 619/* 620 * Some glue to prevent calling termcap functions if tgetent() failed. 621 */ 622static int hardcopy; 623 624 static char * 625ltget_env(capname) 626 char *capname; 627{ 628 char name[16]; 629 630 strcpy(name, "LESS_TERMCAP_"); 631 strcat(name, capname); 632 return (lgetenv(name)); 633} 634 635 static int 636ltgetflag(capname) 637 char *capname; 638{ 639 char *s; 640 641 if ((s = ltget_env(capname)) != NULL) 642 return (*s != '\0' && *s != '0'); 643 if (hardcopy) 644 return (0); 645 return (tgetflag(capname)); 646} 647 648 static int 649ltgetnum(capname) 650 char *capname; 651{ 652 char *s; 653 654 if ((s = ltget_env(capname)) != NULL) 655 return (atoi(s)); 656 if (hardcopy) 657 return (-1); 658 return (tgetnum(capname)); 659} 660 661 static char * 662ltgetstr(capname, pp) 663 char *capname; 664 char **pp; 665{ 666 char *s; 667 668 if ((s = ltget_env(capname)) != NULL) 669 return (s); 670 if (hardcopy) 671 return (NULL); 672 return (tgetstr(capname, pp)); 673} 674#endif /* MSDOS_COMPILER */ 675 676/* 677 * Get size of the output screen. 678 */ 679 public void 680scrsize() 681{ 682 register char *s; 683 int sys_height; 684 int sys_width; 685#if !MSDOS_COMPILER 686 int n; 687#endif 688 689#define DEF_SC_WIDTH 80 690#if MSDOS_COMPILER 691#define DEF_SC_HEIGHT 25 692#else 693#define DEF_SC_HEIGHT 24 694#endif 695 696 697 sys_width = sys_height = 0; 698 699#if MSDOS_COMPILER==MSOFTC 700 { 701 struct videoconfig w; 702 _getvideoconfig(&w); 703 sys_height = w.numtextrows; 704 sys_width = w.numtextcols; 705 } 706#else 707#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 708 { 709 struct text_info w; 710 gettextinfo(&w); 711 sys_height = w.screenheight; 712 sys_width = w.screenwidth; 713 } 714#else 715#if MSDOS_COMPILER==WIN32C 716 { 717 CONSOLE_SCREEN_BUFFER_INFO scr; 718 GetConsoleScreenBufferInfo(con_out, &scr); 719 sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; 720 sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; 721 } 722#else 723#if OS2 724 { 725 int s[2]; 726 _scrsize(s); 727 sys_width = s[0]; 728 sys_height = s[1]; 729 /* 730 * When using terminal emulators for XFree86/OS2, the 731 * _scrsize function does not work well. 732 * Call the scrsize.exe program to get the window size. 733 */ 734 windowid = getenv("WINDOWID"); 735 if (windowid != NULL) 736 { 737 FILE *fd = popen("scrsize", "rt"); 738 if (fd != NULL) 739 { 740 int w, h; 741 fscanf(fd, "%i %i", &w, &h); 742 if (w > 0 && h > 0) 743 { 744 sys_width = w; 745 sys_height = h; 746 } 747 pclose(fd); 748 } 749 } 750 } 751#else 752#ifdef TIOCGWINSZ 753 { 754 struct winsize w; 755 if (ioctl(2, TIOCGWINSZ, &w) == 0) 756 { 757 if (w.ws_row > 0) 758 sys_height = w.ws_row; 759 if (w.ws_col > 0) 760 sys_width = w.ws_col; 761 } 762 } 763#else 764#ifdef WIOCGETD 765 { 766 struct uwdata w; 767 if (ioctl(2, WIOCGETD, &w) == 0) 768 { 769 if (w.uw_height > 0) 770 sys_height = w.uw_height / w.uw_vs; 771 if (w.uw_width > 0) 772 sys_width = w.uw_width / w.uw_hs; 773 } 774 } 775#endif 776#endif 777#endif 778#endif 779#endif 780#endif 781 782 if (sys_height > 0) 783 sc_height = sys_height; 784 else if ((s = lgetenv("LINES")) != NULL) 785 sc_height = atoi(s); 786#if !MSDOS_COMPILER 787 else if ((n = ltgetnum("li")) > 0) 788 sc_height = n; 789#endif 790 else 791 sc_height = DEF_SC_HEIGHT; 792 793 if (sys_width > 0) 794 sc_width = sys_width; 795 else if ((s = lgetenv("COLUMNS")) != NULL) 796 sc_width = atoi(s); 797#if !MSDOS_COMPILER 798 else if ((n = ltgetnum("co")) > 0) 799 sc_width = n; 800#endif 801 else 802 sc_width = DEF_SC_WIDTH; 803} 804 805#if MSDOS_COMPILER==MSOFTC 806/* 807 * Figure out how many empty loops it takes to delay a millisecond. 808 */ 809 static void 810get_clock() 811{ 812 clock_t start; 813 814 /* 815 * Get synchronized at the start of a tick. 816 */ 817 start = clock(); 818 while (clock() == start) 819 ; 820 /* 821 * Now count loops till the next tick. 822 */ 823 start = clock(); 824 msec_loops = 0; 825 while (clock() == start) 826 msec_loops++; 827 /* 828 * Convert from (loops per clock) to (loops per millisecond). 829 */ 830 msec_loops *= CLOCKS_PER_SEC; 831 msec_loops /= 1000; 832} 833 834/* 835 * Delay for a specified number of milliseconds. 836 */ 837 static void 838dummy_func() 839{ 840 static long delay_dummy = 0; 841 delay_dummy++; 842} 843 844 static void 845delay(msec) 846 int msec; 847{ 848 long i; 849 850 while (msec-- > 0) 851 { 852 for (i = 0; i < msec_loops; i++) 853 { 854 /* 855 * Make it look like we're doing something here, 856 * so the optimizer doesn't remove the whole loop. 857 */ 858 dummy_func(); 859 } 860 } 861} 862#endif 863 864/* 865 * Return the characters actually input by a "special" key. 866 */ 867 public char * 868special_key_str(key) 869 int key; 870{ 871 static char tbuf[40]; 872 char *s; 873#if MSDOS_COMPILER || OS2 874 static char k_right[] = { '\340', PCK_RIGHT, 0 }; 875 static char k_left[] = { '\340', PCK_LEFT, 0 }; 876 static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; 877 static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; 878 static char k_insert[] = { '\340', PCK_INSERT, 0 }; 879 static char k_delete[] = { '\340', PCK_DELETE, 0 }; 880 static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; 881 static char k_ctl_backspace[] = { '\177', 0 }; 882 static char k_home[] = { '\340', PCK_HOME, 0 }; 883 static char k_end[] = { '\340', PCK_END, 0 }; 884 static char k_up[] = { '\340', PCK_UP, 0 }; 885 static char k_down[] = { '\340', PCK_DOWN, 0 }; 886 static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; 887 static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; 888 static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; 889 static char k_f1[] = { '\340', PCK_F1, 0 }; 890#endif 891#if !MSDOS_COMPILER 892 char *sp = tbuf; 893#endif 894 895 switch (key) 896 { 897#if OS2 898 /* 899 * If windowid is not NULL, assume less is executed in 900 * the XFree86 environment. 901 */ 902 case SK_RIGHT_ARROW: 903 s = windowid ? ltgetstr("kr", &sp) : k_right; 904 break; 905 case SK_LEFT_ARROW: 906 s = windowid ? ltgetstr("kl", &sp) : k_left; 907 break; 908 case SK_UP_ARROW: 909 s = windowid ? ltgetstr("ku", &sp) : k_up; 910 break; 911 case SK_DOWN_ARROW: 912 s = windowid ? ltgetstr("kd", &sp) : k_down; 913 break; 914 case SK_PAGE_UP: 915 s = windowid ? ltgetstr("kP", &sp) : k_pageup; 916 break; 917 case SK_PAGE_DOWN: 918 s = windowid ? ltgetstr("kN", &sp) : k_pagedown; 919 break; 920 case SK_HOME: 921 s = windowid ? ltgetstr("kh", &sp) : k_home; 922 break; 923 case SK_END: 924 s = windowid ? ltgetstr("@7", &sp) : k_end; 925 break; 926 case SK_DELETE: 927 if (windowid) 928 { 929 s = ltgetstr("kD", &sp); 930 if (s == NULL) 931 { 932 tbuf[0] = '\177'; 933 tbuf[1] = '\0'; 934 s = tbuf; 935 } 936 } else 937 s = k_delete; 938 break; 939#endif 940#if MSDOS_COMPILER 941 case SK_RIGHT_ARROW: 942 s = k_right; 943 break; 944 case SK_LEFT_ARROW: 945 s = k_left; 946 break; 947 case SK_UP_ARROW: 948 s = k_up; 949 break; 950 case SK_DOWN_ARROW: 951 s = k_down; 952 break; 953 case SK_PAGE_UP: 954 s = k_pageup; 955 break; 956 case SK_PAGE_DOWN: 957 s = k_pagedown; 958 break; 959 case SK_HOME: 960 s = k_home; 961 break; 962 case SK_END: 963 s = k_end; 964 break; 965 case SK_DELETE: 966 s = k_delete; 967 break; 968#endif 969#if MSDOS_COMPILER || OS2 970 case SK_INSERT: 971 s = k_insert; 972 break; 973 case SK_CTL_LEFT_ARROW: 974 s = k_ctl_left; 975 break; 976 case SK_CTL_RIGHT_ARROW: 977 s = k_ctl_right; 978 break; 979 case SK_CTL_BACKSPACE: 980 s = k_ctl_backspace; 981 break; 982 case SK_CTL_DELETE: 983 s = k_ctl_delete; 984 break; 985 case SK_F1: 986 s = k_f1; 987 break; 988 case SK_BACKTAB: 989 s = k_backtab; 990 break; 991#else 992 case SK_RIGHT_ARROW: 993 s = ltgetstr("kr", &sp); 994 break; 995 case SK_LEFT_ARROW: 996 s = ltgetstr("kl", &sp); 997 break; 998 case SK_UP_ARROW: 999 s = ltgetstr("ku", &sp); 1000 break; 1001 case SK_DOWN_ARROW: 1002 s = ltgetstr("kd", &sp); 1003 break; 1004 case SK_PAGE_UP: 1005 s = ltgetstr("kP", &sp); 1006 break; 1007 case SK_PAGE_DOWN: 1008 s = ltgetstr("kN", &sp); 1009 break; 1010 case SK_HOME: 1011 s = ltgetstr("kh", &sp); 1012 break; 1013 case SK_END: 1014 s = ltgetstr("@7", &sp); 1015 break; 1016 case SK_DELETE: 1017 s = ltgetstr("kD", &sp); 1018 if (s == NULL) 1019 { 1020 tbuf[0] = '\177'; 1021 tbuf[1] = '\0'; 1022 s = tbuf; 1023 } 1024 break; 1025#endif 1026 case SK_CONTROL_K: 1027 tbuf[0] = CONTROL('K'); 1028 tbuf[1] = '\0'; 1029 s = tbuf; 1030 break; 1031 default: 1032 return (NULL); 1033 } 1034 return (s); 1035} 1036 1037/* 1038 * Get terminal capabilities via termcap. 1039 */ 1040 public void 1041get_term() 1042{ 1043#if MSDOS_COMPILER 1044 auto_wrap = 1; 1045 ignaw = 0; 1046 can_goto_line = 1; 1047 clear_bg = 1; 1048 /* 1049 * Set up default colors. 1050 * The xx_s_width and xx_e_width vars are already initialized to 0. 1051 */ 1052#if MSDOS_COMPILER==MSOFTC 1053 sy_bg_color = _getbkcolor(); 1054 sy_fg_color = _gettextcolor(); 1055 get_clock(); 1056#else 1057#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1058 { 1059 struct text_info w; 1060 gettextinfo(&w); 1061 sy_bg_color = (w.attribute >> 4) & 0x0F; 1062 sy_fg_color = (w.attribute >> 0) & 0x0F; 1063 } 1064#else 1065#if MSDOS_COMPILER==WIN32C 1066 { 1067 DWORD nread; 1068 CONSOLE_SCREEN_BUFFER_INFO scr; 1069 1070 con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); 1071 /* 1072 * Always open stdin in binary. Note this *must* be done 1073 * before any file operations have been done on fd0. 1074 */ 1075 SET_BINARY(0); 1076 GetConsoleScreenBufferInfo(con_out, &scr); 1077 ReadConsoleOutputAttribute(con_out, &curr_attr, 1078 1, scr.dwCursorPosition, &nread); 1079 sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ 1080 sy_fg_color = curr_attr & FG_COLORS; 1081 } 1082#endif 1083#endif 1084#endif 1085 nm_fg_color = sy_fg_color; 1086 nm_bg_color = sy_bg_color; 1087 bo_fg_color = 11; 1088 bo_bg_color = 0; 1089 ul_fg_color = 9; 1090 ul_bg_color = 0; 1091 so_fg_color = 15; 1092 so_bg_color = 9; 1093 bl_fg_color = 15; 1094 bl_bg_color = 0; 1095 1096 /* 1097 * Get size of the screen. 1098 */ 1099 scrsize(); 1100 pos_init(); 1101 1102 1103#else /* !MSDOS_COMPILER */ 1104 1105 char *sp; 1106 register char *t1, *t2; 1107 char *term; 1108 char termbuf[TERMBUF_SIZE]; 1109 1110 static char sbuf[TERMSBUF_SIZE]; 1111 1112#if OS2 1113 /* 1114 * Make sure the termcap database is available. 1115 */ 1116 sp = lgetenv("TERMCAP"); 1117 if (sp == NULL || *sp == '\0') 1118 { 1119 char *termcap; 1120 if ((sp = homefile("termcap.dat")) != NULL) 1121 { 1122 termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char)); 1123 sprintf(termcap, "TERMCAP=%s", sp); 1124 free(sp); 1125 putenv(termcap); 1126 } 1127 } 1128#endif 1129 /* 1130 * Find out what kind of terminal this is. 1131 */ 1132 if ((term = lgetenv("TERM")) == NULL) 1133 term = DEFAULT_TERM; 1134 hardcopy = 0; 1135 if (tgetent(termbuf, term) != TGETENT_OK) 1136 hardcopy = 1; 1137 if (ltgetflag("hc")) 1138 hardcopy = 1; 1139 1140 /* 1141 * Get size of the screen. 1142 */ 1143 scrsize(); 1144 pos_init(); 1145 1146 auto_wrap = ltgetflag("am"); 1147 ignaw = ltgetflag("xn"); 1148 above_mem = ltgetflag("da"); 1149 below_mem = ltgetflag("db"); 1150 clear_bg = ltgetflag("ut"); 1151 1152 /* 1153 * Assumes termcap variable "sg" is the printing width of: 1154 * the standout sequence, the end standout sequence, 1155 * the underline sequence, the end underline sequence, 1156 * the boldface sequence, and the end boldface sequence. 1157 */ 1158 if ((so_s_width = ltgetnum("sg")) < 0) 1159 so_s_width = 0; 1160 so_e_width = so_s_width; 1161 1162 bo_s_width = bo_e_width = so_s_width; 1163 ul_s_width = ul_e_width = so_s_width; 1164 bl_s_width = bl_e_width = so_s_width; 1165 1166#if HILITE_SEARCH 1167 if (so_s_width > 0 || so_e_width > 0) 1168 /* 1169 * Disable highlighting by default on magic cookie terminals. 1170 * Turning on highlighting might change the displayed width 1171 * of a line, causing the display to get messed up. 1172 * The user can turn it back on with -g, 1173 * but she won't like the results. 1174 */ 1175 hilite_search = 0; 1176#endif 1177 1178 /* 1179 * Get various string-valued capabilities. 1180 */ 1181 sp = sbuf; 1182 1183#if HAVE_OSPEED 1184 sc_pad = ltgetstr("pc", &sp); 1185 if (sc_pad != NULL) 1186 PC = *sc_pad; 1187#endif 1188 1189 sc_s_keypad = ltgetstr("ks", &sp); 1190 if (sc_s_keypad == NULL) 1191 sc_s_keypad = ""; 1192 sc_e_keypad = ltgetstr("ke", &sp); 1193 if (sc_e_keypad == NULL) 1194 sc_e_keypad = ""; 1195 1196 /* 1197 * This loses for terminals with termcap entries with ti/te strings 1198 * that switch to/from an alternate screen, and we're in quit_at_eof 1199 * (eg, more(1)). 1200 */ 1201 if (!quit_at_eof && !less_is_more) { 1202 sc_init = ltgetstr("ti", &sp); 1203 sc_deinit = ltgetstr("te", &sp); 1204 } 1205 1206 if (sc_init == NULL) 1207 sc_init = ""; 1208 1209 if (sc_deinit == NULL) 1210 sc_deinit = ""; 1211 1212 sc_eol_clear = ltgetstr("ce", &sp); 1213 if (sc_eol_clear == NULL || *sc_eol_clear == '\0') 1214 { 1215 missing_cap = 1; 1216 sc_eol_clear = ""; 1217 } 1218 1219 sc_eos_clear = ltgetstr("cd", &sp); 1220 if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) 1221 { 1222 missing_cap = 1; 1223 sc_eos_clear = ""; 1224 } 1225 1226 sc_clear = ltgetstr("cl", &sp); 1227 if (sc_clear == NULL || *sc_clear == '\0') 1228 { 1229 missing_cap = 1; 1230 sc_clear = "\n\n"; 1231 } 1232 1233 sc_move = ltgetstr("cm", &sp); 1234 if (sc_move == NULL || *sc_move == '\0') 1235 { 1236 /* 1237 * This is not an error here, because we don't 1238 * always need sc_move. 1239 * We need it only if we don't have home or lower-left. 1240 */ 1241 sc_move = ""; 1242 can_goto_line = 0; 1243 } else 1244 can_goto_line = 1; 1245 1246 tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); 1247 tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); 1248 tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); 1249 tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); 1250 1251 sc_visual_bell = ltgetstr("vb", &sp); 1252 if (sc_visual_bell == NULL) 1253 sc_visual_bell = ""; 1254 1255 if (ltgetflag("bs")) 1256 sc_backspace = "\b"; 1257 else 1258 { 1259 sc_backspace = ltgetstr("bc", &sp); 1260 if (sc_backspace == NULL || *sc_backspace == '\0') 1261 sc_backspace = "\b"; 1262 } 1263 1264 /* 1265 * Choose between using "ho" and "cm" ("home" and "cursor move") 1266 * to move the cursor to the upper left corner of the screen. 1267 */ 1268 t1 = ltgetstr("ho", &sp); 1269 if (t1 == NULL) 1270 t1 = ""; 1271 if (*sc_move == '\0') 1272 t2 = ""; 1273 else 1274 { 1275 strcpy(sp, tgoto(sc_move, 0, 0)); 1276 t2 = sp; 1277 sp += strlen(sp) + 1; 1278 } 1279 sc_home = cheaper(t1, t2, "|\b^"); 1280 1281 /* 1282 * Choose between using "ll" and "cm" ("lower left" and "cursor move") 1283 * to move the cursor to the lower left corner of the screen. 1284 */ 1285 t1 = ltgetstr("ll", &sp); 1286 if (t1 == NULL) 1287 t1 = ""; 1288 if (*sc_move == '\0') 1289 t2 = ""; 1290 else 1291 { 1292 strcpy(sp, tgoto(sc_move, 0, sc_height-1)); 1293 t2 = sp; 1294 sp += strlen(sp) + 1; 1295 } 1296 sc_lower_left = cheaper(t1, t2, "\r"); 1297 1298 /* 1299 * Get carriage return string. 1300 */ 1301 sc_return = ltgetstr("cr", &sp); 1302 if (sc_return == NULL) 1303 sc_return = "\r"; 1304 1305 /* 1306 * Choose between using "al" or "sr" ("add line" or "scroll reverse") 1307 * to add a line at the top of the screen. 1308 */ 1309 t1 = ltgetstr("al", &sp); 1310 if (t1 == NULL) 1311 t1 = ""; 1312 t2 = ltgetstr("sr", &sp); 1313 if (t2 == NULL) 1314 t2 = ""; 1315#if OS2 1316 if (*t1 == '\0' && *t2 == '\0') 1317 sc_addline = ""; 1318 else 1319#endif 1320 if (above_mem) 1321 sc_addline = t1; 1322 else 1323 sc_addline = cheaper(t1, t2, ""); 1324 if (*sc_addline == '\0') 1325 { 1326 /* 1327 * Force repaint on any backward movement. 1328 */ 1329 no_back_scroll = 1; 1330 } 1331#endif /* MSDOS_COMPILER */ 1332} 1333 1334#if !MSDOS_COMPILER 1335/* 1336 * Return the cost of displaying a termcap string. 1337 * We use the trick of calling tputs, but as a char printing function 1338 * we give it inc_costcount, which just increments "costcount". 1339 * This tells us how many chars would be printed by using this string. 1340 * {{ Couldn't we just use strlen? }} 1341 */ 1342static int costcount; 1343 1344/*ARGSUSED*/ 1345 static int 1346inc_costcount(c) 1347 int c; 1348{ 1349 costcount++; 1350 return (c); 1351} 1352 1353 static int 1354cost(t) 1355 char *t; 1356{ 1357 costcount = 0; 1358 tputs(t, sc_height, inc_costcount); 1359 return (costcount); 1360} 1361 1362/* 1363 * Return the "best" of the two given termcap strings. 1364 * The best, if both exist, is the one with the lower 1365 * cost (see cost() function). 1366 */ 1367 static char * 1368cheaper(t1, t2, def) 1369 char *t1, *t2; 1370 char *def; 1371{ 1372 if (*t1 == '\0' && *t2 == '\0') 1373 { 1374 missing_cap = 1; 1375 return (def); 1376 } 1377 if (*t1 == '\0') 1378 return (t2); 1379 if (*t2 == '\0') 1380 return (t1); 1381 if (cost(t1) < cost(t2)) 1382 return (t1); 1383 return (t2); 1384} 1385 1386 static void 1387tmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp) 1388 char *incap; 1389 char *outcap; 1390 char **instr; 1391 char **outstr; 1392 char *def_instr; 1393 char *def_outstr; 1394 char **spp; 1395{ 1396 *instr = ltgetstr(incap, spp); 1397 if (*instr == NULL) 1398 { 1399 /* Use defaults. */ 1400 *instr = def_instr; 1401 *outstr = def_outstr; 1402 return; 1403 } 1404 1405 *outstr = ltgetstr(outcap, spp); 1406 if (*outstr == NULL) 1407 /* No specific out capability; use "me". */ 1408 *outstr = ltgetstr("me", spp); 1409 if (*outstr == NULL) 1410 /* Don't even have "me"; use a null string. */ 1411 *outstr = ""; 1412} 1413 1414#endif /* MSDOS_COMPILER */ 1415 1416 1417/* 1418 * Below are the functions which perform all the 1419 * terminal-specific screen manipulation. 1420 */ 1421 1422 1423#if MSDOS_COMPILER 1424 1425#if MSDOS_COMPILER==WIN32C 1426 static void 1427_settextposition(int row, int col) 1428{ 1429 COORD cpos; 1430 CONSOLE_SCREEN_BUFFER_INFO csbi; 1431 1432 GetConsoleScreenBufferInfo(con_out, &csbi); 1433 cpos.X = csbi.srWindow.Left + (col - 1); 1434 cpos.Y = csbi.srWindow.Top + (row - 1); 1435 SetConsoleCursorPosition(con_out, cpos); 1436} 1437#endif 1438 1439/* 1440 * Initialize the screen to the correct color at startup. 1441 */ 1442 static void 1443initcolor() 1444{ 1445 SETCOLORS(nm_fg_color, nm_bg_color); 1446#if 0 1447 /* 1448 * This clears the screen at startup. This is different from 1449 * the behavior of other versions of less. Disable it for now. 1450 */ 1451 char *blanks; 1452 int row; 1453 int col; 1454 1455 /* 1456 * Create a complete, blank screen using "normal" colors. 1457 */ 1458 SETCOLORS(nm_fg_color, nm_bg_color); 1459 blanks = (char *) ecalloc(width+1, sizeof(char)); 1460 for (col = 0; col < sc_width; col++) 1461 blanks[col] = ' '; 1462 blanks[sc_width] = '\0'; 1463 for (row = 0; row < sc_height; row++) 1464 _outtext(blanks); 1465 free(blanks); 1466#endif 1467} 1468#endif 1469 1470#if MSDOS_COMPILER==WIN32C 1471 1472/* 1473 * Termcap-like init with a private win32 console. 1474 */ 1475 static void 1476win32_init_term() 1477{ 1478 CONSOLE_SCREEN_BUFFER_INFO scr; 1479 COORD size; 1480 1481 if (con_out_save == INVALID_HANDLE_VALUE) 1482 return; 1483 1484 GetConsoleScreenBufferInfo(con_out_save, &scr); 1485 1486 if (con_out_ours == INVALID_HANDLE_VALUE) 1487 { 1488 /* 1489 * Create our own screen buffer, so that we 1490 * may restore the original when done. 1491 */ 1492 con_out_ours = CreateConsoleScreenBuffer( 1493 GENERIC_WRITE | GENERIC_READ, 1494 FILE_SHARE_WRITE | FILE_SHARE_READ, 1495 (LPSECURITY_ATTRIBUTES) NULL, 1496 CONSOLE_TEXTMODE_BUFFER, 1497 (LPVOID) NULL); 1498 } 1499 1500 size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 1501 size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 1502 SetConsoleScreenBufferSize(con_out_ours, size); 1503 SetConsoleActiveScreenBuffer(con_out_ours); 1504 con_out = con_out_ours; 1505} 1506 1507/* 1508 * Restore the startup console. 1509 */ 1510static void 1511win32_deinit_term() 1512{ 1513 if (con_out_save == INVALID_HANDLE_VALUE) 1514 return; 1515 if (quitting) 1516 (void) CloseHandle(con_out_ours); 1517 SetConsoleActiveScreenBuffer(con_out_save); 1518 con_out = con_out_save; 1519} 1520 1521#endif 1522 1523/* 1524 * Initialize terminal 1525 */ 1526 public void 1527init() 1528{ 1529#if !MSDOS_COMPILER 1530 if (!no_init) 1531 tputs(sc_init, sc_height, putchr); 1532 if (!no_keypad) 1533 tputs(sc_s_keypad, sc_height, putchr); 1534 if (top_scroll) 1535 { 1536 int i; 1537 1538 /* 1539 * This is nice to terminals with no alternate screen, 1540 * but with saved scrolled-off-the-top lines. This way, 1541 * no previous line is lost, but we start with a whole 1542 * screen to ourself. 1543 */ 1544 for (i = 1; i < sc_height; i++) 1545 putchr('\n'); 1546 } 1547#else 1548#if MSDOS_COMPILER==WIN32C 1549 if (!no_init) 1550 win32_init_term(); 1551#endif 1552 initcolor(); 1553 flush(); 1554#endif 1555 init_done = 1; 1556} 1557 1558/* 1559 * Deinitialize terminal 1560 */ 1561 public void 1562deinit() 1563{ 1564 if (!init_done) 1565 return; 1566#if !MSDOS_COMPILER 1567 if (!no_keypad) 1568 tputs(sc_e_keypad, sc_height, putchr); 1569 if (!no_init) 1570 tputs(sc_deinit, sc_height, putchr); 1571#else 1572 /* Restore system colors. */ 1573 SETCOLORS(sy_fg_color, sy_bg_color); 1574#if MSDOS_COMPILER==WIN32C 1575 if (!no_init) 1576 win32_deinit_term(); 1577#else 1578 /* Need clreol to make SETCOLORS take effect. */ 1579 clreol(); 1580#endif 1581#endif 1582 init_done = 0; 1583} 1584 1585/* 1586 * Home cursor (move to upper left corner of screen). 1587 */ 1588 public void 1589home() 1590{ 1591#if !MSDOS_COMPILER 1592 tputs(sc_home, 1, putchr); 1593#else 1594 flush(); 1595 _settextposition(1,1); 1596#endif 1597} 1598 1599/* 1600 * Add a blank line (called with cursor at home). 1601 * Should scroll the display down. 1602 */ 1603 public void 1604add_line() 1605{ 1606#if !MSDOS_COMPILER 1607 tputs(sc_addline, sc_height, putchr); 1608#else 1609 flush(); 1610#if MSDOS_COMPILER==MSOFTC 1611 _scrolltextwindow(_GSCROLLDOWN); 1612 _settextposition(1,1); 1613#else 1614#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1615 movetext(1,1, sc_width,sc_height-1, 1,2); 1616 gotoxy(1,1); 1617 clreol(); 1618#else 1619#if MSDOS_COMPILER==WIN32C 1620 { 1621 CHAR_INFO fillchar; 1622 SMALL_RECT rcSrc, rcClip; 1623 COORD new_org; 1624 CONSOLE_SCREEN_BUFFER_INFO csbi; 1625 1626 GetConsoleScreenBufferInfo(con_out,&csbi); 1627 1628 /* The clip rectangle is the entire visible screen. */ 1629 rcClip.Left = csbi.srWindow.Left; 1630 rcClip.Top = csbi.srWindow.Top; 1631 rcClip.Right = csbi.srWindow.Right; 1632 rcClip.Bottom = csbi.srWindow.Bottom; 1633 1634 /* The source rectangle is the visible screen minus the last line. */ 1635 rcSrc = rcClip; 1636 rcSrc.Bottom--; 1637 1638 /* Move the top left corner of the source window down one row. */ 1639 new_org.X = rcSrc.Left; 1640 new_org.Y = rcSrc.Top + 1; 1641 1642 /* Fill the right character and attributes. */ 1643 fillchar.Char.AsciiChar = ' '; 1644 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 1645 fillchar.Attributes = curr_attr; 1646 ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 1647 _settextposition(1,1); 1648 } 1649#endif 1650#endif 1651#endif 1652#endif 1653} 1654 1655#if 0 1656/* 1657 * Remove the n topmost lines and scroll everything below it in the 1658 * window upward. This is needed to stop leaking the topmost line 1659 * into the scrollback buffer when we go down-one-line (in WIN32). 1660 */ 1661 public void 1662remove_top(n) 1663 int n; 1664{ 1665#if MSDOS_COMPILER==WIN32C 1666 SMALL_RECT rcSrc, rcClip; 1667 CHAR_INFO fillchar; 1668 COORD new_org; 1669 CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ 1670 1671 if (n >= sc_height - 1) 1672 { 1673 clear(); 1674 home(); 1675 return; 1676 } 1677 1678 flush(); 1679 1680 GetConsoleScreenBufferInfo(con_out, &csbi); 1681 1682 /* Get the extent of all-visible-rows-but-the-last. */ 1683 rcSrc.Left = csbi.srWindow.Left; 1684 rcSrc.Top = csbi.srWindow.Top + n; 1685 rcSrc.Right = csbi.srWindow.Right; 1686 rcSrc.Bottom = csbi.srWindow.Bottom; 1687 1688 /* Get the clip rectangle. */ 1689 rcClip.Left = rcSrc.Left; 1690 rcClip.Top = csbi.srWindow.Top; 1691 rcClip.Right = rcSrc.Right; 1692 rcClip.Bottom = rcSrc.Bottom ; 1693 1694 /* Move the source window up n rows. */ 1695 new_org.X = rcSrc.Left; 1696 new_org.Y = rcSrc.Top - n; 1697 1698 /* Fill the right character and attributes. */ 1699 fillchar.Char.AsciiChar = ' '; 1700 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 1701 fillchar.Attributes = curr_attr; 1702 1703 ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 1704 1705 /* Position cursor on first blank line. */ 1706 goto_line(sc_height - n - 1); 1707#endif 1708} 1709#endif 1710 1711#if MSDOS_COMPILER==WIN32C 1712/* 1713 * Clear the screen. 1714 */ 1715 static void 1716win32_clear() 1717{ 1718 /* 1719 * This will clear only the currently visible rows of the NT 1720 * console buffer, which means none of the precious scrollback 1721 * rows are touched making for faster scrolling. Note that, if 1722 * the window has fewer columns than the console buffer (i.e. 1723 * there is a horizontal scrollbar as well), the entire width 1724 * of the visible rows will be cleared. 1725 */ 1726 COORD topleft; 1727 DWORD nchars; 1728 DWORD winsz; 1729 CONSOLE_SCREEN_BUFFER_INFO csbi; 1730 1731 /* get the number of cells in the current buffer */ 1732 GetConsoleScreenBufferInfo(con_out, &csbi); 1733 winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); 1734 topleft.X = 0; 1735 topleft.Y = csbi.srWindow.Top; 1736 1737 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 1738 FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars); 1739 FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars); 1740} 1741 1742/* 1743 * Remove the n topmost lines and scroll everything below it in the 1744 * window upward. 1745 */ 1746 public void 1747win32_scroll_up(n) 1748 int n; 1749{ 1750 SMALL_RECT rcSrc, rcClip; 1751 CHAR_INFO fillchar; 1752 COORD topleft; 1753 COORD new_org; 1754 DWORD nchars; 1755 DWORD size; 1756 CONSOLE_SCREEN_BUFFER_INFO csbi; 1757 1758 if (n <= 0) 1759 return; 1760 1761 if (n >= sc_height - 1) 1762 { 1763 win32_clear(); 1764 _settextposition(1,1); 1765 return; 1766 } 1767 1768 /* Get the extent of what will remain visible after scrolling. */ 1769 GetConsoleScreenBufferInfo(con_out, &csbi); 1770 rcSrc.Left = csbi.srWindow.Left; 1771 rcSrc.Top = csbi.srWindow.Top + n; 1772 rcSrc.Right = csbi.srWindow.Right; 1773 rcSrc.Bottom = csbi.srWindow.Bottom; 1774 1775 /* Get the clip rectangle. */ 1776 rcClip.Left = rcSrc.Left; 1777 rcClip.Top = csbi.srWindow.Top; 1778 rcClip.Right = rcSrc.Right; 1779 rcClip.Bottom = rcSrc.Bottom ; 1780 1781 /* Move the source text to the top of the screen. */ 1782 new_org.X = rcSrc.Left; 1783 new_org.Y = 0; 1784 1785 /* Fill the right character and attributes. */ 1786 fillchar.Char.AsciiChar = ' '; 1787 fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color); 1788 1789 /* Scroll the window. */ 1790 SetConsoleTextAttribute(con_out, fillchar.Attributes); 1791 ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); 1792 1793 /* Clear remaining lines at bottom. */ 1794 topleft.X = csbi.dwCursorPosition.X; 1795 topleft.Y = rcSrc.Bottom - n; 1796 size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X); 1797 FillConsoleOutputCharacter(con_out, ' ', size, topleft, 1798 &nchars); 1799 FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft, 1800 &nchars); 1801 SetConsoleTextAttribute(con_out, curr_attr); 1802 1803 /* Move cursor n lines up from where it was. */ 1804 csbi.dwCursorPosition.Y -= n; 1805 SetConsoleCursorPosition(con_out, csbi.dwCursorPosition); 1806} 1807#endif 1808 1809/* 1810 * Move cursor to lower left corner of screen. 1811 */ 1812 public void 1813lower_left() 1814{ 1815#if !MSDOS_COMPILER 1816 tputs(sc_lower_left, 1, putchr); 1817#else 1818 flush(); 1819 _settextposition(sc_height, 1); 1820#endif 1821} 1822 1823/* 1824 * Move cursor to left position of current line. 1825 */ 1826 public void 1827line_left() 1828{ 1829#if !MSDOS_COMPILER 1830 tputs(sc_return, 1, putchr); 1831#else 1832 int row; 1833 flush(); 1834#if MSDOS_COMPILER==WIN32C 1835 { 1836 CONSOLE_SCREEN_BUFFER_INFO scr; 1837 GetConsoleScreenBufferInfo(con_out, &scr); 1838 row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 1839 } 1840#else 1841 { 1842 struct rccoord tpos = _gettextposition(); 1843 row = tpos.row; 1844 } 1845#endif 1846 _settextposition(row, 1); 1847#endif 1848} 1849 1850/* 1851 * Check if the console size has changed and reset internals 1852 * (in lieu of SIGWINCH for WIN32). 1853 */ 1854 public void 1855check_winch() 1856{ 1857#if MSDOS_COMPILER==WIN32C 1858 CONSOLE_SCREEN_BUFFER_INFO scr; 1859 COORD size; 1860 1861 if (con_out == INVALID_HANDLE_VALUE) 1862 return; 1863 1864 flush(); 1865 GetConsoleScreenBufferInfo(con_out, &scr); 1866 size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; 1867 size.X = scr.srWindow.Right - scr.srWindow.Left + 1; 1868 if (size.Y != sc_height || size.X != sc_width) 1869 { 1870 sc_height = size.Y; 1871 sc_width = size.X; 1872 if (!no_init && con_out_ours == con_out) 1873 SetConsoleScreenBufferSize(con_out, size); 1874 pos_init(); 1875 wscroll = (sc_height + 1) / 2; 1876 screen_trashed = 1; 1877 } 1878#endif 1879} 1880 1881/* 1882 * Goto a specific line on the screen. 1883 */ 1884 public void 1885goto_line(slinenum) 1886 int slinenum; 1887{ 1888#if !MSDOS_COMPILER 1889 tputs(tgoto(sc_move, 0, slinenum), 1, putchr); 1890#else 1891 flush(); 1892 _settextposition(slinenum+1, 1); 1893#endif 1894} 1895 1896#if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC 1897/* 1898 * Create an alternate screen which is all white. 1899 * This screen is used to create a "flash" effect, by displaying it 1900 * briefly and then switching back to the normal screen. 1901 * {{ Yuck! There must be a better way to get a visual bell. }} 1902 */ 1903 static void 1904create_flash() 1905{ 1906#if MSDOS_COMPILER==MSOFTC 1907 struct videoconfig w; 1908 char *blanks; 1909 int row, col; 1910 1911 _getvideoconfig(&w); 1912 videopages = w.numvideopages; 1913 if (videopages < 2) 1914 { 1915 at_enter(AT_STANDOUT); 1916 at_exit(); 1917 } else 1918 { 1919 _setactivepage(1); 1920 at_enter(AT_STANDOUT); 1921 blanks = (char *) ecalloc(w.numtextcols, sizeof(char)); 1922 for (col = 0; col < w.numtextcols; col++) 1923 blanks[col] = ' '; 1924 for (row = w.numtextrows; row > 0; row--) 1925 _outmem(blanks, w.numtextcols); 1926 _setactivepage(0); 1927 _setvisualpage(0); 1928 free(blanks); 1929 at_exit(); 1930 } 1931#else 1932#if MSDOS_COMPILER==BORLANDC 1933 register int n; 1934 1935 whitescreen = (unsigned short *) 1936 malloc(sc_width * sc_height * sizeof(short)); 1937 if (whitescreen == NULL) 1938 return; 1939 for (n = 0; n < sc_width * sc_height; n++) 1940 whitescreen[n] = 0x7020; 1941#else 1942#if MSDOS_COMPILER==WIN32C 1943 register int n; 1944 1945 whitescreen = (WORD *) 1946 malloc(sc_height * sc_width * sizeof(WORD)); 1947 if (whitescreen == NULL) 1948 return; 1949 /* Invert the standard colors. */ 1950 for (n = 0; n < sc_width * sc_height; n++) 1951 whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color); 1952#endif 1953#endif 1954#endif 1955 flash_created = 1; 1956} 1957#endif /* MSDOS_COMPILER */ 1958 1959/* 1960 * Output the "visual bell", if there is one. 1961 */ 1962 public void 1963vbell() 1964{ 1965#if !MSDOS_COMPILER 1966 if (*sc_visual_bell == '\0') 1967 return; 1968 tputs(sc_visual_bell, sc_height, putchr); 1969#else 1970#if MSDOS_COMPILER==DJGPPC 1971 ScreenVisualBell(); 1972#else 1973#if MSDOS_COMPILER==MSOFTC 1974 /* 1975 * Create a flash screen on the second video page. 1976 * Switch to that page, then switch back. 1977 */ 1978 if (!flash_created) 1979 create_flash(); 1980 if (videopages < 2) 1981 return; 1982 _setvisualpage(1); 1983 delay(100); 1984 _setvisualpage(0); 1985#else 1986#if MSDOS_COMPILER==BORLANDC 1987 unsigned short *currscreen; 1988 1989 /* 1990 * Get a copy of the current screen. 1991 * Display the flash screen. 1992 * Then restore the old screen. 1993 */ 1994 if (!flash_created) 1995 create_flash(); 1996 if (whitescreen == NULL) 1997 return; 1998 currscreen = (unsigned short *) 1999 malloc(sc_width * sc_height * sizeof(short)); 2000 if (currscreen == NULL) return; 2001 gettext(1, 1, sc_width, sc_height, currscreen); 2002 puttext(1, 1, sc_width, sc_height, whitescreen); 2003 delay(100); 2004 puttext(1, 1, sc_width, sc_height, currscreen); 2005 free(currscreen); 2006#else 2007#if MSDOS_COMPILER==WIN32C 2008 /* paint screen with an inverse color */ 2009 clear(); 2010 2011 /* leave it displayed for 100 msec. */ 2012 Sleep(100); 2013 2014 /* restore with a redraw */ 2015 repaint(); 2016#endif 2017#endif 2018#endif 2019#endif 2020#endif 2021} 2022 2023/* 2024 * Make a noise. 2025 */ 2026 static void 2027beep() 2028{ 2029#if !MSDOS_COMPILER 2030 putchr(CONTROL('G')); 2031#else 2032#if MSDOS_COMPILER==WIN32C 2033 MessageBeep(0); 2034#else 2035 write(1, "\7", 1); 2036#endif 2037#endif 2038} 2039 2040/* 2041 * Ring the terminal bell. 2042 */ 2043 public void 2044bell() 2045{ 2046 if (quiet == VERY_QUIET) 2047 vbell(); 2048 else 2049 beep(); 2050} 2051 2052/* 2053 * Clear the screen. 2054 */ 2055 public void 2056clear() 2057{ 2058#if !MSDOS_COMPILER 2059 tputs(sc_clear, sc_height, putchr); 2060#else 2061 flush(); 2062#if MSDOS_COMPILER==WIN32C 2063 win32_clear(); 2064#else 2065 _clearscreen(_GCLEARSCREEN); 2066#endif 2067#endif 2068} 2069 2070/* 2071 * Clear from the cursor to the end of the cursor's line. 2072 * {{ This must not move the cursor. }} 2073 */ 2074 public void 2075clear_eol() 2076{ 2077#if !MSDOS_COMPILER 2078 tputs(sc_eol_clear, 1, putchr); 2079#else 2080#if MSDOS_COMPILER==MSOFTC 2081 short top, left; 2082 short bot, right; 2083 struct rccoord tpos; 2084 2085 flush(); 2086 /* 2087 * Save current state. 2088 */ 2089 tpos = _gettextposition(); 2090 _gettextwindow(&top, &left, &bot, &right); 2091 /* 2092 * Set a temporary window to the current line, 2093 * from the cursor's position to the right edge of the screen. 2094 * Then clear that window. 2095 */ 2096 _settextwindow(tpos.row, tpos.col, tpos.row, sc_width); 2097 _clearscreen(_GWINDOW); 2098 /* 2099 * Restore state. 2100 */ 2101 _settextwindow(top, left, bot, right); 2102 _settextposition(tpos.row, tpos.col); 2103#else 2104#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2105 flush(); 2106 clreol(); 2107#else 2108#if MSDOS_COMPILER==WIN32C 2109 DWORD nchars; 2110 COORD cpos; 2111 CONSOLE_SCREEN_BUFFER_INFO scr; 2112 2113 flush(); 2114 memset(&scr, 0, sizeof(scr)); 2115 GetConsoleScreenBufferInfo(con_out, &scr); 2116 cpos.X = scr.dwCursorPosition.X; 2117 cpos.Y = scr.dwCursorPosition.Y; 2118 curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); 2119 FillConsoleOutputAttribute(con_out, curr_attr, 2120 scr.dwSize.X - cpos.X, cpos, &nchars); 2121 FillConsoleOutputCharacter(con_out, ' ', 2122 scr.dwSize.X - cpos.X, cpos, &nchars); 2123#endif 2124#endif 2125#endif 2126#endif 2127} 2128 2129/* 2130 * Clear the current line. 2131 * Clear the screen if there's off-screen memory below the display. 2132 */ 2133 static void 2134clear_eol_bot() 2135{ 2136#if MSDOS_COMPILER 2137 clear_eol(); 2138#else 2139 if (below_mem) 2140 tputs(sc_eos_clear, 1, putchr); 2141 else 2142 tputs(sc_eol_clear, 1, putchr); 2143#endif 2144} 2145 2146/* 2147 * Clear the bottom line of the display. 2148 * Leave the cursor at the beginning of the bottom line. 2149 */ 2150 public void 2151clear_bot() 2152{ 2153 /* 2154 * If we're in a non-normal attribute mode, temporarily exit 2155 * the mode while we do the clear. Some terminals fill the 2156 * cleared area with the current attribute. 2157 */ 2158 if (oldbot) 2159 lower_left(); 2160 else 2161 line_left(); 2162 2163 if (attrmode == AT_NORMAL) 2164 clear_eol_bot(); 2165 else 2166 { 2167 int saved_attrmode = attrmode; 2168 2169 at_exit(); 2170 clear_eol_bot(); 2171 at_enter(saved_attrmode); 2172 } 2173} 2174 2175 public void 2176at_enter(attr) 2177 int attr; 2178{ 2179 attr = apply_at_specials(attr); 2180 2181#if !MSDOS_COMPILER 2182 /* The one with the most priority is last. */ 2183 if (attr & AT_UNDERLINE) 2184 tputs(sc_u_in, 1, putchr); 2185 if (attr & AT_BOLD) 2186 tputs(sc_b_in, 1, putchr); 2187 if (attr & AT_BLINK) 2188 tputs(sc_bl_in, 1, putchr); 2189 if (attr & AT_STANDOUT) 2190 tputs(sc_s_in, 1, putchr); 2191#else 2192 flush(); 2193 /* The one with the most priority is first. */ 2194 if (attr & AT_STANDOUT) 2195 { 2196 SETCOLORS(so_fg_color, so_bg_color); 2197 } else if (attr & AT_BLINK) 2198 { 2199 SETCOLORS(bl_fg_color, bl_bg_color); 2200 } 2201 else if (attr & AT_BOLD) 2202 { 2203 SETCOLORS(bo_fg_color, bo_bg_color); 2204 } 2205 else if (attr & AT_UNDERLINE) 2206 { 2207 SETCOLORS(ul_fg_color, ul_bg_color); 2208 } 2209#endif 2210 2211 attrmode = attr; 2212} 2213 2214 public void 2215at_exit() 2216{ 2217#if !MSDOS_COMPILER 2218 /* Undo things in the reverse order we did them. */ 2219 if (attrmode & AT_STANDOUT) 2220 tputs(sc_s_out, 1, putchr); 2221 if (attrmode & AT_BLINK) 2222 tputs(sc_bl_out, 1, putchr); 2223 if (attrmode & AT_BOLD) 2224 tputs(sc_b_out, 1, putchr); 2225 if (attrmode & AT_UNDERLINE) 2226 tputs(sc_u_out, 1, putchr); 2227#else 2228 flush(); 2229 SETCOLORS(nm_fg_color, nm_bg_color); 2230#endif 2231 2232 attrmode = AT_NORMAL; 2233} 2234 2235 public void 2236at_switch(attr) 2237 int attr; 2238{ 2239 int new_attrmode = apply_at_specials(attr); 2240 int ignore_modes = AT_ANSI; 2241 2242 if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) 2243 { 2244 at_exit(); 2245 at_enter(attr); 2246 } 2247} 2248 2249 public int 2250is_at_equiv(attr1, attr2) 2251 int attr1; 2252 int attr2; 2253{ 2254 attr1 = apply_at_specials(attr1); 2255 attr2 = apply_at_specials(attr2); 2256 2257 return (attr1 == attr2); 2258} 2259 2260 public int 2261apply_at_specials(attr) 2262 int attr; 2263{ 2264 if (attr & AT_BINARY) 2265 attr |= binattr; 2266 if (attr & AT_HILITE) 2267 attr |= AT_STANDOUT; 2268 attr &= ~(AT_BINARY|AT_HILITE); 2269 2270 return attr; 2271} 2272 2273#if 0 /* No longer used */ 2274/* 2275 * Erase the character to the left of the cursor 2276 * and move the cursor left. 2277 */ 2278 public void 2279backspace() 2280{ 2281#if !MSDOS_COMPILER 2282 /* 2283 * Erase the previous character by overstriking with a space. 2284 */ 2285 tputs(sc_backspace, 1, putchr); 2286 putchr(' '); 2287 tputs(sc_backspace, 1, putchr); 2288#else 2289#if MSDOS_COMPILER==MSOFTC 2290 struct rccoord tpos; 2291 2292 flush(); 2293 tpos = _gettextposition(); 2294 if (tpos.col <= 1) 2295 return; 2296 _settextposition(tpos.row, tpos.col-1); 2297 _outtext(" "); 2298 _settextposition(tpos.row, tpos.col-1); 2299#else 2300#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2301 cputs("\b"); 2302#else 2303#if MSDOS_COMPILER==WIN32C 2304 COORD cpos; 2305 DWORD cChars; 2306 CONSOLE_SCREEN_BUFFER_INFO scr; 2307 2308 flush(); 2309 GetConsoleScreenBufferInfo(con_out, &scr); 2310 cpos = scr.dwCursorPosition; 2311 if (cpos.X <= 0) 2312 return; 2313 cpos.X--; 2314 SetConsoleCursorPosition(con_out, cpos); 2315 FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); 2316 SetConsoleCursorPosition(con_out, cpos); 2317#endif 2318#endif 2319#endif 2320#endif 2321} 2322#endif /* 0 */ 2323 2324/* 2325 * Output a plain backspace, without erasing the previous char. 2326 */ 2327 public void 2328putbs() 2329{ 2330#if !MSDOS_COMPILER 2331 tputs(sc_backspace, 1, putchr); 2332#else 2333 int row, col; 2334 2335 flush(); 2336 { 2337#if MSDOS_COMPILER==MSOFTC 2338 struct rccoord tpos; 2339 tpos = _gettextposition(); 2340 row = tpos.row; 2341 col = tpos.col; 2342#else 2343#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 2344 row = wherey(); 2345 col = wherex(); 2346#else 2347#if MSDOS_COMPILER==WIN32C 2348 CONSOLE_SCREEN_BUFFER_INFO scr; 2349 GetConsoleScreenBufferInfo(con_out, &scr); 2350 row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; 2351 col = scr.dwCursorPosition.X - scr.srWindow.Left + 1; 2352#endif 2353#endif 2354#endif 2355 } 2356 if (col <= 1) 2357 return; 2358 _settextposition(row, col-1); 2359#endif /* MSDOS_COMPILER */ 2360} 2361 2362#if MSDOS_COMPILER==WIN32C 2363/* 2364 * Determine whether an input character is waiting to be read. 2365 */ 2366 static int 2367win32_kbhit(tty) 2368 HANDLE tty; 2369{ 2370 INPUT_RECORD ip; 2371 DWORD read; 2372 2373 if (keyCount > 0) 2374 return (TRUE); 2375 2376 currentKey.ascii = 0; 2377 currentKey.scan = 0; 2378 2379 /* 2380 * Wait for a real key-down event, but 2381 * ignore SHIFT and CONTROL key events. 2382 */ 2383 do 2384 { 2385 PeekConsoleInput(tty, &ip, 1, &read); 2386 if (read == 0) 2387 return (FALSE); 2388 ReadConsoleInput(tty, &ip, 1, &read); 2389 } while (ip.EventType != KEY_EVENT || 2390 ip.Event.KeyEvent.bKeyDown != TRUE || 2391 ip.Event.KeyEvent.wVirtualScanCode == 0 || 2392 ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || 2393 ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || 2394 ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU); 2395 2396 currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar; 2397 currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode; 2398 keyCount = ip.Event.KeyEvent.wRepeatCount; 2399 2400 if (ip.Event.KeyEvent.dwControlKeyState & 2401 (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) 2402 { 2403 switch (currentKey.scan) 2404 { 2405 case PCK_ALT_E: /* letter 'E' */ 2406 currentKey.ascii = 0; 2407 break; 2408 } 2409 } else if (ip.Event.KeyEvent.dwControlKeyState & 2410 (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) 2411 { 2412 switch (currentKey.scan) 2413 { 2414 case PCK_RIGHT: /* right arrow */ 2415 currentKey.scan = PCK_CTL_RIGHT; 2416 break; 2417 case PCK_LEFT: /* left arrow */ 2418 currentKey.scan = PCK_CTL_LEFT; 2419 break; 2420 case PCK_DELETE: /* delete */ 2421 currentKey.scan = PCK_CTL_DELETE; 2422 break; 2423 } 2424 } 2425 return (TRUE); 2426} 2427 2428/* 2429 * Read a character from the keyboard. 2430 */ 2431 public char 2432WIN32getch(tty) 2433 int tty; 2434{ 2435 int ascii; 2436 2437 if (pending_scancode) 2438 { 2439 pending_scancode = 0; 2440 return ((char)(currentKey.scan & 0x00FF)); 2441 } 2442 2443 while (win32_kbhit((HANDLE)tty) == FALSE) 2444 { 2445 Sleep(20); 2446 if (ABORT_SIGS()) 2447 return ('\003'); 2448 continue; 2449 } 2450 keyCount --; 2451 ascii = currentKey.ascii; 2452 /* 2453 * On PC's, the extended keys return a 2 byte sequence beginning 2454 * with '00', so if the ascii code is 00, the next byte will be 2455 * the lsb of the scan code. 2456 */ 2457 pending_scancode = (ascii == 0x00); 2458 return ((char)ascii); 2459} 2460#endif 2461