/* * All video and keyboard functions were gathered into one file. * * In version 3.2, this file was split into 3 sections: 1) unix curses * made to look and feel like a PC, 2) our PC hardware specific stuff, * and 3) hardware independent stuff. * * This file contains the keyboard and video i/o stuff. Most of this stuff * is specific to the PC hardware, but it should be easily modified when * porting to other platforms. With a few key functions written in * assembly, we have fairly fast video performance and good keyboard control. * Incidentally, the commented C code in the functions perform the same * function as the assembly code. In earlier versions of TDE, I didn't * update the commented C code when I changed the assembly code. The * C and assembly should be equivalent in version 2.2. * * Although using a curses type package would be more portable, curses * can be slow on PCs. Let's keep our video and keyboard routines in * assembly. I feel the need for speed. * * Being that TDE 2.2 keeps an accurate count of characters in each line, we * can allow the user to enter any ASCII or Extended ASCII key. * * Determining the video adapter type on the PC requires a function. In * TDE, that function is: * * void video_config( struct vcfg *cfg ) * * video_config( ) is based on Appendix C in _Programmer's Guide to * PC & PS/2 Video Systems_ by Richard Wilton. * * See: * * Richard Wilton, _Programmer's Guide to PC & PS/2 Video Systems_, * Microsoft Press, Redmond, Washington, 1987, Appendix C, pp 511-521. * ISBN 1-55615-103-9. * * * New editor name: TDE, the Thomson-Davis Editor. * Author: Frank Davis * Date: June 5, 1991, version 1.0 * Date: July 29, 1991, version 1.1 * Date: October 5, 1991, version 1.2 * Date: January 20, 1992, version 1.3 * Date: February 17, 1992, version 1.4 * Date: April 1, 1992, version 1.5 * Date: June 5, 1992, version 2.0 * Date: October 31, 1992, version 2.1 * Date: April 1, 1993, version 2.2 * Date: June 5, 1993, version 3.0 * Date: August 29, 1993 version 3.1 * Date: November 13, version 3.2 * Date: June 5, version 4.0 * * This code is released into the public domain, Frank Davis. * You may distribute it freely. */ #include "tdestr.h" #include "common.h" #include "define.h" #include "tdefunc.h" #if defined( __UNIX__ ) /* ********************************************************************** ****************************** PART 1 ****************************** ********************************************************************** * * Let's try to make unix have the look and feel of a PC. */ /* * Name: video_config * Purpose: simulate a call the BIOS keyboard status subfunction * Date: November 13, 1993 * Passed: cfg: not used * Notes: curses has three (?) cursor shapes: invisible, normal, large. */ void video_config( struct vcfg *cfg ) { /* g_display.insert_cursor = mode.cursor_size == SMALL_INS ? CURSES_SMALL : CURSES_LARGE; g_display.overw_cursor = mode.cursor_size == SMALL_INS ? CURSES_LARGE : CURSES_SMALL; */ g_display.insert_cursor = g_display.overw_cursor = CURSES_SMALL; if (mode.insert) g_display.curses_cursor = g_display.insert_cursor; else g_display.curses_cursor = g_display.overw_cursor; } /* * Name: getkey * Purpose: use unix curses to get keyboard input * Date: November 13, 1993 * Passed: None * Notes: the getch( ) function is not part of the ANSI C standard. * most (if not all) PC C compilers include getch( ) with the * conio stuff. in unix, getch( ) is in the curses package. * in TDE, lets try to map the curses function keys to their * "natural" positions on PC hardware. most of the key mapping * is at the bottom of default.h. * this function is based on the ncurses package in Linux. It * probably needs to be modified for curses in other unices. */ int getkey( void ) { unsigned key; key = getch( ); /* * map the Control keys to their natural place in TDE. */ if (key < 32) key += 430; else if (key > 255) { /* * map ncurses keys to their natural place in TDE. * ncurses defines function keys in the range 256-408. */ if (key > 408) key = 256; key = curses_to_tde[key - 256]; } return( key ); } /* * Name: waitkey * Purpose: nothing right now * Date: November 13, 1993 * Passed: enh_keyboard: boolean - TRUE if 101 keyboard, FALSE otherwise * Returns: 1 if no key ready, 0 if key is waiting * Notes: we might do something with this function later... */ int waitkey( int enh_keyboard ) { return( 0 ); } /* * Name: flush_keyboard * Purpose: flush keys from the keyboard buffer. flushinp is a curses func. * Date: November 13, 1993 * Passed: none */ void flush_keyboard( void ) { flushinp( ); } /* * Name: xygoto * Purpose: To move the cursor to the required column and line. * Date: November 13, 1993 * Passed: col: desired column (0 up to max) * line: desired line (0 up to max) * Notes; on the PC, we use col = -1 and line = -1 to turn the cursor off. * in unix, we try to trap the -1's. * curs_set is a curses function. */ void xygoto( int col, int line ) { if (col < 0 || line < 0) { curs_set( CURSES_INVISBL ); g_display.curses_cursor = CURSES_INVISBL; } else { /* * if the unix cursor is invisible, lets turn it back on. */ if (g_display.curses_cursor == CURSES_INVISBL) { /* if (mode.insert == TRUE) { if (g_display.insert_cursor == SMALL_INS) set_cursor_size( CURSES_SMALL ); else set_cursor_size( CURSES_LARGE ); } else { if (g_display.insert_cursor == SMALL_INS) set_cursor_size( CURSES_LARGE ); else set_cursor_size( CURSES_SMALL ); } */ set_cursor_size( CURSES_SMALL ); g_display.curses_cursor = CURSES_SMALL; } move( line, col ); } } /* * Name: update_line * Purpose: Display the current line in window * Date: November 13, 1993 * Passed: window: pointer to current window * Notes: use the curses mvaddch( ) function to put char + attribute * on the screen. * let's check for control characters before they get to curses. * unix and/or curses is brain-damaged when it comes to * control characters and extended ASCII characters. */ void update_line( TDE_WIN *window ) { text_ptr text; /* current character of orig begin considered */ int attr; /* index into TDE's chtype table */ int line; int col; int bcol; int bc; int ec; int normal; int block; int max_col; int block_line; int len; int show_eol; unsigned int c; long rline; file_infos *file; chtype curses_attribute; /* chtype is defined in curses.h */ /* * we don't use this function to display the EOF message. * return if this display is turned off. */ if (window->rline > window->file_info->length || window->ll->len == EOF || !g_status.screen_display) return; file = window->file_info; max_col = window->end_col + 1 - window->start_col; line = window->cline; normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color; block = g_display.block_color; show_eol = mode.show_eol; /* * figure which line to display. * actually, we could be displaying any line in any file. we display * the line_buffer only if window->ll == g_status.buff_node * and window->ll-line has been copied to g_status.line_buff. */ text = window->ll->line; len = window->ll->len; if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) { text = (text_ptr)g_status.line_buff; len = g_status.line_buff_len; } if (mode.inflate_tabs) text = tabout( text, &len ); /* * lets look at the base column. if the line to display is shorter * than the base column, then set text to eol and we can't see the * eol either. */ bc = window->bcol; if (bc > 0) { if (text == NULL) { show_eol = FALSE; len = 0; } else { if ((col = len) < bc) { bc = col; show_eol = FALSE; } text += bc; len -= bc; } } /* * for display purposes, set the line length to screen width if line * is longer than screen. our assembly routine uses bytes and the * the line length can be longer than a byte. */ if (len > max_col) len = max_col; bcol = window->bcol; rline = window->rline; if (file->block_type && rline >= file->block_br && rline <= file->block_er) block_line = TRUE; else block_line = FALSE; /* * do this if 1) a box block is marked, or 2) a stream block begins * and ends on the same line. */ if (block_line == TRUE && (file->block_type == BOX || (file->block_type == STREAM && rline == file->block_br && rline == file->block_er))) { /* * start with the bc and ec equal to physical block marker. */ bc = file->block_bc; ec = file->block_ec; if (ec < bcol || bc >= bcol + max_col) /* * we can't see block if ending column is less than the base col or * the beginning column is greater than max_col. */ ec = bc = max_col + 1; else if (ec < bcol + max_col) { /* * if the ec is less than the max column, make ec relative to * base column then figure the bc. */ ec = ec - bcol; if (bc < bcol) bc = 0; else bc = bc - bcol; } else if (bc < bcol + max_col) { /* * if the bc is less than the max column, make bc relative to * base column then figure the ec. */ bc = bc - bcol; if (ec > bcol + max_col) ec = max_col; else ec = ec - bcol; } else if (bc < bcol && ec >= bcol + max_col) { /* * if the block is wider than the screen, make bc start at the * logical begin and make ec end at the logical end of the * window. */ bc = 0; ec = max_col; } bcol = window->start_col; for (col=0; col < max_col; col++, bcol++) { attr = normal; if (col >= bc && col <= ec) attr = block; if (col < len) c = *text++; else if (col == len && show_eol) c = EOL_CHAR; else c = ' '; if (c < 32) mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] ); else if (c >= 127) mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] ); else mvaddch( line, bcol, c | tde_color_table[attr] ); } } else if (block_line == TRUE && file->block_type == STREAM && (rline == file->block_br || rline == file->block_er)) { if (rline == file->block_br) bc = file->block_bc; else { bc = file->block_ec + 1; ec = normal; normal = block; block = ec; } ec = max_col + 1; if (bc < bcol) bc = 0; else if (bc < bcol + max_col) bc = bc - bcol; else bc = max_col + 1; bcol = window->start_col; for (col=0; col < max_col; col++, bcol++) { attr = normal; if (col >= bc && col <= ec) attr = block; if (col < len) c = *text++; else if (col == len && show_eol) c = EOL_CHAR; else c = ' '; if (c < 32) mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] ); else if (c >= 127) mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] ); else mvaddch( line, bcol, c | tde_color_table[attr] ); } } else { if (block_line) attr = block; else attr = normal; assert( len >= 0 ); assert( len <= g_display.ncols ); curses_attribute = tde_color_table[attr]; bcol = window->start_col; for (col=0; col < max_col; col++, bcol++) { if (col < len) c = *text++; else if (col == len && show_eol) c = EOL_CHAR; else c = ' '; if (c < 32) mvaddch( line, bcol, (c+64) | tde_color_table[g_display.curl_color] ); else if (c >= 127) mvaddch( line, bcol, '.' | tde_color_table[g_display.curl_color] ); else mvaddch( line, bcol, c | curses_attribute ); } } } /* * Name: c_output * Purpose: Output one character on prompt lines * Date: November 13, 1993 * Passed: c: character to output to screen * col: col to display character * line: line number to display character * attr: attribute of character * Returns: none */ void c_output( int c, int col, int line, int attr ) { register unsigned int uc; uc = c; if (uc < 32) mvaddch( line, col, (uc+64) | tde_color_table[g_display.curl_color] ); else if (uc >= 127) mvaddch( line, col, '.' | tde_color_table[g_display.curl_color] ); else mvaddch( line, col, uc | tde_color_table[attr] ); } /* * Name: s_output * Purpose: To output a string * Date: November 13, 1993 * Passed: s: string to output * line: line to display * col: column to begin display * attr: color to display string * Notes: This function is used to output most strings not part of file text. */ void s_output( char *s, int line, int col, int attr ) { int max; register unsigned int uc; max = g_display.ncols; if (line == g_display.mode_line && (strlen( s ) + col >= g_display.ncols)) max--; while ((uc = (unsigned int)*s) && col < max) { if (uc < 32) mvaddch( line, col, (uc + 64) | tde_color_table[g_display.curl_color] ); else if (uc >= 127) mvaddch( line, col, '.' | tde_color_table[g_display.curl_color] ); else mvaddch( line, col, uc | tde_color_table[attr] ); col++; s++; } } /* * Name: eol_clear * Purpose: To clear the line from col to max columns * Date: November 13, 1993 * Passed: col: column to begin clear * line: line to clear * attr: color to clear * Notes: use unix curses clrtoeol( ) to clear the line. */ void eol_clear( int col, int line, int attr ) { move( line, col ); clrtoeol( ); } /* * Name: window_eol_clear * Purpose: To clear the line from start_col to end_col * Date: November 13, 1993 * Passed: window: pointer to window * attr: color to clear * Notes: don't use unix curses clrtoeol, because we could be in a * vertical window. lines don't always extend to end of screen * in a vertical window. */ void window_eol_clear( TDE_WIN *window, int attr ) { int max_col; chtype c; /* chtype is defined in curses.h */ if (!g_status.screen_display) return; assert( attr >= 0 && attr < 128 ); c = ' ' | tde_color_table[attr]; max_col = window->start_col; while (max_col <= window->end_col) mvaddch( window->cline, max_col++, c ); } /* * Name: hlight_line * Date: November 13, 1993 * Passed: x: column to begin hi lite * y: line to begin hi lite * lgth: number of characters to hi lite * attr: attribute color */ void hlight_line( int x, int y, int lgth, int attr ) { int max; max = g_display.ncols; if (y == g_display.mode_line) max--; for (; lgth > 0 && x < max; x++, lgth--) { move( y, x ); addch( (inch( ) & A_CHARTEXT) | tde_color_table[attr] ); } refresh( ); } /* * Name: cls * Purpose: clear screen * Date: November 13, 1993 * Notes: Call the curses clear screen function. */ void cls( void ) { touchwin( curscr ); clear( ); refresh( ); } /* * Name: set_cursor_size * Purpose: To set cursor size according to insert mode. * Date: November 13, 1993 * Passed: csize: not used in unix curses * Notes: use the global display structures to set the cursor size * curs_set( ) is a curses function. */ void set_cursor_size( int csize ) { /* if (mode.insert == TRUE) { if (g_display.insert_cursor == SMALL_INS) curs_set( CURSES_SMALL ); else curs_set( CURSES_LARGE ); } else { if (g_display.insert_cursor == SMALL_INS) curs_set( CURSES_LARGE ); else curs_set( CURSES_SMALL ); } */ curs_set( CURSES_SMALL ); g_display.curses_cursor = CURSES_SMALL; } /* * Name: set_overscan_color * Purpose: To set overscan color * Date: November 13, 1993 * Passed: color: overscan color * Notes: i'm not sure how to set the overscan in Linux (yet?). */ void set_overscan_color( int color ) { } /* * Name: save_screen_line * Purpose: To save the characters and attributes of a line on screen. * Date: November 13, 1993 * Passed: col: desired column, usually always zero * line: line on screen to save (0 up to max) * screen_buffer: buffer for screen contents, must be >= 80 chtype * Notes: Save the contents of the line on screen where prompt is * to be displayed. */ void save_screen_line( int col, int line, chtype *screen_buffer ) { int i; for (i=0; col < g_display.ncols; col++, i++) screen_buffer[i] = mvinch( line, col ); } /* * Name: restore_screen_line * Purpose: To restore the characters and attributes of a line on screen. * Date: November 13, 1993 * Passed: col: usually always zero * line: line to restore (0 up to max) * screen_buffer: buffer for screen contents, must be >= 80 chtype * Notes: Restore the contents of the line on screen where the prompt * was displayed */ void restore_screen_line( int col, int line, chtype *screen_buffer ) { int i; for (i=0; col < g_display.ncols; col++, i++) mvaddch( line, col, screen_buffer[i] ); refresh( ); } /* * Name: save_minor_area * Purpose: save text and attribute under the pulled menu * Date: November 13, 1993 * Passed: buffer: storage for text and attribute * wid: width of the pulled menu * len: length of pulled menu * row: starting row of pulled menu * col: starting column of pulled menu * Notes: use curses to get char and attr */ void save_minor_area( chtype *buffer, int wid, int len, int row, int col ) { int i; int j; wid--; len--; for (i=0; len >= 0; len--) { for (j=wid; j >= 0; j--, i++) buffer[i] = mvinch( row+len, col+j ); } } /* * Name: retore_minor_area * Purpose: restore text and attribute under the pulled menu * Date: November 13, 1993 * Passed: buffer: storage for text and attribute * wid: width of the pulled menu * len: length of pulled menu * row: starting row of pulled menu * col: starting column of pulled menu * Notes: use curses to set char and attr */ void restore_minor_area( chtype *buffer, int wid, int len, int row, int col ) { int i; int j; wid--; len--; for (i=0; len >= 0; len--) { for (j=wid; j >= 0; j--, i++) mvaddch( row+len, col+j, buffer[i] ); } refresh( ); } #else /* ********************************************************************** ****************************** PART 2 ****************************** ********************************************************************** * * Calls to BIOS and writes to PC hardware. */ #include /* for direct BIOS keyboard input */ /* * BIOS Data Areas * * See: * * IBM Corp., _Technical Reference: Personal Computer AT_, * Boca Raton, Florida, 1984, IBM part no. 1502494, * pp 5-29 thru 5-32. * * These addresses, variable names, types, and descriptions are directly * from the IBM AT Technical Reference manual, BIOS listing, copyright IBM. * * Address Name Type Description * 0x0449 CRT_MODE Byte Current CRT mode * 0x044a CRT_COLS Word Number columns on screen * 0x044c CRT_LEN Word length of regen buffer, video buffer, bytes * 0x044e CRT_START Word Starting address of regen buffer * 0x0450 CURSOR_POSN Word cursor for each of up to 8 pages. * 0x0460 CURSOR_MODE Word current cursor mode setting. * 0x0462 ACTIVE_PAGE Byte Current page * 0x0463 ADDR_6845 Word base address for active display card * 0x0465 CRT_MODE_SET Byte current mode of display card * 0x0466 CRT_PALETTE Byte overscan color for CGA, EGA, and VGA. * 0x0467 io_rom_init Word Pointer to optional i/o rom init routine * 0x0469 io_rom_seg Word Pointer to io rom segment * 0x046b intr_flag Byte Flag to indicate an interrupt happened * 0x046c timer_low Word Low word of timer count * 0x046e timer_high Word High word of timer count * 0x0470 timer_ofl Byte Timer has rolled over since last count * 0x0471 bios_break Byte Bit 7 = 1 if Break Key has been hit * 0x0472 reset_flag Word Word = 1234h if keyboard reset underway * 0x0484 ROWS Byte Number of displayed character rows - 1 * 0x0485 POINTS Word Height of character matrix * 0x0487 INFO Byte EGA and VGA display data * 0x0488 INFO_3 Byte Configuration switches for EGA and VGA * 0x0489 flags Byte Miscellaneous flags * 0x0496 kb_flag_3 Byte Additional keyboard flag * 0x048A DCC Byte Display Combination Code * 0x04A8 SAVE_PTR Dword Pointer to BIOS save area */ void video_config( struct vcfg *cfg ) { #pragma pack( 1 ) /* Use pragma to force packing on byte boundaries. */ struct LOWMEMVID { char vidmode; /* 0x449 */ unsigned scrwid; /* 0x44A */ unsigned scrlen; /* 0x44C */ unsigned scroff; /* 0x44E */ struct LOCATE { unsigned char col; unsigned char row; } csrpos[8]; /* 0x450 */ struct CURSIZE { unsigned char end; unsigned char start; } csrsize; /* 0x460 */ char page; /* 0x462 */ unsigned addr_6845; /* 0x463 */ char crt_mode_set; /* 0x465 */ char crt_palette; /* 0x466 */ char system_stuff[29]; /* 0x467 */ unsigned char rows; /* 0x484 */ unsigned points; /* 0x485 */ char ega_info; /* 0x487 */ char info_3; /* 0x488 */ char skip[13]; /* 0x489 */ char kb_flag_3; /* 0x496 */ } vid; struct LOWMEMVID _far *pvid = &vid; #pragma pack( ) /* revert to previously defined pack pragma. */ union REGS in, out; unsigned char temp, active_display; /* * Move system information into our video structure. */ my_memmove( pvid, (void FAR *)0x00000449l, sizeof( vid ) ); /* * this next code was contributed by Jim Derr */ cfg->cols = vid.scrwid; cfg->regen_len = vid.scrlen; cfg->rows = vid.rows; cfg->rescan = FALSE; in.x.ax = 0x1a00; int86( VIDEO_INT, &in, &out ); temp = out.h.al; active_display = out.h.bl; if (temp == 0x1a && (active_display == 7 || active_display == 8)) g_display.adapter = VGA; else { in.h.ah = 0x12; in.h.bl = 0x10; int86( VIDEO_INT, &in, &out ); if (out.h.bl != 0x10) { /* EGA */ if (vid.ega_info & 0x08) g_display.adapter = vid.addr_6845 == 0x3d4 ? CGA : MDA; else g_display.adapter = EGA; } else if (vid.addr_6845 == 0x3d4) g_display.adapter = CGA; else g_display.adapter = MDA; } if (g_display.adapter == CGA || g_display.adapter == EGA) { if (g_display.adapter == CGA) cfg->rescan = TRUE; g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0607 : 0x0407; g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x0407 : 0x0607; } else { g_display.insert_cursor = mode.cursor_size == SMALL_INS ? 0x0b0c : 0x070b; g_display.overw_cursor = mode.cursor_size == SMALL_INS ? 0x070b : 0x0b0c; } cfg->mode = vid.vidmode; if (vid.addr_6845 == 0x3D4) { cfg->color = TRUE; cfg->videomem = (void FAR *)0xb8000000l; } else { cfg->color = FALSE; cfg->videomem = (void FAR *)0xb0000000l; } /* * let save the overscan color */ g_display.old_overscan = vid.crt_palette; /* * Get keyboard type. Since there is no interrupt that determines * keyboard type, use this method. Look at bit 4 in keyboard flag3. * This method is not always foolproof on clones. */ if ((vid.kb_flag_3 & 0x10) != 0) mode.enh_kbd = TRUE; else mode.enh_kbd = FALSE; if (mode.enh_kbd == FALSE) simulate_enh_kbd( 1 ); } /* * The next function was written by Tom Waters, twaters@relay.nswc.navy.mil, and * modified extensively by Frank Davis. * * "I use ANSI.SYS to redefine a few of my function keys and this causes a * problem when getch() is used in a program. For example, instead of returning * 321 for the F7, I get the redefined string inserted in the text. So, instead * of using getch(), I use the following function ..." * * Tom, thanks for the info and solution. I'm sure your function will be * be appreciated by everyone with ANSI key defs, Frank. */ /* * Name: getkey * Purpose: use bios to get keyboard input (getch has trouble w/ ANSI * redefined keys) * Date: July 2, 1991 * Modified:July 12, 1991, Frank Davis - accept ALT-xxx keyboard entry * September 10, 1991, Frank Davis - add support for Ctrl+Up, etc... * Passed: None * Notes: Uses the BIOS to read the next keyboard character. Service 0x00 * is the XT keyboard read. Service 0x10 is the extended keyboard * read. Test for a bunch of special cases. Allow the user to enter * any ASCII or Extended ASCII code as a normal text characters. * * Control @ is defined as 0. we need to do a special test * for this key, otherwise it's interpretted as an Alt key. It's * the only "regular" Control key that returns 0 in AL and the scan * byte in AH. The "regular" Control keys are those in the range * 0-31 and they return the Control character in AL and the scan * code in AH. All of the Alt + keys return 0 in AL and * the scan code in ah. * * This function was written for US keyboards. It may have to be * modified for other keyboards, eg. Belgium, Canada, Czech, * Slovak, Denmark, France, Germany, etc... * * if Ctrl-Break is pressed, it returns 0xffff as the key pressed. * let's set it to CONTROL_BREAK == 269 and do nothing. */ int getkey( void ) { unsigned key, num_lock, control, shift; register scan; register unsigned lo; /* * this code is used during testing to check the amount of memory * in the near heap. * * char temp[MAX_COLS+2]; * * ultoa( _memavl( ), temp, 10 ); * s_output( "h= ", g_display.mode_line, 37, g_display.mode_color ); * s_output( temp, g_display.mode_line, 39, g_display.mode_color ); */ /* * lets spin on waitkey until the user presses a key. waitkey polls * the keyboard and returns 0 when a key is waiting. */ while (waitkey( mode.enh_kbd )); /* * _bios_keybrd == int 16. It returns the scan code in ah, hi part of key, * and the ascii key code in al, lo part of key. If the character was * entered via ALT-xxx, the scan code, hi part of key, is 0. */ if (mode.enh_kbd) { key = _bios_keybrd( 0x10 ); lo = _bios_keybrd( 0x12 ); /* * couple of special cases: * on the numeric keypad, some keys return 0xe0 in the lo byte. * 1) if user enters Alt-224, then the hi byte == 0 and lo byte == 0xe0. * we need to let this get thru as an Extended ASCII char. 2) although * we could make the cursor pad keys do different functions than the * numeric pad cursor keys, let's set the 0xe0 in the lo byte to zero * and forget about support for those keys. */ if ((key & 0x00ff) == 0x00e0 && (key & 0xff00) != 0) key = key & 0xff00; } else { key = _bios_keybrd( 0 ); lo = _bios_keybrd( 2 ); } num_lock = lo & 0x20; control = lo & 0x04; shift = lo & 0x03; scan = (key & 0xff00) >> 8; lo = key & 0X00FF; if (lo == 0) { /* * special case for Control @, which is defined as 0 or NULL. */ if (scan == 3) lo = 430; /* * when first byte is 0, map it above 256, so that we can * let ALT-xxx keys map to their 'natural' place. In * otherwords, use 0-255 as normal text characters and * those >= 256 are function keys. */ else lo = scan | 0x100; /* * now test for Control-Break. let's set this to do nothing in the * editor. manually map Control-Break to 269 - DO NOT assign * any function to 269. */ } else if (key == 0xffff) lo = CONTROL_BREAK; /* * Pressing Control+BackSpace generates the 0x7f character. Instead of * 0x7f, make lo the ASCII backspace character. If anyone wants the * 0x7f character, then they can enter it via ALT+xxx. */ if (scan == 14 && lo == 0x7f) lo = 8; /* * At the bottom of page 195 in MASM 6.0 ref manual, "..when the keypad * ENTER and / keys are read through the BIOS interrupt 16h, only E0h * is seen since the interrupt only gives one-byte scan codes." */ else if (scan == 0xe0) { /* * plain Grey Enter */ if (lo == 13 && !shift) lo = 285; /* * shift Grey Enter */ else if (lo == 13) lo = 298; /* * control Grey Enter */ else if (lo == 10) lo = 299; } /* * let's massage all of the control key combinations. */ if (lo < 32) { /* * My machine at home is sorta weird. On every machine that I've * tested at the awffice, the ALT-xxx combination returns 0 for the * scan byte and xxx for the ASCII code. My machine returns 184 (decimal) * as the scan code?!?!? I added the next two lines for my machine at * home. I wonder if someone forgot to zero out ah for Alt keypad entry * when they wrote my bios? */ if (scan > 0x80) scan = 0; /* * Separate the ESC key from the ^[ key. The scan code for the ESC * key is 1. Map this to a different index into the key function * array just in case someone wants to define ESC or ^[ to different * functions. BTW, ESC and ^[ return the same ASCII code, 27. */ else if (scan == 1) { if (shift) lo = 259; else if (control) lo = 260; else lo = 258; } /* * Scan code for Enter = 28. Separate the various Enter keys. */ else if (scan == 28) { if (shift) lo = 263; else if (control) lo = 264; else lo = 262; } /* * Scan code for Backspace = 14. Separate the various BackSpace keys. */ else if (scan == 14) { if (shift) lo = 266; else if (control) lo = 267; else lo = 265; } /* * Scan code for Tab = 15. Separate the tab key. */ else if (scan == 15) { lo = 268; } /* * if scan code is not 0, then a Control key was pressed. Map * those keys to the WordStar commands. */ else if (scan > 0) lo += 430; } else if (!num_lock) { switch (scan) { /* * scan code for grey - == 74. if num_lock is not toggled, assign it * to the scroll line up function. */ case 74 : lo = 423; break; /* * scan code for grey + == 78. if num_lock is not toggled, assign it * to the scroll line down function. if shift grey + then stationary * scroll down. */ case 78 : lo = 424; break; } } /* * let's set up for the Shift+Alt and Control+Alt keys. * With these key combinations, we can do the International keyboard * stuff, see the Microsoft MS DOS 5.0 manual pages 623-637. */ if (lo > 256 && (shift || control)) { /* * add 55 to Ctrl+Left thru Ctrl+Home when the shift key is pressed. * this is not part of the International keyboard stuff, just a way * to assign the horizontal scroll left and right funcs to cursor keys. */ if (shift) { if (lo >= 371 && lo <= 374) lo += 55; /* * if shift is down, map alt 1! thru alt =+ to shift alt 1! thru alt =+ */ else if (lo >= 376 && lo <= 387) lo += 86; /* * internation keyboard stuff */ else if (lo >= 272 && lo <= 309) lo += 202; } } /* * map the enter key to line feed. */ if (lo == 10 && scan != 0) lo = 425; return( lo ); } /* * Name: waitkey * Purpose: call the BIOS keyboard status subfunction * Date: October 31, 1992 * Passed: enh_keyboard: boolean - TRUE if 101 keyboard, FALSE otherwise * Returns: 1 if no key ready, 0 if key is waiting * Notes: lets get the keyboard status so we can spin on this function until * the user presses a key. some OS replacements for DOS want * application programs to poll the keyboard instead of rudely * sitting on the BIOS read key function. */ int waitkey( int enh_keyboard ) { return( _bios_keybrd( enh_keyboard ? 0x11 : 0x01 ) == 0 ? 1 : 0 ); } /* * Name: flush_keyboard * Purpose: flush keys from the keyboard buffer * Date: June 5, 1993 * Passed: enh_keyboard: boolean - TRUE if 101 keyboard, FALSE otherwise * Returns: 1 if no key ready, 0 if key is waiting * Notes: lets get the keyboard status so we can spin on this function until * the user presses a key. some OS replacements for DOS want * application programs to poll the keyboard instead of rudely * sitting on the BIOS read key function. */ void flush_keyboard( void ) { if (mode.enh_kbd) { while (!waitkey( mode.enh_kbd )) _bios_keybrd( 0x10 ); } else { while (!waitkey( mode.enh_kbd )) _bios_keybrd( 0 ); } } /*********************************************/ /* */ /* 3) video output routines, PC specific */ /* */ /*********************************************/ /* * Name: xygoto * Purpose: To move the cursor to the required column and line. * Date: September 28, 1991 * Passed: col: desired column (0 up to max) * line: desired line (0 up to max) * Notes; use standard BIOS video interrupt 0x10 to set the set. */ void xygoto( int col, int line ) { union REGS inregs, outregs; inregs.h.ah = 2; inregs.h.bh = 0; inregs.h.dh = (unsigned char)line; inregs.h.dl = (unsigned char)col; int86( 0x10, &inregs, &outregs ); } /* * Name: update_line * Purpose: Display the current line in window * Date: June 5, 1991 * Passed: window: pointer to current window * Notes: Show string starting at column zero and if needed blank rest * of line. Put max_col in cx and count down. When we run into * len, cx contains number of columns to blank out. Use the * fast 'rep stosw' to clear the end of line. * The C routine was probably fast enough, but let's do some * assembly because it's so fun. * To handle line lengths longer than 255 characters, * block begin and end columns were changed from real * to virtual columns in this display routine. */ void update_line( TDE_WIN *window ) { text_ptr text; /* current character of orig begin considered */ char FAR *screen_ptr; int off; int attr; int line; int col; int bcol; int bc; int ec; int normal; int block; int max_col; int block_line; int len; int show_eol; int c; long rline; file_infos *file; if (window->rline > window->file_info->length || window->ll->len == EOF || !g_status.screen_display) return; file = window->file_info; max_col = window->end_col + 1 - window->start_col; line = window->cline; normal = window->ll->dirty == FALSE ? g_display.text_color : g_display.dirty_color; block = g_display.block_color; show_eol = mode.show_eol; /* * set the screen pointer to physical screen memory. * 160 = 80 chars + 80 attr for each line */ screen_ptr = g_display.display_address; /* * this next suggestion is part of chen's screen changes. * * off = line * 160 + window->start_col * 2; * * change to: */ off = line * (g_display.ncols*2) + window->start_col * 2; /* * figure which line to display. * actually, we could be displaying any line in any file. we display * the line_buffer only if window->ll == g_status.buff_node * and window->ll-line has been copied to g_status.line_buff. */ text = window->ll->line; len = window->ll->len; if (g_status.copied && ptoul( window->ll ) == ptoul( g_status.buff_node )) { text = (text_ptr)g_status.line_buff; len = g_status.line_buff_len; } if (mode.inflate_tabs) text = tabout( text, &len ); /* * lets look at the base column. if the line to display is shorter * than the base column, then set text to eol and we can't see the * eol either. */ bc = window->bcol; if (bc > 0) { if (text == NULL) { show_eol = FALSE; len = 0; } else { if ((col = len) < bc) { bc = col; show_eol = FALSE; } text += bc; len -= bc; } } /* * for display purposes, set the line length to screen width if line * is longer than screen. our assembly routine uses bytes and the * the line length can be longer than a byte. */ if (len > max_col) len = max_col; bcol = window->bcol; rline = window->rline; if (file->block_type && rline >= file->block_br && rline <= file->block_er) block_line = TRUE; else block_line = FALSE; /* * do this if 1) a box block is marked, or 2) a stream block begins * and ends on the same line. */ if (block_line == TRUE && (file->block_type == BOX || (file->block_type == STREAM && rline == file->block_br && rline == file->block_er))) { /* * start with the bc and ec equal to physical block marker. */ bc = file->block_bc; ec = file->block_ec; if (ec < bcol || bc >= bcol + max_col) /* * we can't see block if ending column is less than the base col or * the beginning column is greater than max_col. */ ec = bc = max_col + 1; else if (ec < bcol + max_col) { /* * if the ec is less than the max column, make ec relative to * base column then figure the bc. */ ec = ec - bcol; if (bc < bcol) bc = 0; else bc = bc - bcol; } else if (bc < bcol + max_col) { /* * if the bc is less than the max column, make bc relative to * base column then figure the ec. */ bc = bc - bcol; if (ec > bcol + max_col) ec = max_col; else ec = ec - bcol; } else if (bc < bcol && ec >= bcol + max_col) { /* * if the block is wider than the screen, make bc start at the * logical begin and make ec end at the logical end of the * window. */ bc = 0; ec = max_col; } ASSEMBLE { /* ; Register strategy: ; bx == beginning column ; == ending column ; dl == normal text attribute ; dh == block attribute ; cx == current virtual column ; == maximum columns in window ; ES:DI == screen pointer (destination) ; DS:SI == text pointer (source) ; [bp+show_eol] == access for local C variable */ push ds /* MUST save ds - push it on stack */ push si /* save si on stack */ push di /* save di on stack */ /* ; ; set up local register variables ; */ mov bx, WORD PTR bc /* get beginning column */ mov ax, WORD PTR normal /* get normal attribute */ mov dl, al /* keep it in dl */ mov ax, WORD PTR block /* get block attribute */ mov dh, al /* keep it in dh */ xor cx, cx /* col = 0, keep col in cl */ /* ; ; load screen and text pointer ; */ mov di, WORD PTR screen_ptr /* load OFFSET of screen ptr */ add di, WORD PTR off /* add offset of line */ mov ax, WORD PTR screen_ptr+2 /* load SEGMENT of screen ptr */ mov es, ax mov si, WORD PTR text /* load OFFSET of text ptr */ mov ax, WORD PTR text+2 /* load SEGMENT of text ptr */ mov ds, ax /* move segment of text in ds */ cmp si, 0 /* is offset of text ptr == NULL? */ jne not_null /* no, output string */ cmp ax, 0 /* is segment of text ptr == NULL? */ je dspl_eol /* yes, clear end of line */ } not_null: ASSEMBLE { cmp cx, Word Ptr max_col /* is col == max_col? */ jge getout /* yes, thru with line */ cmp cx, Word Ptr len /* is col == len? */ je dspl_eol /* yes, must check block past eol */ } top: ASSEMBLE { lodsb /* get next char in string */ mov ah, dl /* assume normal attribute */ cmp cx, bx /* is col < bc? (less than beginning col) */ jl ch_out1 /* yes, show char and normal attribute */ cmp cx, Word Ptr ec /* is col > ec? (greater than ending col) */ jg ch_out1 /* yes, show char and normal attribute */ mov ah, dh /* must be in a block - block attribute */ } ch_out1: ASSEMBLE { stosw /* now show char on screen w/ attribute */ inc cx /* ++col */ cmp cx, Word Ptr max_col /* is col == max_col? */ jge getout /* yes, thru with line */ cmp cx, Word Ptr len /* is col == len? */ jl top /* yes, must check block past eol */ } dspl_eol: ASSEMBLE { cmp WORD PTR show_eol, FALSE /* look at the show_eol flag */ je block_eol /* show_eol flag is FALSE, blank line */ mov al, EOL_CHAR /* load some eol indicator */ mov ah, dl /* assume normal attribute */ cmp cx, bx /* is col < bc? (less than beginning col) */ jl ch_out2 /* yes, show char and normal attribute */ cmp cx, Word Ptr ec /* is col > ec? (greater than ending col) */ jg ch_out2 /* yes, show char and normal attribute */ mov ah, dh /* must be in a block - show block attribute */ } ch_out2: ASSEMBLE { stosw /* write eol and attribute to screen */ inc cx /* ++col */ cmp cx, Word Ptr max_col /* is col == max_col? */ je getout /* yes, we're done */ } block_eol: ASSEMBLE { mov al, ' ' /* clear rest of line w/ spaces */ } b1: ASSEMBLE { mov ah, dl /* assume normal attribute */ cmp cx, bx /* is col < bc? (less than beginning col) */ jl ch_out3 /* yes, show char and normal attribute */ cmp cx, Word Ptr ec /* is col > ec? (greater than ending col) */ jg ch_out3 /* yes, show char and normal attribute */ mov ah, dh /* must be in a block - show block attribute */ } ch_out3: ASSEMBLE { stosw /* write blank and attribute to screen */ inc cx /* ++col */ cmp cx, Word Ptr max_col /* is col == max_col? */ jl b1 /* while less output block */ } getout: ASSEMBLE { pop di pop si pop ds } /* screen_ptr += off; bcol = window->start_col; for (col=0; col < max_col; col++, bcol++) { attr = normal; if (col >= bc && col <= ec) attr = block; if (col < len) c = *text++; else if (col == len && show_eol) c = EOL_CHAR; else c = ' '; *screen_ptr++ = c; *screen_ptr++ = attr; c_output( c, bcol, line, attr ); } */ } else if (block_line == TRUE && file->block_type == STREAM && (rline == file->block_br || rline == file->block_er)) { if (rline == file->block_br) bc = file->block_bc; else { bc = file->block_ec + 1; ec = normal; normal = block; block = ec; } if (bc < bcol) bc = 0; else if (bc < bcol + max_col) bc = bc - bcol; else bc = max_col + 1; ASSEMBLE { /* ; Register strategy: ; bx == beginning column ; == relative line length ; dl == normal text attribute ; dh == block attribute ; cx == current virtual column ; == maximum columns in window ; ES:DI == screen pointer (destination) ; DS:SI == text pointer (source) ; [bp+show_eol] == access for local C variable */ push ds /* MUST save ds - push it on stack */ push si /* save si on stack */ push di /* save di on stack */ /* ; ; set up local register variables ; */ mov bx, WORD PTR bc /* get beginning column */ mov ax, WORD PTR normal /* get normal attribute */ mov dl, al /* keep it in dl */ mov ax, WORD PTR block /* get block attribute */ mov dh, al /* keep it in dh */ xor cx, cx /* col = 0, keep col in cl */ /* ; ; load screen and text pointer ; */ mov di, WORD PTR screen_ptr /* load OFFSET of screen ptr */ add di, WORD PTR off /* add offset of line */ mov ax, WORD PTR screen_ptr+2 /* load SEGMENT of screen ptr */ mov es, ax mov si, WORD PTR text /* load OFFSET of text ptr */ mov ax, WORD PTR text+2 /* load SEGMENT of text ptr */ mov ds, ax /* move segment of text in ds */ cmp si, 0 /* is offset of text ptr == NULL? */ jne nott_null /* no, output string */ cmp ax, 0 /* is segment of text ptr == NULL? */ je ddspl_eol /* yes, clear end of line */ } nott_null: ASSEMBLE { cmp cx, Word Ptr max_col /* is col == max_col? */ je ggetout /* yes, thru with line */ cmp cx, Word Ptr len /* is col == len? */ je ddspl_eol /* yes, check eol display */ } ttop: ASSEMBLE { lodsb /* get next char in string */ mov ah, dl /* assume normal attribute */ cmp cx, bx /* is col < bc? (less than beginning col) */ jl str_out1 /* yes, show char and normal attribute */ mov ah, dh /* must be in a block - show block attribute */ } str_out1: ASSEMBLE { stosw /* else show char on screen */ inc cx /* ++col */ cmp cx, Word Ptr max_col /* is col == max_col? */ je ggetout /* yes, thru with line */ cmp cx, Word Ptr len /* is col == len? */ jl ttop /* yes, check eol display */ } ddspl_eol: ASSEMBLE { cmp WORD PTR show_eol, FALSE /* look at the show_eol flag */ je stream_eol /* show_eol flag is FALSE, blank line */ mov al, EOL_CHAR /* load some eol indicator */ mov ah, dl /* assume normal attribute */ cmp cx, bx /* is col < bc? (less than beginning col) */ jl str_out2 /* yes, show char and normal attribute */ mov ah, dh /* must be in a block - show block attribute */ } str_out2: ASSEMBLE { stosw /* write blank and attribute to screen */ inc cx /* ++col */ cmp cx, Word Ptr max_col /* is col == max_col? */ jge ggetout /* yes, we're done */ } stream_eol: ASSEMBLE { mov al, ' ' /* clear rest of line w/ spaces */ } c1: ASSEMBLE { mov ah, dl /* assume normal attribute */ cmp cx, bx /* is col < bc? (less than beginning col) */ jl str_out3 /* yes, show char and normal attribute */ mov ah, dh /* must be in a block - show block attribute */ } str_out3: ASSEMBLE { stosw /* write blank and attribute to screen */ inc cx /* ++col */ cmp cx, Word Ptr max_col /* is col == max_col? */ jl c1 /* while less output block */ } ggetout: ASSEMBLE { pop di pop si pop ds } /* screen_ptr += off; bcol = window->start_col; for (col=0; col < max_col; col++, bcol++) { attr = normal; if (col >= bc && col <= ec) attr = block; if (col < len) c = *text++; else if (col == len && show_eol) c = EOL_CHAR; else c = ' '; *screen_ptr++ = c; *screen_ptr++ = attr; c_output( c, bcol, line, attr ); } */ } else { if (block_line) attr = block; else attr = normal; assert( len >= 0 ); assert( len <= g_display.ncols ); ASSEMBLE { /* ; Register strategy: ; bl == normal text attribute ; == relative line length ; cx == current virtual column ; dx == maximum columns in window ; ES:DI == screen pointer (destination) ; DS:SI == text pointer (source) ; [bp+show_eol] == access for local C variable */ push ds /* MUST save ds - push it on stack */ push di /* save di on stack */ push si /* save si on stack */ mov bx, WORD PTR attr /* keep attribute in bl */ mov dx, WORD PTR max_col /* keep max_col in dx */ xor cx, cx /* zero out cx (col) */ mov di, WORD PTR screen_ptr /* load OFFST of screen ptr */ add di, WORD PTR off /* add offset of line */ mov ax, WORD PTR screen_ptr+2 /* load SEGMENT of screen ptr */ mov es, ax mov si, WORD PTR text /* load OFFSET of text ptr */ mov ax, WORD PTR text+2 /* load SEGMENT of text ptr */ mov ds, ax /* move segment of text in ds */ cmp si, 0 /* is offset of pointer == NULL? */ jne nnot_null /* no, output string */ cmp ax, 0 /* is segment of pointer == NULL? */ je normeol /* yes, then clear rest of line */ } nnot_null: ASSEMBLE { mov ah, bl /* get attribute */ cmp cx, dx /* compare count with max columns */ jge getoutt /* yes, thru with line */ cmp cx, Word Ptr len /* compare count with len */ je normeol /* yes, clear end of line */ } topp: ASSEMBLE { lodsb /* get next char in string */ stosw /* else show char on screen */ inc cx /* ++col, count up to max_column */ cmp cx, dx /* compare count with max columns */ jge getoutt /* yes, thru with line */ cmp cx, Word Ptr len /* compare count with len */ jl topp /* yes, clear end of line */ } normeol: ASSEMBLE { cmp WORD PTR show_eol, FALSE /* look at the show_eol flag */ je clreol /* show_eol flag is FALSE, blank line */ mov al, EOL_CHAR /* load some eol indicator */ mov ah, bl /* assume normal attribute */ stosw /* write blank and attribute to screen */ inc cx /* ++col */ cmp cx, dx /* is col == max_col? */ jge getoutt /* yes, we're done */ } clreol: ASSEMBLE { mov ah, bl /* get attribute */ mov al, ' ' /* clear eol with ' ' */ sub dx, cx /* find number of columns left */ mov cx, dx /* put number of column left in cl */ rep stosw /* count is in cx - set rest of line to ' ' */ } getoutt: ASSEMBLE { pop si pop di pop ds } /* screen_ptr += off; bcol = window->start_col; for (col=0; col < max_col; col++, bcol++) { if (col < len) c = *text++; else if (col == len && show_eol) c = EOL_CHAR; else c = ' '; *screen_ptr++ = c; *screen_ptr++ = attr; c_output( c, bcol, line, attr ); } */ } } /* * Name: c_output * Purpose: Output one character on prompt lines * Date: June 5, 1991 * Passed: c: character to output to screen * col: col to display character * line: line number to display character * attr: attribute of character * Returns: none */ void c_output( int c, int col, int line, int attr ) { void FAR *screen_ptr; int off; screen_ptr = (void FAR *)g_display.display_address; /* * this next suggestion is part of chen's screen changes. * * off = line * 160 + col * 2; * * change to: */ off = line * (g_display.ncols*2) + col * 2; ASSEMBLE { mov bx, WORD PTR screen_ptr /* load OFFSET of screen ptr */ add bx, WORD PTR off /* add offset of line:col */ mov ax, WORD PTR screen_ptr+2 /* load SEGMENT of screen ptr */ mov es, ax mov cx, WORD PTR attr /* get attribute */ mov ah, cl /* put in ah */ mov cx, WORD PTR c /* get character */ mov al, cl /* put in al */ mov WORD PTR es:[bx], ax /* show char on screen */ } /* * this next suggestion is part of chen's screen changes. * * screen_ptr = g_display.display_address + line * 160 + col * 2; * * change to: * screen_ptr = g_display.display_address + line * (g_display.ncols*2) + col * 2; *screen_ptr++ = c; *screen_ptr = attr; */ } /* * Name: s_output * Purpose: To output a string * Date: June 5, 1991 * Passed: s: string to output * line: line to display * col: column to begin display * attr: color to display string * Notes: This function is used to output most strings not part of file text. */ void s_output( char FAR *s, int line, int col, int attr ) { void FAR *screen_ptr; int off; int max_col; max_col = g_display.ncols; screen_ptr = (void FAR *)g_display.display_address; /* * this next suggestion is part of chen's screen changes. * * off = line * 160 + col * 2; * * change to: */ off = line * (g_display.ncols*2) + col * 2; ASSEMBLE { push ds /* save ds on stack */ push di /* save di on stack */ push si /* save si on stack */ mov bx, WORD PTR attr /* keep attribute in bx */ mov cx, WORD PTR col /* put cols in cx */ mov dx, WORD PTR max_col /* keep max_col in dx */ mov di, WORD PTR screen_ptr /* load OFFSET of screen ptr */ add di, WORD PTR off /* add offset of line:col */ mov ax, WORD PTR screen_ptr+2 /* load SEGMENT of screen ptr */ mov es, ax mov si, WORD PTR s /* load offset of string ptr */ or si, si /* is it == NULL? */ je getout /* yes, no output needed */ mov ax, WORD PTR s+2 /* load segment of string ptr */ or ax, ax /* is pointer == NULL? */ je getout /* yes, no output needed */ mov ds, ax /* load segment of text in ds */ mov ah, bl /* put attribute in AH */ } top: ASSEMBLE { cmp cx, dx /* col < max_cols? */ jge getout /* no, thru with line */ lodsb /* get next char in string - put in al */ or al, al /* is it '\0' */ je getout /* yes, end of string */ cmp al, 0x0a /* is it '\n'? */ je getout /* yes, end of string */ stosw /* else show attr + char on screen (ah + al) */ inc cx /* col++ */ jmp SHORT top /* get another character */ } getout: ASSEMBLE { pop si /* get back si */ pop di /* get back di */ pop ds /* get back ds */ } /* * this next suggestion is part of chen's screen changes. * * screen_ptr = g_display.display_address + line * 160 + col * 2; * * change to: * screen_ptr = g_display.display_address + line * (g_display.ncols*2) + col * 2; max_col = g_display.ncols; while (*s && col < max) { *screen_ptr++ = *s++; *screen_ptr++ = attr; } */ } /* * Name: eol_clear * Purpose: To clear the line from col to max columns * Date: June 5, 1991 * Passed: col: column to begin clear * line: line to clear * attr: color to clear * Notes: Basic assembly */ void eol_clear( int col, int line, int attr ) { int max_col; void FAR *screen_ptr; int off; max_col = g_display.ncols; screen_ptr = (void FAR *)g_display.display_address; /* * this next suggestion is part of chen's screen changes. * * off = line * 160 + col * 2; * * change to: */ off = line * (g_display.ncols*2) + col * 2; ASSEMBLE { push di /* save di on stack */ mov bx, WORD PTR attr /* keep attribute in bx */ mov dx, WORD PTR col /* put cols in dx */ mov cx, WORD PTR max_col /* put max_col in cx */ cmp dx, cx /* max_cols < cols? */ jge getout /* no, thru with line */ sub cx, dx /* number of column to clear */ mov di, WORD PTR screen_ptr /* load OFFSET of screen ptr */ add di, WORD PTR off /* add offset of line:col */ mov ax, WORD PTR screen_ptr+2 /* load SEGMENT of screen ptr */ mov es, ax mov ah, bl /* get attribute in ah */ mov al, ' ' /* store ' ' in al */ rep stosw /* clear to end of line */ } getout: ASSEMBLE { pop di /* get back di from stack */ } /* for (; col < g_display.ncols; col++) { *p++ = ' '; *p++ = attr; } */ } /* * Name: window_eol_clear * Purpose: To clear the line from start_col to end_col * Date: June 5, 1991 * Passed: window: pointer to window * attr: color to clear * Notes: Basic assembly */ void window_eol_clear( TDE_WIN *window, int attr ) { int max_col; void FAR *screen_ptr; int off; if (!g_status.screen_display) return; screen_ptr = (void FAR *)g_display.display_address; /* * this next suggestion is part of chen's screen changes. * * off = window->cline * 160 + window->start_col * 2; * * change to: */ off = window->cline * (g_display.ncols*2) + window->start_col * 2; max_col = window->end_col + 1 - window->start_col; ASSEMBLE { push di /* save di on stack */ mov bx, WORD PTR attr /* keep attribute in bx */ mov cx, WORD PTR max_col /* put max_col in cx */ mov di, WORD PTR screen_ptr /* load OFFSET of screen ptr */ add di, WORD PTR off /* add offset of line:col */ mov ax, WORD PTR screen_ptr+2 /* load SEGMENT of screen ptr */ mov es, ax mov ah, bl /* get attribute in ah */ mov al, ' ' /* store ' ' in al */ rep stosw /* clear to end of line */ pop di /* get back di from stack */ } /* for (max_col=window->start_col; max_col <= window->end_col; max_col++) { *screen_ptr++ = ' '; *screen_ptr++ = attr; } */ } /* * Name: hlight_line * Date: July 21, 1991 * Passed: x: column to begin hi lite * y: line to begin hi lite * lgth: number of characters to hi lite * attr: attribute color * Notes: The attribute byte is the hi byte. */ void hlight_line( int x, int y, int lgth, int attr ) { int off; void FAR *screen_ptr; screen_ptr = (void FAR *)g_display.display_address; /* * this next suggestion is part of chen's screen changes. * * off = y * 160 + 2 * x + 1; * * change to: */ off = y * (g_display.ncols*2) + 2 * x + 1; /* add one - so it points to attribute byte */ ASSEMBLE { push di /* save di */ mov cx, lgth /* number of characters to change color */ mov di, WORD PTR screen_ptr /* get destination - video memory */ add di, off /* add offset */ mov ax, WORD PTR screen_ptr+2 mov es, ax mov ax, attr /* attribute */ } lite_len: ASSEMBLE { stosb /* store a BYTE */ inc di /* skip over character to next attribute */ loop lite_len /* change next attribute */ pop di /* restore di */ } } /* * Name: cls * Purpose: clear screen * Date: June 5, 1991 * Notes: Call the video BIOS routine to clear the screen. */ void cls( void ) { int line; unsigned char column; line = g_display.nlines + 1; /* * this next suggestion is part of chen's screen changes. * * add: */ column = (unsigned char)(g_display.ncols - 1); ASSEMBLE { xor ch, ch /* starting row in ch = 0 */ xor cl, cl /* starting column in cl = 0 */ mov ax, WORD PTR line /* get ending row */ mov dh, al /* put it in dh */ mov dl, Byte Ptr column /* ending column in dl = 79 */ mov bh, 7 /* attribute in bh = 7 (normal) */ mov al, 0 /* get number of lines */ mov ah, 6 /* get function number */ push bp /* some BIOS versions wipe out bp */ int 0x10 pop bp } } /* * Name: set_cursor_size * Purpose: To set cursor size according to insert mode. * Date: June 5, 1991 * Passed: csize: desired cursor size * Notes: use the global display structures to set the cursor size */ void set_cursor_size( int csize ) { ASSEMBLE { mov ah, 1 /* function 1 - set cursor size */ mov cx, WORD PTR csize /* get cursor size ch:cl == top:bot */ push bp int VIDEO_INT /* video interrupt = 10h */ pop bp } } /* * Name: set_overscan_color * Purpose: To set overscan color * Date: April 1, 1993 * Passed: color: overscan color * Notes: before setting the overscan color, the old overscan color * needs to be saved so it can be restored. */ void set_overscan_color( int color ) { ASSEMBLE { mov ah, 0x0b /* function 0x0b */ mov bl, BYTE PTR color /* get new overscan color */ xor bh, bh push bp int VIDEO_INT /* video interrupt = 10h */ pop bp } } /* * Name: save_screen_line * Purpose: To save the characters and attributes of a line on screen. * Date: June 5, 1991 * Passed: col: desired column, usually always zero * line: line on screen to save (0 up to max) * screen_buffer: buffer for screen contents, must be >= 160 chars * Notes: Save the contents of the line on screen where prompt is * to be displayed */ void save_screen_line( int col, int line, char *screen_buffer ) { char FAR *p; /* * this next suggestion is part of chen's screen changes. * * p = g_display.display_address + line * 160 + col * 2; * _fmemcpy( screen_buffer, p, 160 ); * * change to: */ p = g_display.display_address + line * (g_display.ncols*2) + col * 2; _fmemcpy( screen_buffer, p, (g_display.ncols*2) ); } /* * Name: restore_screen_line * Purpose: To restore the characters and attributes of a line on screen. * Date: June 5, 1991 * Passed: col: usually always zero * line: line to restore (0 up to max) * screen_buffer: buffer for screen contents, must be >= 160 chars * Notes: Restore the contents of the line on screen where the prompt * was displayed */ void restore_screen_line( int col, int line, char *screen_buffer ) { char FAR *p; /* * this next suggestion is part of chen's screen changes. * * p = g_display.display_address + line * 160 + col * 2; * _fmemcpy( p, screen_buffer, 160 ); * * change to: */ p = g_display.display_address + line * (g_display.ncols*2) + col * 2; _fmemcpy( p, screen_buffer, (g_display.ncols*2) ); } /* * Name: save_minor_area * Purpose: save text and attribute under the pulled menu * Date: November 13, 1993 * Passed: buffer: storage for text and attribute * wid: width of the pulled menu * len: length of pulled menu * row: starting row of pulled menu * col: starting column of pulled menu * Notes: assume 80 column mode */ void save_minor_area( int *buffer, int wid, int len, int row, int col ) { int off; int FAR *pointer; int i; int j; wid--; /* * this next suggestion is part of chen's screen changes. * * off = row * 80 + col; * * change to: */ off = row * g_display.ncols + col; pointer = (int FAR *)g_display.display_address + off; for (i=0; len > 0; len--) { for (j=wid; j >= 0; j--, i++) buffer[i] = pointer[j]; pointer += g_display.ncols; } } /* * Name: retore_minor_area * Purpose: restore text and attribute under the pulled menu * Date: November 13, 1993 * Passed: buffer: storage for text and attribute * wid: width of the pulled menu * len: length of pulled menu * row: starting row of pulled menu * col: starting column of pulled menu * Notes: assume 80 column mode */ void restore_minor_area( int *buffer, int wid, int len, int row, int col ) { int off; int FAR *pointer; int i; int j; wid--; /* * this next suggestion is part of chen's screen changes. * * off = row * 80 + col; * * change to: */ off = row * g_display.ncols + col; pointer = (int FAR *)g_display.display_address + off; for (i=0; len > 0; len--) { for (j=wid; j >= 0; j--, i++) pointer[j] = buffer[i]; pointer += g_display.ncols; } } #endif /* ********************************************************************** ****************************** PART 3 ****************************** ********************************************************************** * * System independent keyboard stuff. */ /* * Name: getfunc * Purpose: get the function assigned to key c * Date: July 11, 1991 * Passed: c: key just pressed * Notes: key codes less than 256 or 0x100 are not assigned a function. * The codes in the range 0-255 are ASCII and extended ASCII chars. */ int getfunc( int c ) { register int i = c; int key_found; if (!g_status.key_pending) { i = c; if (i <= 256) i = 0; else i = key_func.key[i-256]; } else { /* * allow the user to enter two-key combinations */ key_found = FALSE; for (i=0; i < MAX_TWO_KEYS; i++) { if (g_status.first_key == two_key_list.key[i].parent_key && c == two_key_list.key[i].child_key) { i = two_key_list.key[i].func; key_found = TRUE; break; } } if (key_found == FALSE) i = ERROR; } return( i ); } /* * Name: two_key * Purpose: set the two_key flag and prompt for the next key. * Date: April 1, 1992 * Notes: this function accepts two key commands. */ int two_key( TDE_WIN *arg_filler ) { s_output( console1, g_display.mode_line, 67, g_display.diag_color ); g_status.key_pending = TRUE; g_status.first_key = g_status.key_pressed; return( OK ); } /* * Name: getanswerkey * Purpose: To get answer to questions etc. * Author: Byrial Jensen * Date: September 2, 1993 * Modified: Frank Davis, November 13, 1993 (comments and bj_toupper()) * Returns: The pressed key, changed to uppercase if alfabetic * Notes: If a key of a macro starting with: * IfCapsLock character, or IfNotCapsLock character * is presed, the character will be returned, changed to uppercase * if a letter. */ int getanswerkey( void ) { int key; int macrokey; int macrofunc; int macronext; /* * get a response from the user. if ascii or extended ascii, return upper */ key = getkey( ); if (key <= 255) key = bj_toupper( key ); /* * else if key is assigned a character via macro, return upper key */ else if (getfunc( key ) == PlayBack) { macronext = macro.first_stroke[key - 256]; macrokey = macro.strokes[macronext].key; macrofunc = getfunc( macrokey ); /* * if this a letter, return upper. */ if (macrofunc == IfCapsLock || macrofunc == IfNotCapsLock) { macronext = macro.strokes[macronext].next; if (macronext != -1) { macrokey = macro.strokes[macronext].key; if (macrokey <= 255) key = bj_toupper( macrokey ); } } } return( key ); }