1 /* 2 * Copyright (C) 1984-2002 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12 /* 13 * Routines which deal with the characteristics of the terminal. 14 * Uses termcap to be as terminal-independent as possible. 15 */ 16 17 #include "less.h" 18 #include "cmd.h" 19 20 #if MSDOS_COMPILER 21 #include "pckeys.h" 22 #if MSDOS_COMPILER==MSOFTC 23 #include <graph.h> 24 #else 25 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 26 #include <conio.h> 27 #if MSDOS_COMPILER==DJGPPC 28 #include <pc.h> 29 extern int fd0; 30 #endif 31 #else 32 #if MSDOS_COMPILER==WIN32C 33 #include <windows.h> 34 #endif 35 #endif 36 #endif 37 #include <time.h> 38 39 #else 40 41 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 42 #include <termios.h> 43 #if HAVE_SYS_IOCTL_H 44 #include <sys/ioctl.h> 45 #endif 46 #else 47 #if HAVE_TERMIO_H 48 #include <termio.h> 49 #else 50 #if HAVE_SGSTAT_H 51 #include <sgstat.h> 52 #else 53 #include <sgtty.h> 54 #endif 55 #if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD)) 56 #include <sys/ioctl.h> 57 #endif 58 #endif 59 #endif 60 61 #if HAVE_TERMCAP_H 62 #include <termcap.h> 63 #endif 64 #ifdef _OSK 65 #include <signal.h> 66 #endif 67 #if OS2 68 #include <sys/signal.h> 69 #include "pckeys.h" 70 #endif 71 #if HAVE_SYS_STREAM_H 72 #include <sys/stream.h> 73 #endif 74 #if HAVE_SYS_PTEM_H 75 #include <sys/ptem.h> 76 #endif 77 78 #endif /* MSDOS_COMPILER */ 79 80 /* 81 * Check for broken termios package that forces you to manually 82 * set the line discipline. 83 */ 84 #ifdef __ultrix__ 85 #define MUST_SET_LINE_DISCIPLINE 1 86 #else 87 #define MUST_SET_LINE_DISCIPLINE 0 88 #endif 89 90 #if OS2 91 #define DEFAULT_TERM "ansi" 92 static char *windowid; 93 #else 94 #define DEFAULT_TERM "unknown" 95 #endif 96 97 #if MSDOS_COMPILER==MSOFTC 98 static int videopages; 99 static long msec_loops; 100 static int flash_created = 0; 101 #define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } 102 #endif 103 104 #if MSDOS_COMPILER==BORLANDC 105 static unsigned short *whitescreen; 106 static int flash_created = 0; 107 #endif 108 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 109 #define _settextposition(y,x) gotoxy(x,y) 110 #define _clearscreen(m) clrscr() 111 #define _outtext(s) cputs(s) 112 #define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } 113 extern int sc_height; 114 #endif 115 116 #if MSDOS_COMPILER==WIN32C 117 struct keyRecord 118 { 119 int ascii; 120 int scan; 121 } currentKey; 122 123 static int keyCount = 0; 124 static WORD curr_attr; 125 static int pending_scancode = 0; 126 static WORD *whitescreen; 127 128 static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */ 129 static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */ 130 HANDLE con_out = INVALID_HANDLE_VALUE; /* current console */ 131 132 extern int quitting; 133 static void win32_init_term(); 134 static void win32_deinit_term(); 135 136 #define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) 137 #define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) 138 #define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) 139 #define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ 140 if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ 141 error("SETCOLORS failed"); } 142 #endif 143 144 #if MSDOS_COMPILER 145 public int nm_fg_color; /* Color of normal text */ 146 public int nm_bg_color; 147 public int bo_fg_color; /* Color of bold text */ 148 public int bo_bg_color; 149 public int ul_fg_color; /* Color of underlined text */ 150 public int ul_bg_color; 151 public int so_fg_color; /* Color of standout text */ 152 public int so_bg_color; 153 public int bl_fg_color; /* Color of blinking text */ 154 public int bl_bg_color; 155 static int sy_fg_color; /* Color of system text (before less) */ 156 static int sy_bg_color; 157 158 #else 159 160 /* 161 * Strings passed to tputs() to do various terminal functions. 162 */ 163 static char 164 *sc_pad, /* Pad string */ 165 *sc_home, /* Cursor home */ 166 *sc_addline, /* Add line, scroll down following lines */ 167 *sc_lower_left, /* Cursor to last line, first column */ 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 188 static int init_done = 0; 189 190 public int auto_wrap; /* Terminal does \r\n when write past margin */ 191 public int ignaw; /* Terminal ignores \n immediately after wrap */ 192 public int erase_char, kill_char; /* The user's erase and line-kill chars */ 193 public int werase_char; /* The user's word-erase char */ 194 public int sc_width, sc_height; /* Height & width of screen */ 195 public int bo_s_width, bo_e_width; /* Printing width of boldface seq */ 196 public int ul_s_width, ul_e_width; /* Printing width of underline seq */ 197 public int so_s_width, so_e_width; /* Printing width of standout seq */ 198 public int bl_s_width, bl_e_width; /* Printing width of blink seq */ 199 public int above_mem, below_mem; /* Memory retained above/below screen */ 200 public int can_goto_line; /* Can move cursor to any line */ 201 public int clear_bg; /* Clear fills with background color */ 202 public int missing_cap = 0; /* Some capability is missing */ 203 204 static int attrmode = AT_NORMAL; 205 206 #if !MSDOS_COMPILER 207 static char *cheaper(); 208 static void tmodes(); 209 #endif 210 211 /* 212 * These two variables are sometimes defined in, 213 * and needed by, the termcap library. 214 */ 215 #if MUST_DEFINE_OSPEED 216 extern short ospeed; /* Terminal output baud rate */ 217 extern char PC; /* Pad character */ 218 #endif 219 #ifdef _OSK 220 short ospeed; 221 char PC_, *UP, *BC; 222 #endif 223 224 extern int quiet; /* If VERY_QUIET, use visual bell for bell */ 225 extern int no_back_scroll; 226 extern int swindow; 227 extern int no_init; 228 extern int no_keypad; 229 extern int sigs; 230 extern int wscroll; 231 extern int screen_trashed; 232 extern int tty; 233 extern int quit_at_eof; 234 extern int ismore; 235 #if HILITE_SEARCH 236 extern int hilite_search; 237 #endif 238 239 extern char *tgetstr(); 240 extern char *tgoto(); 241 242 243 /* 244 * Change terminal to "raw mode", or restore to "normal" mode. 245 * "Raw mode" means 246 * 1. An outstanding read will complete on receipt of a single keystroke. 247 * 2. Input is not echoed. 248 * 3. On output, \n is mapped to \r\n. 249 * 4. \t is NOT expanded into spaces. 250 * 5. Signal-causing characters such as ctrl-C (interrupt), 251 * etc. are NOT disabled. 252 * It doesn't matter whether an input \n is mapped to \r, or vice versa. 253 */ 254 public void 255 raw_mode(on) 256 int on; 257 { 258 static int curr_on = 0; 259 260 if (on == curr_on) 261 return; 262 #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS 263 { 264 struct termios s; 265 static struct termios save_term; 266 static int saved_term = 0; 267 268 if (on) 269 { 270 /* 271 * Get terminal modes. 272 */ 273 tcgetattr(tty, &s); 274 275 /* 276 * Save modes and set certain variables dependent on modes. 277 */ 278 if (!saved_term) 279 { 280 save_term = s; 281 saved_term = 1; 282 } 283 #if HAVE_OSPEED 284 switch (cfgetospeed(&s)) 285 { 286 #ifdef B0 287 case B0: ospeed = 0; break; 288 #endif 289 #ifdef B50 290 case B50: ospeed = 1; break; 291 #endif 292 #ifdef B75 293 case B75: ospeed = 2; break; 294 #endif 295 #ifdef B110 296 case B110: ospeed = 3; break; 297 #endif 298 #ifdef B134 299 case B134: ospeed = 4; break; 300 #endif 301 #ifdef B150 302 case B150: ospeed = 5; break; 303 #endif 304 #ifdef B200 305 case B200: ospeed = 6; break; 306 #endif 307 #ifdef B300 308 case B300: ospeed = 7; break; 309 #endif 310 #ifdef B600 311 case B600: ospeed = 8; break; 312 #endif 313 #ifdef B1200 314 case B1200: ospeed = 9; break; 315 #endif 316 #ifdef B1800 317 case B1800: ospeed = 10; break; 318 #endif 319 #ifdef B2400 320 case B2400: ospeed = 11; break; 321 #endif 322 #ifdef B4800 323 case B4800: ospeed = 12; break; 324 #endif 325 #ifdef B9600 326 case B9600: ospeed = 13; break; 327 #endif 328 #ifdef EXTA 329 case EXTA: ospeed = 14; break; 330 #endif 331 #ifdef EXTB 332 case EXTB: ospeed = 15; break; 333 #endif 334 #ifdef B57600 335 case B57600: ospeed = 16; break; 336 #endif 337 #ifdef B115200 338 case B115200: ospeed = 17; break; 339 #endif 340 default: ; 341 } 342 #endif 343 erase_char = s.c_cc[VERASE]; 344 kill_char = s.c_cc[VKILL]; 345 #ifdef VWERASE 346 werase_char = s.c_cc[VWERASE]; 347 #else 348 werase_char = CONTROL('W'); 349 #endif 350 351 /* 352 * Set the modes to the way we want them. 353 */ 354 s.c_lflag &= ~(0 355 #ifdef ICANON 356 | ICANON 357 #endif 358 #ifdef ECHO 359 | ECHO 360 #endif 361 #ifdef ECHOE 362 | ECHOE 363 #endif 364 #ifdef ECHOK 365 | ECHOK 366 #endif 367 #if ECHONL 368 | ECHONL 369 #endif 370 ); 371 372 s.c_oflag |= (0 373 #ifdef OXTABS 374 | OXTABS 375 #else 376 #ifdef TAB3 377 | TAB3 378 #else 379 #ifdef XTABS 380 | XTABS 381 #endif 382 #endif 383 #endif 384 #ifdef OPOST 385 | OPOST 386 #endif 387 #ifdef ONLCR 388 | ONLCR 389 #endif 390 ); 391 392 s.c_oflag &= ~(0 393 #ifdef ONOEOT 394 | ONOEOT 395 #endif 396 #ifdef OCRNL 397 | OCRNL 398 #endif 399 #ifdef ONOCR 400 | ONOCR 401 #endif 402 #ifdef ONLRET 403 | ONLRET 404 #endif 405 ); 406 s.c_cc[VMIN] = 1; 407 s.c_cc[VTIME] = 0; 408 #ifdef VLNEXT 409 s.c_cc[VLNEXT] = 0; 410 #endif 411 #ifdef VDSUSP 412 s.c_cc[VDSUSP] = 0; 413 #endif 414 #if MUST_SET_LINE_DISCIPLINE 415 /* 416 * System's termios is broken; need to explicitly 417 * request TERMIODISC line discipline. 418 */ 419 s.c_line = TERMIODISC; 420 #endif 421 } else 422 { 423 /* 424 * Restore saved modes. 425 */ 426 s = save_term; 427 } 428 tcsetattr(tty, TCSASOFT | TCSADRAIN, &s); 429 #if HAVE_FSYNC 430 fsync(tty); 431 #endif 432 #if MUST_SET_LINE_DISCIPLINE 433 if (!on) 434 { 435 /* 436 * Broken termios *ignores* any line discipline 437 * except TERMIODISC. A different old line discipline 438 * is therefore not restored, yet. Restore the old 439 * line discipline by hand. 440 */ 441 ioctl(tty, TIOCSETD, &save_term.c_line); 442 } 443 #endif 444 } 445 #else 446 #ifdef TCGETA 447 { 448 struct termio s; 449 static struct termio save_term; 450 static int saved_term = 0; 451 452 if (on) 453 { 454 /* 455 * Get terminal modes. 456 */ 457 ioctl(tty, TCGETA, &s); 458 459 /* 460 * Save modes and set certain variables dependent on modes. 461 */ 462 if (!saved_term) 463 { 464 save_term = s; 465 saved_term = 1; 466 } 467 #if HAVE_OSPEED 468 ospeed = s.c_cflag & CBAUD; 469 #endif 470 erase_char = s.c_cc[VERASE]; 471 kill_char = s.c_cc[VKILL]; 472 #ifdef VWERASE 473 werase_char = s.c_cc[VWERASE]; 474 #else 475 werase_char = CONTROL('W'); 476 #endif 477 478 /* 479 * Set the modes to the way we want them. 480 */ 481 s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); 482 s.c_oflag |= (OPOST|ONLCR|TAB3); 483 s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); 484 s.c_cc[VMIN] = 1; 485 s.c_cc[VTIME] = 0; 486 } else 487 { 488 /* 489 * Restore saved modes. 490 */ 491 s = save_term; 492 } 493 ioctl(tty, TCSETAW, &s); 494 } 495 #else 496 #ifdef TIOCGETP 497 { 498 struct sgttyb s; 499 static struct sgttyb save_term; 500 static int saved_term = 0; 501 502 if (on) 503 { 504 /* 505 * Get terminal modes. 506 */ 507 ioctl(tty, TIOCGETP, &s); 508 509 /* 510 * Save modes and set certain variables dependent on modes. 511 */ 512 if (!saved_term) 513 { 514 save_term = s; 515 saved_term = 1; 516 } 517 #if HAVE_OSPEED 518 ospeed = s.sg_ospeed; 519 #endif 520 erase_char = s.sg_erase; 521 kill_char = s.sg_kill; 522 werase_char = CONTROL('W'); 523 524 /* 525 * Set the modes to the way we want them. 526 */ 527 s.sg_flags |= CBREAK; 528 s.sg_flags &= ~(ECHO|XTABS); 529 } else 530 { 531 /* 532 * Restore saved modes. 533 */ 534 s = save_term; 535 } 536 ioctl(tty, TIOCSETN, &s); 537 } 538 #else 539 #ifdef _OSK 540 { 541 struct sgbuf s; 542 static struct sgbuf save_term; 543 static int saved_term = 0; 544 545 if (on) 546 { 547 /* 548 * Get terminal modes. 549 */ 550 _gs_opt(tty, &s); 551 552 /* 553 * Save modes and set certain variables dependent on modes. 554 */ 555 if (!saved_term) 556 { 557 save_term = s; 558 saved_term = 1; 559 } 560 erase_char = s.sg_bspch; 561 kill_char = s.sg_dlnch; 562 werase_char = CONTROL('W'); 563 564 /* 565 * Set the modes to the way we want them. 566 */ 567 s.sg_echo = 0; 568 s.sg_eofch = 0; 569 s.sg_pause = 0; 570 s.sg_psch = 0; 571 } else 572 { 573 /* 574 * Restore saved modes. 575 */ 576 s = save_term; 577 } 578 _ss_opt(tty, &s); 579 } 580 #else 581 /* MS-DOS, Windows, or OS2 */ 582 #if OS2 583 /* OS2 */ 584 LSIGNAL(SIGINT, SIG_IGN); 585 #endif 586 erase_char = '\b'; 587 #if MSDOS_COMPILER==DJGPPC 588 kill_char = CONTROL('U'); 589 /* 590 * So that when we shell out or run another program, its 591 * stdin is in cooked mode. We do not switch stdin to binary 592 * mode if fd0 is zero, since that means we were called before 593 * tty was reopened in open_getchr, in which case we would be 594 * changing the original stdin device outside less. 595 */ 596 if (fd0 != 0) 597 setmode(0, on ? O_BINARY : O_TEXT); 598 #else 599 kill_char = ESC; 600 #endif 601 werase_char = CONTROL('W'); 602 #endif 603 #endif 604 #endif 605 #endif 606 curr_on = on; 607 } 608 609 #if !MSDOS_COMPILER 610 /* 611 * Some glue to prevent calling termcap functions if tgetent() failed. 612 */ 613 static int hardcopy; 614 615 static char * 616 ltget_env(capname) 617 char *capname; 618 { 619 char name[16]; 620 621 strlcpy(name, "LESS_TERMCAP_", sizeof(name)); 622 strlcat(name, capname, sizeof(name)); 623 return (lgetenv(name)); 624 } 625 626 static int 627 ltgetflag(capname) 628 char *capname; 629 { 630 char *s; 631 632 if ((s = ltget_env(capname)) != NULL) 633 return (*s != '\0' && *s != '0'); 634 if (hardcopy) 635 return (0); 636 return (tgetflag(capname)); 637 } 638 639 static int 640 ltgetnum(capname) 641 char *capname; 642 { 643 char *s; 644 645 if ((s = ltget_env(capname)) != NULL) 646 return (atoi(s)); 647 if (hardcopy) 648 return (-1); 649 return (tgetnum(capname)); 650 } 651 652 static char * 653 ltgetstr(capname, pp) 654 char *capname; 655 char **pp; 656 { 657 char *s; 658 659 if ((s = ltget_env(capname)) != NULL) 660 return (s); 661 if (hardcopy) 662 return (NULL); 663 return (tgetstr(capname, pp)); 664 } 665 #endif /* MSDOS_COMPILER */ 666 667 /* 668 * Get size of the output screen. 669 */ 670 public void 671 scrsize() 672 { 673 register char *s; 674 int sys_height; 675 int sys_width; 676 #if !MSDOS_COMPILER 677 int n; 678 #endif 679 680 #define DEF_SC_WIDTH 80 681 #if MSDOS_COMPILER 682 #define DEF_SC_HEIGHT 25 683 #else 684 #define DEF_SC_HEIGHT 24 685 #endif 686 687 688 sys_width = sys_height = 0; 689 690 #if MSDOS_COMPILER==MSOFTC 691 { 692 struct videoconfig w; 693 _getvideoconfig(&w); 694 sys_height = w.numtextrows; 695 sys_width = w.numtextcols; 696 } 697 #else 698 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 699 { 700 struct text_info w; 701 gettextinfo(&w); 702 sys_height = w.screenheight; 703 sys_width = w.screenwidth; 704 } 705 #else 706 #if MSDOS_COMPILER==WIN32C 707 { 708 CONSOLE_SCREEN_BUFFER_INFO scr; 709 GetConsoleScreenBufferInfo(con_out, &scr); 710 sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; 711 sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; 712 } 713 #else 714 #if OS2 715 { 716 int s[2]; 717 _scrsize(s); 718 sys_width = s[0]; 719 sys_height = s[1]; 720 /* 721 * When using terminal emulators for XFree86/OS2, the 722 * _scrsize function does not work well. 723 * Call the scrsize.exe program to get the window size. 724 */ 725 windowid = getenv("WINDOWID"); 726 if (windowid != NULL) 727 { 728 FILE *fd = popen("scrsize", "rt"); 729 if (fd != NULL) 730 { 731 int w, h; 732 fscanf(fd, "%i %i", &w, &h); 733 if (w > 0 && h > 0) 734 { 735 sys_width = w; 736 sys_height = h; 737 } 738 pclose(fd); 739 } 740 } 741 } 742 #else 743 #ifdef TIOCGWINSZ 744 { 745 struct winsize w; 746 if (ioctl(2, TIOCGWINSZ, &w) == 0) 747 { 748 if (w.ws_row > 0) 749 sys_height = w.ws_row; 750 if (w.ws_col > 0) 751 sys_width = w.ws_col; 752 } 753 } 754 #else 755 #ifdef WIOCGETD 756 { 757 struct uwdata w; 758 if (ioctl(2, WIOCGETD, &w) == 0) 759 { 760 if (w.uw_height > 0) 761 sys_height = w.uw_height / w.uw_vs; 762 if (w.uw_width > 0) 763 sys_width = w.uw_width / w.uw_hs; 764 } 765 } 766 #endif 767 #endif 768 #endif 769 #endif 770 #endif 771 #endif 772 773 if (sys_height > 0) 774 sc_height = sys_height; 775 else if ((s = lgetenv("LINES")) != NULL) 776 sc_height = atoi(s); 777 #if !MSDOS_COMPILER 778 else if ((n = ltgetnum("li")) > 0) 779 sc_height = n; 780 #endif 781 else 782 sc_height = DEF_SC_HEIGHT; 783 784 if (sys_width > 0) 785 sc_width = sys_width; 786 else if ((s = lgetenv("COLUMNS")) != NULL) 787 sc_width = atoi(s); 788 #if !MSDOS_COMPILER 789 else if ((n = ltgetnum("co")) > 0) 790 sc_width = n; 791 #endif 792 else 793 sc_width = DEF_SC_WIDTH; 794 } 795 796 #if MSDOS_COMPILER==MSOFTC 797 /* 798 * Figure out how many empty loops it takes to delay a millisecond. 799 */ 800 static void 801 get_clock() 802 { 803 clock_t start; 804 805 /* 806 * Get synchronized at the start of a tick. 807 */ 808 start = clock(); 809 while (clock() == start) 810 ; 811 /* 812 * Now count loops till the next tick. 813 */ 814 start = clock(); 815 msec_loops = 0; 816 while (clock() == start) 817 msec_loops++; 818 /* 819 * Convert from (loops per clock) to (loops per millisecond). 820 */ 821 msec_loops *= CLOCKS_PER_SEC; 822 msec_loops /= 1000; 823 } 824 825 /* 826 * Delay for a specified number of milliseconds. 827 */ 828 static void 829 dummy_func() 830 { 831 static long delay_dummy = 0; 832 delay_dummy++; 833 } 834 835 static void 836 delay(msec) 837 int msec; 838 { 839 long i; 840 841 while (msec-- > 0) 842 { 843 for (i = 0; i < msec_loops; i++) 844 { 845 /* 846 * Make it look like we're doing something here, 847 * so the optimizer doesn't remove the whole loop. 848 */ 849 dummy_func(); 850 } 851 } 852 } 853 #endif 854 855 /* 856 * Return the characters actually input by a "special" key. 857 */ 858 public char * 859 special_key_str(key) 860 int key; 861 { 862 static char tbuf[40]; 863 char *s; 864 #if MSDOS_COMPILER || OS2 865 static char k_right[] = { '\340', PCK_RIGHT, 0 }; 866 static char k_left[] = { '\340', PCK_LEFT, 0 }; 867 static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; 868 static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; 869 static char k_insert[] = { '\340', PCK_INSERT, 0 }; 870 static char k_delete[] = { '\340', PCK_DELETE, 0 }; 871 static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; 872 static char k_ctl_backspace[] = { '\177', 0 }; 873 static char k_home[] = { '\340', PCK_HOME, 0 }; 874 static char k_end[] = { '\340', PCK_END, 0 }; 875 static char k_up[] = { '\340', PCK_UP, 0 }; 876 static char k_down[] = { '\340', PCK_DOWN, 0 }; 877 static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; 878 static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; 879 static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; 880 static char k_f1[] = { '\340', PCK_F1, 0 }; 881 #endif 882 #if !MSDOS_COMPILER 883 char *sp = tbuf; 884 #endif 885 886 switch (key) 887 { 888 #if OS2 889 /* 890 * If windowid is not NULL, assume less is executed in 891 * the XFree86 environment. 892 */ 893 case SK_RIGHT_ARROW: 894 s = windowid ? ltgetstr("kr", &sp) : k_right; 895 break; 896 case SK_LEFT_ARROW: 897 s = windowid ? ltgetstr("kl", &sp) : k_left; 898 break; 899 case SK_UP_ARROW: 900 s = windowid ? ltgetstr("ku", &sp) : k_up; 901 break; 902 case SK_DOWN_ARROW: 903 s = windowid ? ltgetstr("kd", &sp) : k_down; 904 break; 905 case SK_PAGE_UP: 906 s = windowid ? ltgetstr("kP", &sp) : k_pageup; 907 break; 908 case SK_PAGE_DOWN: 909 s = windowid ? ltgetstr("kN", &sp) : k_pagedown; 910 break; 911 case SK_HOME: 912 s = windowid ? ltgetstr("kh", &sp) : k_home; 913 break; 914 case SK_END: 915 s = windowid ? ltgetstr("@7", &sp) : k_end; 916 break; 917 case SK_DELETE: 918 if (windowid) 919 { 920 s = ltgetstr("kD", &sp); 921 if (s == NULL) 922 { 923 tbuf[0] = '\177'; 924 tbuf[1] = '\0'; 925 s = tbuf; 926 } 927 } else 928 s = k_delete; 929 break; 930 #endif 931 #if MSDOS_COMPILER 932 case SK_RIGHT_ARROW: 933 s = k_right; 934 break; 935 case SK_LEFT_ARROW: 936 s = k_left; 937 break; 938 case SK_UP_ARROW: 939 s = k_up; 940 break; 941 case SK_DOWN_ARROW: 942 s = k_down; 943 break; 944 case SK_PAGE_UP: 945 s = k_pageup; 946 break; 947 case SK_PAGE_DOWN: 948 s = k_pagedown; 949 break; 950 case SK_HOME: 951 s = k_home; 952 break; 953 case SK_END: 954 s = k_end; 955 break; 956 case SK_DELETE: 957 s = k_delete; 958 break; 959 #endif 960 #if MSDOS_COMPILER || OS2 961 case SK_INSERT: 962 s = k_insert; 963 break; 964 case SK_CTL_LEFT_ARROW: 965 s = k_ctl_left; 966 break; 967 case SK_CTL_RIGHT_ARROW: 968 s = k_ctl_right; 969 break; 970 case SK_CTL_BACKSPACE: 971 s = k_ctl_backspace; 972 break; 973 case SK_CTL_DELETE: 974 s = k_ctl_delete; 975 break; 976 case SK_F1: 977 s = k_f1; 978 break; 979 case SK_BACKTAB: 980 s = k_backtab; 981 break; 982 #else 983 case SK_RIGHT_ARROW: 984 s = ltgetstr("kr", &sp); 985 break; 986 case SK_LEFT_ARROW: 987 s = ltgetstr("kl", &sp); 988 break; 989 case SK_UP_ARROW: 990 s = ltgetstr("ku", &sp); 991 break; 992 case SK_DOWN_ARROW: 993 s = ltgetstr("kd", &sp); 994 break; 995 case SK_PAGE_UP: 996 s = ltgetstr("kP", &sp); 997 break; 998 case SK_PAGE_DOWN: 999 s = ltgetstr("kN", &sp); 1000 break; 1001 case SK_HOME: 1002 s = ltgetstr("kh", &sp); 1003 break; 1004 case SK_END: 1005 s = ltgetstr("@7", &sp); 1006 break; 1007 case SK_DELETE: 1008 s = ltgetstr("kD", &sp); 1009 if (s == NULL) 1010 { 1011 tbuf[0] = '\177'; 1012 tbuf[1] = '\0'; 1013 s = tbuf; 1014 } 1015 break; 1016 #endif 1017 case SK_CONTROL_K: 1018 tbuf[0] = CONTROL('K'); 1019 tbuf[1] = '\0'; 1020 s = tbuf; 1021 break; 1022 default: 1023 return (NULL); 1024 } 1025 return (s); 1026 } 1027 1028 /* 1029 * Get terminal capabilities via termcap. 1030 */ 1031 public void 1032 get_term() 1033 { 1034 #if MSDOS_COMPILER 1035 auto_wrap = 1; 1036 ignaw = 0; 1037 can_goto_line = 1; 1038 clear_bg = 1; 1039 /* 1040 * Set up default colors. 1041 * The xx_s_width and xx_e_width vars are already initialized to 0. 1042 */ 1043 #if MSDOS_COMPILER==MSOFTC 1044 sy_bg_color = _getbkcolor(); 1045 sy_fg_color = _gettextcolor(); 1046 get_clock(); 1047 #else 1048 #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC 1049 { 1050 struct text_info w; 1051 gettextinfo(&w); 1052 sy_bg_color = (w.attribute >> 4) & 0x0F; 1053 sy_fg_color = (w.attribute >> 0) & 0x0F; 1054 } 1055 #else 1056 #if MSDOS_COMPILER==WIN32C 1057 { 1058 DWORD nread; 1059 CONSOLE_SCREEN_BUFFER_INFO scr; 1060 1061 con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); 1062 /* 1063 * Always open stdin in binary. Note this *must* be done 1064 * before any file operations have been done on fd0. 1065 */ 1066 SET_BINARY(0); 1067 GetConsoleScreenBufferInfo(con_out, &scr); 1068 ReadConsoleOutputAttribute(con_out, &curr_attr, 1069 1, scr.dwCursorPosition, &nread); 1070 sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ 1071 sy_fg_color = curr_attr & FG_COLORS; 1072 } 1073 #endif 1074 #endif 1075 #endif 1076 nm_fg_color = sy_fg_color; 1077 nm_bg_color = sy_bg_color; 1078 bo_fg_color = 11; 1079 bo_bg_color = 0; 1080 ul_fg_color = 9; 1081 ul_bg_color = 0; 1082 so_fg_color = 15; 1083 so_bg_color = 9; 1084 bl_fg_color = 15; 1085 bl_bg_color = 0; 1086 1087 /* 1088 * Get size of the screen. 1089 */ 1090 scrsize(); 1091 pos_init(); 1092 1093 1094 #else /* !MSDOS_COMPILER */ 1095 1096 char *sp; 1097 register char *t1, *t2; 1098 char *term; 1099 char termbuf[TERMBUF_SIZE]; 1100 1101 static char sbuf[TERMSBUF_SIZE]; 1102 1103 #if OS2 1104 /* 1105 * Make sure the termcap database is available. 1106 */ 1107 sp = lgetenv("TERMCAP"); 1108 if (sp == NULL || *sp == '\0') 1109 { 1110 char *termcap; 1111 if ((sp = homefile("termcap.dat")) != NULL) 1112 { 1113 size_t len = strlen(sp) + 9; 1114 termcap = (char *) ecalloc(len, sizeof(char)); 1115 snprintf(termcap, len, "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 && !ismore) { 1194 sc_init = ltgetstr("ti", &sp); 1195 sc_deinit= ltgetstr("te", &sp); 1196 } 1197 if (sc_init == NULL) 1198 sc_init = ""; 1199 1200 if (sc_deinit == NULL) 1201 sc_deinit = ""; 1202 1203 sc_eol_clear = ltgetstr("ce", &sp); 1204 if (sc_eol_clear == NULL || *sc_eol_clear == '\0') 1205 { 1206 missing_cap = 1; 1207 sc_eol_clear = ""; 1208 } 1209 1210 sc_eos_clear = ltgetstr("cd", &sp); 1211 if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) 1212 { 1213 missing_cap = 1; 1214 sc_eol_clear = ""; 1215 } 1216 1217 sc_clear = ltgetstr("cl", &sp); 1218 if (sc_clear == NULL || *sc_clear == '\0') 1219 { 1220 missing_cap = 1; 1221 sc_clear = "\n\n"; 1222 } 1223 1224 sc_move = ltgetstr("cm", &sp); 1225 if (sc_move == NULL || *sc_move == '\0') 1226 { 1227 /* 1228 * This is not an error here, because we don't 1229 * always need sc_move. 1230 * We need it only if we don't have home or lower-left. 1231 */ 1232 sc_move = ""; 1233 can_goto_line = 0; 1234 } else 1235 can_goto_line = 1; 1236 1237 tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); 1238 tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); 1239 tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); 1240 tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); 1241 1242 sc_visual_bell = ltgetstr("vb", &sp); 1243 if (sc_visual_bell == NULL) 1244 sc_visual_bell = ""; 1245 1246 if (ltgetflag("bs")) 1247 sc_backspace = "\b"; 1248 else 1249 { 1250 sc_backspace = ltgetstr("bc", &sp); 1251 if (sc_backspace == NULL || *sc_backspace == '\0') 1252 sc_backspace = "\b"; 1253 } 1254 1255 /* 1256 * Choose between using "ho" and "cm" ("home" and "cursor move") 1257 * to move the cursor to the upper left corner of the screen. 1258 */ 1259 t1 = ltgetstr("ho", &sp); 1260 if (t1 == NULL) 1261 t1 = ""; 1262 if (*sc_move == '\0') 1263 t2 = ""; 1264 else 1265 { 1266 strlcpy(sp, tgoto(sc_move, 0, 0), sbuf + sizeof(sbuf) - sp); 1267 t2 = sp; 1268 sp += strlen(sp) + 1; 1269 } 1270 sc_home = cheaper(t1, t2, "|\b^"); 1271 1272 /* 1273 * Choose between using "ll" and "cm" ("lower left" and "cursor move") 1274 * to move the cursor to the lower left corner of the screen. 1275 */ 1276 t1 = ltgetstr("ll", &sp); 1277 if (t1 == NULL) 1278 t1 = ""; 1279 if (*sc_move == '\0') 1280 t2 = ""; 1281 else 1282 { 1283 strlcpy(sp, tgoto(sc_move, 0, sc_height-1), 1284 sbuf + sizeof(sbuf) - sp); 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(STDOUT_FILENO, "\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