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