Terminalissues (#89)

#576 - fix the EVENT_CONSOLE_CARET issue.. Wrongly read the X, Y coordinates
#575 - when backspace key is pressed then screen is not refreshed correctly
#574 - when delete key is pressed then screen is not refreshed correctly (the last character is repeated in the end)
#573 - while using up/down arrows, screen is not refreshed correctly (there are some left over characters of bigger command)
#572 - clear screen is not clearing the whole console
#571 - Move the cursor to top of visible window so that nothing will be erased on the console.
#570 - code cleanup for console related logic
#569 - wrong implementation of TIOCGWINSZ. This is causing lot of issues when windows open ssh client is connecting to linux ssh server.
#568 - Scrolling issue when the cursor is at the last line of the visible window.
#567 - Logic to pass the raw buffer to console is wrong.
This commit is contained in:
bagajjal 2017-03-13 14:53:58 -07:00 committed by Manoj Ampalam
parent ca5de7fbbb
commit 8addc04e87
14 changed files with 402 additions and 248 deletions

View File

@ -204,6 +204,8 @@
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\sys\types.h" /> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\sys\types.h" />
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\ctype.h" /> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\ctype.h" />
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\stdlib.h" /> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\stdlib.h" />
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\console.h" />
<ClInclude Include="..\win32compat\tnnet.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -139,6 +139,8 @@
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\ctype.h"> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\inc\ctype.h">
<Filter>inc</Filter> <Filter>inc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\console.h" />
<ClInclude Include="..\win32compat\tnnet.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="inc"> <Filter Include="inc">

View File

@ -48,14 +48,12 @@ extern int ScreenX;
extern int ScreenY; extern int ScreenY;
extern int ScrollTop; extern int ScrollTop;
extern int ScrollBottom; extern int ScrollBottom;
extern BOOL bAnsiParsing;
bool gbVTAppMode = false; bool gbVTAppMode = false;
/* private message for port printing to */ /* private message for port printing to */
unsigned char VT_ST[] = { 0x1b, '/', '\0' }; unsigned char VT_ST[] = { 0x1b, '/', '\0' };
static int AutoWrap = 1; static int AutoWrap = 1;
BOOL bAtEOLN = FALSE; BOOL bAtEOLN = FALSE;
static int term_mode = TERM_ANSI;
/* /*
* ParseANSI globals - these need to be here, because sometimes blocks are sent * ParseANSI globals - these need to be here, because sometimes blocks are sent
@ -142,12 +140,24 @@ BufConvertToG2(char * pszBuffer, int length)
void void
GoToNextLine() GoToNextLine()
{ {
if (ConGetCursorY() >= (ConWindowSizeY() - 1)) { int currentX = 0;
ConScrollDown(ScrollTop, ScrollBottom); int currentY = 0;
ConMoveCursorPosition(-ConGetCursorX(), 0);
ConGetCursorPosition(&currentX, &currentY);
/* If the cursor is the last line of the visible window */
if (is_cursor_at_lastline_of_visible_window()) {
if (currentY >= ConGetBufferHeight()) {
/* handle the max window buffer size */
ConScrollDown(0, currentY);
ConMoveCursorPosition(-currentX, 0);
} else {
/* max window buffer is not breached */
ConMoveVisibleWindow(1);
ConMoveCursorPosition(-currentX, 1);
} }
else } else /* If the cursor is NOT the last line of the visible window */
ConMoveCursorPosition(-ConGetCursorX(), 1); ConMoveCursorPosition(-currentX, 1);
bAtEOLN = FALSE; bAtEOLN = FALSE;
} }
@ -155,8 +165,8 @@ GoToNextLine()
unsigned char* unsigned char*
ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char **respbuf, size_t *resplen) ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char **respbuf, size_t *resplen)
{ {
int CurrentX; int currentX;
int CurrentY; int currentY;
int bufLen, cmpLen, i; int bufLen, cmpLen, i;
if (!fcompletion) { if (!fcompletion) {
@ -164,7 +174,6 @@ ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char
unsigned char * pszCurrent = pszBuffer + 1; unsigned char * pszCurrent = pszBuffer + 1;
unsigned char * pszNewCurrent = pszCurrent; unsigned char * pszNewCurrent = pszCurrent;
if (term_mode == TERM_ANSI && bAnsiParsing)
pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd, respbuf, resplen); pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd, respbuf, resplen);
/* Pointer didn't move inside Parse function */ /* Pointer didn't move inside Parse function */
@ -200,8 +209,8 @@ ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char
case 8: case 8:
pszBuffer++; pszBuffer++;
if (!bAtEOLN) { if (!bAtEOLN) {
CurrentX = ConGetCursorX(); currentX = ConGetCursorX();
if (CurrentX == 0) { if (currentX == 0) {
ConMoveCursorPosition(ScreenX - 1, -1); ConMoveCursorPosition(ScreenX - 1, -1);
ConWriteString(" ", 1); ConWriteString(" ", 1);
} else { } else {
@ -263,10 +272,8 @@ ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char
if (*pszCurrent == 27) { if (*pszCurrent == 27) {
pszNewCurrent += ConWriteString((char *)pszCurrent, 1); pszNewCurrent += ConWriteString((char *)pszCurrent, 1);
return pszBuffer + 1; return pszBuffer + 1;
} else { } else
if (term_mode == TERM_ANSI)
pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd, respbuf, resplen); pszNewCurrent = ParseANSI(pszCurrent, pszBufferEnd, respbuf, resplen);
}
if (pszNewCurrent > pszCurrent) if (pszNewCurrent > pszCurrent)
pszBuffer = pszNewCurrent; pszBuffer = pszNewCurrent;
@ -278,12 +285,12 @@ ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char
if (bAtEOLN) GoToNextLine(); if (bAtEOLN) GoToNextLine();
unsigned char* pszCurrent = pszBuffer; unsigned char* pszCurrent = pszBuffer;
CurrentX = ConGetCursorX(); currentX = ConGetCursorX();
int nCharCount = 0; int nCharCount = 0;
while ((pszCurrent < pszBufferEnd) && (*pszCurrent != (unsigned char)27) while ((pszCurrent < pszBufferEnd) && (*pszCurrent != (unsigned char)27)
&& (*pszCurrent > (unsigned char)15) && (*pszCurrent != (unsigned char)255) && (*pszCurrent > (unsigned char)15) && (*pszCurrent != (unsigned char)255)
&& (CurrentX++ < ScreenX)) { && (currentX++ < ScreenX)) {
if (*pszCurrent > 127) { if (*pszCurrent > 127) {
unsigned char nLead = *pszCurrent; unsigned char nLead = *pszCurrent;
nCharCount++; nCharCount++;
@ -305,7 +312,7 @@ ParseBuffer(unsigned char* pszBuffer, unsigned char* pszBufferEnd, unsigned char
pszBuffer += ConWriteString((char *)pszBuffer, (int)(pszCurrent - pszBuffer)); pszBuffer += ConWriteString((char *)pszBuffer, (int)(pszCurrent - pszBuffer));
if ((CurrentX >= ScreenX) && AutoWrap && !(VTMode & MODE_CURSORAPP)) if ((currentX >= ScreenX) && AutoWrap && !(VTMode & MODE_CURSORAPP))
bAtEOLN = TRUE; bAtEOLN = TRUE;
} }
break; break;
@ -561,10 +568,10 @@ ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEnd, unsigned char
if (iParam[0]) { if (iParam[0]) {
int i; int i;
for (i = 0; i < iParam[0]; i++) for (i = 0; i < iParam[0]; i++)
ConScrollUp(ConGetCursorY() - 1, ScrollTop + ConWindowSizeY() - 2); ConScrollUp(ConGetCursorY() - 1, ScrollTop + ConVisibleWindowHeight() - 2);
} else { } else {
if (ConGetCursorY() <= ScrollTop + ConWindowSizeY() - 2) if (ConGetCursorY() <= ScrollTop + ConVisibleWindowHeight() - 2)
ConScrollUp(ConGetCursorY() - 1, ScrollTop + ConWindowSizeY() - 2); ConScrollUp(ConGetCursorY() - 1, ScrollTop + ConVisibleWindowHeight() - 2);
} }
fcompletion = 1; fcompletion = 1;
bAtEOLN = FALSE; bAtEOLN = FALSE;
@ -600,7 +607,7 @@ ParseANSI(unsigned char * pszBuffer, unsigned char * pszBufferEnd, unsigned char
for (i = 0; i < iParam[0]; i++) for (i = 0; i < iParam[0]; i++)
ConScrollUp(ConGetCursorY(), ScrollTop - ConGetCursorY()); ConScrollUp(ConGetCursorY(), ScrollTop - ConGetCursorY());
} else { } else {
if (ConGetCursorY() <= ScrollTop + ConWindowSizeY() - 2) if (ConGetCursorY() <= ScrollTop + ConVisibleWindowHeight() - 2)
ConScrollUp(ConGetCursorY(), ScrollTop - ConGetCursorY()); ConScrollUp(ConGetCursorY(), ScrollTop - ConGetCursorY());
} }
fcompletion = 1; fcompletion = 1;

View File

@ -52,13 +52,14 @@ int ScrollTop;
int ScrollBottom; int ScrollBottom;
int LastCursorX; int LastCursorX;
int LastCursorY; int LastCursorY;
BOOL bAnsiParsing = FALSE; BOOL isAnsiParsingRequired = FALSE;
char *pSavedScreen = NULL; char *pSavedScreen = NULL;
static COORD ZeroCoord = { 0,0 }; static COORD ZeroCoord = { 0,0 };
COORD SavedScreenSize = { 0,0 }; COORD SavedScreenSize = { 0,0 };
COORD SavedScreenCursor = { 0, 0 }; COORD SavedScreenCursor = { 0, 0 };
SMALL_RECT SavedViewRect = { 0,0,0,0 }; SMALL_RECT SavedViewRect = { 0,0,0,0 };
CONSOLE_SCREEN_BUFFER_INFOEX SavedWindowState; CONSOLE_SCREEN_BUFFER_INFOEX SavedWindowState;
BOOL isConHostParserEnabled = TRUE;
typedef struct _SCREEN_RECORD { typedef struct _SCREEN_RECORD {
PCHAR_INFO pScreenBuf; PCHAR_INFO pScreenBuf;
@ -69,10 +70,11 @@ typedef struct _SCREEN_RECORD {
PSCREEN_RECORD pSavedScreenRec = NULL; PSCREEN_RECORD pSavedScreenRec = NULL;
int in_raw_mode = 0; int in_raw_mode = 0;
char *consoleTitle = "Microsoft openSSH client";
/* Used to Initialize the Console for output */ /* Used to enter the raw mode */
int int
ConInit(DWORD OutputHandle, BOOL fSmartInit) ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit)
{ {
OSVERSIONINFO os; OSVERSIONINFO os;
DWORD dwAttributes = 0; DWORD dwAttributes = 0;
@ -87,16 +89,18 @@ ConInit(DWORD OutputHandle, BOOL fSmartInit)
hOutputConsole = GetStdHandle(OutputHandle); hOutputConsole = GetStdHandle(OutputHandle);
if (hOutputConsole == INVALID_HANDLE_VALUE) { if (hOutputConsole == INVALID_HANDLE_VALUE) {
dwRet = GetLastError(); dwRet = GetLastError();
printf("GetStdHandle on OutputHandle failed with %d\n", dwRet); error("GetStdHandle on OutputHandle failed with %d\n", dwRet);
return dwRet; return dwRet;
} }
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes)) { if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes)) {
dwRet = GetLastError(); dwRet = GetLastError();
printf("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); error("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet);
return dwRet; return dwRet;
} }
SetConsoleTitle(consoleTitle);
dwAttributes = dwSavedAttributes; dwAttributes = dwSavedAttributes;
dwAttributes &= ~(ENABLE_LINE_INPUT | dwAttributes &= ~(ENABLE_LINE_INPUT |
ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT); ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
@ -104,43 +108,59 @@ ConInit(DWORD OutputHandle, BOOL fSmartInit)
if (!SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwAttributes)) { /* Windows NT */ if (!SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwAttributes)) { /* Windows NT */
dwRet = GetLastError(); dwRet = GetLastError();
printf("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet); error("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet);
return dwRet; return dwRet;
} }
if (!GetConsoleMode(hOutputConsole, &dwAttributes)) { if (!GetConsoleMode(hOutputConsole, &dwAttributes)) {
dwRet = GetLastError(); dwRet = GetLastError();
printf("GetConsoleMode on hOutputConsole failed with %d\n", dwRet); error("GetConsoleMode on hOutputConsole failed with %d\n", dwRet);
return dwRet; return dwRet;
} }
dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING; dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(hOutputConsole, dwAttributes)) /* Windows NT */ if (NULL != getenv("SSH_TERM_CONHOST_PARSER"))
bAnsiParsing = TRUE; 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 {
ConMoveCurosorTop(csbi);
debug("console supports the ansi parsing");
}
ConSetScreenX(); ConSetScreenX();
ConSetScreenY(); ConSetScreenY();
ScrollTop = 0; ScrollTop = 0;
ScrollBottom = ConWindowSizeY(); ScrollBottom = ConVisibleWindowHeight();
if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi))
SavedViewRect = csbi.srWindow;
in_raw_mode = 1; in_raw_mode = 1;
return 0; return 0;
} }
/* Used to Uninitialize the Console */ /* Used to Uninitialize the Console */
int int
ConUnInit(void) ConExitRawMode()
{ {
CONSOLE_SCREEN_BUFFER_INFO consoleInfo; CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
in_raw_mode = 0; in_raw_mode = 0;
if (hOutputConsole == NULL) if (hOutputConsole == NULL || !GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
return 0;
if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
return 0; return 0;
SetConsoleMode(hOutputConsole, dwSavedAttributes); SetConsoleMode(hOutputConsole, dwSavedAttributes);
@ -148,9 +168,9 @@ ConUnInit(void)
return 0; return 0;
} }
/* Used to Uninitialize the Console */ /* Used to exit the raw mode */
int int
ConUnInitWithRestore(void) ConUnInitWithRestore()
{ {
DWORD dwWritten; DWORD dwWritten;
COORD Coord; COORD Coord;
@ -446,9 +466,9 @@ ConScreenSizeY()
return (consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1); return (consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1);
} }
/* returns visible size of screen window */ /* returns width of visible window */
int int
ConWindowSizeX() ConVisibleWindowWidth()
{ {
CONSOLE_SCREEN_BUFFER_INFO consoleInfo; CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
@ -458,9 +478,9 @@ ConWindowSizeX()
return (consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1); return (consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1);
} }
/* returns visible size of screen window */ /* returns height of visible window */
int int
ConWindowSizeY() ConVisibleWindowHeight()
{ {
CONSOLE_SCREEN_BUFFER_INFO consoleInfo; CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
@ -837,7 +857,7 @@ ConDisplayCursor(BOOL bVisible)
} }
void void
ConClearScreen(void) ConClearScreen()
{ {
DWORD dwWritten; DWORD dwWritten;
COORD Coord; COORD Coord;
@ -850,7 +870,7 @@ ConClearScreen(void)
Coord.X = 0; Coord.X = 0;
Coord.Y = 0; Coord.Y = 0;
DWORD dwNumChar = (consoleInfo.srWindow.Bottom + 1) * (consoleInfo.srWindow.Right + 1); DWORD dwNumChar = (consoleInfo.dwSize.Y) * (consoleInfo.dwSize.X);
FillConsoleOutputCharacter(hOutputConsole, ' ', dwNumChar, Coord, &dwWritten); FillConsoleOutputCharacter(hOutputConsole, ' ', dwNumChar, Coord, &dwWritten);
FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, dwNumChar, Coord, &dwWritten); FillConsoleOutputAttribute(hOutputConsole, consoleInfo.wAttributes, dwNumChar, Coord, &dwWritten);
srcWindow = consoleInfo.srWindow; srcWindow = consoleInfo.srWindow;
@ -1055,11 +1075,25 @@ ConScrollUp(int topline, int botline)
); );
} }
void
ConMoveVisibleWindow(int offset)
{
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
SMALL_RECT visibleWindowRect;
if (GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) {
memcpy(&visibleWindowRect, &consoleInfo.srWindow, sizeof(visibleWindowRect));
visibleWindowRect.Top += offset;
visibleWindowRect.Bottom += offset;
SetConsoleWindowInfo(hOutputConsole, TRUE, &visibleWindowRect);
}
}
void void
ConScrollDown(int topline, int botline) ConScrollDown(int topline, int botline)
{ {
SMALL_RECT ScrollRect; SMALL_RECT ScrollRect;
SMALL_RECT ClipRect;
COORD destination; COORD destination;
CHAR_INFO Fill; CHAR_INFO Fill;
CONSOLE_SCREEN_BUFFER_INFO consoleInfo; CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
@ -1078,11 +1112,6 @@ ConScrollDown(int topline, int botline)
ScrollRect.Left = 0; ScrollRect.Left = 0;
ScrollRect.Right = ConScreenSizeX() - 1; ScrollRect.Right = ConScreenSizeX() - 1;
ClipRect.Top = ScrollRect.Top;
ClipRect.Bottom = ScrollRect.Bottom;
ClipRect.Left = ScrollRect.Left;
ClipRect.Right = ScrollRect.Right;
destination.X = 0; destination.X = 0;
destination.Y = ScrollRect.Top - 1; destination.Y = ScrollRect.Top - 1;
@ -1152,6 +1181,17 @@ ConChangeCursor(CONSOLE_CURSOR_INFO *pCursorInfo)
return SetConsoleCursorInfo(hOutputConsole, 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 int
ConGetCursorX() ConGetCursorX()
{ {
@ -1163,6 +1203,21 @@ ConGetCursorX()
return consoleInfo.dwCursorPosition.X; 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 int
ConGetCursorY() ConGetCursorY()
{ {
@ -1175,14 +1230,14 @@ ConGetCursorY()
} }
int int
ConGetCursorInBufferY() ConGetBufferHeight()
{ {
CONSOLE_SCREEN_BUFFER_INFO consoleInfo; CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo)) if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
return 0; return 0;
return (consoleInfo.dwCursorPosition.Y); return (consoleInfo.dwSize.Y - 1);
} }
void void
@ -1390,30 +1445,55 @@ ConDeleteScreenHandle(SCREEN_HANDLE hScreen)
/* Restores Previous Saved screen info and buffer */ /* Restores Previous Saved screen info and buffer */
BOOL BOOL
ConRestoreScreen(void) ConRestoreScreen()
{ {
return ConRestoreScreenHandle(pSavedScreenRec); return ConRestoreScreenHandle(pSavedScreenRec);
} }
/* Saves current screen info and buffer */ /* Saves current screen info and buffer */
BOOL void
ConSaveScreen(void) ConSaveScreen()
{ {
pSavedScreenRec = (PSCREEN_RECORD)ConSaveScreenHandle(pSavedScreenRec); pSavedScreenRec = (PSCREEN_RECORD)ConSaveScreenHandle(pSavedScreenRec);
return TRUE;
} }
void void
ConSaveViewRect(void) ConSaveViewRect()
{ {
CONSOLE_SCREEN_BUFFER_INFO csbi; CONSOLE_SCREEN_BUFFER_INFO csbi;
if (!GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi))
return;
SavedViewRect = csbi.srWindow; 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 BOOL
ConIsRedirected(HANDLE hInput) ConIsRedirected(HANDLE hInput)
{ {
@ -1460,7 +1540,7 @@ GetConsoleInputHandle()
} }
void void
ConSaveWindowsState(void) ConSaveWindowsState()
{ {
CONSOLE_SCREEN_BUFFER_INFOEX csbiex; CONSOLE_SCREEN_BUFFER_INFOEX csbiex;
csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX); csbiex.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
@ -1470,3 +1550,12 @@ ConSaveWindowsState(void)
SavedWindowState = csbiex; SavedWindowState = csbiex;
} }
void
ConMoveCurosorTop(CONSOLE_SCREEN_BUFFER_INFO csbi)
{
int offset = csbi.dwCursorPosition.Y - csbi.srWindow.Top;
ConMoveVisibleWindow(offset);
ConSaveViewRect();
}

View File

@ -81,22 +81,22 @@
typedef void * SCREEN_HANDLE; typedef void * SCREEN_HANDLE;
int ConInit( DWORD OutputHandle, BOOL fSmartInit); int ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit);
int ConUnInitWithRestore( void ); int ConUnInitWithRestore();
int ConUnInit( void ); int ConExitRawMode();
BOOL ConIsRedirected(HANDLE hInput); BOOL ConIsRedirected(HANDLE hInput);
HANDLE GetConsoleOutputHandle(); HANDLE GetConsoleOutputHandle();
HANDLE GetConsoleInputHandle(); HANDLE GetConsoleInputHandle();
BOOL ConSetScreenRect(int xSize, int ySize); BOOL ConSetScreenRect(int xSize, int ySize);
BOOL ConSetScreenSize(int X, int Y); BOOL ConSetScreenSize(int X, int Y);
BOOL ConRestoreScreen( void ); BOOL ConRestoreScreen();
BOOL ConSaveScreen( void ); void ConSaveScreen();
void ConSetAttribute(int *iParam, int iParamCount); void ConSetAttribute(int *iParam, int iParamCount);
int ConScreenSizeX(); int ConScreenSizeX();
int ConSetScreenX(); int ConSetScreenX();
int ConScreenSizeY(); int ConScreenSizeY();
int ConWindowSizeX(); int ConVisibleWindowWidth();
int ConWindowSizeY(); int ConVisibleWindowHeight();
int ConSetScreenY(); int ConSetScreenY();
void ConFillToEndOfLine(); void ConFillToEndOfLine();
int ConWriteString(char* pszString, int cbString); int ConWriteString(char* pszString, int cbString);
@ -122,18 +122,20 @@ BOOL ConChangeCursor( CONSOLE_CURSOR_INFO *pCursorInfo );
void ConSetCursorPosition(int x, int y); void ConSetCursorPosition(int x, int y);
int ConGetCursorX(); int ConGetCursorX();
int ConGetCursorY(); int ConGetCursorY();
int ConGetCursorInBufferY(void); int ConGetBufferHeight();
BOOL ConDisplayCursor(BOOL bVisible); BOOL ConDisplayCursor(BOOL bVisible);
void ConMoveCursorPosition(int x, int y); void ConMoveCursorPosition(int x, int y);
void ConGetRelativeCursorPosition(int *x, int *y); void ConGetRelativeCursorPosition(int *x, int *y);
BOOL ConRestoreScreenHandle(SCREEN_HANDLE hScreen); BOOL ConRestoreScreenHandle(SCREEN_HANDLE hScreen);
BOOL ConRestoreScreenColors( void ); BOOL ConRestoreScreenColors();
SCREEN_HANDLE ConSaveScreenHandle(SCREEN_HANDLE); SCREEN_HANDLE ConSaveScreenHandle(SCREEN_HANDLE);
void ConDeleteScreenHandle(SCREEN_HANDLE hScreen); void ConDeleteScreenHandle(SCREEN_HANDLE hScreen);
void ConSaveViewRect( void ); void ConSaveViewRect();
void ConRestoreViewRect( void ); void ConRestoreViewRect();
void ConDeleteChars(int n); void ConDeleteChars(int n);
void ConSaveWindowsState(void); void ConSaveWindowsState();
void ConMoveVisibleWindow(int offset);
int is_cursor_at_lastline_of_visible_window();
void ConGetCursorPosition(int *x, int *y);
void ConMoveCurosorTop(CONSOLE_SCREEN_BUFFER_INFO csbi);
#endif #endif

View File

@ -388,10 +388,12 @@ w32_ioctl(int d, int request, ...)
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
wsize->ws_col = c_info.dwSize.X - 5;
wsize->ws_row = c_info.dwSize.Y; wsize->ws_col = c_info.srWindow.Right - c_info.srWindow.Left + 1;
wsize->ws_row = c_info.srWindow.Bottom - c_info.srWindow.Top + 1;
wsize->ws_xpixel = 640; wsize->ws_xpixel = 640;
wsize->ws_ypixel = 480; wsize->ws_ypixel = 480;
return 0; return 0;
} }
default: default:

View File

@ -1,3 +1,4 @@
#pragma once
#define PATH_MAX MAX_PATH #define PATH_MAX MAX_PATH
/* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */ /* removes first '/' for Windows paths that are unix styled. Ex: /c:/ab.cd */

View File

@ -121,6 +121,9 @@ struct key_translation keys[] = {
{ "\x1b[24~", VK_F12, 0 } { "\x1b[24~", VK_F12, 0 }
}; };
static SHORT lastX = 0;
static SHORT lastY = 0;
consoleEvent* head = NULL; consoleEvent* head = NULL;
consoleEvent* tail = NULL; consoleEvent* tail = NULL;
@ -182,6 +185,17 @@ STARTUPINFO inputSi;
goto cleanup; \ goto cleanup; \
} while(0) } while(0)
int
ConSRWidth()
{
CONSOLE_SCREEN_BUFFER_INFOEX consoleBufferInfo;
ZeroMemory(&consoleBufferInfo, sizeof(consoleBufferInfo));
consoleBufferInfo.cbSize = sizeof(consoleBufferInfo);
GetConsoleScreenBufferInfoEx(child_out, &consoleBufferInfo);
return consoleBufferInfo.srWindow.Right;
}
/* /*
* This function will handle the console keystrokes. * This function will handle the console keystrokes.
*/ */
@ -426,7 +440,7 @@ SendBuffer(HANDLE hInput, CHAR_INFO *buffer, DWORD bufferSize)
} }
void void
CalculateAndSetCursor(HANDLE hInput, UINT aboveTopLine, UINT viewPortHeight, UINT x, UINT y) CalculateAndSetCursor(HANDLE hInput, UINT x, UINT y)
{ {
SendSetCursor(pipe_out, x + 1, y + 1); SendSetCursor(pipe_out, x + 1, y + 1);
@ -548,14 +562,13 @@ ProcessEvent(void *p)
case EVENT_CONSOLE_CARET: case EVENT_CONSOLE_CARET:
{ {
COORD co; COORD co;
co.X = LOWORD(idChild);
co.Y = HIWORD(idChild);
if (idObject == CONSOLE_CARET_SELECTION) { lastX = co.X;
co.X = HIWORD(idChild); lastY = co.Y;
co.Y = LOWORD(idChild);
} else { SendSetCursor(pipe_out, lastX + 1, lastY + 1);
co.X = HIWORD(idChild);
co.Y = LOWORD(idChild);
}
break; break;
} }
@ -568,6 +581,8 @@ ProcessEvent(void *p)
readRect.Bottom = HIWORD(idChild); readRect.Bottom = HIWORD(idChild);
readRect.Right = LOWORD(idChild); readRect.Right = LOWORD(idChild);
readRect.Right = max(readRect.Right, ConSRWidth());
/* Detect a "cls" (Windows) */ /* Detect a "cls" (Windows) */
if (!bStartup && if (!bStartup &&
(readRect.Top == consoleInfo.srWindow.Top || readRect.Top == nextConsoleInfo.srWindow.Top)) { (readRect.Top == consoleInfo.srWindow.Top || readRect.Top == nextConsoleInfo.srWindow.Top)) {
@ -632,7 +647,7 @@ ProcessEvent(void *p)
SendLF(pipe_out); SendLF(pipe_out);
/* Set cursor location based on the reported location from the message */ /* Set cursor location based on the reported location from the message */
CalculateAndSetCursor(pipe_out, ViewPortY, viewPortHeight, readRect.Left, readRect.Top); CalculateAndSetCursor(pipe_out, readRect.Left, readRect.Top);
/* Send the entire block */ /* Send the entire block */
SendBuffer(pipe_out, pBuffer, bufferSize); SendBuffer(pipe_out, pBuffer, bufferSize);
@ -650,11 +665,36 @@ ProcessEvent(void *p)
wX = LOWORD(idObject); wX = LOWORD(idObject);
wY = HIWORD(idObject); wY = HIWORD(idObject);
/* Set cursor location based on the reported location from the message */ SMALL_RECT readRect;
CalculateAndSetCursor(pipe_out, ViewPortY, viewPortHeight, wX, wY); readRect.Top = wY;
readRect.Bottom = wY;
readRect.Left = wX;
readRect.Right = ConSRWidth();
/* Set cursor location based on the reported location from the message */
CalculateAndSetCursor(pipe_out, wX, wY);
COORD coordBufSize;
coordBufSize.Y = readRect.Bottom - readRect.Top + 1;
coordBufSize.X = readRect.Right - readRect.Left + 1;
/* The top left destination cell of the temporary buffer is row 0, col 0 */
COORD coordBufCoord;
coordBufCoord.X = 0;
coordBufCoord.Y = 0;
int pBufferSize = coordBufSize.X * coordBufSize.Y;
/* Send the one character. Note that a CR doesn't end up here */ /* Send the one character. Note that a CR doesn't end up here */
SendCharacter(pipe_out, wAttributes, chUpdate); CHAR_INFO *pBuffer = (PCHAR_INFO)malloc(sizeof(CHAR_INFO) * pBufferSize);
/* Copy the block from the screen buffer to the temp. buffer */
if (!ReadConsoleOutput(child_out, pBuffer, coordBufSize, coordBufCoord, &readRect)) {
DWORD dwError = GetLastError();
free(pBuffer);
return dwError;
}
SendBuffer(pipe_out, pBuffer, pBufferSize);
free(pBuffer);
break; break;
} }
@ -699,18 +739,24 @@ ProcessEvent(void *p)
} }
} }
ZeroMemory(&consoleInfo, sizeof(consoleInfo));
consoleInfo.cbSize = sizeof(consoleInfo);
GetConsoleScreenBufferInfoEx(child_out, &consoleInfo);
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
DWORD WINAPI DWORD WINAPI
ProcessEventQueue(LPVOID p) ProcessEventQueue(LPVOID p)
{ {
static SHORT lastX = 0; if (child_in != INVALID_HANDLE_VALUE && child_in != NULL &&
static SHORT lastY = 0; child_out != INVALID_HANDLE_VALUE && child_out != NULL) {
DWORD dwInputMode;
DWORD dwOutputMode;
if (GetConsoleMode(child_in, &dwInputMode) && GetConsoleMode(child_out, &dwOutputMode))
if (((dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == ENABLE_VIRTUAL_TERMINAL_PROCESSING) &&
((dwInputMode & ENABLE_VIRTUAL_TERMINAL_INPUT) == ENABLE_VIRTUAL_TERMINAL_INPUT))
bAnsi = TRUE;
else
bAnsi = FALSE;
}
while (1) { while (1) {
while (head) { while (head) {
@ -738,14 +784,6 @@ ProcessEventQueue(LPVOID p)
DWORD dwInputMode; DWORD dwInputMode;
DWORD dwOutputMode; DWORD dwOutputMode;
if (GetConsoleMode(child_in, &dwInputMode) && GetConsoleMode(child_out, &dwOutputMode)) {
if (((dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == ENABLE_VIRTUAL_TERMINAL_PROCESSING) &&
((dwInputMode & ENABLE_VIRTUAL_TERMINAL_INPUT) == ENABLE_VIRTUAL_TERMINAL_INPUT))
bAnsi = TRUE;
else
bAnsi = FALSE;
}
ZeroMemory(&consoleInfo, sizeof(consoleInfo)); ZeroMemory(&consoleInfo, sizeof(consoleInfo));
consoleInfo.cbSize = sizeof(consoleInfo); consoleInfo.cbSize = sizeof(consoleInfo);
@ -963,7 +1001,7 @@ start_with_pty(wchar_t *command)
hostThreadId = GetCurrentThreadId(); hostThreadId = GetCurrentThreadId();
hostProcessId = GetCurrentProcessId(); hostProcessId = GetCurrentProcessId();
InitializeCriticalSection(&criticalSection); InitializeCriticalSection(&criticalSection);
hEventHook = __SetWinEventHook(EVENT_CONSOLE_CARET, EVENT_CONSOLE_LAYOUT, NULL, hEventHook = __SetWinEventHook(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, NULL,
ConsoleEventProc, 0, 0, WINEVENT_OUTOFCONTEXT); ConsoleEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
memset(&si, 0, sizeof(STARTUPINFO)); memset(&si, 0, sizeof(STARTUPINFO));
memset(&pi, 0, sizeof(PROCESS_INFORMATION)); memset(&pi, 0, sizeof(PROCESS_INFORMATION));

View File

@ -39,6 +39,7 @@
#include "w32fd.h" #include "w32fd.h"
#include "tncon.h" #include "tncon.h"
#include "inc\utf.h" #include "inc\utf.h"
#include "tnnet.h"
#define TERM_IO_BUF_SIZE 2048 #define TERM_IO_BUF_SIZE 2048
@ -136,6 +137,7 @@ WriteAPCProc(_In_ ULONG_PTR dwParam)
pio->write_overlapped.hEvent = 0; pio->write_overlapped.hEvent = 0;
} }
/* Write worker thread */ /* Write worker thread */
static DWORD WINAPI static DWORD WINAPI
WriteThread(_In_ LPVOID lpParameter) WriteThread(_In_ LPVOID lpParameter)
@ -146,26 +148,26 @@ WriteThread(_In_ LPVOID lpParameter)
DWORD dwSavedAttributes = ENABLE_PROCESSED_INPUT; DWORD dwSavedAttributes = ENABLE_PROCESSED_INPUT;
debug3("TermWrite thread, io:%p", pio); debug3("TermWrite thread, io:%p", pio);
if (in_raw_mode == 0) {
/* convert stream to utf16 and dump on console */
pio->write_details.buf[write_status.to_transfer] = '\0'; pio->write_details.buf[write_status.to_transfer] = '\0';
if (0 == in_raw_mode) {
wchar_t* t = utf8_to_utf16(pio->write_details.buf); wchar_t* t = utf8_to_utf16(pio->write_details.buf);
WriteConsoleW(WINHANDLE(pio), t, wcslen(t), 0, 0); WriteConsoleW(WINHANDLE(pio), t, wcslen(t), 0, 0);
free(t); free(t);
write_status.transferred = write_status.to_transfer;
} else { } else {
/* console mode */ processBuffer(WINHANDLE(pio), pio->write_details.buf, write_status.to_transfer, &respbuf, &resplen);
telProcessNetwork(pio->write_details.buf, write_status.to_transfer, &respbuf, &resplen);
/* TODO - respbuf is not null in some cases, this needs to be returned back via read stream */ /* TODO - respbuf is not null in some cases, this needs to be returned back via read stream */
write_status.transferred = write_status.to_transfer;
} }
write_status.transferred = write_status.to_transfer;
if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) { if (0 == QueueUserAPC(WriteAPCProc, main_thread, (ULONG_PTR)pio)) {
debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio); debug("TermWrite thread - ERROR QueueUserAPC failed %d, io:%p", GetLastError(), pio);
pio->write_details.pending = FALSE; pio->write_details.pending = FALSE;
pio->write_details.error = GetLastError(); pio->write_details.error = GetLastError();
DebugBreak(); DebugBreak();
} }
return 0; return 0;
} }

View File

@ -35,17 +35,20 @@
#include <string.h> #include <string.h>
#include <windows.h> #include <windows.h>
#include "ansiprsr.h" #include "ansiprsr.h"
#include "inc\utf.h"
#define dwBuffer 4096 #define dwBuffer 4096
extern BOOL isAnsiParsingRequired;
/* /*
* Server will always be returning a sequence of ANSI control characters which the client * Server will always be returning a sequence of ANSI control characters which the client
* protocol can either passthru directly to the console or transform based on an output terminal * protocol can either passthru directly to the console or transform based on an output terminal
* type. We're not using termcap so we're only supporting the ANSI (vt100) sequences that * type. We're not using termcap so we're only supporting the ANSI (vt100) sequences that
* are hardcoded in the server and will be transformed to Windows Console commands. * are hardcoded in the server and will be transformed to Windows Console commands.
*/ */
size_t void
telProcessNetwork(char *buf, size_t len, unsigned char **respbuf, size_t *resplen) processBuffer(HANDLE handle, char *buf, size_t len, unsigned char **respbuf, size_t *resplen)
{ {
unsigned char szBuffer[dwBuffer + 8]; unsigned char szBuffer[dwBuffer + 8];
unsigned char* pszNewHead = NULL; unsigned char* pszNewHead = NULL;
@ -53,7 +56,17 @@ telProcessNetwork(char *buf, size_t len, unsigned char **respbuf, size_t *resple
unsigned char* pszTail = NULL; unsigned char* pszTail = NULL;
if (len == 0) if (len == 0)
return len; return;
if (false == isAnsiParsingRequired) {
/* Console has the capability to parse so pass the raw buffer to console directly */
ConRestoreViewRect(); /* Restore the visible window, otherwise WriteConsoleW() gets messy */
wchar_t* t = utf8_to_utf16(buf);
WriteConsoleW(handle, t, wcslen(t), 0, 0);
free(t);
ConSaveViewRect();
return;
}
/* Transform a single carriage return into a single linefeed before continuing */ /* Transform a single carriage return into a single linefeed before continuing */
if ((len == 1) && (buf[0] == 13)) if ((len == 1) && (buf[0] == 13))
@ -74,6 +87,4 @@ telProcessNetwork(char *buf, size_t len, unsigned char **respbuf, size_t *resple
pszNewHead = ParseBuffer(pszHead, pszTail, respbuf, resplen); pszNewHead = ParseBuffer(pszHead, pszTail, respbuf, resplen);
} while ((pszNewHead != pszHead) && (pszNewHead < pszTail) && (resplen == NULL || (resplen != NULL && *resplen == 0))); } while ((pszNewHead != pszHead) && (pszNewHead < pszTail) && (resplen == NULL || (resplen != NULL && *resplen == 0)));
len = 0;
return len;
} }

View File

@ -35,8 +35,6 @@
#ifndef __TNNET_H #ifndef __TNNET_H
#define __TNNET_H #define __TNNET_H
void processBuffer(HANDLE handle, char *buf, size_t len, unsigned char **respbuf, size_t *resplen);
size_t telProcessNetwork (char *buf, size_t len, unsigned char **respbuf, size_t *resplen);
#endif #endif

View File

@ -52,8 +52,8 @@ static int _in_raw_mode = 0;
* TTY raw mode routines for Windows * TTY raw mode routines for Windows
*/ */
int ConInit(DWORD OutputHandle, BOOL fSmartInit); int ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit);
int ConUnInit(void); int ConExitRawMode(void);
struct termios term_settings; struct termios term_settings;
@ -70,12 +70,12 @@ struct termios *
void void
leave_raw_mode(int quiet) { leave_raw_mode(int quiet) {
ConUnInit(); ConExitRawMode();
} }
void void
enter_raw_mode(int quiet) { enter_raw_mode(int quiet) {
ConInit(STD_OUTPUT_HANDLE, TRUE); ConEnterRawMode(STD_OUTPUT_HANDLE, TRUE);
} }
#else /* !WINDOWS */ #else /* !WINDOWS */
struct termios * struct termios *