Sync with trunk r63383 .
[reactos.git] / win32ss / user / winsrv / consrv / frontends / tui / tuiterm.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/frontends/tui/tuiterm.c
5 * PURPOSE: TUI Terminal Front-End - Virtual Consoles...
6 * PROGRAMMERS: David Welch
7 * Gé van Geldorp
8 * Jeffrey Morlan
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 */
11
12 #ifdef TUITERM_COMPILE
13
14 #include "consrv.h"
15 #include "include/conio.h"
16 #include "include/console.h"
17 #include "include/settings.h"
18 #include "tuiterm.h"
19 #include <drivers/blue/ntddblue.h>
20
21 #define NDEBUG
22 #include <debug.h>
23
24
25 /* GLOBALS ********************************************************************/
26
27 #define GetNextConsole(Console) \
28 CONTAINING_RECORD(Console->Entry.Flink, TUI_CONSOLE_DATA, Entry)
29
30 #define GetPrevConsole(Console) \
31 CONTAINING_RECORD(Console->Entry.Blink, TUI_CONSOLE_DATA, Entry)
32
33
34 /* TUI Console Window Class name */
35 #define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass"
36
37 typedef struct _TUI_CONSOLE_DATA
38 {
39 CRITICAL_SECTION Lock;
40 LIST_ENTRY Entry; /* Entry in the list of virtual consoles */
41 // HANDLE hTuiInitEvent;
42
43 HWND hWindow; /* Handle to the console's window (used for the window's procedure */
44
45 PCONSOLE Console; /* Pointer to the owned console */
46 // TUI_CONSOLE_INFO TuiInfo; /* TUI terminal settings */
47 } TUI_CONSOLE_DATA, *PTUI_CONSOLE_DATA;
48
49 /* List of the maintained virtual consoles and its lock */
50 static LIST_ENTRY VirtConsList;
51 static PTUI_CONSOLE_DATA ActiveConsole; /* The active console on screen */
52 static CRITICAL_SECTION ActiveVirtConsLock;
53
54 static COORD PhysicalConsoleSize;
55 static HANDLE ConsoleDeviceHandle;
56
57 static BOOL ConsInitialized = FALSE;
58
59 /******************************************************************************\
60 |** BlueScreen Driver management **|
61 \**/
62 /* Code taken and adapted from base/system/services/driver.c */
63 static DWORD
64 ScmLoadDriver(LPCWSTR lpServiceName)
65 {
66 NTSTATUS Status = STATUS_SUCCESS;
67 BOOLEAN WasPrivilegeEnabled = FALSE;
68 PWSTR pszDriverPath;
69 UNICODE_STRING DriverPath;
70
71 /* Build the driver path */
72 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
73 pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
74 (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR));
75 if (pszDriverPath == NULL)
76 return ERROR_NOT_ENOUGH_MEMORY;
77
78 wcscpy(pszDriverPath,
79 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
80 wcscat(pszDriverPath,
81 lpServiceName);
82
83 RtlInitUnicodeString(&DriverPath,
84 pszDriverPath);
85
86 DPRINT(" Path: %wZ\n", &DriverPath);
87
88 /* Acquire driver-loading privilege */
89 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
90 TRUE,
91 FALSE,
92 &WasPrivilegeEnabled);
93 if (!NT_SUCCESS(Status))
94 {
95 /* We encountered a failure, exit properly */
96 DPRINT1("CONSRV: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status);
97 goto done;
98 }
99
100 Status = NtLoadDriver(&DriverPath);
101
102 /* Release driver-loading privilege */
103 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
104 WasPrivilegeEnabled,
105 FALSE,
106 &WasPrivilegeEnabled);
107
108 done:
109 ConsoleFreeHeap(pszDriverPath);
110 return RtlNtStatusToDosError(Status);
111 }
112
113 #ifdef BLUESCREEN_DRIVER_UNLOADING
114 static DWORD
115 ScmUnloadDriver(LPCWSTR lpServiceName)
116 {
117 NTSTATUS Status = STATUS_SUCCESS;
118 BOOLEAN WasPrivilegeEnabled = FALSE;
119 PWSTR pszDriverPath;
120 UNICODE_STRING DriverPath;
121
122 /* Build the driver path */
123 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
124 pszDriverPath = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
125 (52 + wcslen(lpServiceName) + 1) * sizeof(WCHAR));
126 if (pszDriverPath == NULL)
127 return ERROR_NOT_ENOUGH_MEMORY;
128
129 wcscpy(pszDriverPath,
130 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
131 wcscat(pszDriverPath,
132 lpServiceName);
133
134 RtlInitUnicodeString(&DriverPath,
135 pszDriverPath);
136
137 DPRINT(" Path: %wZ\n", &DriverPath);
138
139 /* Acquire driver-unloading privilege */
140 Status = RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
141 TRUE,
142 FALSE,
143 &WasPrivilegeEnabled);
144 if (!NT_SUCCESS(Status))
145 {
146 /* We encountered a failure, exit properly */
147 DPRINT1("CONSRV: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status);
148 goto done;
149 }
150
151 Status = NtUnloadDriver(&DriverPath);
152
153 /* Release driver-unloading privilege */
154 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE,
155 WasPrivilegeEnabled,
156 FALSE,
157 &WasPrivilegeEnabled);
158
159 done:
160 ConsoleFreeHeap(pszDriverPath);
161 return RtlNtStatusToDosError(Status);
162 }
163 #endif
164 /**\
165 \******************************************************************************/
166
167 static BOOL
168 TuiSwapConsole(INT Next)
169 {
170 static PTUI_CONSOLE_DATA SwapConsole = NULL; /* Console we are thinking about swapping with */
171 DWORD BytesReturned;
172 ANSI_STRING Title;
173 PVOID Buffer;
174 PCOORD pos;
175
176 if (0 != Next)
177 {
178 /*
179 * Alt-Tab, swap consoles.
180 * move SwapConsole to next console, and print its title.
181 */
182 EnterCriticalSection(&ActiveVirtConsLock);
183 if (!SwapConsole) SwapConsole = ActiveConsole;
184
185 SwapConsole = (0 < Next ? GetNextConsole(SwapConsole) : GetPrevConsole(SwapConsole));
186 Title.MaximumLength = RtlUnicodeStringToAnsiSize(&SwapConsole->Console->Title);
187 Title.Length = 0;
188 Buffer = ConsoleAllocHeap(0, sizeof(COORD) + Title.MaximumLength);
189 pos = (PCOORD)Buffer;
190 Title.Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(COORD));
191
192 RtlUnicodeStringToAnsiString(&Title, &SwapConsole->Console->Title, FALSE);
193 pos->X = (PhysicalConsoleSize.X - Title.Length) / 2;
194 pos->Y = PhysicalConsoleSize.Y / 2;
195 /* Redraw the console to clear off old title */
196 ConioDrawConsole(ActiveConsole->Console);
197 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER,
198 NULL, 0, Buffer, sizeof(COORD) + Title.Length,
199 &BytesReturned, NULL))
200 {
201 DPRINT1( "Error writing to console\n" );
202 }
203 ConsoleFreeHeap(Buffer);
204 LeaveCriticalSection(&ActiveVirtConsLock);
205
206 return TRUE;
207 }
208 else if (NULL != SwapConsole)
209 {
210 EnterCriticalSection(&ActiveVirtConsLock);
211 if (SwapConsole != ActiveConsole)
212 {
213 /* First remove swapconsole from the list */
214 SwapConsole->Entry.Blink->Flink = SwapConsole->Entry.Flink;
215 SwapConsole->Entry.Flink->Blink = SwapConsole->Entry.Blink;
216 /* Now insert before activeconsole */
217 SwapConsole->Entry.Flink = &ActiveConsole->Entry;
218 SwapConsole->Entry.Blink = ActiveConsole->Entry.Blink;
219 ActiveConsole->Entry.Blink->Flink = &SwapConsole->Entry;
220 ActiveConsole->Entry.Blink = &SwapConsole->Entry;
221 }
222 ActiveConsole = SwapConsole;
223 SwapConsole = NULL;
224 ConioDrawConsole(ActiveConsole->Console);
225 LeaveCriticalSection(&ActiveVirtConsLock);
226 return TRUE;
227 }
228 else
229 {
230 return FALSE;
231 }
232 }
233
234 static VOID
235 TuiCopyRect(PCHAR Dest, PTEXTMODE_SCREEN_BUFFER Buff, SMALL_RECT* Region)
236 {
237 UINT SrcDelta, DestDelta;
238 LONG i;
239 PCHAR_INFO Src, SrcEnd;
240
241 Src = ConioCoordToPointer(Buff, Region->Left, Region->Top);
242 SrcDelta = Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
243 SrcEnd = Buff->Buffer + Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
244 DestDelta = ConioRectWidth(Region) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */;
245 for (i = Region->Top; i <= Region->Bottom; i++)
246 {
247 ConsoleUnicodeCharToAnsiChar(Buff->Header.Console, (PCHAR)Dest, &Src->Char.UnicodeChar);
248 *(PBYTE)(Dest + 1) = (BYTE)Src->Attributes;
249
250 Src += SrcDelta;
251 if (SrcEnd <= Src)
252 {
253 Src -= Buff->ScreenBufferSize.Y * Buff->ScreenBufferSize.X * sizeof(CHAR_INFO);
254 }
255 Dest += DestDelta;
256 }
257 }
258
259 static LRESULT CALLBACK
260 TuiConsoleWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
261 {
262 /*
263 PTUI_CONSOLE_DATA TuiData = NULL;
264 PCONSOLE Console = NULL;
265
266 TuiData = TuiGetGuiData(hWnd);
267 if (TuiData == NULL) return 0;
268 */
269
270 switch (msg)
271 {
272 case WM_CHAR:
273 case WM_SYSCHAR:
274 case WM_KEYDOWN:
275 case WM_SYSKEYDOWN:
276 case WM_KEYUP:
277 case WM_SYSKEYUP:
278 {
279 if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
280 {
281 MSG Message;
282 Message.hwnd = hWnd;
283 Message.message = msg;
284 Message.wParam = wParam;
285 Message.lParam = lParam;
286
287 ConioProcessKey(ActiveConsole->Console, &Message);
288 LeaveCriticalSection(&ActiveConsole->Console->Lock);
289 }
290 break;
291 }
292
293 case WM_ACTIVATE:
294 {
295 if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
296 {
297 if (LOWORD(wParam) != WA_INACTIVE)
298 {
299 SetFocus(hWnd);
300 ConioDrawConsole(ActiveConsole->Console);
301 }
302 LeaveCriticalSection(&ActiveConsole->Console->Lock);
303 }
304 break;
305 }
306
307 default:
308 break;
309 }
310
311 return DefWindowProcW(hWnd, msg, wParam, lParam);
312 }
313
314 static DWORD NTAPI
315 TuiConsoleThread(PVOID Data)
316 {
317 PTUI_CONSOLE_DATA TuiData = (PTUI_CONSOLE_DATA)Data;
318 PCONSOLE Console = TuiData->Console;
319 HWND NewWindow;
320 MSG msg;
321
322 NewWindow = CreateWindowW(TUI_CONSOLE_WINDOW_CLASS,
323 Console->Title.Buffer,
324 0,
325 -32000, -32000, 0, 0,
326 NULL, NULL,
327 ConSrvDllInstance,
328 (PVOID)Console);
329 if (NULL == NewWindow)
330 {
331 DPRINT1("CONSRV: Unable to create console window\n");
332 return 1;
333 }
334 TuiData->hWindow = NewWindow;
335
336 SetForegroundWindow(TuiData->hWindow);
337 NtUserConsoleControl(ConsoleAcquireDisplayOwnership, NULL, 0);
338
339 while (GetMessageW(&msg, NULL, 0, 0))
340 {
341 TranslateMessage(&msg);
342 DispatchMessageW(&msg);
343 }
344
345 return 0;
346 }
347
348 static BOOL
349 TuiInit(DWORD OemCP)
350 {
351 BOOL Ret = FALSE;
352 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
353 DWORD BytesReturned;
354 WNDCLASSEXW wc;
355 ATOM ConsoleClassAtom;
356 USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
357
358 /* Exit if we were already initialized */
359 if (ConsInitialized) return TRUE;
360
361 /*
362 * Initialize the TUI front-end:
363 * - load the console driver,
364 * - set default screen attributes,
365 * - grab the console size.
366 */
367 ScmLoadDriver(L"Blue");
368
369 ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen",
370 FILE_ALL_ACCESS,
371 0, NULL,
372 OPEN_EXISTING,
373 0, NULL);
374 if (INVALID_HANDLE_VALUE == ConsoleDeviceHandle)
375 {
376 DPRINT1("Failed to open BlueScreen.\n");
377 return FALSE;
378 }
379
380 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT,
381 &OemCP, sizeof(OemCP), NULL, 0,
382 &BytesReturned, NULL))
383 {
384 DPRINT1("Failed to load the font for codepage %d\n", OemCP);
385 /* Let's suppose the font is good enough to continue */
386 }
387
388 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
389 &TextAttribute, sizeof(TextAttribute), NULL, 0,
390 &BytesReturned, NULL))
391 {
392 DPRINT1("Failed to set text attribute\n");
393 }
394
395 ActiveConsole = NULL;
396 InitializeListHead(&VirtConsList);
397 InitializeCriticalSection(&ActiveVirtConsLock);
398
399 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
400 NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL))
401 {
402 DPRINT1("Failed to get console info\n");
403 Ret = FALSE;
404 goto Quit;
405 }
406 PhysicalConsoleSize = ScrInfo.dwSize;
407
408 /* Register the TUI notification window class */
409 RtlZeroMemory(&wc, sizeof(WNDCLASSEXW));
410 wc.cbSize = sizeof(WNDCLASSEXW);
411 wc.lpszClassName = TUI_CONSOLE_WINDOW_CLASS;
412 wc.lpfnWndProc = TuiConsoleWndProc;
413 wc.cbWndExtra = 0;
414 wc.hInstance = ConSrvDllInstance;
415
416 ConsoleClassAtom = RegisterClassExW(&wc);
417 if (ConsoleClassAtom == 0)
418 {
419 DPRINT1("Failed to register TUI console wndproc\n");
420 Ret = FALSE;
421 }
422 else
423 {
424 Ret = TRUE;
425 }
426
427 Quit:
428 if (Ret == FALSE)
429 {
430 DeleteCriticalSection(&ActiveVirtConsLock);
431 CloseHandle(ConsoleDeviceHandle);
432 }
433
434 ConsInitialized = Ret;
435 return Ret;
436 }
437
438
439
440 /******************************************************************************
441 * TUI Console Driver *
442 ******************************************************************************/
443
444 static VOID NTAPI
445 TuiDeinitFrontEnd(IN OUT PFRONTEND This /*,
446 IN PCONSOLE Console */);
447
448 NTSTATUS NTAPI
449 TuiInitFrontEnd(IN OUT PFRONTEND This,
450 IN PCONSOLE Console)
451 {
452 PTUI_CONSOLE_DATA TuiData;
453 HANDLE ThreadHandle;
454
455 if (This == NULL || Console == NULL)
456 return STATUS_INVALID_PARAMETER;
457
458 // if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER)
459 // return STATUS_INVALID_PARAMETER;
460
461 // /* Initialize the console */
462 // Console->FrontEndIFace.Vtbl = &TuiVtbl;
463
464 TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA));
465 if (!TuiData)
466 {
467 DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n");
468 return STATUS_UNSUCCESSFUL;
469 }
470 // Console->FrontEndIFace.Data = (PVOID)TuiData;
471 TuiData->Console = Console;
472 TuiData->hWindow = NULL;
473
474 InitializeCriticalSection(&TuiData->Lock);
475
476 /*
477 * HACK: Resize the console since we don't support for now changing
478 * the console size when we display it with the hardware.
479 */
480 // Console->ConsoleSize = PhysicalConsoleSize;
481 // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize);
482
483 // /* The console cannot be resized anymore */
484 // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !!
485 // // TermResizeTerminal(Console);
486
487 /*
488 * Contrary to what we do in the GUI front-end, here we create
489 * an input thread for each console. It will dispatch all the
490 * input messages to the proper console (on the GUI it is done
491 * via the default GUI dispatch thread).
492 */
493 ThreadHandle = CreateThread(NULL,
494 0,
495 TuiConsoleThread,
496 (PVOID)TuiData,
497 0,
498 NULL);
499 if (NULL == ThreadHandle)
500 {
501 DPRINT1("CONSRV: Unable to create console thread\n");
502 // TuiDeinitFrontEnd(Console);
503 TuiDeinitFrontEnd(This);
504 return STATUS_UNSUCCESSFUL;
505 }
506 CloseHandle(ThreadHandle);
507
508 /*
509 * Insert the newly created console in the list of virtual consoles
510 * and activate it (give it the focus).
511 */
512 EnterCriticalSection(&ActiveVirtConsLock);
513 InsertTailList(&VirtConsList, &TuiData->Entry);
514 ActiveConsole = TuiData;
515 LeaveCriticalSection(&ActiveVirtConsLock);
516
517 /* Finally, initialize the frontend structure */
518 This->Data = TuiData;
519 This->OldData = NULL;
520
521 return STATUS_SUCCESS;
522 }
523
524 static VOID NTAPI
525 TuiDeinitFrontEnd(IN OUT PFRONTEND This)
526 {
527 // PCONSOLE Console = This->Console;
528 PTUI_CONSOLE_DATA TuiData = This->Data; // Console->FrontEndIFace.Data;
529
530 /* Close the notification window */
531 DestroyWindow(TuiData->hWindow);
532
533 /*
534 * Set the active console to the next one
535 * and remove the console from the list.
536 */
537 EnterCriticalSection(&ActiveVirtConsLock);
538 ActiveConsole = GetNextConsole(TuiData);
539 RemoveEntryList(&TuiData->Entry);
540
541 // /* Switch to next console */
542 // if (ActiveConsole == TuiData)
543 // if (ActiveConsole->Console == Console)
544 // {
545 // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL);
546 // }
547
548 // if (GetNextConsole(TuiData) != TuiData)
549 // {
550 // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink;
551 // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink;
552 // }
553
554 LeaveCriticalSection(&ActiveVirtConsLock);
555
556 /* Switch to the next console */
557 if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console);
558
559 // Console->FrontEndIFace.Data = NULL;
560 This->Data = NULL;
561 DeleteCriticalSection(&TuiData->Lock);
562 ConsoleFreeHeap(TuiData);
563 }
564
565 static VOID NTAPI
566 TuiDrawRegion(IN OUT PFRONTEND This,
567 SMALL_RECT* Region)
568 {
569 DWORD BytesReturned;
570 PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
571 PCONSOLE_DRAW ConsoleDraw;
572 UINT ConsoleDrawSize;
573
574 if (ActiveConsole->Console != Console || GetType(Buff) != TEXTMODE_BUFFER) return;
575
576 ConsoleDrawSize = sizeof(CONSOLE_DRAW) +
577 (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2;
578 ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize);
579 if (NULL == ConsoleDraw)
580 {
581 DPRINT1("ConsoleAllocHeap failed\n");
582 return;
583 }
584 ConsoleDraw->X = Region->Left;
585 ConsoleDraw->Y = Region->Top;
586 ConsoleDraw->SizeX = ConioRectWidth(Region);
587 ConsoleDraw->SizeY = ConioRectHeight(Region);
588 ConsoleDraw->CursorX = Buff->CursorPosition.X;
589 ConsoleDraw->CursorY = Buff->CursorPosition.Y;
590
591 TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region);
592
593 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW,
594 NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL))
595 {
596 DPRINT1("Failed to draw console\n");
597 ConsoleFreeHeap(ConsoleDraw);
598 return;
599 }
600
601 ConsoleFreeHeap(ConsoleDraw);
602 }
603
604 static VOID NTAPI
605 TuiWriteStream(IN OUT PFRONTEND This,
606 SMALL_RECT* Region,
607 SHORT CursorStartX,
608 SHORT CursorStartY,
609 UINT ScrolledLines,
610 PWCHAR Buffer,
611 UINT Length)
612 {
613 PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
614 PCHAR NewBuffer;
615 ULONG NewLength;
616 DWORD BytesWritten;
617
618 if (ActiveConsole->Console->ActiveBuffer != Buff) return;
619
620 NewLength = WideCharToMultiByte(Console->OutputCodePage, 0,
621 Buffer, Length,
622 NULL, 0, NULL, NULL);
623 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength * sizeof(CHAR));
624 if (!NewBuffer) return;
625
626 WideCharToMultiByte(Console->OutputCodePage, 0,
627 Buffer, Length,
628 NewBuffer, NewLength, NULL, NULL);
629
630 if (!WriteFile(ConsoleDeviceHandle, NewBuffer, NewLength * sizeof(CHAR), &BytesWritten, NULL))
631 {
632 DPRINT1("Error writing to BlueScreen\n");
633 }
634
635 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
636 }
637
638 static BOOL NTAPI
639 TuiSetCursorInfo(IN OUT PFRONTEND This,
640 PCONSOLE_SCREEN_BUFFER Buff)
641 {
642 CONSOLE_CURSOR_INFO Info;
643 DWORD BytesReturned;
644
645 if (ActiveConsole->Console->ActiveBuffer != Buff) return TRUE;
646
647 Info.dwSize = ConioEffectiveCursorSize(Console, 100);
648 Info.bVisible = Buff->CursorInfo.bVisible;
649
650 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
651 &Info, sizeof(Info), NULL, 0, &BytesReturned, NULL))
652 {
653 DPRINT1( "Failed to set cursor info\n" );
654 return FALSE;
655 }
656
657 return TRUE;
658 }
659
660 static BOOL NTAPI
661 TuiSetScreenInfo(IN OUT PFRONTEND This,
662 PCONSOLE_SCREEN_BUFFER Buff,
663 SHORT OldCursorX,
664 SHORT OldCursorY)
665 {
666 CONSOLE_SCREEN_BUFFER_INFO Info;
667 DWORD BytesReturned;
668
669 if (ActiveConsole->Console->ActiveBuffer != Buff) return TRUE;
670 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE;
671
672 Info.dwCursorPosition = Buff->CursorPosition;
673 Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib;
674
675 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
676 &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0,
677 &BytesReturned, NULL))
678 {
679 DPRINT1( "Failed to set cursor position\n" );
680 return FALSE;
681 }
682
683 return TRUE;
684 }
685
686 static VOID NTAPI
687 TuiResizeTerminal(IN OUT PFRONTEND This)
688 {
689 }
690
691 static BOOL NTAPI
692 TuiProcessKeyCallback(IN OUT PFRONTEND This,
693 MSG* msg,
694 BYTE KeyStateMenu,
695 DWORD ShiftState,
696 UINT VirtualKeyCode,
697 BOOL Down)
698 {
699 if (0 != (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) &&
700 VK_TAB == VirtualKeyCode)
701 {
702 if (Down)
703 {
704 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
705 }
706
707 return TRUE;
708 }
709 else if (VK_MENU == VirtualKeyCode && !Down)
710 {
711 return TuiSwapConsole(0);
712 }
713
714 return FALSE;
715 }
716
717 static VOID NTAPI
718 TuiRefreshInternalInfo(IN OUT PFRONTEND This)
719 {
720 }
721
722 static VOID NTAPI
723 TuiChangeTitle(IN OUT PFRONTEND This)
724 {
725 }
726
727 static BOOL NTAPI
728 TuiChangeIcon(IN OUT PFRONTEND This,
729 HICON IconHandle)
730 {
731 return TRUE;
732 }
733
734 static HWND NTAPI
735 TuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
736 {
737 PTUI_CONSOLE_DATA TuiData = This->Data;
738 return TuiData->hWindow;
739 }
740
741 static VOID NTAPI
742 TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
743 PCOORD pSize)
744 {
745 if (!pSize) return;
746 *pSize = PhysicalConsoleSize;
747 }
748
749 static BOOL NTAPI
750 TuiGetSelectionInfo(IN OUT PFRONTEND This,
751 PCONSOLE_SELECTION_INFO pSelectionInfo)
752 {
753 return TRUE;
754 }
755
756 static BOOL NTAPI
757 TuiSetPalette(IN OUT PFRONTEND This,
758 HPALETTE PaletteHandle,
759 UINT PaletteUsage)
760 {
761 return TRUE;
762 }
763
764 static ULONG NTAPI
765 TuiGetDisplayMode(IN OUT PFRONTEND This)
766 {
767 return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN;
768 }
769
770 static BOOL NTAPI
771 TuiSetDisplayMode(IN OUT PFRONTEND This,
772 ULONG NewMode)
773 {
774 // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
775 // return FALSE;
776 return TRUE;
777 }
778
779 static INT NTAPI
780 TuiShowMouseCursor(IN OUT PFRONTEND This,
781 BOOL Show)
782 {
783 return 0;
784 }
785
786 static BOOL NTAPI
787 TuiSetMouseCursor(IN OUT PFRONTEND This,
788 HCURSOR CursorHandle)
789 {
790 return TRUE;
791 }
792
793 static HMENU NTAPI
794 TuiMenuControl(IN OUT PFRONTEND This,
795 UINT CmdIdLow,
796 UINT CmdIdHigh)
797 {
798 return NULL;
799 }
800
801 static BOOL NTAPI
802 TuiSetMenuClose(IN OUT PFRONTEND This,
803 BOOL Enable)
804 {
805 return TRUE;
806 }
807
808 static FRONTEND_VTBL TuiVtbl =
809 {
810 TuiInitFrontEnd,
811 TuiDeinitFrontEnd,
812 TuiDrawRegion,
813 TuiWriteStream,
814 TuiSetCursorInfo,
815 TuiSetScreenInfo,
816 TuiResizeTerminal,
817 TuiProcessKeyCallback,
818 TuiRefreshInternalInfo,
819 TuiChangeTitle,
820 TuiChangeIcon,
821 TuiGetConsoleWindowHandle,
822 TuiGetLargestConsoleWindowSize,
823 TuiGetSelectionInfo,
824 TuiSetPalette,
825 TuiGetDisplayMode,
826 TuiSetDisplayMode,
827 TuiShowMouseCursor,
828 TuiSetMouseCursor,
829 TuiMenuControl,
830 TuiSetMenuClose,
831 };
832
833 // static BOOL
834 // DtbgIsDesktopVisible(VOID)
835 // {
836 // return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
837 // }
838 static BOOLEAN
839 IsConsoleMode(VOID)
840 {
841 return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE);
842 }
843
844 NTSTATUS NTAPI
845 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
846 IN OUT PCONSOLE_INFO ConsoleInfo,
847 IN OUT PVOID ExtraConsoleInfo,
848 IN ULONG ProcessId)
849 {
850 if (FrontEnd == NULL || ConsoleInfo == NULL)
851 return STATUS_INVALID_PARAMETER;
852
853 /* We must be in console mode already */
854 if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL;
855
856 /* Initialize the TUI terminal emulator */
857 if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL;
858
859 /* Finally, initialize the frontend structure */
860 FrontEnd->Vtbl = &TuiVtbl;
861 FrontEnd->Data = NULL;
862 FrontEnd->OldData = NULL;
863
864 return STATUS_SUCCESS;
865 }
866
867 NTSTATUS NTAPI
868 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
869 {
870 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
871 if (FrontEnd->Data) TuiDeinitFrontEnd(FrontEnd);
872
873 return STATUS_SUCCESS;
874 }
875
876 #endif
877
878 /* EOF */