/* console.c * * AUTHOR: John L. Miller, johnmil@cs.cmu.edu / johnmil@jprc.com * DATE: 8/4/96 * * Copyright (c) 1996 John L. Miller * * Full permission is granted to use, modify and distribute * this code, provided: * 1) This comment field is included in its entirity * 2) No money is charged for any work including or based on * portions of this code. * * If you're a nice person and find this useful, I'd appreciate a * note letting me know about it. e-mail is usually what spurs me * on to improve and support software I've written. * * This file contains functions intended to provide the back * end to a console window for my semi-vt100 emulator. */ /* Note - one HUGE difference between console windows and terminal * windows. Console windows displays start at (0,0). Terminal displays * start at (1,1). YUCK! */ #include #include "vt100.h" int topScrollRow=TOP_EDGE; int bottomScrollRow=BOTTOM_EDGE; /* This variable will contain terminal configuration flags, such as * reverse/standard video, whether wrapping is enabled, and so on. */ int conTermMode; /* Variable to hold the cursor position for save/restore cursor calls */ COORD cursorPosSave={1,1}; /* Handles to the current console for input and output */ HANDLE hConIn, hConOut; /* Array of all the tabs which are currently set. Ironically, I think the * primary emulator can CLEAR tags, but not set them. */ int tabSet[132]={0}; int numTabs = 0; /* This section contains console-specific color information. NT consoles can * have Red, blue, green, and intensity flags set. Hence, 4 con_colors. */ #define NUM_CON_COLORS 4 /* Foreground and background colors are separated out */ int conForeColors, conBackColors; /* mapping between foreground and background console colors: needed * when reverse video is being used */ int conColorMapping[NUM_CON_COLORS][2] = { {FOREGROUND_RED, BACKGROUND_RED}, {FOREGROUND_BLUE, BACKGROUND_BLUE}, {FOREGROUND_GREEN, BACKGROUND_GREEN}, {FOREGROUND_INTENSITY, BACKGROUND_INTENSITY} }; /* Device-independant foreground and background flags stored here. * probably a bad division of labor, but hey, since we don't use * all of their flags in our console stuff (and hence can't retrieve * them), the information has to live SOMEWHERE. */ int scForeFlags, scBackFlags; /* Defines for array indexing for translation of flags */ #define SC_FLAG 0 #define CONSOLE_FLAG 1 /* Color mapping between SC (the vt-100 emulator device independant * flags) and NT console character specific flags. Flags which have no analog * are set to 0. Note that all global character attributes (character set * underline, bold, reverse) are all stored in foreground only */ const int scForeMapping[NUM_SC_ATTRIBUTES][2] = { {SC_RED,FOREGROUND_RED}, {SC_GREEN,FOREGROUND_GREEN}, {SC_BLUE,FOREGROUND_BLUE}, {SC_BOLD,FOREGROUND_INTENSITY}, {SC_UL,0}, {SC_BL,0}, {SC_RV,0}, {SC_ASCII,0}, {SC_G0,0}, {SC_G1,0}, {SC_GRAPHICS,0} }; /* Background color mapping between SC and console */ const int scBackMapping[NUM_SC_ATTRIBUTES][2] = { {SC_RED,BACKGROUND_RED}, {SC_GREEN,BACKGROUND_GREEN}, {SC_BLUE,BACKGROUND_BLUE}, {SC_BOLD,BACKGROUND_INTENSITY}, {SC_UL,0}, {SC_BL,0}, {SC_RV,0}, {SC_ASCII,0}, {SC_G0,0}, {SC_G1,0}, {SC_GRAPHICS,0} }; /* These arrays map character vals 0-255 to new values. * Since the G0 and G1 character sets don't have a direct analog in * NT, I'm settling for replacing the ones I know what to set them * to. */ char G0Chars[256]; char G1Chars[256]; /* These four sets of variables are just precomputed combinations of * all the possible flags to save time for masking. */ int allFore[2], allBack[2]; int bothFore[2], bothBack[2]; /* FORWARD DECLARATIONS */ int RawPrintLine( char *text, int len, int scrollAtEnd ); int Scroll( int row ); /* END FORWARD DECLARATIONS */ /* beInitVT100Terminal() - * * This function is called by the VT100 emulator as soon as the * front-end terminal is initialized. It's responsible for setting * initial state of the terminal, and initing our many wacky variables. */ int beInitVT100Terminal() { int i; CONSOLE_SCREEN_BUFFER_INFO csbi; /* Set tabs to every 8 spaces initially */ numTabs = 0; for (numTabs=0; numTabs < 132/8; numTabs++) tabSet[numTabs] = (numTabs+1)*8; /* Init the cursor save position to HOME */ cursorPosSave.X = 1; cursorPosSave.Y = 1; /* Disable scrolling window limits */ topScrollRow=TOP_EDGE; bottomScrollRow=BOTTOM_EDGE; conTermMode = ANSI_MODE|WRAP_MODE|REPEAT_MODE; hConIn = GetStdHandle(STD_INPUT_HANDLE); hConOut = GetStdHandle(STD_OUTPUT_HANDLE); /* Init our time-saving mask variables */ allFore[SC_FLAG] = allBack[SC_FLAG] = 0; allFore[CONSOLE_FLAG] = allBack[CONSOLE_FLAG] = 0; bothFore[SC_FLAG] = bothBack[SC_FLAG] = 0; bothFore[CONSOLE_FLAG] = bothBack[CONSOLE_FLAG] = 0; for (i=0; i= csbi.dwSize.X) { cursorPos.X -= csbi.dwSize.X; cursorPos.Y += 1; } if (cursorPos.Y < 0) cursorPos.Y = 0; SetConsoleCursorPosition(hConOut, cursorPos); return(0); } /* beRestoreCursor - * * Saved cursor position should be stored in a static * variable in the back end. This function restores the * cursor to the position stored in that variable. */ int beRestoreCursor(void) { CONSOLE_SCREEN_BUFFER_INFO csbi; COORD cursorPos; GetConsoleScreenBufferInfo(hConOut, &csbi); cursorPos = csbi.dwCursorPosition; cursorPos.Y += cursorPosSave.Y; SetConsoleCursorPosition(hConOut, cursorPos); return(0); } /* beSaveCursor - * * The back-end should maintain a static variable with the * last STORED cursor position in it. This function replaces * the contents of that variable with the current cursor position. * The cursor may be restored to this position by using the * beRestoreCursor function. */ int beSaveCursor(void) { CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(hConOut, &csbi); cursorPosSave = csbi.dwCursorPosition; cursorPosSave.Y -= csbi.srWindow.Top; return(0); } /* beGetTextAttributes - * * given a pointer to 'fore'ground and 'back'ground ints, * fill them with a device-independant description of the * current foreground and background colors, as well as any * font information in the foreground variable. */ int beGetTextAttributes( int *fore, int *back ) { CONSOLE_SCREEN_BUFFER_INFO csbi; int i; /* Since it's entirely possible that the text attributes were * changed without our terminal being notified, we might as well * make sure they're accurate. */ /* First, strip out everything in the screen buffer variables * that we can detect */ scForeFlags &= ~bothFore[SC_FLAG]; scBackFlags &= ~bothBack[SC_FLAG]; /* Now, find out what the real settings are, and set the * flag values accordingly. */ GetConsoleScreenBufferInfo(hConOut, &csbi); /* If reverse video is set, we need to reverse our color mappings * before any calculations get made. */ if (scForeFlags & SC_RV) { int tmpFore, tmpBack; tmpFore = csbi.wAttributes & conForeColors; tmpBack = csbi.wAttributes & conBackColors; csbi.wAttributes &= ~(conForeColors | conBackColors); for (i=0; i (csbi.dwSize.X - csbi.dwCursorPosition.X)) end = (csbi.dwSize.X - csbi.dwCursorPosition.X); /* If we're in non-ascii mode, we need to do a little * magic to get the right characters out. */ if (scForeFlags & SC_G1) { for (i=0; i toRow) return(-1); topScrollRow = fromRow; bottomScrollRow = toRow; return(0); } /* beRingBell - * * Ring the system bell once. */ int beRingBell(void) { MessageBeep((UINT)-1); return(0); } /* beGetTermMode - * * Return the value of conTermMode, which is the terminal settings which * can be queried/set by [?#h/l. */ int beGetTermMode() { return(conTermMode); } /* beSetTermMode - * * Set the terminal as requested, assuming we can. Right now we only handle a * couple of the possible flags, but we store many of the others. */ int beSetTermMode( int newMode ) { int i, changes; CONSOLE_SCREEN_BUFFER_INFO csbi; COORD newSize; SMALL_RECT newWindowRect; DWORD dwConMode; changes = conTermMode ^ newMode; /* For each bit set in 'changes', determine the * appropriate course of action. */ for (i=0; i < NUM_TERM_ATTR_MODES; i++) { if (termAttrMode[i] & changes) { switch(termAttrMode[i]) { case COL132_MODE: GetConsoleScreenBufferInfo(hConOut, &csbi); newSize.Y = csbi.dwSize.Y; newSize.X = (newMode & COL132_MODE) ? 132 : 80; if (newSize.X != csbi.dwSize.X) { newWindowRect.Top = csbi.srWindow.Top; newWindowRect.Bottom = csbi.srWindow.Bottom; newWindowRect.Left = 0; newWindowRect.Right = csbi.dwSize.X - 1; SetConsoleScreenBufferSize(hConOut, newSize); SetConsoleWindowInfo(hConOut, TRUE, &newWindowRect); } break; case WRAP_MODE: GetConsoleMode(hConOut,&dwConMode); if ( (newMode & WRAP_MODE) && (! (dwConMode & ENABLE_WRAP_AT_EOL_OUTPUT)) ) { dwConMode |= ENABLE_WRAP_AT_EOL_OUTPUT; SetConsoleMode(hConOut, dwConMode); } if ( (!(newMode & WRAP_MODE)) && (dwConMode & ENABLE_WRAP_AT_EOL_OUTPUT) ) { dwConMode &= ~ENABLE_WRAP_AT_EOL_OUTPUT; SetConsoleMode(hConOut, dwConMode); } break; case CURSORAPPL_MODE: case ANSI_MODE: case SMOOTHSCROLL_MODE: case REVSCREEN_MODE: case ORIGINREL_MODE: case REPEAT_MODE: /* bugbug - we don't handle any of these. */ break; } } } conTermMode = newMode; return(0); }