Terminal fixes (#182)
Terminal code cleanup and control sequence handling.. PowerShell/Win32-OpenSSH#799 Picking the user32/kernel32 from the systemdirectory. PowerShell/Win32-OpenSSH#814 Console settings are not restored properly PowerShell/Win32-OpenSSH#813 Fix the clearscreen issue while connecting to non-windows (UNIX/LINUX) servers. PowerShell/Win32-OpenSSH#807 vi arrow keys are not working PowerShell/Win32-OpenSSH#806 Fix the nopty unix ssh session. PowerShell/Win32-OpenSSH#805 Fix emacs issue PowerShell/Win32-OpenSSH#802
This commit is contained in:
parent
327f514f27
commit
69ede6fef2
|
@ -42,7 +42,8 @@
|
||||||
#include "ansiprsr.h"
|
#include "ansiprsr.h"
|
||||||
|
|
||||||
HANDLE hOutputConsole = NULL;
|
HANDLE hOutputConsole = NULL;
|
||||||
DWORD dwSavedAttributes = 0;
|
DWORD stdin_dwSavedAttributes = 0;
|
||||||
|
DWORD stdout_dwSavedAttributes = 0;
|
||||||
WORD wStartingAttributes = 0;
|
WORD wStartingAttributes = 0;
|
||||||
|
|
||||||
int ScreenX;
|
int ScreenX;
|
||||||
|
@ -72,8 +73,8 @@ int in_raw_mode = 0;
|
||||||
char *consoleTitle = "OpenSSH SSH client";
|
char *consoleTitle = "OpenSSH SSH client";
|
||||||
|
|
||||||
/* Used to enter the raw mode */
|
/* Used to enter the raw mode */
|
||||||
int
|
void
|
||||||
ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit)
|
ConEnterRawMode()
|
||||||
{
|
{
|
||||||
DWORD dwAttributes = 0;
|
DWORD dwAttributes = 0;
|
||||||
DWORD dwRet = 0;
|
DWORD dwRet = 0;
|
||||||
|
@ -81,22 +82,22 @@ ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit)
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
static bool bFirstConInit = true;
|
static bool bFirstConInit = true;
|
||||||
|
|
||||||
hOutputConsole = GetStdHandle(OutputHandle);
|
hOutputConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
if (hOutputConsole == INVALID_HANDLE_VALUE) {
|
if (hOutputConsole == INVALID_HANDLE_VALUE) {
|
||||||
dwRet = GetLastError();
|
dwRet = GetLastError();
|
||||||
error("GetStdHandle on OutputHandle failed with %d\n", dwRet);
|
error("GetStdHandle on OutputHandle failed with %d\n", dwRet);
|
||||||
return dwRet;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwSavedAttributes)) {
|
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &stdin_dwSavedAttributes)) {
|
||||||
dwRet = GetLastError();
|
dwRet = GetLastError();
|
||||||
error("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet);
|
error("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet);
|
||||||
return dwRet;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetConsoleTitle(consoleTitle);
|
SetConsoleTitle(consoleTitle);
|
||||||
|
|
||||||
dwAttributes = dwSavedAttributes;
|
dwAttributes = stdin_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);
|
||||||
dwAttributes |= ENABLE_WINDOW_INPUT;
|
dwAttributes |= ENABLE_WINDOW_INPUT;
|
||||||
|
@ -104,17 +105,17 @@ ConEnterRawMode(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();
|
||||||
error("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet);
|
error("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", dwRet);
|
||||||
return dwRet;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetConsoleMode(hOutputConsole, &dwAttributes)) {
|
if (!GetConsoleMode(hOutputConsole, &stdout_dwSavedAttributes)) {
|
||||||
dwRet = GetLastError();
|
dwRet = GetLastError();
|
||||||
error("GetConsoleMode on hOutputConsole failed with %d\n", dwRet);
|
error("GetConsoleMode on hOutputConsole failed with %d\n", dwRet);
|
||||||
return dwRet;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
dwAttributes = stdout_dwSavedAttributes;
|
||||||
|
dwAttributes |= (DWORD)ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
||||||
|
|
||||||
char *envValue = NULL;
|
char *envValue = NULL;
|
||||||
_dupenv_s(&envValue, NULL, "SSH_TERM_CONHOST_PARSER");
|
_dupenv_s(&envValue, NULL, "SSH_TERM_CONHOST_PARSER");
|
||||||
|
@ -140,7 +141,7 @@ ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit)
|
||||||
SavedViewRect = csbi.srWindow;
|
SavedViewRect = csbi.srWindow;
|
||||||
debug("console doesn't support the ansi parsing");
|
debug("console doesn't support the ansi parsing");
|
||||||
} else {
|
} else {
|
||||||
ConMoveCursorTop(csbi);
|
ConSaveViewRect();
|
||||||
debug("console supports the ansi parsing");
|
debug("console supports the ansi parsing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,26 +151,18 @@ ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit)
|
||||||
ScrollBottom = ConVisibleWindowHeight();
|
ScrollBottom = ConVisibleWindowHeight();
|
||||||
|
|
||||||
in_raw_mode = 1;
|
in_raw_mode = 1;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used to Uninitialize the Console */
|
/* Used to Uninitialize the Console */
|
||||||
int
|
void
|
||||||
ConExitRawMode()
|
ConExitRawMode()
|
||||||
{
|
{
|
||||||
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), stdin_dwSavedAttributes);
|
||||||
in_raw_mode = 0;
|
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), stdout_dwSavedAttributes);
|
||||||
if (hOutputConsole == NULL || !GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
SetConsoleMode(hOutputConsole, dwSavedAttributes);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used to exit the raw mode */
|
/* Used to exit the raw mode */
|
||||||
int
|
void
|
||||||
ConUnInitWithRestore()
|
ConUnInitWithRestore()
|
||||||
{
|
{
|
||||||
DWORD dwWritten;
|
DWORD dwWritten;
|
||||||
|
@ -177,19 +170,19 @@ ConUnInitWithRestore()
|
||||||
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
|
||||||
|
|
||||||
if (hOutputConsole == NULL)
|
if (hOutputConsole == NULL)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
|
if (!GetConsoleScreenBufferInfo(hOutputConsole, &consoleInfo))
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
SetConsoleMode(hOutputConsole, dwSavedAttributes);
|
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), stdin_dwSavedAttributes);
|
||||||
|
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), stdout_dwSavedAttributes);
|
||||||
Coord = consoleInfo.dwCursorPosition;
|
Coord = consoleInfo.dwCursorPosition;
|
||||||
Coord.X = 0;
|
Coord.X = 0;
|
||||||
DWORD dwNumChar = (consoleInfo.dwSize.Y - consoleInfo.dwCursorPosition.Y) * consoleInfo.dwSize.X;
|
DWORD dwNumChar = (consoleInfo.dwSize.Y - consoleInfo.dwCursorPosition.Y) * consoleInfo.dwSize.X;
|
||||||
FillConsoleOutputCharacter(hOutputConsole, ' ', dwNumChar, Coord, &dwWritten);
|
FillConsoleOutputCharacter(hOutputConsole, ' ', dwNumChar, Coord, &dwWritten);
|
||||||
FillConsoleOutputAttribute(hOutputConsole, wStartingAttributes, dwNumChar, Coord, &dwWritten);
|
FillConsoleOutputAttribute(hOutputConsole, wStartingAttributes, dwNumChar, Coord, &dwWritten);
|
||||||
SetConsoleTextAttribute(hOutputConsole, wStartingAttributes);
|
SetConsoleTextAttribute(hOutputConsole, wStartingAttributes);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
|
@ -1571,16 +1564,17 @@ ConSaveWindowsState()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ConMoveCursorTop(CONSOLE_SCREEN_BUFFER_INFO csbi)
|
ConMoveCursorTopOfVisibleWindow()
|
||||||
{
|
{
|
||||||
/* Windows server at first sends the "cls" after the connection is established.
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
* Since we don't want to loose any data on the console, we would like to scroll down
|
int offset;
|
||||||
* the visible window.
|
|
||||||
*/
|
|
||||||
int offset = csbi.dwCursorPosition.Y - csbi.srWindow.Top;
|
|
||||||
ConMoveVisibleWindow(offset);
|
|
||||||
|
|
||||||
ConSaveViewRect();
|
if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi)) {
|
||||||
|
offset = csbi.dwCursorPosition.Y - csbi.srWindow.Top;
|
||||||
|
ConMoveVisibleWindow(offset);
|
||||||
|
|
||||||
|
ConSaveViewRect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE
|
HANDLE
|
||||||
|
|
|
@ -83,11 +83,15 @@
|
||||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DISABLE_NEWLINE_AUTO_RETURN
|
||||||
|
#define DISABLE_NEWLINE_AUTO_RETURN 0x8
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef void * SCREEN_HANDLE;
|
typedef void * SCREEN_HANDLE;
|
||||||
|
|
||||||
int ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit);
|
void ConEnterRawMode();
|
||||||
int ConUnInitWithRestore();
|
void ConUnInitWithRestore();
|
||||||
int ConExitRawMode();
|
void ConExitRawMode();
|
||||||
BOOL ConIsRedirected(HANDLE hInput);
|
BOOL ConIsRedirected(HANDLE hInput);
|
||||||
HANDLE GetConsoleOutputHandle();
|
HANDLE GetConsoleOutputHandle();
|
||||||
HANDLE GetConsoleInputHandle();
|
HANDLE GetConsoleInputHandle();
|
||||||
|
@ -141,6 +145,6 @@ void ConSaveWindowsState();
|
||||||
void ConMoveVisibleWindow(int offset);
|
void ConMoveVisibleWindow(int offset);
|
||||||
int is_cursor_at_lastline_of_visible_window();
|
int is_cursor_at_lastline_of_visible_window();
|
||||||
void ConGetCursorPosition(int *x, int *y);
|
void ConGetCursorPosition(int *x, int *y);
|
||||||
void ConMoveCursorTop(CONSOLE_SCREEN_BUFFER_INFO csbi);
|
void ConMoveCursorTopOfVisibleWindow();
|
||||||
HANDLE get_console_handle(FILE *, DWORD *);
|
HANDLE get_console_handle(FILE *, DWORD *);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
#include <Strsafe.h>
|
#include <Strsafe.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <Shlobj.h>
|
||||||
|
#include <Sddl.h>
|
||||||
#include "misc_internal.h"
|
#include "misc_internal.h"
|
||||||
#include "inc\utf.h"
|
#include "inc\utf.h"
|
||||||
|
|
||||||
|
@ -92,9 +94,10 @@ struct key_translation {
|
||||||
int in_key_len;
|
int in_key_len;
|
||||||
} key_translation;
|
} key_translation;
|
||||||
|
|
||||||
/* All the substrings (Ex- "\x1b") should be in the end, otherwise ProcessIncomingKeys() will not work as expected */
|
/* All the substrings should be in the end, otherwise ProcessIncomingKeys() will not work as expected */
|
||||||
struct key_translation keys[] = {
|
struct key_translation keys[] = {
|
||||||
{ L"\r", VK_RETURN, L'\r' , 0},
|
{ L"\r", VK_RETURN, L'\r' , 0},
|
||||||
|
{ L"\n", VK_RETURN, L'\r' , 0 },
|
||||||
{ L"\b", VK_BACK, L'\b' , 0},
|
{ L"\b", VK_BACK, L'\b' , 0},
|
||||||
{ L"\x7f", VK_BACK, L'\b' , 0},
|
{ L"\x7f", VK_BACK, L'\b' , 0},
|
||||||
{ L"\t", VK_TAB, L'\t' , 0},
|
{ L"\t", VK_TAB, L'\t' , 0},
|
||||||
|
@ -102,9 +105,9 @@ struct key_translation keys[] = {
|
||||||
{ L"\x1b[B", VK_DOWN, 0 , 0},
|
{ L"\x1b[B", VK_DOWN, 0 , 0},
|
||||||
{ L"\x1b[C", VK_RIGHT, 0 , 0},
|
{ L"\x1b[C", VK_RIGHT, 0 , 0},
|
||||||
{ L"\x1b[D", VK_LEFT, 0 , 0},
|
{ L"\x1b[D", VK_LEFT, 0 , 0},
|
||||||
{ L"\x1b[F", VK_END, 0 , 0 }, /* KeyPad END */
|
{ L"\x1b[F", VK_END, 0 , 0}, /* KeyPad END */
|
||||||
{ L"\x1b[H", VK_HOME, 0 , 0 }, /* KeyPad HOME */
|
{ L"\x1b[H", VK_HOME, 0 , 0}, /* KeyPad HOME */
|
||||||
{ L"\x1b[Z", 0, 0 , 0 }, /* ignore Shift+TAB */
|
{ L"\x1b[Z", 0, 0 , 0}, /* ignore Shift+TAB */
|
||||||
{ L"\x1b[1~", VK_HOME, 0 , 0},
|
{ L"\x1b[1~", VK_HOME, 0 , 0},
|
||||||
{ L"\x1b[2~", VK_INSERT, 0 , 0},
|
{ L"\x1b[2~", VK_INSERT, 0 , 0},
|
||||||
{ L"\x1b[3~", VK_DELETE, 0 , 0},
|
{ L"\x1b[3~", VK_DELETE, 0 , 0},
|
||||||
|
@ -123,15 +126,21 @@ struct key_translation keys[] = {
|
||||||
{ L"\x1b[21~", VK_F10, 0 , 0},
|
{ L"\x1b[21~", VK_F10, 0 , 0},
|
||||||
{ L"\x1b[23~", VK_F11, 0 , 0},
|
{ L"\x1b[23~", VK_F11, 0 , 0},
|
||||||
{ L"\x1b[24~", VK_F12, 0 , 0},
|
{ L"\x1b[24~", VK_F12, 0 , 0},
|
||||||
{ L"\x1bOP", VK_F1, 0 , 0 },
|
{ L"\x1bOA", VK_UP, 0 , 0},
|
||||||
{ L"\x1bOQ", VK_F2, 0 , 0 },
|
{ L"\x1bOB", VK_DOWN, 0 , 0},
|
||||||
{ L"\x1bOR", VK_F3, 0 , 0 },
|
{ L"\x1bOC", VK_RIGHT, 0 , 0},
|
||||||
{ L"\x1bOS", VK_F4, 0 , 0 },
|
{ L"\x1bOD", VK_LEFT, 0 , 0},
|
||||||
{ L"\x1b", VK_ESCAPE, L'\x1b' , 0}
|
{ L"\x1bOF", VK_END, 0 , 0}, /* KeyPad END */
|
||||||
|
{ L"\x1bOH", VK_HOME, 0 , 0}, /* KeyPad HOME */
|
||||||
|
{ L"\x1bOP", VK_F1, 0 , 0},
|
||||||
|
{ L"\x1bOQ", VK_F2, 0 , 0},
|
||||||
|
{ L"\x1bOR", VK_F3, 0 , 0},
|
||||||
|
{ L"\x1bOS", VK_F4, 0 , 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static SHORT lastX = 0;
|
static SHORT lastX = 0;
|
||||||
static SHORT lastY = 0;
|
static SHORT lastY = 0;
|
||||||
|
static wchar_t system32_path[PATH_MAX];
|
||||||
static wchar_t cmd_exe_path[PATH_MAX];
|
static wchar_t cmd_exe_path[PATH_MAX];
|
||||||
|
|
||||||
SHORT currentLine = 0;
|
SHORT currentLine = 0;
|
||||||
|
@ -201,27 +210,58 @@ ConSRWidth()
|
||||||
return consoleBufferInfo.srWindow.Right;
|
return consoleBufferInfo.srWindow.Right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct key_translation *
|
||||||
|
FindKeyTransByMask(wchar_t prefix, const wchar_t * value, int vlen, wchar_t suffix)
|
||||||
|
{
|
||||||
|
struct key_translation *k = NULL;
|
||||||
|
for (int i = 0; i < ARRAYSIZE(keys); i++) {
|
||||||
|
k = &keys[i];
|
||||||
|
if (k->in_key_len < vlen + 2) continue;
|
||||||
|
if (k->in[0] != L'\033') continue;
|
||||||
|
if (k->in[1] != prefix) continue;
|
||||||
|
if (k->in[vlen + 2] != suffix) continue;
|
||||||
|
|
||||||
|
if (vlen <= 1 && value[0] == k->in[2])
|
||||||
|
return k;
|
||||||
|
if (vlen > 1 && wcsncmp(&k->in[2], value, vlen) == 0)
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GetVirtualKeyByMask(wchar_t prefix, const wchar_t * value, int vlen, wchar_t suffix)
|
||||||
|
{
|
||||||
|
struct key_translation * pk = FindKeyTransByMask(prefix, value, vlen, suffix);
|
||||||
|
return pk ? pk->vk : 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function will handle the console keystrokes.
|
* This function will handle the console keystrokes.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
SendKeyStroke(HANDLE hInput, int keyStroke, wchar_t character)
|
SendKeyStrokeEx(HANDLE hInput, int vKey, wchar_t character, DWORD ctrlState, BOOL keyDown)
|
||||||
{
|
{
|
||||||
DWORD wr = 0;
|
DWORD wr = 0;
|
||||||
INPUT_RECORD ir;
|
INPUT_RECORD ir;
|
||||||
|
|
||||||
ir.EventType = KEY_EVENT;
|
ir.EventType = KEY_EVENT;
|
||||||
ir.Event.KeyEvent.bKeyDown = TRUE;
|
ir.Event.KeyEvent.bKeyDown = keyDown;
|
||||||
ir.Event.KeyEvent.wRepeatCount = 1;
|
ir.Event.KeyEvent.wRepeatCount = 0;
|
||||||
ir.Event.KeyEvent.wVirtualKeyCode = keyStroke;
|
ir.Event.KeyEvent.wVirtualKeyCode = vKey;
|
||||||
ir.Event.KeyEvent.wVirtualScanCode = 0;
|
ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyA(vKey, MAPVK_VK_TO_VSC);
|
||||||
ir.Event.KeyEvent.dwControlKeyState = 0;
|
ir.Event.KeyEvent.dwControlKeyState = ctrlState;
|
||||||
ir.Event.KeyEvent.uChar.UnicodeChar = character;
|
ir.Event.KeyEvent.uChar.UnicodeChar = character;
|
||||||
|
|
||||||
WriteConsoleInputW(hInput, &ir, 1, &wr);
|
WriteConsoleInputW(hInput, &ir, 1, &wr);
|
||||||
|
}
|
||||||
|
|
||||||
ir.Event.KeyEvent.bKeyDown = FALSE;
|
void
|
||||||
WriteConsoleInputW(hInput, &ir, 1, &wr);
|
SendKeyStroke(HANDLE hInput, int keyStroke, wchar_t character)
|
||||||
|
{
|
||||||
|
SendKeyStrokeEx(hInput, keyStroke, character, 0, TRUE);
|
||||||
|
SendKeyStrokeEx(hInput, keyStroke, character, 0, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -231,26 +271,80 @@ initialize_keylen()
|
||||||
keys[i].in_key_len = (int) wcslen(keys[i].in);
|
keys[i].in_key_len = (int) wcslen(keys[i].in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ProcessCtrlSequence(wchar_t *buf, int buf_len)
|
||||||
|
{
|
||||||
|
int vkey = 0;
|
||||||
|
/* Decode special keys when pressed CTRL key */
|
||||||
|
if (buf[0] == L'\033' && buf[1] == L'[' && buf[buf_len - 3] == L';' && buf[buf_len - 2] == L'5') {
|
||||||
|
if (buf[buf_len - 1] == L'~') {
|
||||||
|
/* VK_DELETE, VK_PGDN, VK_PGUP */
|
||||||
|
if (!vkey && buf_len == 6)
|
||||||
|
vkey = GetVirtualKeyByMask(L'[', &buf[2], 1, L'~');
|
||||||
|
|
||||||
|
/* VK_F1 ... VK_F12 */
|
||||||
|
if (!vkey && buf_len == 7)
|
||||||
|
vkey = GetVirtualKeyByMask(L'[', &buf[2], 2, L'~');
|
||||||
|
} else {
|
||||||
|
/* VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN */
|
||||||
|
if (!vkey && buf_len == 6 && buf[2] == L'1')
|
||||||
|
vkey = GetVirtualKeyByMask(L'[', &buf[5], 1, 0);
|
||||||
|
|
||||||
|
/* VK_F1 ... VK_F4 */
|
||||||
|
if (!vkey && buf_len == 6 && buf[2] == L'1' && isalpha(buf[5]))
|
||||||
|
vkey = GetVirtualKeyByMask(L'O', &buf[5], 1, 0);
|
||||||
|
}
|
||||||
|
if (vkey) {
|
||||||
|
SendKeyStrokeEx(child_in, VK_CONTROL, 0, LEFT_CTRL_PRESSED, TRUE);
|
||||||
|
SendKeyStrokeEx(child_in, vkey, 0, LEFT_CTRL_PRESSED, TRUE);
|
||||||
|
SendKeyStrokeEx(child_in, VK_CONTROL, 0, 0, FALSE);
|
||||||
|
SendKeyStrokeEx(child_in, vkey, 0, 0, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vkey;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ProcessIncomingKeys(char * ansikey)
|
ProcessIncomingKeys(char * ansikey)
|
||||||
{
|
{
|
||||||
|
int buf_len = 0;
|
||||||
|
const int MAX_CTRL_SEQ_LEN = 7;
|
||||||
|
const wchar_t *ESC_SEQ = L"\x1b";
|
||||||
wchar_t *buf = utf8_to_utf16(ansikey);
|
wchar_t *buf = utf8_to_utf16(ansikey);
|
||||||
|
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
printf("\nFailed to deserialize the client data, error:%d\n", GetLastError());
|
printf("\nFailed to deserialize the client data, error:%d\n", GetLastError());
|
||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
while (buf && (wcslen(buf) > 0)) {
|
while (buf && ((buf_len=(int)wcslen(buf)) > 0)) {
|
||||||
for (int j = 0; j < ARRAYSIZE(keys); j++) {
|
for (int j = 0; j < ARRAYSIZE(keys); j++) {
|
||||||
if ( (wcslen(buf) >= keys[j].in_key_len) && (wcsncmp(buf, keys[j].in, keys[j].in_key_len) == 0) ) {
|
if ( (buf_len >= keys[j].in_key_len) && (wcsncmp(buf, keys[j].in, keys[j].in_key_len) == 0) ) {
|
||||||
SendKeyStroke(child_in, keys[j].vk, keys[j].out);
|
SendKeyStroke(child_in, keys[j].vk, keys[j].out);
|
||||||
buf += keys[j].in_key_len;
|
buf += keys[j].in_key_len;
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Decode special keys when pressed CTRL key. CTRL sequences can be of size 6 or 7. */
|
||||||
|
if ((buf_len >= MAX_CTRL_SEQ_LEN) && ProcessCtrlSequence(buf, MAX_CTRL_SEQ_LEN)) {
|
||||||
|
buf += MAX_CTRL_SEQ_LEN;
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf_len >= (MAX_CTRL_SEQ_LEN - 1)) && ProcessCtrlSequence(buf, MAX_CTRL_SEQ_LEN - 1)) {
|
||||||
|
buf += (MAX_CTRL_SEQ_LEN - 1);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(wcsncmp(buf, ESC_SEQ, wcslen(ESC_SEQ)) == 0) {
|
||||||
|
SendKeyStroke(child_in, VK_ESCAPE, L'\x1b');
|
||||||
|
buf += wcslen(ESC_SEQ);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
if (*buf == L'\x3') /*Ctrl+C - Raise Ctrl+C*/
|
if (*buf == L'\x3') /*Ctrl+C - Raise Ctrl+C*/
|
||||||
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||||||
else
|
else
|
||||||
|
@ -460,10 +554,13 @@ SendBuffer(HANDLE hInput, CHAR_INFO *buffer, DWORD bufferSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CalculateAndSetCursor(HANDLE hInput, UINT x, UINT y)
|
CalculateAndSetCursor(HANDLE hInput, short x, short y, BOOL scroll)
|
||||||
{
|
{
|
||||||
|
if (scroll && y > currentLine)
|
||||||
|
for (short n = currentLine; n < y; n++)
|
||||||
|
SendLF(hInput);
|
||||||
|
|
||||||
SendSetCursor(pipe_out, x + 1, y + 1);
|
SendSetCursor(hInput, x + 1, y + 1);
|
||||||
currentLine = y;
|
currentLine = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,16 +583,16 @@ SizeWindow(HANDLE hInput)
|
||||||
matchingFont.FontWeight = FW_NORMAL;
|
matchingFont.FontWeight = FW_NORMAL;
|
||||||
wcscpy_s(matchingFont.FaceName, LF_FACESIZE, L"Consolas");
|
wcscpy_s(matchingFont.FaceName, LF_FACESIZE, L"Consolas");
|
||||||
|
|
||||||
bSuccess = __SetCurrentConsoleFontEx(child_out, FALSE, &matchingFont);
|
bSuccess = __SetCurrentConsoleFontEx(hInput, FALSE, &matchingFont);
|
||||||
|
|
||||||
/* This information is the live screen */
|
/* This information is the live screen */
|
||||||
ZeroMemory(&consoleInfo, sizeof(consoleInfo));
|
ZeroMemory(&consoleInfo, sizeof(consoleInfo));
|
||||||
consoleInfo.cbSize = sizeof(consoleInfo);
|
consoleInfo.cbSize = sizeof(consoleInfo);
|
||||||
|
|
||||||
bSuccess = GetConsoleScreenBufferInfoEx(child_out, &consoleInfo);
|
bSuccess = GetConsoleScreenBufferInfoEx(hInput, &consoleInfo);
|
||||||
|
|
||||||
/* Get the largest size we can size the console window to */
|
/* Get the largest size we can size the console window to */
|
||||||
coordScreen = GetLargestConsoleWindowSize(child_out);
|
coordScreen = GetLargestConsoleWindowSize(hInput);
|
||||||
|
|
||||||
/* Define the new console window size and scroll position */
|
/* Define the new console window size and scroll position */
|
||||||
if (inputSi.dwXCountChars == 0 || inputSi.dwYCountChars == 0) {
|
if (inputSi.dwXCountChars == 0 || inputSi.dwYCountChars == 0) {
|
||||||
|
@ -507,18 +604,18 @@ SizeWindow(HANDLE hInput)
|
||||||
srWindowRect.Bottom = min((SHORT)inputSi.dwYCountChars, coordScreen.Y) - 1;
|
srWindowRect.Bottom = min((SHORT)inputSi.dwYCountChars, coordScreen.Y) - 1;
|
||||||
srWindowRect.Left = srWindowRect.Top = (SHORT)0;
|
srWindowRect.Left = srWindowRect.Top = (SHORT)0;
|
||||||
|
|
||||||
/* Define the new console buffer size to be the maximum possible */
|
/* Define the new console buffer history to be the maximum possible */
|
||||||
coordScreen.X = 100;
|
coordScreen.X = srWindowRect.Right + 1; /* buffer width must be equ window width */
|
||||||
coordScreen.Y = 9999;
|
coordScreen.Y = 9999;
|
||||||
|
|
||||||
if (SetConsoleWindowInfo(child_out, TRUE, &srWindowRect))
|
if (SetConsoleWindowInfo(hInput, TRUE, &srWindowRect))
|
||||||
bSuccess = SetConsoleScreenBufferSize(child_out, coordScreen);
|
bSuccess = SetConsoleScreenBufferSize(hInput, coordScreen);
|
||||||
else {
|
else {
|
||||||
if (SetConsoleScreenBufferSize(child_out, coordScreen))
|
if (SetConsoleScreenBufferSize(hInput, coordScreen))
|
||||||
bSuccess = SetConsoleWindowInfo(child_out, TRUE, &srWindowRect);
|
bSuccess = SetConsoleWindowInfo(hInput, TRUE, &srWindowRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
bSuccess = GetConsoleScreenBufferInfoEx(child_out, &consoleInfo);
|
bSuccess = GetConsoleScreenBufferInfoEx(hInput, &consoleInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI
|
DWORD WINAPI
|
||||||
|
@ -543,20 +640,25 @@ ProcessEvent(void *p)
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
LONG idObject;
|
LONG idObject;
|
||||||
LONG idChild;
|
LONG idChild;
|
||||||
|
CHAR_INFO pBuffer[MAX_EXPECTED_BUFFER_SIZE] = {0,};
|
||||||
|
DWORD bufferSize;
|
||||||
|
SMALL_RECT readRect;
|
||||||
|
COORD coordBufSize;
|
||||||
|
COORD coordBufCoord;
|
||||||
|
|
||||||
if (!p)
|
if (!p)
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
consoleEvent* current = (consoleEvent *)p;
|
consoleEvent* current = (consoleEvent *)p;
|
||||||
|
|
||||||
if (current) {
|
if (!current)
|
||||||
event = current->event;
|
|
||||||
hwnd = current->hwnd;
|
|
||||||
idObject = current->idObject;
|
|
||||||
idChild = current->idChild;
|
|
||||||
} else
|
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
event = current->event;
|
||||||
|
hwnd = current->hwnd;
|
||||||
|
idObject = current->idObject;
|
||||||
|
idChild = current->idChild;
|
||||||
|
|
||||||
if (event < EVENT_CONSOLE_CARET || event > EVENT_CONSOLE_LAYOUT)
|
if (event < EVENT_CONSOLE_CARET || event > EVENT_CONSOLE_LAYOUT)
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
@ -586,14 +688,15 @@ ProcessEvent(void *p)
|
||||||
lastX = co.X;
|
lastX = co.X;
|
||||||
lastY = co.Y;
|
lastY = co.Y;
|
||||||
|
|
||||||
SendSetCursor(pipe_out, lastX + 1, lastY + 1);
|
if (lastX == 0 && lastY > currentLine)
|
||||||
|
CalculateAndSetCursor(pipe_out, lastX, lastY, TRUE);
|
||||||
|
else
|
||||||
|
SendSetCursor(pipe_out, lastX + 1, lastY + 1);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_CONSOLE_UPDATE_REGION:
|
case EVENT_CONSOLE_UPDATE_REGION:
|
||||||
{
|
{
|
||||||
SMALL_RECT readRect;
|
|
||||||
|
|
||||||
readRect.Top = HIWORD(idObject);
|
readRect.Top = HIWORD(idObject);
|
||||||
readRect.Left = LOWORD(idObject);
|
readRect.Left = LOWORD(idObject);
|
||||||
readRect.Bottom = HIWORD(idChild);
|
readRect.Bottom = HIWORD(idChild);
|
||||||
|
@ -617,8 +720,7 @@ ProcessEvent(void *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out the buffer size */
|
/* Figure out the buffer size */
|
||||||
COORD coordBufSize;
|
|
||||||
coordBufSize.Y = readRect.Bottom - readRect.Top + 1;
|
coordBufSize.Y = readRect.Bottom - readRect.Top + 1;
|
||||||
coordBufSize.X = readRect.Right - readRect.Left + 1;
|
coordBufSize.X = readRect.Right - readRect.Left + 1;
|
||||||
|
|
||||||
|
@ -632,7 +734,7 @@ ProcessEvent(void *p)
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
/* Compute buffer size */
|
/* Compute buffer size */
|
||||||
DWORD bufferSize = coordBufSize.X * coordBufSize.Y;
|
bufferSize = coordBufSize.X * coordBufSize.Y;
|
||||||
if (bufferSize > MAX_EXPECTED_BUFFER_SIZE) {
|
if (bufferSize > MAX_EXPECTED_BUFFER_SIZE) {
|
||||||
if (!bStartup) {
|
if (!bStartup) {
|
||||||
SendClearScreen(pipe_out);
|
SendClearScreen(pipe_out);
|
||||||
|
@ -641,38 +743,22 @@ ProcessEvent(void *p)
|
||||||
}
|
}
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the screen scrape buffer */
|
/* The top left destination cell of the temporary buffer is row 0, col 0 */
|
||||||
CHAR_INFO *pBuffer = (PCHAR_INFO)malloc(sizeof(CHAR_INFO) * bufferSize);
|
|
||||||
if (!pBuffer)
|
|
||||||
return ERROR_INSUFFICIENT_BUFFER;
|
|
||||||
|
|
||||||
/* The top left destination cell of the temporary buffer is row 0, col 0 */
|
|
||||||
COORD coordBufCoord;
|
|
||||||
coordBufCoord.X = 0;
|
coordBufCoord.X = 0;
|
||||||
coordBufCoord.Y = 0;
|
coordBufCoord.Y = 0;
|
||||||
|
|
||||||
/* Copy the block from the screen buffer to the temp. buffer */
|
/* Copy the block from the screen buffer to the temp. buffer */
|
||||||
if (!ReadConsoleOutput(child_out, pBuffer, coordBufSize, coordBufCoord, &readRect)) {
|
if (!ReadConsoleOutput(child_out, pBuffer, coordBufSize, coordBufCoord, &readRect))
|
||||||
DWORD dwError = GetLastError();
|
return GetLastError();
|
||||||
|
|
||||||
free(pBuffer);
|
|
||||||
return dwError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readRect.Top > currentLine)
|
|
||||||
for (SHORT n = currentLine; n < readRect.Top; n++)
|
|
||||||
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, readRect.Left, readRect.Top);
|
CalculateAndSetCursor(pipe_out, readRect.Left, readRect.Top, TRUE);
|
||||||
|
|
||||||
/* Send the entire block */
|
/* Send the entire block */
|
||||||
SendBuffer(pipe_out, pBuffer, bufferSize);
|
SendBuffer(pipe_out, pBuffer, bufferSize);
|
||||||
lastViewPortY = ViewPortY;
|
lastViewPortY = ViewPortY;
|
||||||
lastLineLength = readRect.Left;
|
lastLineLength = readRect.Left;
|
||||||
|
|
||||||
free(pBuffer);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -683,38 +769,27 @@ ProcessEvent(void *p)
|
||||||
wX = LOWORD(idObject);
|
wX = LOWORD(idObject);
|
||||||
wY = HIWORD(idObject);
|
wY = HIWORD(idObject);
|
||||||
|
|
||||||
SMALL_RECT readRect;
|
|
||||||
readRect.Top = wY;
|
readRect.Top = wY;
|
||||||
readRect.Bottom = wY;
|
readRect.Bottom = wY;
|
||||||
readRect.Left = wX;
|
readRect.Left = wX;
|
||||||
readRect.Right = ConSRWidth();
|
readRect.Right = ConSRWidth();
|
||||||
|
|
||||||
/* 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, wX, wY);
|
CalculateAndSetCursor(pipe_out, wX, wY, TRUE);
|
||||||
|
|
||||||
COORD coordBufSize;
|
|
||||||
coordBufSize.Y = readRect.Bottom - readRect.Top + 1;
|
coordBufSize.Y = readRect.Bottom - readRect.Top + 1;
|
||||||
coordBufSize.X = readRect.Right - readRect.Left + 1;
|
coordBufSize.X = readRect.Right - readRect.Left + 1;
|
||||||
|
bufferSize = coordBufSize.X * coordBufSize.Y;
|
||||||
|
|
||||||
/* The top left destination cell of the temporary buffer is row 0, col 0 */
|
/* The top left destination cell of the temporary buffer is row 0, col 0 */
|
||||||
COORD coordBufCoord;
|
|
||||||
coordBufCoord.X = 0;
|
coordBufCoord.X = 0;
|
||||||
coordBufCoord.Y = 0;
|
coordBufCoord.Y = 0;
|
||||||
int pBufferSize = coordBufSize.X * coordBufSize.Y;
|
|
||||||
/* Send the one character. Note that a CR doesn't end up here */
|
|
||||||
CHAR_INFO *pBuffer = (PCHAR_INFO)malloc(sizeof(CHAR_INFO) * pBufferSize);
|
|
||||||
if (!pBuffer)
|
|
||||||
return ERROR_INSUFFICIENT_BUFFER;
|
|
||||||
|
|
||||||
/* Copy the block from the screen buffer to the temp. buffer */
|
/* Copy the block from the screen buffer to the temp. buffer */
|
||||||
if (!ReadConsoleOutput(child_out, pBuffer, coordBufSize, coordBufCoord, &readRect)) {
|
if (!ReadConsoleOutput(child_out, pBuffer, coordBufSize, coordBufCoord, &readRect))
|
||||||
DWORD dwError = GetLastError();
|
return GetLastError();
|
||||||
free(pBuffer);
|
|
||||||
return dwError;
|
|
||||||
}
|
|
||||||
|
|
||||||
SendBuffer(pipe_out, pBuffer, pBufferSize);
|
SendBuffer(pipe_out, pBuffer, bufferSize);
|
||||||
free(pBuffer);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -951,13 +1026,9 @@ cleanup:
|
||||||
wchar_t *
|
wchar_t *
|
||||||
w32_cmd_path()
|
w32_cmd_path()
|
||||||
{
|
{
|
||||||
ZeroMemory(cmd_exe_path, PATH_MAX);
|
wcsncpy_s(cmd_exe_path, (sizeof(cmd_exe_path)/sizeof(wchar_t)), system32_path, wcslen(system32_path)+1);
|
||||||
if (!GetSystemDirectory(cmd_exe_path, sizeof(cmd_exe_path))) {
|
wcscat_s(cmd_exe_path, (sizeof(cmd_exe_path)/sizeof(wchar_t)), L"\\cmd.exe");
|
||||||
printf("GetSystemDirectory failed");
|
|
||||||
exit(255);
|
|
||||||
}
|
|
||||||
|
|
||||||
wcscat_s(cmd_exe_path, sizeof(cmd_exe_path), L"\\cmd.exe");
|
|
||||||
return cmd_exe_path;
|
return cmd_exe_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,14 +1043,21 @@ start_with_pty(wchar_t *command)
|
||||||
DWORD dwStatus;
|
DWORD dwStatus;
|
||||||
HANDLE hEventHook = NULL;
|
HANDLE hEventHook = NULL;
|
||||||
HMODULE hm_kernel32 = NULL, hm_user32 = NULL;
|
HMODULE hm_kernel32 = NULL, hm_user32 = NULL;
|
||||||
|
wchar_t kernel32_dll_path[PATH_MAX]={0,}, user32_dll_path[PATH_MAX]={0,};
|
||||||
|
|
||||||
if(cmd == NULL) {
|
if(cmd == NULL) {
|
||||||
printf("ssh-shellhost is out of memory");
|
printf("ssh-shellhost is out of memory");
|
||||||
exit(255);
|
exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((hm_kernel32 = LoadLibraryW(L"kernel32.dll")) == NULL ||
|
wcsncpy_s(kernel32_dll_path, (sizeof(kernel32_dll_path)/sizeof(wchar_t)), system32_path, wcslen(system32_path)+1);
|
||||||
(hm_user32 = LoadLibraryW(L"user32.dll")) == NULL ||
|
wcscat_s(kernel32_dll_path, (sizeof(kernel32_dll_path)/sizeof(wchar_t)), L"\\kernel32.dll");
|
||||||
|
|
||||||
|
wcsncpy_s(user32_dll_path, (sizeof(user32_dll_path)/sizeof(wchar_t)), system32_path, wcslen(system32_path)+1);
|
||||||
|
wcscat_s(user32_dll_path, (sizeof(user32_dll_path)/sizeof(wchar_t)), L"\\user32.dll");
|
||||||
|
|
||||||
|
if ((hm_kernel32 = LoadLibraryW(kernel32_dll_path)) == NULL ||
|
||||||
|
(hm_user32 = LoadLibraryW(user32_dll_path)) == NULL ||
|
||||||
(__SetCurrentConsoleFontEx = (__t_SetCurrentConsoleFontEx)GetProcAddress(hm_kernel32, "SetCurrentConsoleFontEx")) == NULL ||
|
(__SetCurrentConsoleFontEx = (__t_SetCurrentConsoleFontEx)GetProcAddress(hm_kernel32, "SetCurrentConsoleFontEx")) == NULL ||
|
||||||
(__UnhookWinEvent = (__t_UnhookWinEvent)GetProcAddress(hm_user32, "UnhookWinEvent")) == NULL ||
|
(__UnhookWinEvent = (__t_UnhookWinEvent)GetProcAddress(hm_user32, "UnhookWinEvent")) == NULL ||
|
||||||
(__SetWinEventHook = (__t_SetWinEventHook)GetProcAddress(hm_user32, "SetWinEventHook")) == NULL) {
|
(__SetWinEventHook = (__t_SetWinEventHook)GetProcAddress(hm_user32, "SetWinEventHook")) == NULL) {
|
||||||
|
@ -1310,9 +1388,6 @@ cleanup:
|
||||||
return child_exit_code;
|
return child_exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <Shlobj.h>
|
|
||||||
#include <Sddl.h>
|
|
||||||
|
|
||||||
static void* xmalloc(size_t size) {
|
static void* xmalloc(size_t size) {
|
||||||
void* ptr;
|
void* ptr;
|
||||||
if ((ptr = malloc(size)) == NULL) {
|
if ((ptr = malloc(size)) == NULL) {
|
||||||
|
@ -1447,6 +1522,12 @@ wmain(int ac, wchar_t **av)
|
||||||
free(cmd_utf8);
|
free(cmd_utf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZeroMemory(system32_path, sizeof(system32_path) / sizeof(wchar_t));
|
||||||
|
if (!GetSystemDirectory(system32_path, sizeof(system32_path)/sizeof(wchar_t))) {
|
||||||
|
printf("GetSystemDirectory failed");
|
||||||
|
exit(255);
|
||||||
|
}
|
||||||
|
|
||||||
if (pty_requested)
|
if (pty_requested)
|
||||||
return start_with_pty(cmd);
|
return start_with_pty(cmd);
|
||||||
else
|
else
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#define TERM_IO_BUF_SIZE 2048
|
#define TERM_IO_BUF_SIZE 2048
|
||||||
|
|
||||||
extern int in_raw_mode;
|
extern int in_raw_mode;
|
||||||
|
BOOL isFirstTime = TRUE;
|
||||||
|
|
||||||
struct io_status {
|
struct io_status {
|
||||||
DWORD to_transfer;
|
DWORD to_transfer;
|
||||||
|
@ -84,11 +85,44 @@ ReadThread(_In_ LPVOID lpParameter)
|
||||||
debug5("TermRead thread, io:%p", pio);
|
debug5("TermRead thread, io:%p", pio);
|
||||||
memset(&read_status, 0, sizeof(read_status));
|
memset(&read_status, 0, sizeof(read_status));
|
||||||
if (FILETYPE(pio) == FILE_TYPE_CHAR) {
|
if (FILETYPE(pio) == FILE_TYPE_CHAR) {
|
||||||
while (nBytesReturned == 0) {
|
if (in_raw_mode) {
|
||||||
nBytesReturned = ReadConsoleForTermEmul(WINHANDLE(pio),
|
while (nBytesReturned == 0) {
|
||||||
pio->read_details.buf, pio->read_details.buf_size);
|
nBytesReturned = ReadConsoleForTermEmul(WINHANDLE(pio),
|
||||||
|
pio->read_details.buf, pio->read_details.buf_size);
|
||||||
|
}
|
||||||
|
read_status.transferred = nBytesReturned;
|
||||||
|
} else {
|
||||||
|
if (isFirstTime) {
|
||||||
|
isFirstTime = false;
|
||||||
|
|
||||||
|
DWORD dwAttributes;
|
||||||
|
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &dwAttributes))
|
||||||
|
error("GetConsoleMode on STD_INPUT_HANDLE failed with %d\n", GetLastError());
|
||||||
|
|
||||||
|
dwAttributes |= (ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
|
||||||
|
|
||||||
|
if (!SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), dwAttributes))
|
||||||
|
error("SetConsoleMode on STD_INPUT_HANDLE failed with %d\n", GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReadFile(WINHANDLE(pio), pio->read_details.buf,
|
||||||
|
pio->read_details.buf_size, &read_status.transferred, NULL)) {
|
||||||
|
read_status.error = GetLastError();
|
||||||
|
debug("ReadThread - ReadFile failed %d, io:%p", GetLastError(), pio);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *p = NULL;
|
||||||
|
if (p = strstr(pio->read_details.buf, "\r\n"))
|
||||||
|
*p++ = '\n';
|
||||||
|
else if (p = strstr(pio->read_details.buf, "\r"))
|
||||||
|
*p++ = '\n';
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
*p = '\0';
|
||||||
|
pio->read_details.buf_size = (DWORD)strlen(pio->read_details.buf);
|
||||||
|
read_status.transferred = pio->read_details.buf_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
read_status.transferred = nBytesReturned;
|
|
||||||
} else {
|
} else {
|
||||||
if (!ReadFile(WINHANDLE(pio), pio->read_details.buf,
|
if (!ReadFile(WINHANDLE(pio), pio->read_details.buf,
|
||||||
pio->read_details.buf_size, &read_status.transferred, NULL)) {
|
pio->read_details.buf_size, &read_status.transferred, NULL)) {
|
||||||
|
@ -221,7 +255,7 @@ syncio_close(struct w32_io* pio)
|
||||||
/* If io is pending, let worker threads exit. */
|
/* If io is pending, let worker threads exit. */
|
||||||
if (pio->read_details.pending) {
|
if (pio->read_details.pending) {
|
||||||
/* For console - the read thread is blocked so terminate it. */
|
/* For console - the read thread is blocked so terminate it. */
|
||||||
if (FILETYPE(pio) == FILE_TYPE_CHAR)
|
if (FILETYPE(pio) == FILE_TYPE_CHAR && in_raw_mode)
|
||||||
TerminateThread(pio->read_overlapped.hEvent, 0);
|
TerminateThread(pio->read_overlapped.hEvent, 0);
|
||||||
else
|
else
|
||||||
WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE);
|
WaitForSingleObject(pio->read_overlapped.hEvent, INFINITE);
|
||||||
|
|
|
@ -155,7 +155,7 @@ ReadConsoleForTermEmul(HANDLE hInput, char *destin, int destinlen)
|
||||||
switch (InputRecord.Event.KeyEvent.uChar.UnicodeChar) {
|
switch (InputRecord.Event.KeyEvent.uChar.UnicodeChar) {
|
||||||
case 0xd:
|
case 0xd:
|
||||||
if (pParams->nReceiveCRLF == ENUM_LF)
|
if (pParams->nReceiveCRLF == ENUM_LF)
|
||||||
NetWriteString2(pParams->Socket, "\r", 1, 0);
|
NetWriteString2(pParams->Socket, "\n", 1, 0);
|
||||||
else
|
else
|
||||||
NetWriteString2(pParams->Socket, "\r\n", 2, 0);
|
NetWriteString2(pParams->Socket, "\r\n", 2, 0);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
#define PREV_KEY "\x1b[5~"
|
#define PREV_KEY "\x1b[5~"
|
||||||
#define NEXT_KEY "\x1b[6~"
|
#define NEXT_KEY "\x1b[6~"
|
||||||
#define SHIFT_TAB_KEY "\x1b[~"
|
#define SHIFT_TAB_KEY "\x1b[~"
|
||||||
#define ESCAPE_KEY "\x1b"
|
#define ESCAPE_KEY "\x1b"
|
||||||
#define BACKSPACE_KEY "\b"
|
#define BACKSPACE_KEY "\b"
|
||||||
|
|
||||||
// VT100 Function Key's
|
// VT100 Function Key's
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
#define dwBuffer 4096
|
#define dwBuffer 4096
|
||||||
|
|
||||||
extern BOOL isAnsiParsingRequired;
|
extern BOOL isAnsiParsingRequired;
|
||||||
|
extern bool gbVTAppMode;
|
||||||
|
BOOL isFirstPacket = TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
|
@ -51,14 +53,34 @@ extern BOOL isAnsiParsingRequired;
|
||||||
void
|
void
|
||||||
processBuffer(HANDLE handle, 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* pszNewHead = NULL;
|
unsigned char *pszNewHead = NULL;
|
||||||
unsigned char* pszHead = NULL;
|
unsigned char *pszHead = NULL;
|
||||||
unsigned char* pszTail = NULL;
|
unsigned char *pszTail = NULL;
|
||||||
|
const char *applicationModeSeq = "\x1b[?1h";
|
||||||
|
const int applicationModeSeqLen = (int)strlen(applicationModeSeq);
|
||||||
|
const char *normalModeSeq = "\x1b[?1l";
|
||||||
|
const int normalModeSeqLen = (int)strlen(normalModeSeq);
|
||||||
|
const char *clsSeq = "\x1b[2J";
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (false == isAnsiParsingRequired) {
|
if (false == isAnsiParsingRequired) {
|
||||||
|
if(isFirstPacket) {
|
||||||
|
isFirstPacket = FALSE;
|
||||||
|
/* Windows server at first sends the "cls" after the connection is established.
|
||||||
|
* There is a bug in the conhost which causes the visible window data to loose so to
|
||||||
|
* mitigate that issue we need to first move the visible window so that the cursor is at the top of the visible window.
|
||||||
|
*/
|
||||||
|
if (strstr(buf, clsSeq))
|
||||||
|
ConMoveCursorTopOfVisibleWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(len >= applicationModeSeqLen && strstr(buf, applicationModeSeq))
|
||||||
|
gbVTAppMode = true;
|
||||||
|
else if(len >= normalModeSeqLen && strstr(buf, normalModeSeq))
|
||||||
|
gbVTAppMode = false;
|
||||||
|
|
||||||
/* Console has the capability to parse so pass the raw buffer to console directly */
|
/* Console has the capability to parse so pass the raw buffer to console directly */
|
||||||
ConRestoreViewRect(); /* Restore the visible window, otherwise WriteConsoleW() gets messy */
|
ConRestoreViewRect(); /* Restore the visible window, otherwise WriteConsoleW() gets messy */
|
||||||
wchar_t* t = utf8_to_utf16(buf);
|
wchar_t* t = utf8_to_utf16(buf);
|
||||||
|
|
|
@ -4,27 +4,17 @@
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include "..\..\..\sshpty.h"
|
#include "..\..\..\sshpty.h"
|
||||||
|
|
||||||
static struct termios _saved_tio;
|
static struct termios _saved_tio;
|
||||||
static int _in_raw_mode = 0;
|
static int _in_raw_mode = 0;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TTY raw mode routines for Windows
|
* TTY raw mode routines for Windows
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ConEnterRawMode(DWORD OutputHandle, BOOL fSmartInit);
|
|
||||||
int ConExitRawMode(void);
|
|
||||||
|
|
||||||
struct termios term_settings;
|
struct termios term_settings;
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO - clean this up for Windows, ConInit should return previous terminal
|
|
||||||
* settings that need to be stored in term_settings
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct termios *
|
struct termios *
|
||||||
get_saved_tio(void) {
|
get_saved_tio(void) {
|
||||||
memset(&term_settings, 0, sizeof(term_settings));
|
memset(&term_settings, 0, sizeof(term_settings));
|
||||||
return &term_settings;
|
return &term_settings;
|
||||||
}
|
}
|
||||||
|
@ -36,5 +26,5 @@ leave_raw_mode(int quiet) {
|
||||||
|
|
||||||
void
|
void
|
||||||
enter_raw_mode(int quiet) {
|
enter_raw_mode(int quiet) {
|
||||||
ConEnterRawMode(STD_OUTPUT_HANDLE, TRUE);
|
ConEnterRawMode();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue