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