/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
- * FILE: frontends/terminal.c
+ * FILE: win32ss/user/winsrv/consrv/frontends/terminal.c
* PURPOSE: ConSrv terminal.
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#include <consrv.h>
+#include "concfg/font.h"
// #include "frontends/gui/guiterm.h"
#ifdef TUITERM_COMPILE
#define NDEBUG
#include <debug.h>
+
+
+
+
+/********** HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ************/
+
+/* GLOBALS ********************************************************************/
+
+/*
+ * From MSDN:
+ * "The lpMultiByteStr and lpWideCharStr pointers must not be the same.
+ * If they are the same, the function fails, and GetLastError returns
+ * ERROR_INVALID_PARAMETER."
+ */
+#define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
+do { \
+ ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \
+ WideCharToMultiByte((Console)->InputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \
+} while (0)
+
+#define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
+do { \
+ ASSERT((ULONG_PTR)(dWChar) != (ULONG_PTR)(sChar)); \
+ MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1); \
+} while (0)
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+#if 0
+
+static VOID
+ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
+{
+ if (InputEvent->EventType == KEY_EVENT)
+ {
+ WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
+ InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
+ ConsoleInputUnicodeCharToAnsiChar(Console,
+ &InputEvent->Event.KeyEvent.uChar.AsciiChar,
+ &UnicodeChar);
+ }
+}
+
+static VOID
+ConioInputEventToUnicode(PCONSOLE Console, PINPUT_RECORD InputEvent)
+{
+ if (InputEvent->EventType == KEY_EVENT)
+ {
+ CHAR AsciiChar = InputEvent->Event.KeyEvent.uChar.AsciiChar;
+ InputEvent->Event.KeyEvent.uChar.AsciiChar = 0;
+ ConsoleInputAnsiCharToUnicodeChar(Console,
+ &InputEvent->Event.KeyEvent.uChar.UnicodeChar,
+ &AsciiChar);
+ }
+}
+
+#endif
+
+/********** HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ************/
+
+
+
+
+
+
+
+
/* CONSRV TERMINAL FRONTENDS INTERFACE ****************************************/
/***************/
#ifdef TUITERM_COMPILE
NTSTATUS NTAPI
TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
- IN OUT PCONSOLE_INFO ConsoleInfo,
- IN OUT PVOID ExtraConsoleInfo,
- IN ULONG ProcessId);
+ IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
+ IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+ IN HANDLE ConsoleLeaderProcessHandle);
NTSTATUS NTAPI
TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
#endif
NTSTATUS NTAPI
GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
- IN OUT PCONSOLE_INFO ConsoleInfo,
- IN OUT PVOID ExtraConsoleInfo,
- IN ULONG ProcessId);
+ IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
+ IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+ IN HANDLE ConsoleLeaderProcessHandle);
NTSTATUS NTAPI
GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
/***************/
typedef
NTSTATUS (NTAPI *FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd,
- IN OUT PCONSOLE_INFO ConsoleInfo,
- IN OUT PVOID ExtraConsoleInfo,
- IN ULONG ProcessId);
+ IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
+ IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+ IN HANDLE ConsoleLeaderProcessHandle);
typedef
NTSTATUS (NTAPI *FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd);
* NOTE: Each entry of the table should be retrieved when loading a front-end
* (examples of the CSR servers which register some data for CSRSS).
*/
-struct
+static struct
{
CHAR FrontEndName[80];
FRONTEND_LOAD FrontEndLoad;
static NTSTATUS
ConSrvLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
- IN OUT PCONSOLE_INFO ConsoleInfo,
- IN OUT PVOID ExtraConsoleInfo,
- IN ULONG ProcessId)
+ IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
+ IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+ IN HANDLE ConsoleLeaderProcessHandle)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i;
/*
* Choose an adequate terminal front-end to load, and load it
*/
- for (i = 0; i < sizeof(FrontEndLoadingMethods) / sizeof(FrontEndLoadingMethods[0]); ++i)
+ for (i = 0; i < ARRAYSIZE(FrontEndLoadingMethods); ++i)
{
DPRINT("CONSRV: Trying to load %s frontend...\n",
FrontEndLoadingMethods[i].FrontEndName);
Status = FrontEndLoadingMethods[i].FrontEndLoad(FrontEnd,
ConsoleInfo,
- ExtraConsoleInfo,
- ProcessId);
+ ConsoleInitInfo,
+ ConsoleLeaderProcessHandle);
if (NT_SUCCESS(Status))
{
/* Save the unload callback */
NTSTATUS NTAPI
ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
- IN OUT PCONSOLE_INFO ConsoleInfo,
- IN OUT PVOID ExtraConsoleInfo,
- IN ULONG ProcessId)
+ IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
+ IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
+ IN HANDLE ConsoleLeaderProcessHandle)
{
NTSTATUS Status;
PFRONTEND FrontEnd;
Status = ConSrvLoadFrontEnd(FrontEnd,
ConsoleInfo,
- ExtraConsoleInfo,
- ProcessId);
+ ConsoleInitInfo,
+ ConsoleLeaderProcessHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status);
/* Initialize the ConSrv terminal */
Terminal->Vtbl = &ConSrvTermVtbl;
- // Terminal->Console will be initialized by ConDrvRegisterTerminal
- Terminal->Data = FrontEnd; /* We store the frontend pointer in the terminal private data */
+ // Terminal->Console will be initialized by ConDrvAttachTerminal
+ Terminal->Context = FrontEnd; /* We store the frontend pointer in the terminal private context */
return STATUS_SUCCESS;
}
ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal)
{
NTSTATUS Status = STATUS_SUCCESS;
- PFRONTEND FrontEnd = Terminal->Data;
+ PFRONTEND FrontEnd = Terminal->Context;
/* Reset the ConSrv terminal */
- Terminal->Data = NULL;
+ Terminal->Context = NULL;
Terminal->Vtbl = NULL;
/* Unload the frontend */
static NTSTATUS NTAPI
ConSrvTermInitTerminal(IN OUT PTERMINAL This,
- IN PCONSOLE Console)
+ IN PCONSOLE Console)
{
NTSTATUS Status;
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
+ PCONSRV_CONSOLE ConSrvConsole = (PCONSRV_CONSOLE)Console;
/* Initialize the console pointer for our frontend */
- FrontEnd->Console = Console;
+ FrontEnd->Console = ConSrvConsole;
/** HACK HACK!! Copy FrontEnd into the console!! **/
- DPRINT1("Using FrontEndIFace HACK(1), should be removed after proper implementation!\n");
- Console->FrontEndIFace = *FrontEnd;
+ DPRINT("Using FrontEndIFace HACK(1), should be removed after proper implementation!\n");
+ ConSrvConsole->FrontEndIFace = *FrontEnd;
- Status = FrontEnd->Vtbl->InitFrontEnd(FrontEnd, FrontEnd->Console);
+ Status = FrontEnd->Vtbl->InitFrontEnd(FrontEnd, ConSrvConsole);
+ if (!NT_SUCCESS(Status))
+ DPRINT1("InitFrontEnd failed, Status = 0x%08lx\n", Status);
/** HACK HACK!! Be sure FrontEndIFace is correctly updated in the console!! **/
- DPRINT1("Using FrontEndIFace HACK(2), should be removed after proper implementation!\n");
- Console->FrontEndIFace = *FrontEnd;
+ DPRINT("Using FrontEndIFace HACK(2), should be removed after proper implementation!\n");
+ ConSrvConsole->FrontEndIFace = *FrontEnd;
return Status;
}
static VOID NTAPI
ConSrvTermDeinitTerminal(IN OUT PTERMINAL This)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
FrontEnd->Vtbl->DeinitFrontEnd(FrontEnd);
}
-static VOID NTAPI
-ConSrvTermDrawRegion(IN OUT PTERMINAL This,
- SMALL_RECT* Region)
+
+
+/************ Line discipline ***************/
+
+static NTSTATUS NTAPI
+ConSrvTermReadStream(IN OUT PTERMINAL This,
+ IN BOOLEAN Unicode,
+ /**PWCHAR Buffer,**/
+ OUT PVOID Buffer,
+ IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
+ IN PVOID Parameter OPTIONAL,
+ IN ULONG NumCharsToRead,
+ OUT PULONG NumCharsRead OPTIONAL)
{
- PFRONTEND FrontEnd = This->Data;
- FrontEnd->Vtbl->DrawRegion(FrontEnd, Region);
+ PFRONTEND FrontEnd = This->Context;
+ PCONSRV_CONSOLE Console = FrontEnd->Console;
+ PCONSOLE_INPUT_BUFFER InputBuffer = &Console->InputBuffer;
+ PUNICODE_STRING ExeName = Parameter;
+
+ // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
+ NTSTATUS Status = STATUS_PENDING;
+
+ PLIST_ENTRY CurrentEntry;
+ ConsoleInput *Input;
+ ULONG i = 0;
+
+ /* Validity checks */
+ // ASSERT(Console == InputBuffer->Header.Console);
+ ASSERT((Buffer != NULL) || (Buffer == NULL && NumCharsToRead == 0));
+
+ /* We haven't read anything (yet) */
+
+ if (InputBuffer->Mode & ENABLE_LINE_INPUT)
+ {
+ /* COOKED mode, call the line discipline */
+
+ if (Console->LineBuffer == NULL)
+ {
+ /* Start a new line */
+ Console->LineMaxSize = max(256, NumCharsToRead);
+
+ /*
+ * Fixup ReadControl->nInitialChars in case the number of initial
+ * characters is bigger than the number of characters to be read.
+ * It will always be, lesser than or equal to Console->LineMaxSize.
+ */
+ ReadControl->nInitialChars = min(ReadControl->nInitialChars, NumCharsToRead);
+
+ Console->LineBuffer = ConsoleAllocHeap(0, Console->LineMaxSize * sizeof(WCHAR));
+ if (Console->LineBuffer == NULL) return STATUS_NO_MEMORY;
+
+ Console->LinePos = Console->LineSize = ReadControl->nInitialChars;
+ Console->LineComplete = Console->LineUpPressed = FALSE;
+ Console->LineInsertToggle = Console->InsertMode;
+ Console->LineWakeupMask = ReadControl->dwCtrlWakeupMask;
+
+ /*
+ * Pre-fill the buffer with the nInitialChars from the user buffer.
+ * Since pre-filling is only allowed in Unicode, we don't need to
+ * worry about ANSI <-> Unicode conversion.
+ */
+ memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
+ if (Console->LineSize >= Console->LineMaxSize)
+ {
+ Console->LineComplete = TRUE;
+ Console->LinePos = 0;
+ }
+ }
+
+ /* If we don't have a complete line yet, process the pending input */
+ while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents))
+ {
+ /* Remove an input event from the queue */
+ _InterlockedDecrement((PLONG)&InputBuffer->NumberOfEvents);
+ CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
+ if (IsListEmpty(&InputBuffer->InputEvents))
+ {
+ NtClearEvent(InputBuffer->ActiveEvent);
+ }
+ Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+
+ /* Only pay attention to key down */
+ if (Input->InputEvent.EventType == KEY_EVENT &&
+ Input->InputEvent.Event.KeyEvent.bKeyDown)
+ {
+ LineInputKeyDown(Console, ExeName,
+ &Input->InputEvent.Event.KeyEvent);
+ ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
+ }
+ ConsoleFreeHeap(Input);
+ }
+
+ /* Check if we have a complete line to read from */
+ if (Console->LineComplete)
+ {
+ /*
+ * Console->LinePos keeps the next position of the character to read
+ * in the line buffer across the different calls of the function,
+ * so that the line buffer can be read by chunks after all the input
+ * has been buffered.
+ */
+
+ while (i < NumCharsToRead && Console->LinePos < Console->LineSize)
+ {
+ WCHAR Char = Console->LineBuffer[Console->LinePos++];
+
+ if (Unicode)
+ {
+ ((PWCHAR)Buffer)[i] = Char;
+ }
+ else
+ {
+ ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
+ }
+ ++i;
+ }
+
+ if (Console->LinePos >= Console->LineSize)
+ {
+ /* The entire line has been read */
+ ConsoleFreeHeap(Console->LineBuffer);
+ Console->LineBuffer = NULL;
+ Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
+ // Console->LineComplete = Console->LineUpPressed = FALSE;
+ Console->LineComplete = FALSE;
+ }
+
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* RAW mode */
+
+ /* Character input */
+ while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents))
+ {
+ /* Remove an input event from the queue */
+ _InterlockedDecrement((PLONG)&InputBuffer->NumberOfEvents);
+ CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
+ if (IsListEmpty(&InputBuffer->InputEvents))
+ {
+ NtClearEvent(InputBuffer->ActiveEvent);
+ }
+ Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
+
+ /* Only pay attention to valid characters, on key down */
+ if (Input->InputEvent.EventType == KEY_EVENT &&
+ Input->InputEvent.Event.KeyEvent.bKeyDown &&
+ Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
+ {
+ WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
+
+ if (Unicode)
+ {
+ ((PWCHAR)Buffer)[i] = Char;
+ }
+ else
+ {
+ ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
+ }
+ ++i;
+
+ /* Did read something */
+ Status = STATUS_SUCCESS;
+ }
+ ConsoleFreeHeap(Input);
+ }
+ }
+
+ // FIXME: Only set if Status == STATUS_SUCCESS ???
+ if (NumCharsRead) *NumCharsRead = i;
+
+ return Status;
}
-static VOID NTAPI
+
+
+
+/* GLOBALS ********************************************************************/
+
+#define TAB_WIDTH 8
+
+// See condrv/text.c
+/*static*/ VOID
+ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff);
+
+static VOID
+ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, PSMALL_RECT UpdateRect, PUINT ScrolledLines)
+{
+ /* If we hit bottom, slide the viewable screen */
+ if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y)
+ {
+ Buff->CursorPosition.Y--;
+ if (++Buff->VirtualY == Buff->ScreenBufferSize.Y)
+ {
+ Buff->VirtualY = 0;
+ }
+ (*ScrolledLines)++;
+ ClearLineBuffer(Buff);
+ if (UpdateRect->Top != 0)
+ {
+ UpdateRect->Top--;
+ }
+ }
+ UpdateRect->Left = 0;
+ UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
+ UpdateRect->Bottom = Buff->CursorPosition.Y;
+}
+
+static NTSTATUS
+ConioWriteConsole(PFRONTEND FrontEnd,
+ PTEXTMODE_SCREEN_BUFFER Buff,
+ PWCHAR Buffer,
+ DWORD Length,
+ BOOL Attrib)
+{
+ PCONSRV_CONSOLE Console = FrontEnd->Console;
+
+ UINT i;
+ PCHAR_INFO Ptr;
+ SMALL_RECT UpdateRect;
+ SHORT CursorStartX, CursorStartY;
+ UINT ScrolledLines;
+ BOOLEAN bFullwidth;
+ BOOLEAN bCJK = Console->IsCJK;
+
+ /* If nothing to write, bail out now */
+ if (Length == 0)
+ return STATUS_SUCCESS;
+
+ CursorStartX = Buff->CursorPosition.X;
+ CursorStartY = Buff->CursorPosition.Y;
+ UpdateRect.Left = Buff->ScreenBufferSize.X;
+ UpdateRect.Top = Buff->CursorPosition.Y;
+ UpdateRect.Right = -1;
+ UpdateRect.Bottom = Buff->CursorPosition.Y;
+ ScrolledLines = 0;
+
+ for (i = 0; i < Length; i++)
+ {
+ /*
+ * If we are in processed mode, interpret special characters and
+ * display them correctly. Otherwise, just put them into the buffer.
+ */
+ if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
+ {
+ /* --- CR --- */
+ if (Buffer[i] == L'\r')
+ {
+ Buff->CursorPosition.X = 0;
+ CursorStartX = Buff->CursorPosition.X;
+ UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
+ UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
+ continue;
+ }
+ /* --- LF --- */
+ else if (Buffer[i] == L'\n')
+ {
+ Buff->CursorPosition.X = 0; // TODO: Make this behaviour optional!
+ CursorStartX = Buff->CursorPosition.X;
+ ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+ continue;
+ }
+ /* --- BS --- */
+ else if (Buffer[i] == L'\b')
+ {
+ /* Only handle BS if we are not on the first position of the first line */
+ if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
+ continue;
+
+ if (Buff->CursorPosition.X == 0)
+ {
+ /* Slide virtual position up */
+ Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
+ Buff->CursorPosition.Y--;
+ // TODO? : Update CursorStartY = Buff->CursorPosition.Y;
+ UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
+ }
+ else
+ {
+ Buff->CursorPosition.X--;
+ }
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+
+ if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
+ {
+ /*
+ * The cursor just moved on the leading byte of the same
+ * current character. We should go one position before to
+ * go to the actual previous character to erase.
+ */
+
+ /* Only handle BS if we are not on the first position of the first line */
+ if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
+ continue;
+
+ if (Buff->CursorPosition.X == 0)
+ {
+ /* Slide virtual position up */
+ Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
+ Buff->CursorPosition.Y--;
+ // TODO? : Update CursorStartY = Buff->CursorPosition.Y;
+ UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
+ }
+ else
+ {
+ Buff->CursorPosition.X--;
+ }
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ }
+
+ if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+ {
+ /* The cursor is on the trailing byte of a full-width character */
+
+ /* Delete its trailing byte... */
+ Ptr->Char.UnicodeChar = L' ';
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+
+ if (Buff->CursorPosition.X > 0)
+ Buff->CursorPosition.X--;
+ /* ... and now its leading byte */
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ }
+
+ Ptr->Char.UnicodeChar = L' ';
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+
+ UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
+ UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
+ continue;
+ }
+ /* --- TAB --- */
+ else if (Buffer[i] == L'\t')
+ {
+ UINT EndX;
+
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+
+ if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+ {
+ /*
+ * The cursor is on the trailing byte of a full-width character.
+ * Go back one position to be on its leading byte.
+ */
+ if (Buff->CursorPosition.X > 0)
+ Buff->CursorPosition.X--;
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ }
+
+ UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
+
+ EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1);
+ EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X);
+
+ while ((UINT)Buff->CursorPosition.X < EndX)
+ {
+ Ptr->Char.UnicodeChar = L' ';
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+
+ ++Ptr;
+ Buff->CursorPosition.X++;
+ }
+ if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
+ {
+ /* If the following cell is the trailing byte of a full-width character, reset it */
+ if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+ {
+ Ptr->Char.UnicodeChar = L' ';
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+ }
+ }
+ UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
+
+ if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
+ {
+ if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
+ {
+ /* Wrapping mode: Go to next line */
+ Buff->CursorPosition.X = 0;
+ CursorStartX = Buff->CursorPosition.X;
+ ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+ }
+ else
+ {
+ /* The cursor wraps back to its starting position on the same line */
+ Buff->CursorPosition.X = CursorStartX;
+ }
+ }
+ continue;
+ }
+ /* --- BEL ---*/
+ else if (Buffer[i] == L'\a')
+ {
+ FrontEnd->Vtbl->RingBell(FrontEnd);
+ continue;
+ }
+ }
+ UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
+ UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
+
+ /* For Chinese, Japanese and Korean */
+ bFullwidth = (bCJK && IS_FULL_WIDTH(Buffer[i]));
+
+ /* Check whether we can insert the full-width character */
+ if (bFullwidth)
+ {
+ /* It spans two cells and should all fit on the current line */
+ if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
+ {
+ if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
+ {
+ /* Wrapping mode: Go to next line */
+ Buff->CursorPosition.X = 0;
+ CursorStartX = Buff->CursorPosition.X;
+ ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+ }
+ else
+ {
+ /* The cursor wraps back to its starting position on the same line */
+ Buff->CursorPosition.X = CursorStartX;
+ }
+ }
+
+ /*
+ * Now be sure we can fit the full-width character.
+ * If the screenbuffer is one cell wide we cannot display
+ * the full-width character, so just skip it.
+ */
+ if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
+ {
+ DPRINT1("Cannot display full-width character! CursorPosition.X = %d, ScreenBufferSize.X = %d\n",
+ Buff->CursorPosition.X, Buff->ScreenBufferSize.X);
+ continue;
+ }
+ }
+
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+
+ /*
+ * Check whether we are overwriting part of a full-width character,
+ * in which case we need to invalidate it.
+ */
+ if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+ {
+ /*
+ * The cursor is on the trailing byte of a full-width character.
+ * Go back one position to kill the previous leading byte.
+ */
+ if (Buff->CursorPosition.X > 0)
+ {
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X - 1, Buff->CursorPosition.Y);
+ Ptr->Char.UnicodeChar = L' ';
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+ }
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ }
+
+ /* Insert the character */
+ if (bFullwidth)
+ {
+ ASSERT(Buff->CursorPosition.X < Buff->ScreenBufferSize.X - 1);
+
+ /* Set the leading byte */
+ Ptr->Char.UnicodeChar = Buffer[i];
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+ Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
+
+ /* Set the trailing byte */
+ Buff->CursorPosition.X++;
+ Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+ // Ptr->Char.UnicodeChar = Buffer[i]; // L' ';
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+ Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
+ }
+ else
+ {
+ Ptr->Char.UnicodeChar = Buffer[i];
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+ }
+
+ ++Ptr;
+ Buff->CursorPosition.X++;
+
+ if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
+ {
+ /* If the following cell is the trailing byte of a full-width character, reset it */
+ if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+ {
+ Ptr->Char.UnicodeChar = L' ';
+ if (Attrib)
+ Ptr->Attributes = Buff->ScreenDefaultAttrib;
+ Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+ }
+ }
+
+ if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
+ {
+ if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
+ {
+ /* Wrapping mode: Go to next line */
+ Buff->CursorPosition.X = 0;
+ CursorStartX = Buff->CursorPosition.X;
+ ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+ }
+ else
+ {
+ /* The cursor wraps back to its starting position on the same line */
+ Buff->CursorPosition.X = CursorStartX;
+ }
+ }
+ }
+
+ if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer)
+ {
+ // TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
+ // ScrolledLines, Buffer, Length);
+ FrontEnd->Vtbl->WriteStream(FrontEnd,
+ &UpdateRect,
+ CursorStartX,
+ CursorStartY,
+ ScrolledLines,
+ Buffer,
+ Length);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+
+static NTSTATUS NTAPI
ConSrvTermWriteStream(IN OUT PTERMINAL This,
- SMALL_RECT* Region,
- SHORT CursorStartX,
- SHORT CursorStartY,
- UINT ScrolledLines,
- PWCHAR Buffer,
- UINT Length)
+ PTEXTMODE_SCREEN_BUFFER Buff,
+ PWCHAR Buffer,
+ DWORD Length,
+ BOOL Attrib)
+{
+ PFRONTEND FrontEnd = This->Context;
+ return ConioWriteConsole(FrontEnd,
+ Buff,
+ Buffer,
+ Length,
+ Attrib);
+}
+
+/************ Line discipline ***************/
+
+
+
+VOID
+ConioDrawConsole(PCONSRV_CONSOLE Console)
+{
+ SMALL_RECT Region;
+ PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
+
+ if (!ActiveBuffer) return;
+
+ ConioInitRect(&Region, 0, 0,
+ ActiveBuffer->ViewSize.Y - 1,
+ ActiveBuffer->ViewSize.X - 1);
+ TermDrawRegion(Console, &Region);
+ // Console->FrontEndIFace.Vtbl->DrawRegion(&Console->FrontEndIFace, &Region);
+}
+
+static VOID NTAPI
+ConSrvTermDrawRegion(IN OUT PTERMINAL This,
+ SMALL_RECT* Region)
{
- PFRONTEND FrontEnd = This->Data;
- FrontEnd->Vtbl->WriteStream(FrontEnd,
- Region,
- CursorStartX,
- CursorStartY,
- ScrolledLines,
- Buffer,
- Length);
+ PFRONTEND FrontEnd = This->Context;
+ FrontEnd->Vtbl->DrawRegion(FrontEnd, Region);
}
static BOOL NTAPI
ConSrvTermSetCursorInfo(IN OUT PTERMINAL This,
PCONSOLE_SCREEN_BUFFER ScreenBuffer)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
return FrontEnd->Vtbl->SetCursorInfo(FrontEnd, ScreenBuffer);
}
SHORT OldCursorX,
SHORT OldCursorY)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
return FrontEnd->Vtbl->SetScreenInfo(FrontEnd,
ScreenBuffer,
OldCursorX,
static VOID NTAPI
ConSrvTermResizeTerminal(IN OUT PTERMINAL This)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
FrontEnd->Vtbl->ResizeTerminal(FrontEnd);
}
static VOID NTAPI
ConSrvTermSetActiveScreenBuffer(IN OUT PTERMINAL This)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
FrontEnd->Vtbl->SetActiveScreenBuffer(FrontEnd);
}
ConSrvTermReleaseScreenBuffer(IN OUT PTERMINAL This,
IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
FrontEnd->Vtbl->ReleaseScreenBuffer(FrontEnd, ScreenBuffer);
}
-static VOID NTAPI
-ConSrvTermChangeTitle(IN OUT PTERMINAL This)
-{
- PFRONTEND FrontEnd = This->Data;
- FrontEnd->Vtbl->ChangeTitle(FrontEnd);
-}
-
static VOID NTAPI
ConSrvTermGetLargestConsoleWindowSize(IN OUT PTERMINAL This,
PCOORD pSize)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
FrontEnd->Vtbl->GetLargestConsoleWindowSize(FrontEnd, pSize);
}
-/*
-static BOOL NTAPI
-ConSrvTermGetSelectionInfo(IN OUT PTERMINAL This,
- PCONSOLE_SELECTION_INFO pSelectionInfo)
-{
- PFRONTEND FrontEnd = This->Data;
- return FrontEnd->Vtbl->GetSelectionInfo(FrontEnd, pSelectionInfo);
-}
-*/
-
static BOOL NTAPI
ConSrvTermSetPalette(IN OUT PTERMINAL This,
HPALETTE PaletteHandle,
UINT PaletteUsage)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
return FrontEnd->Vtbl->SetPalette(FrontEnd, PaletteHandle, PaletteUsage);
}
+static BOOL NTAPI
+ConSrvTermSetCodePage(IN OUT PTERMINAL This,
+ UINT CodePage)
+{
+ PFRONTEND FrontEnd = This->Context;
+ return FrontEnd->Vtbl->SetCodePage(FrontEnd, CodePage);
+}
+
static INT NTAPI
ConSrvTermShowMouseCursor(IN OUT PTERMINAL This,
BOOL Show)
{
- PFRONTEND FrontEnd = This->Data;
+ PFRONTEND FrontEnd = This->Context;
return FrontEnd->Vtbl->ShowMouseCursor(FrontEnd, Show);
}
{
ConSrvTermInitTerminal,
ConSrvTermDeinitTerminal,
- ConSrvTermDrawRegion,
+
+ ConSrvTermReadStream,
ConSrvTermWriteStream,
+
+ ConSrvTermDrawRegion,
ConSrvTermSetCursorInfo,
ConSrvTermSetScreenInfo,
ConSrvTermResizeTerminal,
ConSrvTermSetActiveScreenBuffer,
ConSrvTermReleaseScreenBuffer,
- ConSrvTermChangeTitle,
ConSrvTermGetLargestConsoleWindowSize,
- // ConSrvTermGetSelectionInfo,
ConSrvTermSetPalette,
+ ConSrvTermSetCodePage,
ConSrvTermShowMouseCursor,
};
VOID
ResetFrontEnd(IN PCONSOLE Console)
{
+ PCONSRV_CONSOLE ConSrvConsole = (PCONSRV_CONSOLE)Console;
if (!Console) return;
/* Reinitialize the frontend interface */
- RtlZeroMemory(&Console->FrontEndIFace, sizeof(Console->FrontEndIFace));
- Console->FrontEndIFace.Vtbl = &ConSrvTermVtbl;
+ RtlZeroMemory(&ConSrvConsole->FrontEndIFace, sizeof(ConSrvConsole->FrontEndIFace));
+ ConSrvConsole->FrontEndIFace.Vtbl = &ConSrvTermVtbl;
}
#endif