ReactOS  0.4.15-dev-994-ga9f6032
terminal.c
Go to the documentation of this file.
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
54 {
55  if (InputEvent->EventType == KEY_EVENT)
56  {
57  WCHAR UnicodeChar = InputEvent->Event.KeyEvent.uChar.UnicodeChar;
58  InputEvent->Event.KeyEvent.uChar.UnicodeChar = 0;
60  &InputEvent->Event.KeyEvent.uChar.AsciiChar,
61  &UnicodeChar);
62  }
63 }
64 
65 static VOID
67 {
68  if (InputEvent->EventType == KEY_EVENT)
69  {
70  CHAR AsciiChar = InputEvent->Event.KeyEvent.uChar.AsciiChar;
71  InputEvent->Event.KeyEvent.uChar.AsciiChar = 0;
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
94 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
96  IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
97  IN HANDLE ConsoleLeaderProcessHandle);
99 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd);
100 #endif
101 
105  IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
106  IN HANDLE ConsoleLeaderProcessHandle);
109 /***************/
110 
111 typedef
114  IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
115  IN HANDLE ConsoleLeaderProcessHandle);
116 
117 typedef
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 {
144 {
145 #ifdef TUITERM_COMPILE
146  {"TUI", TuiLoadFrontEnd, TuiUnloadFrontEnd},
147 #endif
149 
150 // {"Not found", 0, NULL}
151 };
152 
153 static NTSTATUS
156  IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
157  IN HANDLE ConsoleLeaderProcessHandle)
158 {
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",
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",
180  break;
181  }
182  else
183  {
184  DPRINT1("CONSRV: Loading %s frontend failed, Status = 0x%08lx , continuing...\n",
186  }
187  }
188 
189  return Status;
190 }
191 
192 static NTSTATUS
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...
202 
206  IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
207  IN HANDLE ConsoleLeaderProcessHandle)
208 {
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 
238 {
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
262 {
264  PFRONTEND FrontEnd = This->Context;
265  PCONSRV_CONSOLE ConSrvConsole = (PCONSRV_CONSOLE)Console;
266 
267  /* Initialize the console pointer for our frontend */
268  FrontEnd->Console = ConSrvConsole;
269 
271  DPRINT("Using FrontEndIFace HACK(1), should be removed after proper implementation!\n");
272  ConSrvConsole->FrontEndIFace = *FrontEnd;
273 
274  Status = FrontEnd->Vtbl->InitFrontEnd(FrontEnd, ConSrvConsole);
275  if (!NT_SUCCESS(Status))
276  DPRINT1("InitFrontEnd failed, Status = 0x%08lx\n", Status);
277 
279  DPRINT("Using FrontEndIFace HACK(2), should be removed after proper implementation!\n");
280  ConSrvConsole->FrontEndIFace = *FrontEnd;
281 
282  return Status;
283 }
284 
285 static VOID NTAPI
287 {
288  PFRONTEND FrontEnd = This->Context;
289  FrontEnd->Vtbl->DeinitFrontEnd(FrontEnd);
290 }
291 
292 
293 
294 /************ Line discipline ***************/
295 
296 static NTSTATUS NTAPI
298  IN BOOLEAN Unicode,
300  OUT PVOID Buffer,
301  IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl,
303  IN ULONG NumCharsToRead,
304  OUT PULONG NumCharsRead OPTIONAL)
305 {
306  PFRONTEND FrontEnd = This->Context;
307  PCONSRV_CONSOLE Console = FrontEnd->Console;
308  PCONSOLE_INPUT_BUFFER InputBuffer = &Console->InputBuffer;
309  PUNICODE_STRING ExeName = Parameter;
310 
311  // STATUS_PENDING : Wait if more to read ; STATUS_SUCCESS : Don't wait.
313 
314  PLIST_ENTRY CurrentEntry;
316  ULONG i = 0;
317 
318  /* Validity checks */
319  // ASSERT(Console == InputBuffer->Header.Console);
320  ASSERT((Buffer != NULL) || (Buffer == NULL && NumCharsToRead == 0));
321 
322  /* We haven't read anything (yet) */
323 
324  if (InputBuffer->Mode & ENABLE_LINE_INPUT)
325  {
326  /* COOKED mode, call the line discipline */
327 
328  if (Console->LineBuffer == NULL)
329  {
330  /* Start a new line */
331  Console->LineMaxSize = max(256, NumCharsToRead);
332 
333  /*
334  * Fixup ReadControl->nInitialChars in case the number of initial
335  * characters is bigger than the number of characters to be read.
336  * It will always be, lesser than or equal to Console->LineMaxSize.
337  */
338  ReadControl->nInitialChars = min(ReadControl->nInitialChars, 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-fill the buffer with the nInitialChars from the user buffer.
350  * Since pre-filling is only allowed in Unicode, we don't need to
351  * worry about ANSI <-> Unicode conversion.
352  */
353  memcpy(Console->LineBuffer, Buffer, Console->LineSize * sizeof(WCHAR));
354  if (Console->LineSize >= Console->LineMaxSize)
355  {
356  Console->LineComplete = TRUE;
357  Console->LinePos = 0;
358  }
359  }
360 
361  /* If we don't have a complete line yet, process the pending input */
362  while (!Console->LineComplete && !IsListEmpty(&InputBuffer->InputEvents))
363  {
364  /* Remove an input event from the queue */
365  _InterlockedDecrement((PLONG)&InputBuffer->NumberOfEvents);
366  CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
367  if (IsListEmpty(&InputBuffer->InputEvents))
368  {
369  NtClearEvent(InputBuffer->ActiveEvent);
370  }
371  Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
372 
373  /* Only pay attention to key down */
374  if (Input->InputEvent.EventType == KEY_EVENT &&
375  Input->InputEvent.Event.KeyEvent.bKeyDown)
376  {
377  LineInputKeyDown(Console, ExeName,
378  &Input->InputEvent.Event.KeyEvent);
379  ReadControl->dwControlKeyState = Input->InputEvent.Event.KeyEvent.dwControlKeyState;
380  }
382  }
383 
384  /* Check if we have a complete line to read from */
385  if (Console->LineComplete)
386  {
387  /*
388  * Console->LinePos keeps the next position of the character to read
389  * in the line buffer across the different calls of the function,
390  * so that the line buffer can be read by chunks after all the input
391  * has been buffered.
392  */
393 
394  while (i < NumCharsToRead && Console->LinePos < Console->LineSize)
395  {
396  WCHAR Char = Console->LineBuffer[Console->LinePos++];
397 
398  if (Unicode)
399  {
400  ((PWCHAR)Buffer)[i] = Char;
401  }
402  else
403  {
405  }
406  ++i;
407  }
408 
409  if (Console->LinePos >= Console->LineSize)
410  {
411  /* The entire line has been read */
412  ConsoleFreeHeap(Console->LineBuffer);
413  Console->LineBuffer = NULL;
414  Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
415  // Console->LineComplete = Console->LineUpPressed = FALSE;
416  Console->LineComplete = FALSE;
417  }
418 
420  }
421  }
422  else
423  {
424  /* RAW mode */
425 
426  /* Character input */
427  while (i < NumCharsToRead && !IsListEmpty(&InputBuffer->InputEvents))
428  {
429  /* Remove an input event from the queue */
430  _InterlockedDecrement((PLONG)&InputBuffer->NumberOfEvents);
431  CurrentEntry = RemoveHeadList(&InputBuffer->InputEvents);
432  if (IsListEmpty(&InputBuffer->InputEvents))
433  {
434  NtClearEvent(InputBuffer->ActiveEvent);
435  }
436  Input = CONTAINING_RECORD(CurrentEntry, ConsoleInput, ListEntry);
437 
438  /* Only pay attention to valid characters, on key down */
439  if (Input->InputEvent.EventType == KEY_EVENT &&
440  Input->InputEvent.Event.KeyEvent.bKeyDown &&
441  Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar != L'\0')
442  {
443  WCHAR Char = Input->InputEvent.Event.KeyEvent.uChar.UnicodeChar;
444 
445  if (Unicode)
446  {
447  ((PWCHAR)Buffer)[i] = Char;
448  }
449  else
450  {
452  }
453  ++i;
454 
455  /* Did read something */
457  }
459  }
460  }
461 
462  // FIXME: Only set if Status == STATUS_SUCCESS ???
463  if (NumCharsRead) *NumCharsRead = i;
464 
465  return Status;
466 }
467 
468 
469 
470 
471 /* GLOBALS ********************************************************************/
472 
473 #define TAB_WIDTH 8
474 
475 // See condrv/text.c
476 /*static*/ VOID
478 
479 static VOID
481 {
482  /* If we hit bottom, slide the viewable screen */
483  if (++Buff->CursorPosition.Y == Buff->ScreenBufferSize.Y)
484  {
485  Buff->CursorPosition.Y--;
486  if (++Buff->VirtualY == Buff->ScreenBufferSize.Y)
487  {
488  Buff->VirtualY = 0;
489  }
490  (*ScrolledLines)++;
491  ClearLineBuffer(Buff);
492  if (UpdateRect->Top != 0)
493  {
494  UpdateRect->Top--;
495  }
496  }
497  UpdateRect->Left = 0;
498  UpdateRect->Right = Buff->ScreenBufferSize.X - 1;
499  UpdateRect->Bottom = Buff->CursorPosition.Y;
500 }
501 
502 static NTSTATUS
505  PWCHAR Buffer,
506  DWORD Length,
507  BOOL Attrib)
508 {
509  PCONSRV_CONSOLE Console = FrontEnd->Console;
510 
511  UINT i;
512  PCHAR_INFO Ptr;
514  SHORT CursorStartX, CursorStartY;
515  UINT ScrolledLines;
516  BOOLEAN bFullwidth;
517  BOOLEAN bCJK = Console->IsCJK;
518 
519  /* If nothing to write, bail out now */
520  if (Length == 0)
521  return STATUS_SUCCESS;
522 
523  CursorStartX = Buff->CursorPosition.X;
524  CursorStartY = Buff->CursorPosition.Y;
525  UpdateRect.Left = Buff->ScreenBufferSize.X;
526  UpdateRect.Top = Buff->CursorPosition.Y;
527  UpdateRect.Right = -1;
528  UpdateRect.Bottom = Buff->CursorPosition.Y;
529  ScrolledLines = 0;
530 
531  for (i = 0; i < Length; i++)
532  {
533  /*
534  * If we are in processed mode, interpret special characters and
535  * display them correctly. Otherwise, just put them into the buffer.
536  */
537  if (Buff->Mode & ENABLE_PROCESSED_OUTPUT)
538  {
539  /* --- CR --- */
540  if (Buffer[i] == L'\r')
541  {
542  Buff->CursorPosition.X = 0;
543  CursorStartX = Buff->CursorPosition.X;
544  UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
545  UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
546  continue;
547  }
548  /* --- LF --- */
549  else if (Buffer[i] == L'\n')
550  {
551  Buff->CursorPosition.X = 0; // TODO: Make this behaviour optional!
552  CursorStartX = Buff->CursorPosition.X;
553  ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
554  continue;
555  }
556  /* --- BS --- */
557  else if (Buffer[i] == L'\b')
558  {
559  /* Only handle BS if we are not on the first position of the first line */
560  if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
561  continue;
562 
563  if (Buff->CursorPosition.X == 0)
564  {
565  /* Slide virtual position up */
566  Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
567  Buff->CursorPosition.Y--;
568  // TODO? : Update CursorStartY = Buff->CursorPosition.Y;
569  UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
570  }
571  else
572  {
573  Buff->CursorPosition.X--;
574  }
575  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
576 
577  if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
578  {
579  /*
580  * The cursor just moved on the leading byte of the same
581  * current character. We should go one position before to
582  * go to the actual previous character to erase.
583  */
584 
585  /* Only handle BS if we are not on the first position of the first line */
586  if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
587  continue;
588 
589  if (Buff->CursorPosition.X == 0)
590  {
591  /* Slide virtual position up */
592  Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
593  Buff->CursorPosition.Y--;
594  // TODO? : Update CursorStartY = Buff->CursorPosition.Y;
595  UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
596  }
597  else
598  {
599  Buff->CursorPosition.X--;
600  }
601  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
602  }
603 
604  if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
605  {
606  /* The cursor is on the trailing byte of a full-width character */
607 
608  /* Delete its trailing byte... */
609  Ptr->Char.UnicodeChar = L' ';
610  if (Attrib)
611  Ptr->Attributes = Buff->ScreenDefaultAttrib;
612  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
613 
614  if (Buff->CursorPosition.X > 0)
615  Buff->CursorPosition.X--;
616  /* ... and now its leading byte */
617  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
618  }
619 
620  Ptr->Char.UnicodeChar = L' ';
621  if (Attrib)
622  Ptr->Attributes = Buff->ScreenDefaultAttrib;
623  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
624 
625  UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
626  UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
627  continue;
628  }
629  /* --- TAB --- */
630  else if (Buffer[i] == L'\t')
631  {
632  UINT EndX;
633 
634  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
635 
636  if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
637  {
638  /*
639  * The cursor is on the trailing byte of a full-width character.
640  * Go back one position to be on its leading byte.
641  */
642  if (Buff->CursorPosition.X > 0)
643  Buff->CursorPosition.X--;
644  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
645  }
646 
647  UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
648 
649  EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1);
650  EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X);
651 
652  while ((UINT)Buff->CursorPosition.X < EndX)
653  {
654  Ptr->Char.UnicodeChar = L' ';
655  if (Attrib)
656  Ptr->Attributes = Buff->ScreenDefaultAttrib;
657  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
658 
659  ++Ptr;
660  Buff->CursorPosition.X++;
661  }
662  if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
663  {
664  /* If the following cell is the trailing byte of a full-width character, reset it */
665  if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
666  {
667  Ptr->Char.UnicodeChar = L' ';
668  if (Attrib)
669  Ptr->Attributes = Buff->ScreenDefaultAttrib;
670  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
671  }
672  }
673  UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
674 
675  if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
676  {
677  if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
678  {
679  /* Wrapping mode: Go to next line */
680  Buff->CursorPosition.X = 0;
681  CursorStartX = Buff->CursorPosition.X;
682  ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
683  }
684  else
685  {
686  /* The cursor wraps back to its starting position on the same line */
687  Buff->CursorPosition.X = CursorStartX;
688  }
689  }
690  continue;
691  }
692  /* --- BEL ---*/
693  else if (Buffer[i] == L'\a')
694  {
695  FrontEnd->Vtbl->RingBell(FrontEnd);
696  continue;
697  }
698  }
699  UpdateRect.Left = min(UpdateRect.Left , Buff->CursorPosition.X);
700  UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
701 
702  /* For Chinese, Japanese and Korean */
703  bFullwidth = (bCJK && IS_FULL_WIDTH(Buffer[i]));
704 
705  /* Check whether we can insert the full-width character */
706  if (bFullwidth)
707  {
708  /* It spans two cells and should all fit on the current line */
709  if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
710  {
711  if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
712  {
713  /* Wrapping mode: Go to next line */
714  Buff->CursorPosition.X = 0;
715  CursorStartX = Buff->CursorPosition.X;
716  ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
717  }
718  else
719  {
720  /* The cursor wraps back to its starting position on the same line */
721  Buff->CursorPosition.X = CursorStartX;
722  }
723  }
724 
725  /*
726  * Now be sure we can fit the full-width character.
727  * If the screenbuffer is one cell wide we cannot display
728  * the full-width character, so just skip it.
729  */
730  if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
731  {
732  DPRINT1("Cannot display full-width character! CursorPosition.X = %d, ScreenBufferSize.X = %d\n",
733  Buff->CursorPosition.X, Buff->ScreenBufferSize.X);
734  continue;
735  }
736  }
737 
738  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
739 
740  /*
741  * Check whether we are overwriting part of a full-width character,
742  * in which case we need to invalidate it.
743  */
744  if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
745  {
746  /*
747  * The cursor is on the trailing byte of a full-width character.
748  * Go back one position to kill the previous leading byte.
749  */
750  if (Buff->CursorPosition.X > 0)
751  {
752  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X - 1, Buff->CursorPosition.Y);
753  Ptr->Char.UnicodeChar = L' ';
754  if (Attrib)
755  Ptr->Attributes = Buff->ScreenDefaultAttrib;
756  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
757  }
758  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
759  }
760 
761  /* Insert the character */
762  if (bFullwidth)
763  {
764  ASSERT(Buff->CursorPosition.X < Buff->ScreenBufferSize.X - 1);
765 
766  /* Set the leading byte */
767  Ptr->Char.UnicodeChar = Buffer[i];
768  if (Attrib)
769  Ptr->Attributes = Buff->ScreenDefaultAttrib;
770  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
771  Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
772 
773  /* Set the trailing byte */
774  Buff->CursorPosition.X++;
775  Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
776  // Ptr->Char.UnicodeChar = Buffer[i]; // L' ';
777  if (Attrib)
778  Ptr->Attributes = Buff->ScreenDefaultAttrib;
779  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
780  Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
781  }
782  else
783  {
784  Ptr->Char.UnicodeChar = Buffer[i];
785  if (Attrib)
786  Ptr->Attributes = Buff->ScreenDefaultAttrib;
787  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
788  }
789 
790  ++Ptr;
791  Buff->CursorPosition.X++;
792 
793  if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
794  {
795  /* If the following cell is the trailing byte of a full-width character, reset it */
796  if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
797  {
798  Ptr->Char.UnicodeChar = L' ';
799  if (Attrib)
800  Ptr->Attributes = Buff->ScreenDefaultAttrib;
801  Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
802  }
803  }
804 
805  if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
806  {
807  if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
808  {
809  /* Wrapping mode: Go to next line */
810  Buff->CursorPosition.X = 0;
811  CursorStartX = Buff->CursorPosition.X;
812  ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
813  }
814  else
815  {
816  /* The cursor wraps back to its starting position on the same line */
817  Buff->CursorPosition.X = CursorStartX;
818  }
819  }
820  }
821 
822  if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer)
823  {
824  // TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
825  // ScrolledLines, Buffer, Length);
826  FrontEnd->Vtbl->WriteStream(FrontEnd,
827  &UpdateRect,
828  CursorStartX,
829  CursorStartY,
830  ScrolledLines,
831  Buffer,
832  Length);
833  }
834 
835  return STATUS_SUCCESS;
836 }
837 
838 
839 
840 static NTSTATUS NTAPI
843  PWCHAR Buffer,
844  DWORD Length,
845  BOOL Attrib)
846 {
847  PFRONTEND FrontEnd = This->Context;
848  return ConioWriteConsole(FrontEnd,
849  Buff,
850  Buffer,
851  Length,
852  Attrib);
853 }
854 
855 /************ Line discipline ***************/
856 
857 
858 
859 VOID
861 {
863  PCONSOLE_SCREEN_BUFFER ActiveBuffer = Console->ActiveBuffer;
864 
865  if (!ActiveBuffer) return;
866 
867  ConioInitRect(&Region, 0, 0,
868  ActiveBuffer->ViewSize.Y - 1,
869  ActiveBuffer->ViewSize.X - 1);
871  // Console->FrontEndIFace.Vtbl->DrawRegion(&Console->FrontEndIFace, &Region);
872 }
873 
874 static VOID NTAPI
877 {
878  PFRONTEND FrontEnd = This->Context;
879  FrontEnd->Vtbl->DrawRegion(FrontEnd, Region);
880 }
881 
882 static BOOL NTAPI
885 {
886  PFRONTEND FrontEnd = This->Context;
887  return FrontEnd->Vtbl->SetCursorInfo(FrontEnd, ScreenBuffer);
888 }
889 
890 static BOOL NTAPI
893  SHORT OldCursorX,
894  SHORT OldCursorY)
895 {
896  PFRONTEND FrontEnd = This->Context;
897  return FrontEnd->Vtbl->SetScreenInfo(FrontEnd,
898  ScreenBuffer,
899  OldCursorX,
900  OldCursorY);
901 }
902 
903 static VOID NTAPI
905 {
906  PFRONTEND FrontEnd = This->Context;
907  FrontEnd->Vtbl->ResizeTerminal(FrontEnd);
908 }
909 
910 static VOID NTAPI
912 {
913  PFRONTEND FrontEnd = This->Context;
914  FrontEnd->Vtbl->SetActiveScreenBuffer(FrontEnd);
915 }
916 
917 static VOID NTAPI
920 {
921  PFRONTEND FrontEnd = This->Context;
922  FrontEnd->Vtbl->ReleaseScreenBuffer(FrontEnd, ScreenBuffer);
923 }
924 
925 static VOID NTAPI
927  PCOORD pSize)
928 {
929  PFRONTEND FrontEnd = This->Context;
930  FrontEnd->Vtbl->GetLargestConsoleWindowSize(FrontEnd, pSize);
931 }
932 
933 static BOOL NTAPI
935  HPALETTE PaletteHandle,
936  UINT PaletteUsage)
937 {
938  PFRONTEND FrontEnd = This->Context;
939  return FrontEnd->Vtbl->SetPalette(FrontEnd, PaletteHandle, PaletteUsage);
940 }
941 
942 static INT NTAPI
944  BOOL Show)
945 {
946  PFRONTEND FrontEnd = This->Context;
947  return FrontEnd->Vtbl->ShowMouseCursor(FrontEnd, Show);
948 }
949 
951 {
954 
957 
967 };
968 
969 #if 0
970 VOID
971 ResetFrontEnd(IN PCONSOLE Console)
972 {
973  PCONSRV_CONSOLE ConSrvConsole = (PCONSRV_CONSOLE)Console;
974  if (!Console) return;
975 
976  /* Reinitialize the frontend interface */
977  RtlZeroMemory(&ConSrvConsole->FrontEndIFace, sizeof(ConSrvConsole->FrontEndIFace));
978  ConSrvConsole->FrontEndIFace.Vtbl = &ConSrvTermVtbl;
979 }
980 #endif
981 
982 /* EOF */
signed char * PCHAR
Definition: retypes.h:7
#define IN
Definition: typedefs.h:39
#define max(a, b)
Definition: svc.c:63
VOID ClearLineBuffer(PTEXTMODE_SCREEN_BUFFER Buff)
Definition: text.c:151
WCHAR UnicodeChar
Definition: wincon.h:245
union _INPUT_RECORD::@3233 Event
#define TRUE
Definition: types.h:120
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
PCHAR_INFO ConioCoordToPointer(PTEXTMODE_SCREEN_BUFFER Buff, ULONG X, ULONG Y)
Definition: text.c:143
char CHAR
Definition: xmlstorage.h:175
_Must_inspect_result_ _In_ PFSRTL_PER_STREAM_CONTEXT Ptr
Definition: fsrtlfuncs.h:898
static struct @4261 FrontEndLoadingMethods[]
VOID ConioDrawConsole(PCONSRV_CONSOLE Console)
Definition: terminal.c:860
LONG NTSTATUS
Definition: precomp.h:26
#define COMMON_LVB_SBCSDBCS
Definition: wincon.h:56
#define ConsoleAllocHeap(Flags, Size)
Definition: heap.h:14
#define TermDrawRegion(Console, Region)
Definition: term.h:22
Definition: arc.h:84
static NTSTATUS NTAPI ConSrvTermWriteStream(IN OUT PTERMINAL This, PTEXTMODE_SCREEN_BUFFER Buff, PWCHAR Buffer, DWORD Length, BOOL Attrib)
Definition: terminal.c:841
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
static VOID ConioInputEventToUnicode(PCONSOLE Console, PINPUT_RECORD InputEvent)
Definition: coninput.c:74
uint16_t * PWCHAR
Definition: typedefs.h:56
static HPALETTE PaletteHandle
Definition: svga.c:215
_In_ PVOID Parameter
Definition: ldrtypes.h:241
VOID LineInputKeyDown(PCONSRV_CONSOLE Console, PUNICODE_STRING ExeName, KEY_EVENT_RECORD *KeyEvent)
Definition: lineinput.c:147
static NTSTATUS NTAPI ConSrvTermReadStream(IN OUT PTERMINAL This, IN BOOLEAN Unicode, OUT PVOID Buffer, IN OUT PCONSOLE_READCONSOLE_CONTROL ReadControl, IN PVOID Parameter OPTIONAL, IN ULONG NumCharsToRead, OUT PULONG NumCharsRead OPTIONAL)
Definition: terminal.c:297
int32_t INT
Definition: typedefs.h:58
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
NTSTATUS NTAPI ConSrvInitTerminal(IN OUT PTERMINAL Terminal, IN OUT PCONSOLE_STATE_INFO ConsoleInfo, IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, IN HANDLE ConsoleLeaderProcessHandle)
Definition: terminal.c:204
CHAR InputBuffer[80]
Definition: conmgr.c:33
FRONTEND FrontEndIFace
Definition: conio_winsrv.h:128
struct _CONSRV_CONSOLE * Console
Definition: conio_winsrv.h:101
static VOID NTAPI ConSrvTermResizeTerminal(IN OUT PTERMINAL This)
Definition: terminal.c:904
NTSTATUS NTAPI GuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
Definition: guiterm.c:1307
static NTSTATUS ConioWriteConsole(PFRONTEND FrontEnd, PTEXTMODE_SCREEN_BUFFER Buff, PWCHAR Buffer, DWORD Length, BOOL Attrib)
Definition: terminal.c:503
static VOID ConioInputEventToAnsi(PCONSOLE Console, PINPUT_RECORD InputEvent)
Definition: coninput.c:61
NTSTATUS NTAPI GuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd, IN OUT PCONSOLE_STATE_INFO ConsoleInfo, IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, IN HANDLE ConsoleLeaderProcessHandle)
Definition: guiterm.c:1177
NTSTATUS(NTAPI * FRONTEND_LOAD)(IN OUT PFRONTEND FrontEnd, IN OUT PCONSOLE_STATE_INFO ConsoleInfo, IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, IN HANDLE ConsoleLeaderProcessHandle)
Definition: terminal.c:112
static BOOL NTAPI ConSrvTermSetPalette(IN OUT PTERMINAL This, HPALETTE PaletteHandle, UINT PaletteUsage)
Definition: terminal.c:934
#define ENABLE_WRAP_AT_EOL_OUTPUT
Definition: blue.h:54
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
static NTSTATUS ConSrvUnloadFrontEnd(IN PFRONTEND FrontEnd)
Definition: terminal.c:193
unsigned int BOOL
Definition: ntddk_ex.h:94
short SHORT
Definition: pedump.c:59
#define KEY_EVENT
Definition: wincon.h:128
static VOID NTAPI ConSrvTermGetLargestConsoleWindowSize(IN OUT PTERMINAL This, PCOORD pSize)
Definition: terminal.c:926
unsigned char BOOLEAN
long __cdecl _InterlockedDecrement(_Interlocked_operand_ long volatile *_Addend)
smooth NULL
Definition: ftsmooth.c:416
PVOID Context
Definition: conio_winsrv.h:102
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
void DPRINT(...)
Definition: polytest.cpp:61
Definition: bufpool.h:45
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
ULONG X
Definition: bl.h:1340
static BOOL NTAPI ConSrvTermSetCursorInfo(IN OUT PTERMINAL This, PCONSOLE_SCREEN_BUFFER ScreenBuffer)
Definition: terminal.c:883
#define TAB_WIDTH
Definition: terminal.c:473
NTSTATUS(NTAPI * FRONTEND_UNLOAD)(IN OUT PFRONTEND FrontEnd)
Definition: terminal.c:118
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
NTSTATUS NTAPI ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal)
Definition: terminal.c:237
union _KEY_EVENT_RECORD::@3232 uChar
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:278
unsigned long DWORD
Definition: ntddk_ex.h:95
static BOOL NTAPI ConSrvTermSetScreenInfo(IN OUT PTERMINAL This, PCONSOLE_SCREEN_BUFFER ScreenBuffer, SHORT OldCursorX, SHORT OldCursorY)
Definition: terminal.c:891
#define ENABLE_LINE_INPUT
Definition: wincon.h:79
PFRONTEND_VTBL Vtbl
Definition: conio_winsrv.h:98
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
CHAR FrontEndName[80]
Definition: terminal.c:140
#define ConsoleInputUnicodeCharToAnsiChar(Console, dChar, sWChar)
Definition: terminal.c:36
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
static TERMINAL_VTBL ConSrvTermVtbl
Definition: terminal.c:201
Status
Definition: gdiplustypes.h:24
FRONTEND_UNLOAD FrontEndUnload
Definition: terminal.c:142
static const WCHAR L[]
Definition: oid.c:1250
static VOID NTAPI ConSrvTermDeinitTerminal(IN OUT PTERMINAL This)
Definition: terminal.c:286
static NTSTATUS ConSrvLoadFrontEnd(IN OUT PFRONTEND FrontEnd, IN OUT PCONSOLE_STATE_INFO ConsoleInfo, IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo, IN HANDLE ConsoleLeaderProcessHandle)
Definition: terminal.c:154
#define NTSTATUS
Definition: precomp.h:20
USHORT ScreenDefaultAttrib
Definition: conio.h:131
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
Definition: typedefs.h:119
struct _CONSRV_CONSOLE * PCONSRV_CONSOLE
Definition: bl.h:1338
#define ConioInitRect(Rect, top, left, bottom, right)
Definition: rect.h:20
#define ENABLE_PROCESSED_OUTPUT
Definition: blue.h:53
static VOID ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, PSMALL_RECT UpdateRect, PUINT ScrolledLines)
Definition: terminal.c:480
static VOID NTAPI ConSrvTermDrawRegion(IN OUT PTERMINAL This, SMALL_RECT *Region)
Definition: terminal.c:875
static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
Definition: video.c:47
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
static VOID NTAPI ConSrvTermReleaseScreenBuffer(IN OUT PTERMINAL This, IN PCONSOLE_SCREEN_BUFFER ScreenBuffer)
Definition: terminal.c:918
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
static VOID NTAPI ConSrvTermSetActiveScreenBuffer(IN OUT PTERMINAL This)
Definition: terminal.c:911
CConsole Console
WORD EventType
Definition: wincon.h:276
#define DPRINT1
Definition: precomp.h:8
#define ConsoleFreeHeap(HeapBase)
Definition: heap.h:15
HANDLE ScreenBuffer
Definition: notevil.c:37
#define OUT
Definition: typedefs.h:40
#define COMMON_LVB_LEADING_BYTE
Definition: wincon.h:48
static INT NTAPI ConSrvTermShowMouseCursor(IN OUT PTERMINAL This, BOOL Show)
Definition: terminal.c:943
NTSTATUS NTAPI NtClearEvent(IN HANDLE EventHandle)
Definition: event.c:69
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
static int UpdateRect(TreeListData *pData, unsigned uItem, unsigned uSub)
Definition: treelist.c:1529
#define COMMON_LVB_TRAILING_BYTE
Definition: wincon.h:49
FRONTEND_LOAD FrontEndLoad
Definition: terminal.c:141
#define ConioIsRectEmpty(Rect)
Definition: rect.h:28
#define ConsoleInputAnsiCharToUnicodeChar(Console, dWChar, sChar)
Definition: terminal.c:42
return STATUS_SUCCESS
Definition: btrfs.c:3014
ULONG Y
Definition: bl.h:1341
signed int * PLONG
Definition: retypes.h:5
#define IS_FULL_WIDTH(wch)
Definition: conio.h:333
unsigned int * PUINT
Definition: ndis.h:50
static NTSTATUS NTAPI ConSrvTermInitTerminal(IN OUT PTERMINAL This, IN PCONSOLE Console)
Definition: terminal.c:260
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68