1607 lines
40 KiB
C
1607 lines
40 KiB
C
/*
|
|
* 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 "console.h"
|
|
|
|
HANDLE hOutputConsole = NULL;
|
|
DWORD 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 */
|
|
int
|
|
ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit)
|
|
{
|
|
OSVERSIONINFO os;
|
|
DWORD dwAttributes = 0;
|
|
DWORD dwRet = 0;
|
|
BOOL bRet = FALSE;
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
static bool bFirstConInit = true;
|
|
|
|
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&os);
|
|
|
|
hOutputConsole = GetStdHandle(OutputHandle);
|
|
if (hOutputConsole == INVALID_HANDLE_VALUE) {
|
|
dwRet = GetLastError();
|
|
error("GetStdHandle on OutputHandle failed with %d\n", dwRet);
|
|
return dwRet;
|
|
}
|
|
|
|
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes)) {
|
|
dwRet = GetLastError();
|
|
error("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet);
|
|
return dwRet;
|
|
}
|
|
|
|
SetConsoleTitle(consoleTitle);
|
|
|
|
dwAttributes = 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 dwRet;
|
|
}
|
|
|
|
if (!GetConsoleMode(hOutputConsole, &dwAttributes)) {
|
|
dwRet = GetLastError();
|
|
error("GetConsoleMode on hOutputConsole failed with %d\n", dwRet);
|
|
return dwRet;
|
|
|
|
}
|
|
|
|
dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
|
|
if (NULL != getenv("SSH_TERM_CONHOST_PARSER"))
|
|
isConHostParserEnabled = atoi(getenv("SSH_TERM_CONHOST_PARSER"));
|
|
|
|
/* 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 {
|
|
ConMoveCursorTop(csbi);
|
|
debug("console supports the ansi parsing");
|
|
}
|
|
|
|
ConSetScreenX();
|
|
ConSetScreenY();
|
|
ScrollTop = 0;
|
|
ScrollBottom = ConVisibleWindowHeight();
|
|
|
|
in_raw_mode = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Used to Uninitialize the Console */
|
|
int
|
|
ConExitRawMode()
|
|
{
|
|
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
|
in_raw_mode = 0;
|
|
if (hOutputConsole == NULL || !GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
|
|
return 0;
|
|
|
|
SetConsoleMode(hOutputConsole, dwSavedAttributes);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Used to exit the raw mode */
|
|
int
|
|
ConUnInitWithRestore()
|
|
{
|
|
DWORD dwWritten;
|
|
COORD Coord;
|
|
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
|
|
|
if (hOutputConsole == NULL)
|
|
return 0;
|
|
|
|
if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
|
|
return 0;
|
|
|
|
SetConsoleMode(hOutputConsole, 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);
|
|
return 0;
|
|
}
|
|
|
|
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 ((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(pszString);
|
|
} else {
|
|
if (hOutputConsole)
|
|
WriteConsoleW(hOutputConsole, utf16, cnt, &Result, 0);
|
|
else
|
|
Result = (DWORD)wprintf(utf16);
|
|
}
|
|
|
|
if (utf16)
|
|
free(utf16);
|
|
|
|
return cbString;
|
|
}
|
|
|
|
int
|
|
ConTranslateAndWriteString(char* pszString, int cbString)
|
|
{
|
|
DWORD Result = 0;
|
|
|
|
if (hOutputConsole)
|
|
WriteConsole(hOutputConsole, pszString, cbString, &Result, 0);
|
|
else
|
|
Result = (DWORD)printf(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(temp, sizeof(temp), Format, va_data);
|
|
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;
|
|
|
|
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))
|
|
memcpy(&visibleWindowRect, &consoleInfo.srWindow, sizeof(visibleWindowRect));
|
|
} else {
|
|
memcpy(&visibleWindowRect, &consoleInfo.srWindow, sizeof(visibleWindowRect));
|
|
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));
|
|
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
|
|
ConMoveCursorTop(CONSOLE_SCREEN_BUFFER_INFO csbi)
|
|
{
|
|
/* Windows server at first sends the "cls" after the connection is established.
|
|
* Since we don't want to loose any data on the console, we would like to scroll down
|
|
* the visible window.
|
|
*/
|
|
int 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;
|
|
}
|