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