[CONSRV]
[reactos.git] / win32ss / user / winsrv / consrv / frontends / terminal.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: frontends/terminal.c
5 * PURPOSE: ConSrv terminal.
6 * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <consrv.h>
12
13 // #include "frontends/gui/guiterm.h"
14 #ifdef TUITERM_COMPILE
15 #include "frontends/tui/tuiterm.h"
16 #endif
17
18 #define NDEBUG
19 #include <debug.h>
20
21
22
23
24
25 /********** HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ************/
26
27 /* GLOBALS ********************************************************************/
28
29 /*
30 * From MSDN:
31 * "The lpMultiByteStr and lpWideCharStr pointers must not be the same.
32 * If they are the same, the function fails, and GetLastError returns
33 * ERROR_INVALID_PARAMETER."
34 */
35 #define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar) \
36 ASSERT((ULONG_PTR)dChar != (ULONG_PTR)sWChar); \
37 WideCharToMultiByte((Console)->InputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL)
38
39 #define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar) \
40 ASSERT((ULONG_PTR)dWChar != (ULONG_PTR)sChar); \
41 MultiByteToWideChar((Console)->InputCodePage, 0, (sChar), 1, (dWChar), 1)
42
43 typedef struct ConsoleInput_t
44 {
45 LIST_ENTRY ListEntry;
46 INPUT_RECORD InputEvent;
47 } ConsoleInput;
48
49
50 /* PRIVATE FUNCTIONS **********************************************************/
51
52 #if 0
53
54 static VOID
55 ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
56 {
57 if (InputEvent->EventType == KEY_EVENT)
58 {
59 WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
60 InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
61 ConsoleInputUnicodeCharToAnsiChar(Console,
62 &InputEvent->Event.KeyEvent.uChar.AsciiChar,
63 &UnicodeChar);
64 }
65 }
66
67 static VOID
68 ConioInputEventToUnicode(PCONSOLE Console, PINPUT_RECORD InputEvent)
69 {
70 if (InputEvent->EventType == KEY_EVENT)
71 {
72 CHAR AsciiChar = InputEvent->Event.KeyEvent.uChar.AsciiChar;
73 InputEvent->Event.KeyEvent.uChar.AsciiChar = 0;
74 ConsoleInputAnsiCharToUnicodeChar(Console,
75 &InputEvent->Event.KeyEvent.uChar.UnicodeChar,
76 &AsciiChar);
77 }
78 }
79
80 #endif
81
82 /********** HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ************/
83
84
85
86
87
88
89
90
91 /* CONSRV TERMINAL FRONTENDS INTERFACE ****************************************/
92
93 /***************/
94 #ifdef TUITERM_COMPILE
95 NTSTATUS NTAPI
96 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
97 IN OUT PCONSOLE_INFO ConsoleInfo,
98 IN OUT PVOID ExtraConsoleInfo,
99 IN ULONG ProcessId);
100 NTSTATUS NTAPI
101 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
102 #endif
103
104 NTSTATUS NTAPI
105 GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
106 IN OUT PCONSOLE_INFO ConsoleInfo,
107 IN OUT PVOID ExtraConsoleInfo,
108 IN ULONG ProcessId);
109 NTSTATUS NTAPI
110 GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
111 /***************/
112
113 typedef
114 NTSTATUS (NTAPI *FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd,
115 IN OUT PCONSOLE_INFO ConsoleInfo,
116 IN OUT PVOID ExtraConsoleInfo,
117 IN ULONG ProcessId);
118
119 typedef
120 NTSTATUS (NTAPI *FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd);
121
122 /*
123 * If we are not in GUI-mode, start the text-mode terminal emulator.
124 * If we fail, try to start the GUI-mode terminal emulator.
125 *
126 * Try to open the GUI-mode terminal emulator. Two cases are possible:
127 * - We are in GUI-mode, therefore GuiMode == TRUE, the previous test-case
128 * failed and we start GUI-mode terminal emulator.
129 * - We are in text-mode, therefore GuiMode == FALSE, the previous test-case
130 * succeeded BUT we failed at starting text-mode terminal emulator.
131 * Then GuiMode was switched to TRUE in order to try to open the GUI-mode
132 * terminal emulator (Win32k will automatically switch to graphical mode,
133 * therefore no additional code is needed).
134 */
135
136 /*
137 * NOTE: Each entry of the table should be retrieved when loading a front-end
138 * (examples of the CSR servers which register some data for CSRSS).
139 */
140 struct
141 {
142 CHAR FrontEndName[80];
143 FRONTEND_LOAD FrontEndLoad;
144 FRONTEND_UNLOAD FrontEndUnload;
145 } FrontEndLoadingMethods[] =
146 {
147 #ifdef TUITERM_COMPILE
148 {"TUI", TuiLoadFrontEnd, TuiUnloadFrontEnd},
149 #endif
150 {"GUI", GuiLoadFrontEnd, GuiUnloadFrontEnd},
151
152 // {"Not found", 0, NULL}
153 };
154
155 static NTSTATUS
156 ConSrvLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
157 IN OUT PCONSOLE_INFO ConsoleInfo,
158 IN OUT PVOID ExtraConsoleInfo,
159 IN ULONG ProcessId)
160 {
161 NTSTATUS Status = STATUS_SUCCESS;
162 ULONG i;
163
164 /*
165 * Choose an adequate terminal front-end to load, and load it
166 */
167 for (i = 0; i < sizeof(FrontEndLoadingMethods) / sizeof(FrontEndLoadingMethods[0]); ++i)
168 {
169 DPRINT("CONSRV: Trying to load %s frontend...\n",
170 FrontEndLoadingMethods[i].FrontEndName);
171 Status = FrontEndLoadingMethods[i].FrontEndLoad(FrontEnd,
172 ConsoleInfo,
173 ExtraConsoleInfo,
174 ProcessId);
175 if (NT_SUCCESS(Status))
176 {
177 /* Save the unload callback */
178 FrontEnd->UnloadFrontEnd = FrontEndLoadingMethods[i].FrontEndUnload;
179
180 DPRINT("CONSRV: %s frontend loaded successfully\n",
181 FrontEndLoadingMethods[i].FrontEndName);
182 break;
183 }
184 else
185 {
186 DPRINT1("CONSRV: Loading %s frontend failed, Status = 0x%08lx , continuing...\n",
187 FrontEndLoadingMethods[i].FrontEndName, Status);
188 }
189 }
190
191 return Status;
192 }
193
194 static NTSTATUS
195 ConSrvUnloadFrontEnd(IN PFRONTEND FrontEnd)
196 {
197 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
198 // return FrontEnd->Vtbl->UnloadFrontEnd(FrontEnd);
199 return FrontEnd->UnloadFrontEnd(FrontEnd);
200 }
201
202 // See after...
203 static TERMINAL_VTBL ConSrvTermVtbl;
204
205 NTSTATUS NTAPI
206 ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
207 IN OUT PCONSOLE_INFO ConsoleInfo,
208 IN OUT PVOID ExtraConsoleInfo,
209 IN ULONG ProcessId)
210 {
211 NTSTATUS Status;
212 PFRONTEND FrontEnd;
213
214 /* Load a suitable frontend for the ConSrv terminal */
215 FrontEnd = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*FrontEnd));
216 if (!FrontEnd) return STATUS_NO_MEMORY;
217
218 Status = ConSrvLoadFrontEnd(FrontEnd,
219 ConsoleInfo,
220 ExtraConsoleInfo,
221 ProcessId);
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT1("CONSRV: Failed to initialize a frontend, Status = 0x%08lx\n", Status);
225 ConsoleFreeHeap(FrontEnd);
226 return Status;
227 }
228 DPRINT("CONSRV: Frontend initialized\n");
229
230 /* Initialize the ConSrv terminal */
231 Terminal->Vtbl = &ConSrvTermVtbl;
232 // Terminal->Console will be initialized by ConDrvRegisterTerminal
233 Terminal->Data = FrontEnd; /* We store the frontend pointer in the terminal private data */
234
235 return STATUS_SUCCESS;
236 }
237
238 NTSTATUS NTAPI
239 ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal)
240 {
241 NTSTATUS Status = STATUS_SUCCESS;
242 PFRONTEND FrontEnd = Terminal->Data;
243
244 /* Reset the ConSrv terminal */
245 Terminal->Data = NULL;
246 Terminal->Vtbl = NULL;
247
248 /* Unload the frontend */
249 if (FrontEnd != NULL)
250 {
251 Status = ConSrvUnloadFrontEnd(FrontEnd);
252 ConsoleFreeHeap(FrontEnd);
253 }
254
255 return Status;
256 }
257
258
259 /* CONSRV TERMINAL INTERFACE **************************************************/
260
261 static NTSTATUS NTAPI
262 ConSrvTermInitTerminal(IN OUT PTERMINAL This,
263 IN PCONSOLE Console)
264 {
265 NTSTATUS Status;
266 PFRONTEND FrontEnd = This->Data;
267
268 /* Initialize the console pointer for our frontend */
269 FrontEnd->Console = Console;
270
271 /** HACK HACK!! Copy FrontEnd into the console!! **/
272 DPRINT1("Using FrontEndIFace HACK(1), should be removed after proper implementation!\n");
273 Console->FrontEndIFace = *FrontEnd;
274
275 Status = FrontEnd->Vtbl->InitFrontEnd(FrontEnd, FrontEnd->Console);
276
277 /** HACK HACK!! Be sure FrontEndIFace is correctly updated in the console!! **/
278 DPRINT1("Using FrontEndIFace HACK(2), should be removed after proper implementation!\n");
279 Console->FrontEndIFace = *FrontEnd;
280
281 return Status;
282 }
283
284 static VOID NTAPI
285 ConSrvTermDeinitTerminal(IN OUT PTERMINAL This)
286 {
287 PFRONTEND FrontEnd = This->Data;
288 FrontEnd->Vtbl->DeinitFrontEnd(FrontEnd);
289 }
290
291 static VOID NTAPI
292 ConSrvTermDrawRegion(IN OUT PTERMINAL This,
293 SMALL_RECT* Region)
294 {
295 PFRONTEND FrontEnd = This->Data;
296 FrontEnd->Vtbl->DrawRegion(FrontEnd, Region);
297 }
298
299
300
301 /************ Line discipline ***************/
302
303 static NTSTATUS NTAPI
304 ConSrvTermReadStream(IN OUT PTERMINAL This,
305 /**/IN PUNICODE_STRING ExeName /**/OPTIONAL/**/,/**/
306 IN BOOLEAN Unicode,
307 /**PWCHAR Buffer,**/
308 OUT PVOID Buffer,
309 IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
310 IN ULONG NumCharsToRead,
311 OUT PULONG NumCharsRead OPTIONAL)
312 {
313 PFRONTEND FrontEnd = This->Data;
314 PCONSRV_CONSOLE Console = FrontEnd->Console;
315 PCONSOLE_INPUT_BUFFER InputBuffer = &Console->InputBuffer;
316
317 // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
318 NTSTATUS Status = STATUS_PENDING;
319
320 PLIST_ENTRY CurrentEntry;
321 ConsoleInput *Input;
322 ULONG i;
323
324 /* Validity checks */
325 // ASSERT(Console == InputBuffer->Header.Console);
326 ASSERT((Buffer != NULL) || (Buffer == NULL && NumCharsToRead == 0));
327
328 /* We haven't read anything (yet) */
329 i = ReadControl->nInitialChars;
330
331 if (InputBuffer->Mode & ENABLE_LINE_INPUT)
332 {
333 /* COOKED mode, call the line discipline */
334
335 if (Console->LineBuffer == NULL)
336 {
337 /* Starting a new line */
338 Console->LineMaxSize = max(256, NumCharsToRead);
339
340 Console->LineBuffer = ConsoleAllocHeap(0, Console->LineMaxSize * sizeof(WCHAR));
341 if (Console->LineBuffer == NULL) return STATUS_NO_MEMORY;
342
343 Console->LinePos = Console->LineSize = ReadControl->nInitialChars;
344 Console->LineComplete = Console->LineUpPressed = FALSE;
345 Console->LineInsertToggle = Console->InsertMode;
346 Console->LineWakeupMask = ReadControl->dwCtrlWakeupMask;
347
348 /*
349 * Pre-filling the buffer is only allowed in the Unicode API,
350 * so we don't need to worry about ANSI <-> Unicode conversion.
351 */
352 memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
353 if (Console->LineSize == Console->LineMaxSize)
354 {
355 Console->LineComplete = TRUE;
356 Console->LinePos = 0;
357 }
358 }
359
360 /* If we don't have a complete line yet, process the pending input */
361 while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents))
362 {
363 /* Remove input event from queue */
364 CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
365 if (IsListEmpty(&InputBuffer->InputEvents))
366 {
367 ResetEvent(InputBuffer->ActiveEvent);
368 }
369 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
370
371 /* Only pay attention to key down */
372 if (Input->InputEvent.EventType == KEY_EVENT &&
373 Input->InputEvent.Event.KeyEvent.bKeyDown)
374 {
375 LineInputKeyDown(Console, ExeName,
376 &Input->InputEvent.Event.KeyEvent);
377 ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
378 }
379 ConsoleFreeHeap(Input);
380 }
381
382 /* Check if we have a complete line to read from */
383 if (Console->LineComplete)
384 {
385 while (i < NumCharsToRead && Console->LinePos != Console->LineSize)
386 {
387 WCHAR Char = Console->LineBuffer[Console->LinePos++];
388
389 if (Unicode)
390 {
391 ((PWCHAR)Buffer)[i] = Char;
392 }
393 else
394 {
395 ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
396 }
397 ++i;
398 }
399
400 if (Console->LinePos == Console->LineSize)
401 {
402 /* Entire line has been read */
403 ConsoleFreeHeap(Console->LineBuffer);
404 Console->LineBuffer = NULL;
405 }
406
407 Status = STATUS_SUCCESS;
408 }
409 }
410 else
411 {
412 /* RAW mode */
413
414 /* Character input */
415 while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents))
416 {
417 /* Remove input event from queue */
418 CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
419 if (IsListEmpty(&InputBuffer->InputEvents))
420 {
421 ResetEvent(InputBuffer->ActiveEvent);
422 }
423 Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
424
425 /* Only pay attention to valid characters, on key down */
426 if (Input->InputEvent.EventType == KEY_EVENT &&
427 Input->InputEvent.Event.KeyEvent.bKeyDown &&
428 Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
429 {
430 WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
431
432 if (Unicode)
433 {
434 ((PWCHAR)Buffer)[i] = Char;
435 }
436 else
437 {
438 ConsoleInputUnicodeCharToAnsiChar(Console, &((PCHAR)Buffer)[i], &Char);
439 }
440 ++i;
441
442 /* Did read something */
443 Status = STATUS_SUCCESS;
444 }
445 ConsoleFreeHeap(Input);
446 }
447 }
448
449 // FIXME: Only set if Status == STATUS_SUCCESS ???
450 if (NumCharsRead) *NumCharsRead = i;
451
452 return Status;
453 }
454
455
456
457
458 /* GLOBALS ********************************************************************/
459
460 #define TAB_WIDTH 8
461
462 // See condrv/text.c
463 /*static*/ VOID
464 ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff);
465
466 static VOID
467 ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, PSMALL_RECT UpdateRect, PUINT ScrolledLines)
468 {
469 /* If we hit bottom, slide the viewable screen */
470 if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y)
471 {
472 Buff->CursorPosition.Y--;
473 if (++Buff->VirtualY == Buff->ScreenBufferSize.Y)
474 {
475 Buff->VirtualY = 0;
476 }
477 (*ScrolledLines)++;
478 ClearLineBuffer(Buff);
479 if (UpdateRect->Top != 0)
480 {
481 UpdateRect->Top--;
482 }
483 }
484 UpdateRect->Left = 0;
485 UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
486 UpdateRect->Bottom = Buff->CursorPosition.Y;
487 }
488
489 static NTSTATUS
490 ConioWriteConsole(PFRONTEND FrontEnd,
491 PTEXTMODE_SCREEN_BUFFER Buff,
492 PWCHAR Buffer,
493 DWORD Length,
494 BOOL Attrib)
495 {
496 PCONSRV_CONSOLE Console = FrontEnd->Console;
497
498 UINT i;
499 PCHAR_INFO Ptr;
500 SMALL_RECT UpdateRect;
501 SHORT CursorStartX, CursorStartY;
502 UINT ScrolledLines;
503
504 CursorStartX = Buff->CursorPosition.X;
505 CursorStartY = Buff->CursorPosition.Y;
506 UpdateRect.Left = Buff->ScreenBufferSize.X;
507 UpdateRect.Top = Buff->CursorPosition.Y;
508 UpdateRect.Right = -1;
509 UpdateRect.Bottom = Buff->CursorPosition.Y;
510 ScrolledLines = 0;
511
512 for (i = 0; i < Length; i++)
513 {
514 /*
515 * If we are in processed mode, interpret special characters and
516 * display them correctly. Otherwise, just put them into the buffer.
517 */
518 if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
519 {
520 /* --- CR --- */
521 if (Buffer[i] == L'\r')
522 {
523 Buff->CursorPosition.X = 0;
524 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
525 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
526 continue;
527 }
528 /* --- LF --- */
529 else if (Buffer[i] == L'\n')
530 {
531 Buff->CursorPosition.X = 0;
532 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
533 continue;
534 }
535 /* --- BS --- */
536 else if (Buffer[i] == L'\b')
537 {
538 /* Only handle BS if we're not on the first pos of the first line */
539 if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y)
540 {
541 if (0 == Buff->CursorPosition.X)
542 {
543 /* slide virtual position up */
544 Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
545 Buff->CursorPosition.Y--;
546 UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
547 }
548 else
549 {
550 Buff->CursorPosition.X--;
551 }
552 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
553 Ptr->Char.UnicodeChar = L' ';
554 Ptr->Attributes = Buff->ScreenDefaultAttrib;
555 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
556 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
557 }
558 continue;
559 }
560 /* --- TAB --- */
561 else if (Buffer[i] == L'\t')
562 {
563 UINT EndX;
564
565 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
566 EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1);
567 EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X);
568 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
569 while (Buff->CursorPosition.X < EndX)
570 {
571 Ptr->Char.UnicodeChar = L' ';
572 Ptr->Attributes = Buff->ScreenDefaultAttrib;
573 ++Ptr;
574 Buff->CursorPosition.X++;
575 }
576 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1);
577 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
578 {
579 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
580 {
581 Buff->CursorPosition.X = 0;
582 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
583 }
584 else
585 {
586 Buff->CursorPosition.X--;
587 }
588 }
589 continue;
590 }
591 // /* --- BEL ---*/
592 // else if (Buffer[i] == L'\a')
593 // {
594 // // FIXME: This MUST BE moved to the terminal emulator frontend!!
595 // DPRINT1("Bell\n");
596 // // SendNotifyMessage(Console->hWindow, PM_CONSOLE_BEEP, 0, 0);
597 // continue;
598 // }
599 }
600 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
601 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
602
603 Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
604 Ptr->Char.UnicodeChar = Buffer[i];
605 if (Attrib) Ptr->Attributes = Buff->ScreenDefaultAttrib;
606
607 Buff->CursorPosition.X++;
608 if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
609 {
610 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
611 {
612 Buff->CursorPosition.X = 0;
613 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
614 }
615 else
616 {
617 Buff->CursorPosition.X = CursorStartX;
618 }
619 }
620 }
621
622 if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer)
623 {
624 // TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
625 // ScrolledLines, Buffer, Length);
626 FrontEnd->Vtbl->WriteStream(FrontEnd,
627 &UpdateRect,
628 CursorStartX,
629 CursorStartY,
630 ScrolledLines,
631 Buffer,
632 Length);
633 }
634
635 return STATUS_SUCCESS;
636 }
637
638
639
640 static NTSTATUS NTAPI
641 ConSrvTermWriteStream(IN OUT PTERMINAL This,
642 PTEXTMODE_SCREEN_BUFFER Buff,
643 PWCHAR Buffer,
644 DWORD Length,
645 BOOL Attrib)
646 {
647 PFRONTEND FrontEnd = This->Data;
648 return ConioWriteConsole(FrontEnd,
649 Buff,
650 Buffer,
651 Length,
652 Attrib);
653 }
654
655 /************ Line discipline ***************/
656
657
658
659 static BOOL NTAPI
660 ConSrvTermSetCursorInfo(IN OUT PTERMINAL This,
661 PCONSOLE_SCREEN_BUFFER ScreenBuffer)
662 {
663 PFRONTEND FrontEnd = This->Data;
664 return FrontEnd->Vtbl->SetCursorInfo(FrontEnd, ScreenBuffer);
665 }
666
667 static BOOL NTAPI
668 ConSrvTermSetScreenInfo(IN OUT PTERMINAL This,
669 PCONSOLE_SCREEN_BUFFER ScreenBuffer,
670 SHORT OldCursorX,
671 SHORT OldCursorY)
672 {
673 PFRONTEND FrontEnd = This->Data;
674 return FrontEnd->Vtbl->SetScreenInfo(FrontEnd,
675 ScreenBuffer,
676 OldCursorX,
677 OldCursorY);
678 }
679
680 static VOID NTAPI
681 ConSrvTermResizeTerminal(IN OUT PTERMINAL This)
682 {
683 PFRONTEND FrontEnd = This->Data;
684 FrontEnd->Vtbl->ResizeTerminal(FrontEnd);
685 }
686
687 static VOID NTAPI
688 ConSrvTermSetActiveScreenBuffer(IN OUT PTERMINAL This)
689 {
690 PFRONTEND FrontEnd = This->Data;
691 FrontEnd->Vtbl->SetActiveScreenBuffer(FrontEnd);
692 }
693
694 static VOID NTAPI
695 ConSrvTermReleaseScreenBuffer(IN OUT PTERMINAL This,
696 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
697 {
698 PFRONTEND FrontEnd = This->Data;
699 FrontEnd->Vtbl->ReleaseScreenBuffer(FrontEnd, ScreenBuffer);
700 }
701
702 static VOID NTAPI
703 ConSrvTermChangeTitle(IN OUT PTERMINAL This)
704 {
705 PFRONTEND FrontEnd = This->Data;
706 FrontEnd->Vtbl->ChangeTitle(FrontEnd);
707 }
708
709 static VOID NTAPI
710 ConSrvTermGetLargestConsoleWindowSize(IN OUT PTERMINAL This,
711 PCOORD pSize)
712 {
713 PFRONTEND FrontEnd = This->Data;
714 FrontEnd->Vtbl->GetLargestConsoleWindowSize(FrontEnd, pSize);
715 }
716
717 /*
718 static BOOL NTAPI
719 ConSrvTermGetSelectionInfo(IN OUT PTERMINAL This,
720 PCONSOLE_SELECTION_INFO pSelectionInfo)
721 {
722 PFRONTEND FrontEnd = This->Data;
723 return FrontEnd->Vtbl->GetSelectionInfo(FrontEnd, pSelectionInfo);
724 }
725 */
726
727 static BOOL NTAPI
728 ConSrvTermSetPalette(IN OUT PTERMINAL This,
729 HPALETTE PaletteHandle,
730 UINT PaletteUsage)
731 {
732 PFRONTEND FrontEnd = This->Data;
733 return FrontEnd->Vtbl->SetPalette(FrontEnd, PaletteHandle, PaletteUsage);
734 }
735
736 static INT NTAPI
737 ConSrvTermShowMouseCursor(IN OUT PTERMINAL This,
738 BOOL Show)
739 {
740 PFRONTEND FrontEnd = This->Data;
741 return FrontEnd->Vtbl->ShowMouseCursor(FrontEnd, Show);
742 }
743
744 static TERMINAL_VTBL ConSrvTermVtbl =
745 {
746 ConSrvTermInitTerminal,
747 ConSrvTermDeinitTerminal,
748 ConSrvTermDrawRegion,
749
750 ConSrvTermReadStream,
751 ConSrvTermWriteStream,
752
753 ConSrvTermSetCursorInfo,
754 ConSrvTermSetScreenInfo,
755 ConSrvTermResizeTerminal,
756 ConSrvTermSetActiveScreenBuffer,
757 ConSrvTermReleaseScreenBuffer,
758 ConSrvTermChangeTitle,
759 ConSrvTermGetLargestConsoleWindowSize,
760 // ConSrvTermGetSelectionInfo,
761 ConSrvTermSetPalette,
762 ConSrvTermShowMouseCursor,
763 };
764
765 #if 0
766 VOID
767 ResetFrontEnd(IN PCONSOLE Console)
768 {
769 if (!Console) return;
770
771 /* Reinitialize the frontend interface */
772 RtlZeroMemory(&Console->FrontEndIFace, sizeof(Console->FrontEndIFace));
773 Console->FrontEndIFace.Vtbl = &ConSrvTermVtbl;
774 }
775 #endif
776
777 /* EOF */