int8_t Screen::init( char *userInputBuffer_p, uint8_t *switchToSession_p ) { // This always works: unsigned char mode = *((unsigned char far *)MK_FP( 0x40, 0x49 )); if ( mode == 7 ) { colorCard = 0; screenBase = (uint8_t far *)MK_FP( 0xb000, 0 ); } else { colorCard = 1; screenBase = (uint8_t far *)MK_FP( 0xb800, 0 ); } // Call int 10, ah=12 for EGA/VGA config union REGS inregs, outregs; struct SREGS segregs; inregs.h.ah = 0x12; inregs.h.bl = 0x10; int86x( 0x10, &inregs, &outregs, &segregs ); if ( outregs.h.bl == 0x10 ) { // Failed. Must be MDA or CGA rows = 25; } else { rows = *((unsigned char far *)MK_FP( 0x40, 0x84 )) + 1; } separatorRow = rows - INPUT_ROWS - 1; outputRows = rows - (INPUT_ROWS + 1); separatorRowAddr = screenBase + ( separatorRow * BYTES_PER_ROW ); inputAreaStart = separatorRowAddr + BYTES_PER_ROW; cur_y = cur_x = 0; cur_y2 = separatorRow + 1; input_len = 0; userInputBuffer = userInputBuffer_p; switchToSession = switchToSession_p; insertMode = 1; // Draw initial screen fillUsingWord( screenBase, 7<<8|32, rows * 80 ); fillUsingWord( separatorRowAddr, 7<<8|196, 80 ); return 0; }
void Screen::scrollInternal( void ) { if ( scrollRegion_top == 0 && scrollRegion_bottom == (terminalLines - 1) ) { // Classic scrolling behavior - lines at the top get pushed into to // scroll buffer. topOffset += BYTES_PER_LINE; if ( topOffset == bufferSize ) topOffset = 0; // Clear the newly opened line in the virtual buffer. // In theory we could do this with the clear method but that has far // higher overhead because it is general purpose. uint16_t far *tmp = (uint16_t *)(buffer + ScrOffset( 0, cursor_y )); uint16_t fillWord = (curAttr<<8) | 0x20; fillUsingWord( tmp, fillWord, 80 ); } else { // They are using a scroll region - do not add to our private // backscroll buffer. delLine( scrollRegion_top ); } // Stop updating the real screen - scrolling is slow. updateRealScreen = 0; virtualUpdated = 1; }
void Screen::clearConsole( void ) { #ifdef __TURBOC__ textattr( 7 ); clrscr( ); #else //uint16_t len = ScreenRows*80 + ScreenCols; uint16_t len = ScreenRows*80; fillUsingWord( (uint16_t far *)Screen_base, (7<<8|32), len ); #endif }
void Screen::clearInputArea( void ) { fillUsingWord( inputAreaStart, (7<<8|32), INPUT_ROWS * screenCols ); input_len = 0; cur_y = cur_x = 0; cur_y2 = separatorRow + 1; // Put the cursor back in the right spot to be pretty. gotoxy( cur_x, cur_y2 ); }
void Screen::repaintInputArea( uint16_t offset, char far *buffer, uint16_t len ) { uint8_t far *target = inputAreaStart + offset*2; for ( uint16_t i=0; i < len; i++ ) { *target = *buffer; buffer++; target += 2; } fillUsingWord( target, (7<<8|32), (SCBUFFER_MAX_INPUT_LEN-offset)*2 ); }
void Screen::repaintInputArea( uint16_t offset, char far *buffer, uint16_t len ) { uint8_t far *target = inputAreaStart + offset*2; for ( uint16_t i=0; i < len; i++ ) { if ( *buffer < 32 ) { *target = 254; } else { *target = *buffer; } buffer++; target += 2; } // Clear out to the end of the input area. fillUsingWord( target, (7<<8|32), (SCBUFFER_MAX_INPUT_LEN-offset)*2 ); }
void Screen::clear( uint16_t top_x, uint16_t top_y, uint16_t bot_x, uint16_t bot_y ) { uint16_t far *start = (uint16_t far *)(buffer + ScrOffset( top_x, top_y )); uint16_t far *end = (uint16_t far *)(buffer + ScrOffset( bot_x, bot_y )); // Add the +1 at the end because we need to clear the last byte inclusive, // not just up to the last byte. uint16_t chars = (bot_y*80+bot_x) - (top_y*80+top_x) + 1; uint16_t bytes = chars << 1; uint16_t fillWord = (curAttr<<8) | 0x20; if ( start <= end ) { // Contiguous storage // // for ( uint16_t i=0; i < bytes; i=i+2 ) { *start++ = fillWord; } #ifdef __TURBOC__ asm { push es; push di; cld; mov ax, fillWord; les di, start; mov cx, chars; rep stosw; pop di; pop es; } #else //for ( uint16_t i=0; i < bytes; i=i+2 ) { *start++ = fillWord; } fillUsingWord( start, fillWord, chars ); #endif } else {
void Session::puts( uint8_t attr, const char *str ) { // Indicate that we need repainting. was_updated = 1; // We are never going to add more than a few hundred bytes // at a time. Start by normalizing a pointer into the buffer, // then convert the normalized pointer back to a far pointer. // This avoids the overhead of huge pointer arithmetic on every // character. uint16_t far *current = virtBuffer; uint16_t offset = output_y * BYTES_PER_ROW + (output_x<<1); addToPtr( current, offset, uint16_t far * ); // At this point current pointing at the next location to be written to. // (AddToPtr macro normalized the pointer.) while ( *str ) { if ( *str == '\n' ) { // Newline processing - drop to the start of the next line str++; current += 80-output_x; output_y++; output_x=0; } else { // Normal character: write it and advance one position *current = (attr<<8|*str); current++; str++; output_x++; // Did we wrap around the right edge? if ( output_x == 80 ) { output_y++; output_x=0; } } // If after processing that character we are on a new line then // we need to check to see if we wrapped around the end of the buffer, // clear the new line, and if we have backscroll capability draw the // divider. // Fix me: the divider should only be drawn once outside of the loop. if ( output_x==0 ) { if ( output_y == virtBufferRows ) { // Wrapped around the end of the buffer. output_y = 0; current = virtBuffer; } // Clear new line. (It was probably used before.) fillUsingWord( current, 0, 80 ); // Put a divider on the next line in case the backscroll buffer // is being displayed while it is being modified. if ( virtBufferRows > (Screen::outputRows+1) ) { // Tmp is already at the start of the line, but we need to be // sure that it wasn't supposed to wrap to the start of the buffer. // Skip past open line uint16_t *tmp = current + 80; if ( (output_y + 1) == virtBufferRows ) { tmp = (uint16_t far *)virtBuffer; } fillUsingWord( tmp, 0x0FCD, 80 ); } } } // end for }
int8_t Screen::init( char *userInputBuffer_p, uint8_t *switchToSession_p ) { // This always works: What is our current video mode? unsigned char mode = *((unsigned char far *)MK_FP( 0x40, 0x49 )); if ( mode == 7 ) { colorMode = false; screenBase = (uint8_t far *)MK_FP( 0xb000, 0 ); } else { colorMode = true; screenBase = (uint8_t far *)MK_FP( 0xb800, 0 ); } // Next, find out if we are on an EGA or VGA card // // If EGA or better is installed then BL gets set to 00 to 03, which is // a memory size. If it comes back the same at the input (0x10) then // EGA or better is not installed bool isCGAorMDA; if ( getEgaMemSize( ) == 0x10 ) { // Failed. Must be MDA or CGA screenCols = 80; screenRows = 25; isCGAorMDA = true; } else { screenCols = *((unsigned char far *)MK_FP( 0x40, 0x4A )); screenRows = *((unsigned char far *)MK_FP( 0x40, 0x84 )) + 1; isCGAorMDA = false; } // If we are on a CGA or MDA then do this port voodoo to disable blinking. // Otherwise, use the nice interrupt to do it instead. This is to enable // the high bit background colors. if ( isCGAorMDA ) { uint16_t portBase = *((uint16_t far *)(MK_FP( 0x40, 0x63 ))) + 4; uint8_t modeSelectVal = *((uint8_t far *)(MK_FP( 0x40, 0x65 ))); modeSelectVal = modeSelectVal & 0xDF; outp( portBase, modeSelectVal ); } else { turnOffEgaBlink( ); } separatorRow = screenRows - INPUT_ROWS - 1; outputRows = screenRows - (INPUT_ROWS + 1); separatorRowAddr = screenBase + ( separatorRow * (screenCols<<1) ); inputAreaStart = separatorRowAddr + (screenCols<<1); cur_y = cur_x = 0; cur_y2 = separatorRow + 1; input_len = 0; // Storage areas provided by our caller userInputBuffer = userInputBuffer_p; switchToSession = switchToSession_p; insertMode = true; eatNextChar = false; colorPopup = false; // Draw initial screen fillUsingWord( screenBase, 7<<8|32, screenRows * screenCols ); fillUsingWord( separatorRowAddr, 7<<8|196, screenCols ); return 0; }