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