/* * Author: Microsoft Corp. * * Copyright (c) 2015 Microsoft Corp. * All rights reserved * * Common library for Windows Console Screen IO. * Contains Windows console related definition so that emulation code can draw * on Windows console screen surface. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <windows.h> #include <conio.h> #include <io.h> #include "debug.h" #include "console.h" #include "ansiprsr.h" HANDLE hOutputConsole = NULL; DWORD stdin_dwSavedAttributes = 0; DWORD stdout_dwSavedAttributes = 0; WORD wStartingAttributes = 0; int ScreenX; int ScreenY; int ScrollTop; int ScrollBottom; int LastCursorX; int LastCursorY; BOOL isAnsiParsingRequired = FALSE; char *pSavedScreen = NULL; static COORD ZeroCoord = { 0,0 }; COORD SavedScreenSize = { 0,0 }; COORD SavedScreenCursor = { 0, 0 }; SMALL_RECT SavedViewRect = { 0,0,0,0 }; CONSOLE_SCREEN_BUFFER_INFOEX SavedWindowState; BOOL isConHostParserEnabled = TRUE; typedef struct _SCREEN_RECORD { PCHAR_INFO pScreenBuf; COORD ScreenSize; COORD ScreenCursor; SMALL_RECT srWindowRect; }SCREEN_RECORD, *PSCREEN_RECORD; PSCREEN_RECORD pSavedScreenRec = NULL; int in_raw_mode = 0; char *consoleTitle = "OpenSSH SSH client"; /* Used to enter the raw mode */ void ConEnterRawMode() { DWORD dwAttributes = 0; DWORD dwRet = 0; BOOL bRet = FALSE; CONSOLE_SCREEN_BUFFER_INFO csbi; static bool bFirstConInit = true; hOutputConsole = GetStdHandle(STD_OUTPUT_HANDLE); if (hOutputConsole == INVALID_HANDLE_VALUE) { dwRet = GetLastError(); error("GetStdHandle on OutputHandle failed with %d\n", dwRet); return; } if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &stdin_dwSavedAttributes)) { dwRet = GetLastError(); error("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); return; } SetConsoleTitle(consoleTitle); dwAttributes = stdin_dwSavedAttributes; dwAttributes &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT); dwAttributes |= ENABLE_WINDOW_INPUT; if (!SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwAttributes)) { /* Windows NT */ dwRet = GetLastError(); error("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); return; } if (!GetConsoleMode(hOutputConsole, &stdout_dwSavedAttributes)) { dwRet = GetLastError(); error("GetConsoleMode on hOutputConsole failed with %d\n", dwRet); return; } dwAttributes = stdout_dwSavedAttributes; dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN; char *envValue = NULL; size_t len = 0; _dupenv_s(&envValue, &len, "SSH_TERM_CONHOST_PARSER"); if (NULL != envValue) { isConHostParserEnabled = atoi(envValue); free(envValue); } /* We use our custom ANSI parser when * a) User sets the environment variable "SSH_TERM_CONHOST_PARSER" to 0 * b) or when the console doesn't have the inbuilt capability to parse the ANSI/Xterm raw buffer. */ if (FALSE == isConHostParserEnabled || !SetConsoleMode(hOutputConsole, dwAttributes)) /* Windows NT */ isAnsiParsingRequired = TRUE; GetConsoleScreenBufferInfo(hOutputConsole, &csbi); /* if we are passing rawbuffer to console then we need to move the cursor to top * so that the clearscreen will not erase any lines. */ if (TRUE == isAnsiParsingRequired) { SavedViewRect = csbi.srWindow; debug("console doesn't support the ansi parsing"); } else { ConSaveViewRect(); debug("console supports the ansi parsing"); } ConSetScreenX(); ConSetScreenY(); ScrollTop = 0; ScrollBottom = ConVisibleWindowHeight(); in_raw_mode = 1; } /* Used to Uninitialize the Console */ void ConExitRawMode() { SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), stdin_dwSavedAttributes); SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), stdout_dwSavedAttributes); } /* Used to exit the raw mode */ void ConUnInitWithRestore() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (hOutputConsole == NULL) return; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), stdin_dwSavedAttributes); SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), stdout_dwSavedAttributes); Coord = consoleInfo.dwCursorPosition; Coord.X = 0; DWORD dwNumChar = (consoleInfo.dwSize.Y - consoleInfo.dwCursorPosition.Y) * consoleInfo.dwSize.X; FillConsoleOutputCharacter(hOutputConsole, ' ', dwNumChar, Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, wStartingAttributes, dwNumChar, Coord, &dwWritten); SetConsoleTextAttribute(hOutputConsole, wStartingAttributes); } BOOL ConSetScreenRect(int xSize, int ySize) { BOOL bSuccess = TRUE; CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */ SMALL_RECT srWindowRect; /* hold the new console size */ COORD coordScreen; bSuccess = GetConsoleScreenBufferInfo(hOutputConsole, &csbi); if (!bSuccess) return bSuccess; /* get the largest size we can size the console window to */ coordScreen = GetLargestConsoleWindowSize(hOutputConsole); /* define the new console window size and scroll position */ srWindowRect.Top = csbi.srWindow.Top; srWindowRect.Left = csbi.srWindow.Left; srWindowRect.Right = xSize - 1 + srWindowRect.Left; srWindowRect.Bottom = ySize - 1 + srWindowRect.Top; /* define the new console buffer size */ coordScreen.X = max(csbi.dwSize.X, xSize); coordScreen.Y = max(csbi.dwSize.Y, ySize); /* if the current buffer is larger than what we want, resize the */ /* console window first, then the buffer */ if (csbi.dwSize.X < coordScreen.X || csbi.dwSize.Y < coordScreen.Y) { bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); if (bSuccess) bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); } else { bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); if (bSuccess) bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); } if (bSuccess) ConSaveViewRect(); /* if the current buffer *is* the size we want, don't do anything! */ return bSuccess; } BOOL ConSetScreenSize(int xSize, int ySize) { BOOL bSuccess = TRUE; CONSOLE_SCREEN_BUFFER_INFO csbi; /* hold current console buffer info */ SMALL_RECT srWindowRect; /* hold the new console size */ COORD coordScreen; bSuccess = GetConsoleScreenBufferInfo(hOutputConsole, &csbi); if (!bSuccess) return bSuccess; /* get the largest size we can size the console window to */ coordScreen = GetLargestConsoleWindowSize(hOutputConsole); /* define the new console window size and scroll position */ srWindowRect.Right = (SHORT)(min(xSize, coordScreen.X) - 1); srWindowRect.Bottom = (SHORT)(min(ySize, coordScreen.Y) - 1); srWindowRect.Left = srWindowRect.Top = (SHORT)0; /* define the new console buffer size */ coordScreen.X = xSize; coordScreen.Y = ySize; /* if the current buffer is larger than what we want, resize the */ /* console window first, then the buffer */ if ((DWORD)csbi.dwSize.X * csbi.dwSize.Y > (DWORD)xSize * ySize) { bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); if (bSuccess) bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); } /* if the current buffer is smaller than what we want, resize the */ /* buffer first, then the console window */ if ((DWORD)csbi.dwSize.X * csbi.dwSize.Y < (DWORD)xSize * ySize) { bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen); if (bSuccess) bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect); } if (bSuccess) ConSaveViewRect(); /* if the current buffer *is* the size we want, don't do anything! */ return bSuccess; } /* Used to set the Color of the console and other attributes */ void ConSetAttribute(int *iParam, int iParamCount) { static int iAttr = 0; int i = 0; BOOL bRet = TRUE; if (iParamCount < 1) { iAttr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; iAttr = iAttr & ~BACKGROUND_INTENSITY; iAttr = iAttr & ~FOREGROUND_INTENSITY; iAttr = iAttr & ~COMMON_LVB_UNDERSCORE; iAttr = iAttr & ~COMMON_LVB_REVERSE_VIDEO; SetConsoleTextAttribute(hOutputConsole, (WORD)iAttr); } else { for (i = 0; i < iParamCount; i++) { switch (iParam[i]) { case ANSI_ATTR_RESET: iAttr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; iAttr = iAttr & ~BACKGROUND_RED; iAttr = iAttr & ~BACKGROUND_BLUE; iAttr = iAttr & ~BACKGROUND_GREEN; iAttr = iAttr & ~BACKGROUND_INTENSITY; iAttr = iAttr & ~FOREGROUND_INTENSITY; iAttr = iAttr & ~COMMON_LVB_UNDERSCORE; iAttr = iAttr & ~COMMON_LVB_REVERSE_VIDEO; break; case ANSI_BRIGHT: iAttr |= FOREGROUND_INTENSITY; break; case ANSI_DIM: break; case ANSI_NOUNDERSCORE: iAttr = iAttr & ~COMMON_LVB_UNDERSCORE; break; case ANSI_UNDERSCORE: iAttr |= COMMON_LVB_UNDERSCORE; break; case ANSI_BLINK: break; case ANSI_REVERSE: iAttr |= COMMON_LVB_REVERSE_VIDEO; break; case ANSI_HIDDEN: break; case ANSI_NOREVERSE: iAttr = iAttr & ~COMMON_LVB_REVERSE_VIDEO; break; case ANSI_DEFAULT_FOREGROUND: /* White */ iAttr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; case ANSI_FOREGROUND_BLACK: iAttr = iAttr & ~FOREGROUND_RED; iAttr = iAttr & ~FOREGROUND_BLUE; iAttr = iAttr & ~FOREGROUND_GREEN; iAttr |= 0; break; case ANSI_FOREGROUND_RED: iAttr = iAttr & ~FOREGROUND_GREEN; iAttr = iAttr & ~FOREGROUND_BLUE; iAttr |= FOREGROUND_RED; break; case ANSI_FOREGROUND_GREEN: iAttr = iAttr & ~FOREGROUND_BLUE; iAttr = iAttr & ~FOREGROUND_RED; iAttr |= FOREGROUND_GREEN; break; case ANSI_FOREGROUND_YELLOW: iAttr = iAttr & ~FOREGROUND_BLUE; iAttr |= FOREGROUND_RED | FOREGROUND_GREEN; break; case ANSI_FOREGROUND_BLUE: iAttr = iAttr & ~FOREGROUND_GREEN; iAttr = iAttr & ~FOREGROUND_RED; iAttr |= FOREGROUND_BLUE; break; case ANSI_FOREGROUND_MAGENTA: iAttr = iAttr & ~FOREGROUND_GREEN; iAttr |= FOREGROUND_BLUE | FOREGROUND_RED; break; case ANSI_FOREGROUND_CYAN: iAttr = iAttr & ~FOREGROUND_RED; iAttr |= FOREGROUND_BLUE | FOREGROUND_GREEN; break; case ANSI_FOREGROUND_WHITE: iAttr |= FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; break; case ANSI_DEFAULT_BACKGROUND: /* Black */ iAttr = iAttr & ~BACKGROUND_RED; iAttr = iAttr & ~BACKGROUND_BLUE; iAttr = iAttr & ~BACKGROUND_GREEN; iAttr |= 0; break; case ANSI_BACKGROUND_BLACK: iAttr = iAttr & ~BACKGROUND_RED; iAttr = iAttr & ~BACKGROUND_BLUE; iAttr = iAttr & ~BACKGROUND_GREEN; iAttr |= 0; break; case ANSI_BACKGROUND_RED: iAttr = iAttr & ~BACKGROUND_GREEN; iAttr = iAttr & ~BACKGROUND_BLUE; iAttr |= BACKGROUND_RED; break; case ANSI_BACKGROUND_GREEN: iAttr = iAttr & ~BACKGROUND_RED; iAttr = iAttr & ~BACKGROUND_BLUE; iAttr |= BACKGROUND_GREEN; break; case ANSI_BACKGROUND_YELLOW: iAttr = iAttr & ~BACKGROUND_BLUE; iAttr |= BACKGROUND_RED | BACKGROUND_GREEN; break; case ANSI_BACKGROUND_BLUE: iAttr = iAttr & ~BACKGROUND_GREEN; iAttr = iAttr & ~BACKGROUND_RED; iAttr |= BACKGROUND_BLUE; break; case ANSI_BACKGROUND_MAGENTA: iAttr = iAttr & ~BACKGROUND_GREEN; iAttr |= BACKGROUND_BLUE | BACKGROUND_RED; break; case ANSI_BACKGROUND_CYAN: iAttr = iAttr & ~BACKGROUND_RED; iAttr |= BACKGROUND_BLUE | BACKGROUND_GREEN; break; case ANSI_BACKGROUND_WHITE: iAttr |= BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_GREEN; break; case ANSI_BACKGROUND_BRIGHT: iAttr |= BACKGROUND_INTENSITY; break; default: continue; } } if (iAttr) bRet = SetConsoleTextAttribute(hOutputConsole, (WORD)iAttr); } } /* Returns the width of current screen */ int ConScreenSizeX() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (-1); return (consoleInfo.dwSize.X); } /* Sets the width of the screen */ int ConSetScreenX() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (-1); ScreenX = (consoleInfo.dwSize.X); return 0; } /* returns actual size of screen buffer */ int ConScreenSizeY() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (-1); return (consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1); } /* returns width of visible window */ int ConVisibleWindowWidth() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (-1); return (consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1); } /* returns height of visible window */ int ConVisibleWindowHeight() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (-1); return (consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1); } int ConSetScreenY() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (-1); ScreenY = consoleInfo.dwSize.Y - 1; return 0; } void ConFillToEndOfLine() { DWORD rc = 0; int size = ConScreenSizeX(); for (int i = ConGetCursorX(); i < size; i++) WriteConsole(hOutputConsole, (char *)" ", 1, &rc, 0); } int ConWriteString(char* pszString, int cbString) { DWORD Result = 0; int needed = 0; int cnt = 0; wchar_t* utf16 = NULL; if (pszString == NULL) return 0; if ((needed = MultiByteToWideChar(CP_UTF8, 0, pszString, cbString, NULL, 0)) == 0 || (utf16 = malloc(needed * sizeof(wchar_t))) == NULL || (cnt = MultiByteToWideChar(CP_UTF8, 0, pszString, cbString, utf16, needed)) == 0) { Result = (DWORD)printf_s(pszString); } else { if (hOutputConsole) WriteConsoleW(hOutputConsole, utf16, cnt, &Result, 0); else Result = (DWORD)wprintf_s(utf16); } if (utf16) free(utf16); return cbString; } int ConTranslateAndWriteString(char* pszString, int cbString) { DWORD Result = 0; if (pszString == NULL) return 0; if (hOutputConsole) WriteConsole(hOutputConsole, pszString, cbString, &Result, 0); else Result = (DWORD)printf_s(pszString); return Result; } BOOL ConWriteChar(CHAR ch) { int X, Y, Result; BOOL fOkay = TRUE; Y = ConGetCursorY(); X = ConGetCursorX(); switch (ch) { case 0x8: /* BackSpace */ if (X == 0) { ConSetCursorPosition(ScreenX - 1, --Y); WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); ConSetCursorPosition(ScreenX - 1, Y); } else { ConSetCursorPosition(X - 1, Y); WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); ConSetCursorPosition(X - 1, Y); } break; case '\r': ConSetCursorPosition(0, Y); break; case '\n': Y++; if (Y > ScrollBottom - 1) { ConScrollDown(ScrollTop, ScrollBottom); ConSetCursorPosition(0, ScrollBottom); } else ConSetCursorPosition(0, Y); break; default: fOkay = (BOOL)WriteConsole(hOutputConsole, &ch, 1, (LPDWORD)&Result, 0); /* last coord */ if (X >= ScreenX - 1) { if (Y >= ScrollBottom - 1) { /* last coord */ ConScrollDown(ScrollTop, ScrollBottom); ConMoveCursorPosition(-ConGetCursorX(), 0); } else ConMoveCursorPosition(-ConGetCursorX(), 1); } break; } return fOkay; } BOOL ConWriteCharW(WCHAR ch) { int X, Y, Result; BOOL fOkay = TRUE; Y = ConGetCursorY(); X = ConGetCursorX(); switch (ch) { case 0x8: /* BackSpace */ if (X == 0) { ConSetCursorPosition(ScreenX - 1, --Y); WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); ConSetCursorPosition(ScreenX - 1, Y); } else { ConSetCursorPosition(X - 1, Y); WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); ConSetCursorPosition(X - 1, Y); } break; case L'\r': ConSetCursorPosition(0, Y); break; case L'\n': Y++; if (Y > ScrollBottom - 1) { ConScrollDown(ScrollTop, ScrollBottom); ConSetCursorPosition(0, ScrollBottom); } else ConSetCursorPosition(0, Y); break; default: fOkay = (BOOL)WriteConsoleW(hOutputConsole, &ch, 1, (LPDWORD)&Result, 0); if (X >= ScreenX - 1) { /* last coord */ if (Y >= ScrollBottom - 1) { /* last coord */ ConScrollDown(ScrollTop, ScrollBottom); ConMoveCursorPosition(-ConGetCursorX(), 0); } else ConMoveCursorPosition(-ConGetCursorX(), 1); } break; } return fOkay; } /* Special Function for handling TABS and other bad control chars */ int ConWriteConsole(char *pData, int NumChars) { int X, CurrentY, CurrentX, Result; for (X = 0; (X < NumChars) && (pData[X] != '\0'); X++) { switch (pData[X]) { case 0: /* FALLTHROUGH */ case 1: /* FALLTHROUGH */ case 2: /* FALLTHROUGH */ case 3: /* FALLTHROUGH */ case 4: /* FALLTHROUGH */ case 5: /* FALLTHROUGH */ case 6: /* FALLTHROUGH */ case 11: /* FALLTHROUGH */ break; case 7: Beep(1000, 400); break; case 8: ConMoveCursorPosition(-1, 0); WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); ConMoveCursorPosition(-1, 0); break; case 9: { int i, MoveRight = TAB_LENGTH - (ConGetCursorX() % TAB_LENGTH); for (i = 0; i < MoveRight; i++) WriteConsole(hOutputConsole, " ", 1, (LPDWORD)&Result, 0); } break; case 10: CurrentY = ConGetCursorY() + 1; if (CurrentY >= ScrollBottom) { ConScrollDown(ScrollTop, ScrollBottom); ConMoveCursorPosition(-ConGetCursorX(), 0); } else ConMoveCursorPosition(0, 1); break; case 12: ConClearScreen(); ConSetCursorPosition(0, 0); break; case 13: ConMoveCursorPosition(-ConGetCursorX(), 0); break; case 14: /* FALLTHROUGH */ case 15: break; default: { CurrentY = ConGetCursorY(); CurrentX = ConGetCursorX(); WriteConsole(hOutputConsole, &pData[X], 1, (LPDWORD)&Result, 0); if (CurrentX >= ScreenX - 1) { /* last coord */ if (CurrentY >= ScrollBottom - 1) { /* last coord */ ConScrollDown(ScrollTop, ScrollBottom); ConMoveCursorPosition(-ConGetCursorX(), 0); } else ConMoveCursorPosition(-ConGetCursorX(), 1); } } } } return X; } PCHAR ConWriteLine(char* pData) { PCHAR pCurrent, pNext, pTab; DWORD Result; size_t distance, tabCount, pos; size_t tabLength, charCount; pCurrent = pData; pNext = strchr(pCurrent, '\r'); if (pNext != NULL) { distance = pNext - pCurrent; if (distance > (size_t)ScreenX) distance = (size_t)ScreenX; pos = 0; tabCount = 0; pTab = strchr(pCurrent, TAB_CHAR); if ((pTab != NULL) && (pTab < pNext)) { /* Tab exists in string So we use our WriteString */ while ((pTab != NULL) && (pTab < pNext) && (pos < (size_t)ScreenX)) { tabCount++; charCount = (pTab - pCurrent) - 1; /* Ignore actual TAB since we add 8 for it */ pos = charCount + (tabCount * TAB_LENGTH); pTab++; /* increment past last tab */ pTab = strchr(pTab, TAB_CHAR); } tabLength = (tabCount * TAB_LENGTH); distance = ConWriteConsole(pCurrent, (int)distance); /* Special routine for handling TABS */ } else WriteConsole(hOutputConsole, pCurrent, (DWORD)distance, &Result, 0); ConSetCursorPosition(0, ConGetCursorY() + 1); pCurrent += (distance + 2); /* Add one to always skip last char printed */ } else { distance = strlen(pCurrent); if (distance > (size_t)ScreenX) distance = (size_t)ScreenX; WriteConsole(hOutputConsole, pCurrent, (DWORD)distance, &Result, 0); pCurrent += distance; } return pCurrent; } PCHAR ConDisplayData(char* pData, int NumLines) { PCHAR pCurrent, pNext, pTab; DWORD Result; size_t Y, distance, pos, add; int linecnt = 0; pCurrent = pData; for (; (pCurrent) && ((Y = (size_t)ConGetCursorY()) <= (size_t)ScrollBottom) && (*pCurrent != '\0'); ) { pNext = strchr(pCurrent, '\n'); if (pNext != NULL) { --pNext; if (*pNext != '\r') { pNext++; add = 1; } else add = 2; distance = pNext - pCurrent; if (distance > 0 && linecnt < NumLines) { pos = 0; pTab = strchr(pCurrent, TAB_CHAR); if ((distance > (size_t)ScreenX) || ((pTab != NULL) && (pTab < pNext))) ConWriteConsole(pCurrent, (int)distance); /* Special routine for handling TABS */ else WriteConsole(hOutputConsole, pCurrent, (DWORD)distance, &Result, 0); } ConMoveCursorPosition(-ConGetCursorX(), 1); pCurrent += (distance + add); /* Add one to always skip last char printed */ linecnt++; } else { distance = strlen(pCurrent); if (distance > (size_t)ScreenX) distance = ScreenX; if (linecnt < NumLines) WriteConsole(hOutputConsole, pCurrent, (DWORD)distance, &Result, 0); return pCurrent + distance; } } return pCurrent; } int Con_printf(const char *Format, ...) { va_list va_data; int len; char temp[4096]; memset(temp, '\0', sizeof(temp)); va_start(va_data, Format); len = vsnprintf_s(temp, sizeof(temp), _TRUNCATE, Format, va_data); if (len == -1) { error("Error from vsnprintf_s!"); return -1; } ConWriteConsole(temp, len); va_end(va_data); return len; } BOOL ConDisplayCursor(BOOL bVisible) { CONSOLE_CURSOR_INFO ConsoleCursorInfo; if (GetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo)) { ConsoleCursorInfo.bVisible = bVisible; return SetConsoleCursorInfo(hOutputConsole, &ConsoleCursorInfo); } return FALSE; } void ConClearScreen() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; SMALL_RECT srcWindow; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = 0; Coord.Y = 0; DWORD dwNumChar = (consoleInfo.dwSize.Y) * (consoleInfo.dwSize.X); FillConsoleOutputCharacter(hOutputConsole, ' ', dwNumChar, Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, dwNumChar, Coord, &dwWritten); srcWindow = consoleInfo.srWindow; ConSetCursorPosition(0, 0); } void ConClearScrollRegion() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = 0; Coord.Y = ScrollTop + consoleInfo.srWindow.Top; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)consoleInfo.dwSize.X * (DWORD)ScrollBottom, Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, (DWORD)consoleInfo.dwSize.X * (DWORD)ScrollBottom, Coord, &dwWritten); ConSetCursorPosition(0, ScrollTop); } void ConClearEOScreen() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = 0; Coord.Y = (short)(ConGetCursorY() + 1) + consoleInfo.srWindow.Top; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)(consoleInfo.dwSize.X)* (DWORD)(consoleInfo.srWindow.Bottom - Coord.Y + 1), Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, (DWORD)(consoleInfo.dwSize.X)* (DWORD)(consoleInfo.srWindow.Bottom - Coord.Y + 1), Coord, &dwWritten); ConClearEOLine(); } void ConClearBOScreen() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = 0; Coord.Y = 0; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)(consoleInfo.dwSize.X)* (DWORD)(consoleInfo.dwSize.Y - ConGetCursorY() - 1), Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, (DWORD)(consoleInfo.dwSize.X)* (DWORD)(consoleInfo.dwSize.Y - ConGetCursorY() - 1), Coord, &dwWritten); ConClearBOLine(); } void ConClearLine() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = 0; Coord.Y = ConGetCursorY(); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, ScreenX, Coord, &dwWritten); FillConsoleOutputCharacter(hOutputConsole, ' ', ScreenX, Coord, &dwWritten); } void ConClearEOLine() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return;; Coord.X = ConGetCursorX() + consoleInfo.srWindow.Left; Coord.Y = ConGetCursorY() + consoleInfo.srWindow.Top; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)(ScreenX - ConGetCursorX()), Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, (DWORD)(ScreenX - ConGetCursorX()), Coord, &dwWritten); } void ConClearNFromCursorRight(int n) { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = ConGetCursorX() + consoleInfo.srWindow.Left; Coord.Y = ConGetCursorY() + consoleInfo.srWindow.Top; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)n, Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, (DWORD)n, Coord, &dwWritten); } void ConClearNFromCursorLeft(int n) { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = ConGetCursorX() + consoleInfo.srWindow.Left - n; Coord.Y = ConGetCursorY() + consoleInfo.srWindow.Top; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)n, Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, (DWORD)n, Coord, &dwWritten); } void ConScrollDownEntireBuffer() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; ConScrollDown(0, consoleInfo.dwSize.Y - 1); return; } void ConScrollUpEntireBuffer() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; ConScrollUp(0, consoleInfo.dwSize.Y - 1); return; } void ConScrollUp(int topline, int botline) { SMALL_RECT ScrollRect; SMALL_RECT ClipRect; COORD destination; CHAR_INFO Fill; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; if ((botline - topline) == consoleInfo.dwSize.Y - 1) { /* scrolling whole buffer */ ScrollRect.Top = topline; ScrollRect.Bottom = botline; } else { ScrollRect.Top = topline + consoleInfo.srWindow.Top; ScrollRect.Bottom = botline + consoleInfo.srWindow.Top; } ScrollRect.Left = 0; ScrollRect.Right = ConScreenSizeX() - 1; ClipRect.Top = ScrollRect.Top; ClipRect.Bottom = ScrollRect.Bottom; ClipRect.Left = ScrollRect.Left; ClipRect.Right = ScrollRect.Right; destination.X = 0; destination.Y = ScrollRect.Top + 1; Fill.Attributes = consoleInfo.wAttributes; Fill.Char.AsciiChar = ' '; BOOL bRet = ScrollConsoleScreenBuffer(hOutputConsole, &ScrollRect, &ClipRect, destination, &Fill ); } void ConMoveVisibleWindow(int offset) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; SMALL_RECT visibleWindowRect; errno_t r = 0; memset(&visibleWindowRect, 0, sizeof(SMALL_RECT)); if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) { /* Check if applying the offset results in console buffer overflow. * if yes, then scrolldown the console buffer. */ if ((consoleInfo.srWindow.Bottom + offset) >= (consoleInfo.dwSize.Y - 1)) { for (int i = 0; i < offset; i++) ConScrollDown(0, consoleInfo.dwSize.Y - 1); if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo) == FALSE) { error("GetConsoleScreenBufferInfo failed with %d", GetLastError()); return; } if ((r = memcpy_s(&visibleWindowRect, sizeof(visibleWindowRect), &consoleInfo.srWindow, sizeof(visibleWindowRect))) != 0) { error("memcpy_s failed with error: %d.", r); return; } } else { if ((r = memcpy_s(&visibleWindowRect, sizeof(visibleWindowRect), &consoleInfo.srWindow, sizeof(visibleWindowRect))) != 0) { error("memcpy_s failed with error: %d.", r); return; } visibleWindowRect.Top += offset; visibleWindowRect.Bottom += offset; } SetConsoleWindowInfo(hOutputConsole, TRUE, &visibleWindowRect); } } void ConScrollDown(int topline, int botline) { SMALL_RECT ScrollRect; COORD destination; CHAR_INFO Fill; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; if ((botline - topline) == consoleInfo.dwSize.Y - 1) { /* scrolling whole buffer */ ScrollRect.Top = topline; ScrollRect.Bottom = botline; } else { ScrollRect.Top = topline + consoleInfo.srWindow.Top + 1; ScrollRect.Bottom = botline + consoleInfo.srWindow.Top; } ScrollRect.Left = 0; ScrollRect.Right = ConScreenSizeX() - 1; destination.X = 0; destination.Y = ScrollRect.Top - 1; Fill.Attributes = consoleInfo.wAttributes; Fill.Char.AsciiChar = ' '; BOOL bRet = ScrollConsoleScreenBuffer(hOutputConsole, &ScrollRect, NULL, destination, &Fill ); } void ConClearBOLine() { DWORD dwWritten; COORD Coord; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = 0; Coord.Y = (short)(ConGetCursorY()); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, (DWORD)(ConGetCursorX()), Coord, &dwWritten); FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)(ConGetCursorX()), Coord, &dwWritten); } void ConSetCursorPosition(int x, int y) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; COORD Coord; int rc; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = (short)(x); Coord.Y = (short)(y); if ((y > consoleInfo.dwSize.Y - 1) && y > LastCursorY) { for (int n = LastCursorY; n < y; n++) GoToNextLine(); } if (y >= consoleInfo.dwSize.Y) { Coord.Y = consoleInfo.dwSize.Y - 1; } if (!SetConsoleCursorPosition(hOutputConsole, Coord)) rc = GetLastError(); LastCursorX = x; LastCursorY = y; } BOOL ConChangeCursor(CONSOLE_CURSOR_INFO *pCursorInfo) { return SetConsoleCursorInfo(hOutputConsole, pCursorInfo); } void ConGetCursorPosition(int *x, int *y) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) { *x = consoleInfo.dwCursorPosition.X; *y = consoleInfo.dwCursorPosition.Y; } } int ConGetCursorX() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return 0; return consoleInfo.dwCursorPosition.X; } int is_cursor_at_lastline_of_visible_window() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; int return_val = 0; if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) { int cursor_linenum_in_visible_window = consoleInfo.dwCursorPosition.Y - consoleInfo.srWindow.Top; if (cursor_linenum_in_visible_window >= ConVisibleWindowHeight() - 1) return_val = 1; } return return_val; } int ConGetCursorY() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return 0; return (consoleInfo.dwCursorPosition.Y - consoleInfo.srWindow.Top); } int ConGetBufferHeight() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return 0; return (consoleInfo.dwSize.Y - 1); } void ConMoveCursorPosition(int x, int y) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; COORD Coord; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; Coord.X = (short)(consoleInfo.dwCursorPosition.X + x); Coord.Y = (short)(consoleInfo.dwCursorPosition.Y + y); SetConsoleCursorPosition(hOutputConsole, Coord); } void ConGetRelativeCursorPosition(int *x, int *y) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; *x -= consoleInfo.srWindow.Left; *y -= consoleInfo.srWindow.Top; } void ConDeleteChars(int n) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; COORD coord; CHAR_INFO chiBuffer[256]; // 1 row, 256 characters SMALL_RECT sr; COORD temp; int result; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return; coord.X = (short)(consoleInfo.dwCursorPosition.X); coord.Y = (short)(consoleInfo.dwCursorPosition.Y); sr.Left = coord.X + n; sr.Top = coord.Y; sr.Bottom = coord.Y; sr.Right = consoleInfo.srWindow.Right; temp.X = 256; temp.Y = 1; result = ReadConsoleOutput(hOutputConsole, /* console screen buffer handle */ (PCHAR_INFO)chiBuffer, /* address of buffer that receives data */ temp, /* column-row size of destination buffer */ ZeroCoord, /* upper-left cell to write to */ &sr /* address of rectangle to read from */ ); ConClearEOLine(); sr.Left = coord.X; temp.X = 256; temp.Y = 1; sr.Right -= n; result = WriteConsoleOutput(hOutputConsole, (PCHAR_INFO)chiBuffer, temp, ZeroCoord, &sr); } SCREEN_HANDLE ConSaveScreenHandle(SCREEN_HANDLE hScreen) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; int result, width, height; if (hOutputConsole == NULL) return NULL; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (NULL); if (pScreenRec == NULL) { pScreenRec = (PSCREEN_RECORD)malloc(sizeof(SCREEN_RECORD)); if (pScreenRec == NULL) fatal("out of memory"); pScreenRec->pScreenBuf = NULL; } pScreenRec->srWindowRect = consoleInfo.srWindow; width = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; height = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; pScreenRec->ScreenSize.X = width; pScreenRec->ScreenSize.Y = height; pScreenRec->ScreenCursor.X = consoleInfo.dwCursorPosition.X - consoleInfo.srWindow.Left; pScreenRec->ScreenCursor.Y = consoleInfo.dwCursorPosition.Y - consoleInfo.srWindow.Top; if (pScreenRec->pScreenBuf == NULL) pScreenRec->pScreenBuf = (PCHAR_INFO)malloc(sizeof(CHAR_INFO) * width * height); if (!pScreenRec->pScreenBuf) { if (pScreenRec != (PSCREEN_RECORD)hScreen) free(pScreenRec); return NULL; } result = ReadConsoleOutput(hOutputConsole, /* console screen buffer handle */ (PCHAR_INFO)(pScreenRec->pScreenBuf),/* address of buffer that receives data */ pScreenRec->ScreenSize, /* column-row size of destination buffer */ ZeroCoord, /* upper-left cell to write to */ &consoleInfo.srWindow /* address of rectangle to read from */ ); return((SCREEN_HANDLE)pScreenRec); } BOOL ConRestoreScreenHandle(SCREEN_HANDLE hScreen) { BOOL fOkay = FALSE; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; COORD beginOfScreen = { 0, 0 }; PCHAR_INFO pSavedCharInfo; DWORD dwWritten; PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; int width, height; if (hOutputConsole == NULL) return FALSE; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (FALSE); width = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; height = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; beginOfScreen.X = consoleInfo.srWindow.Left; beginOfScreen.Y = consoleInfo.srWindow.Top; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)width*height, beginOfScreen, &dwWritten); pSavedCharInfo = (PCHAR_INFO)(pScreenRec->pScreenBuf); SetConsoleTextAttribute(hOutputConsole, pSavedCharInfo->Attributes); FillConsoleOutputAttribute(hOutputConsole, pSavedCharInfo->Attributes, (DWORD)width*height, beginOfScreen, &dwWritten); fOkay = WriteConsoleOutput(hOutputConsole, /* handle to a console screen buffer */ (PCHAR_INFO)(pScreenRec->pScreenBuf), /* pointer to buffer with data to write */ pScreenRec->ScreenSize, /* column-row size of source buffer */ ZeroCoord, /* upper-left cell to write from */ &consoleInfo.srWindow /* pointer to rectangle to write to */ ); SetConsoleWindowInfo(hOutputConsole, TRUE, &pScreenRec->srWindowRect); ConSetCursorPosition(pScreenRec->ScreenCursor.X, pScreenRec->ScreenCursor.Y); return fOkay; } BOOL ConRestoreScreenColors() { SCREEN_HANDLE hScreen = pSavedScreenRec; BOOL fOkay = FALSE; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; COORD beginOfScreen = { 0, 0 }; PCHAR_INFO pSavedCharInfo; DWORD dwWritten; PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; if (hOutputConsole == NULL) return FALSE; if (pSavedScreen == NULL) return FALSE; if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) return (FALSE); beginOfScreen.X = consoleInfo.srWindow.Left; beginOfScreen.Y = consoleInfo.srWindow.Top; FillConsoleOutputCharacter(hOutputConsole, ' ', (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, beginOfScreen, &dwWritten); pSavedCharInfo = (PCHAR_INFO)(pScreenRec->pScreenBuf); SetConsoleTextAttribute(hOutputConsole, pSavedCharInfo->Attributes); FillConsoleOutputAttribute(hOutputConsole, pSavedCharInfo->Attributes, (DWORD)pScreenRec->ScreenSize.X*pScreenRec->ScreenSize.Y, beginOfScreen, &dwWritten); return fOkay; } void ConDeleteScreenHandle(SCREEN_HANDLE hScreen) { PSCREEN_RECORD pScreenRec = (PSCREEN_RECORD)hScreen; free(pScreenRec->pScreenBuf); free(pScreenRec); } /* Restores Previous Saved screen info and buffer */ BOOL ConRestoreScreen() { return ConRestoreScreenHandle(pSavedScreenRec); } /* Saves current screen info and buffer */ void ConSaveScreen() { pSavedScreenRec = (PSCREEN_RECORD)ConSaveScreenHandle(pSavedScreenRec); } void ConSaveViewRect() { CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) SavedViewRect = csbi.srWindow; } void ConRestoreViewRect() { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; HWND hwnd = FindWindow(NULL, consoleTitle); WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(hwnd, &wp); if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo) && ((consoleInfo.srWindow.Top != SavedViewRect.Top || consoleInfo.srWindow.Bottom != SavedViewRect.Bottom))) { if ((SavedViewRect.Right - SavedViewRect.Left > consoleInfo.dwSize.X) || (wp.showCmd == SW_SHOWMAXIMIZED)) { COORD coordScreen; coordScreen.X = SavedViewRect.Right - SavedViewRect.Left; coordScreen.Y = consoleInfo.dwSize.Y; SetConsoleScreenBufferSize(hOutputConsole, coordScreen); ShowWindow(hwnd, SW_SHOWMAXIMIZED); } else ShowWindow(hwnd, SW_RESTORE); SetConsoleWindowInfo(hOutputConsole, TRUE, &SavedViewRect); } } BOOL ConIsRedirected(HANDLE hInput) { DWORD dwMode; return !GetConsoleMode(hInput, &dwMode); } HANDLE GetConsoleOutputHandle() { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; HANDLE hTemp = GetStdHandle(STD_OUTPUT_HANDLE); if (ConIsRedirected(hTemp)) hTemp = CreateFile(TEXT("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, OPEN_EXISTING, 0, NULL); return hTemp; } HANDLE GetConsoleInputHandle() { SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; HANDLE hTemp = GetStdHandle(STD_INPUT_HANDLE); if (ConIsRedirected(hTemp)) hTemp = CreateFile(TEXT("CONIN$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, OPEN_EXISTING, 0, NULL); return hTemp; } void ConSaveWindowsState() { CONSOLE_SCREEN_BUFFER_INFOEX csbiex; csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); if (!GetConsoleScreenBufferInfoEx(hOutputConsole, &csbiex)) return; SavedWindowState = csbiex; } void ConMoveCursorTopOfVisibleWindow() { CONSOLE_SCREEN_BUFFER_INFO csbi; int offset; if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) { offset = csbi.dwCursorPosition.Y - csbi.srWindow.Top; ConMoveVisibleWindow(offset); ConSaveViewRect(); } } HANDLE get_console_handle(FILE *stream, DWORD * mode) { int file_num = 0, ret = 0; intptr_t lHandle = 0; HANDLE hFile = NULL; DWORD type = 0; file_num = (_fileno)(stream); if (file_num == -1) { return INVALID_HANDLE_VALUE; } lHandle = _get_osfhandle(file_num); if (lHandle == -1 && errno == EBADF) { return INVALID_HANDLE_VALUE; } type = GetFileType((HANDLE)lHandle); if (type == FILE_TYPE_CHAR && file_num >= 0 && file_num <= 2) { if (file_num == 0) hFile = GetStdHandle(STD_INPUT_HANDLE); else if (file_num == 1) hFile = GetStdHandle(STD_OUTPUT_HANDLE); else if (file_num == 2) hFile = GetStdHandle(STD_ERROR_HANDLE); if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE) && (GetFileType(hFile) == FILE_TYPE_CHAR) && GetConsoleMode(hFile, mode)) return hFile; } return INVALID_HANDLE_VALUE; }