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