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