3e2bed71c3d226653a3863da68eb443dcb829476
[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 /* TUI Console Window Class name */
28 #define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass"
29
30 typedef struct _TUI_CONSOLE_DATA
31 {
32 CRITICAL_SECTION Lock;
33 LIST_ENTRY Entry; /* Entry in the list of virtual consoles */
34 // HANDLE hTuiInitEvent;
35
36 HWND hWindow; /* Handle to the console's window (used for the window's procedure */
37
38 PCONSRV_CONSOLE Console; /* Pointer to the owned console */
39 // TUI_CONSOLE_INFO TuiInfo; /* TUI terminal settings */
40 } TUI_CONSOLE_DATA, *PTUI_CONSOLE_DATA;
41
42 #define GetNextConsole(Console) \
43 CONTAINING_RECORD(Console->Entry.Flink, TUI_CONSOLE_DATA, Entry)
44
45 #define GetPrevConsole(Console) \
46 CONTAINING_RECORD(Console->Entry.Blink, TUI_CONSOLE_DATA, Entry)
47
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 PCONSRV_CONSOLE 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 0
280 if ((HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_TAB)
281 {
282 // if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT)
283 TuiSwapConsole(ShiftState & SHIFT_PRESSED ? -1 : 1);
284
285 break;
286 }
287 else if (wParam == VK_MENU /* && !Down */)
288 {
289 TuiSwapConsole(0);
290 break;
291 }
292 #endif
293
294 if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
295 {
296 MSG Message;
297 Message.hwnd = hWnd;
298 Message.message = msg;
299 Message.wParam = wParam;
300 Message.lParam = lParam;
301
302 ConioProcessKey(ActiveConsole->Console, &Message);
303 LeaveCriticalSection(&ActiveConsole->Console->Lock);
304 }
305 break;
306 }
307
308 case WM_ACTIVATE:
309 {
310 if (ConDrvValidateConsoleUnsafe(ActiveConsole->Console, CONSOLE_RUNNING, TRUE))
311 {
312 if (LOWORD(wParam) != WA_INACTIVE)
313 {
314 SetFocus(hWnd);
315 ConioDrawConsole(ActiveConsole->Console);
316 }
317 LeaveCriticalSection(&ActiveConsole->Console->Lock);
318 }
319 break;
320 }
321
322 default:
323 break;
324 }
325
326 return DefWindowProcW(hWnd, msg, wParam, lParam);
327 }
328
329 static DWORD NTAPI
330 TuiConsoleThread(PVOID Data)
331 {
332 PTUI_CONSOLE_DATA TuiData = (PTUI_CONSOLE_DATA)Data;
333 PCONSRV_CONSOLE Console = TuiData->Console;
334 HWND NewWindow;
335 MSG msg;
336
337 NewWindow = CreateWindowW(TUI_CONSOLE_WINDOW_CLASS,
338 Console->Title.Buffer,
339 0,
340 -32000, -32000, 0, 0,
341 NULL, NULL,
342 ConSrvDllInstance,
343 (PVOID)Console);
344 if (NULL == NewWindow)
345 {
346 DPRINT1("CONSRV: Unable to create console window\n");
347 return 1;
348 }
349 TuiData->hWindow = NewWindow;
350
351 SetForegroundWindow(TuiData->hWindow);
352 NtUserConsoleControl(ConsoleAcquireDisplayOwnership, NULL, 0);
353
354 while (GetMessageW(&msg, NULL, 0, 0))
355 {
356 TranslateMessage(&msg);
357 DispatchMessageW(&msg);
358 }
359
360 return 0;
361 }
362
363 static BOOL
364 TuiInit(DWORD OemCP)
365 {
366 BOOL Ret = FALSE;
367 CONSOLE_SCREEN_BUFFER_INFO ScrInfo;
368 DWORD BytesReturned;
369 WNDCLASSEXW wc;
370 ATOM ConsoleClassAtom;
371 USHORT TextAttribute = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
372
373 /* Exit if we were already initialized */
374 if (ConsInitialized) return TRUE;
375
376 /*
377 * Initialize the TUI front-end:
378 * - load the console driver,
379 * - set default screen attributes,
380 * - grab the console size.
381 */
382 ScmLoadDriver(L"Blue");
383
384 ConsoleDeviceHandle = CreateFileW(L"\\\\.\\BlueScreen",
385 FILE_ALL_ACCESS,
386 0, NULL,
387 OPEN_EXISTING,
388 0, NULL);
389 if (INVALID_HANDLE_VALUE == ConsoleDeviceHandle)
390 {
391 DPRINT1("Failed to open BlueScreen.\n");
392 return FALSE;
393 }
394
395 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_LOADFONT,
396 &OemCP, sizeof(OemCP), NULL, 0,
397 &BytesReturned, NULL))
398 {
399 DPRINT1("Failed to load the font for codepage %d\n", OemCP);
400 /* Let's suppose the font is good enough to continue */
401 }
402
403 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE,
404 &TextAttribute, sizeof(TextAttribute), NULL, 0,
405 &BytesReturned, NULL))
406 {
407 DPRINT1("Failed to set text attribute\n");
408 }
409
410 ActiveConsole = NULL;
411 InitializeListHead(&VirtConsList);
412 InitializeCriticalSection(&ActiveVirtConsLock);
413
414 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO,
415 NULL, 0, &ScrInfo, sizeof(ScrInfo), &BytesReturned, NULL))
416 {
417 DPRINT1("Failed to get console info\n");
418 Ret = FALSE;
419 goto Quit;
420 }
421 PhysicalConsoleSize = ScrInfo.dwSize;
422
423 /* Register the TUI notification window class */
424 RtlZeroMemory(&wc, sizeof(WNDCLASSEXW));
425 wc.cbSize = sizeof(WNDCLASSEXW);
426 wc.lpszClassName = TUI_CONSOLE_WINDOW_CLASS;
427 wc.lpfnWndProc = TuiConsoleWndProc;
428 wc.cbWndExtra = 0;
429 wc.hInstance = ConSrvDllInstance;
430
431 ConsoleClassAtom = RegisterClassExW(&wc);
432 if (ConsoleClassAtom == 0)
433 {
434 DPRINT1("Failed to register TUI console wndproc\n");
435 Ret = FALSE;
436 }
437 else
438 {
439 Ret = TRUE;
440 }
441
442 Quit:
443 if (Ret == FALSE)
444 {
445 DeleteCriticalSection(&ActiveVirtConsLock);
446 CloseHandle(ConsoleDeviceHandle);
447 }
448
449 ConsInitialized = Ret;
450 return Ret;
451 }
452
453
454
455 /******************************************************************************
456 * TUI Console Driver *
457 ******************************************************************************/
458
459 static VOID NTAPI
460 TuiDeinitFrontEnd(IN OUT PFRONTEND This /*,
461 IN PCONSRV_CONSOLE Console */);
462
463 static NTSTATUS NTAPI
464 TuiInitFrontEnd(IN OUT PFRONTEND This,
465 IN PCONSRV_CONSOLE Console)
466 {
467 PTUI_CONSOLE_DATA TuiData;
468 HANDLE ThreadHandle;
469
470 if (This == NULL || Console == NULL)
471 return STATUS_INVALID_PARAMETER;
472
473 // if (GetType(Console->ActiveBuffer) != TEXTMODE_BUFFER)
474 // return STATUS_INVALID_PARAMETER;
475
476 // /* Initialize the console */
477 // Console->FrontEndIFace.Vtbl = &TuiVtbl;
478
479 TuiData = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(TUI_CONSOLE_DATA));
480 if (!TuiData)
481 {
482 DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n");
483 return STATUS_UNSUCCESSFUL;
484 }
485 // Console->FrontEndIFace.Data = (PVOID)TuiData;
486 TuiData->Console = Console;
487 TuiData->hWindow = NULL;
488
489 InitializeCriticalSection(&TuiData->Lock);
490
491 /*
492 * HACK: Resize the console since we don't support for now changing
493 * the console size when we display it with the hardware.
494 */
495 // Console->ConsoleSize = PhysicalConsoleSize;
496 // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize);
497
498 // /* The console cannot be resized anymore */
499 // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !!
500 // // TermResizeTerminal(Console);
501
502 /*
503 * Contrary to what we do in the GUI front-end, here we create
504 * an input thread for each console. It will dispatch all the
505 * input messages to the proper console (on the GUI it is done
506 * via the default GUI dispatch thread).
507 */
508 ThreadHandle = CreateThread(NULL,
509 0,
510 TuiConsoleThread,
511 (PVOID)TuiData,
512 0,
513 NULL);
514 if (NULL == ThreadHandle)
515 {
516 DPRINT1("CONSRV: Unable to create console thread\n");
517 // TuiDeinitFrontEnd(Console);
518 TuiDeinitFrontEnd(This);
519 return STATUS_UNSUCCESSFUL;
520 }
521 CloseHandle(ThreadHandle);
522
523 /*
524 * Insert the newly created console in the list of virtual consoles
525 * and activate it (give it the focus).
526 */
527 EnterCriticalSection(&ActiveVirtConsLock);
528 InsertTailList(&VirtConsList, &TuiData->Entry);
529 ActiveConsole = TuiData;
530 LeaveCriticalSection(&ActiveVirtConsLock);
531
532 /* Finally, initialize the frontend structure */
533 This->Data = TuiData;
534 This->OldData = NULL;
535
536 return STATUS_SUCCESS;
537 }
538
539 static VOID NTAPI
540 TuiDeinitFrontEnd(IN OUT PFRONTEND This)
541 {
542 // PCONSRV_CONSOLE Console = This->Console;
543 PTUI_CONSOLE_DATA TuiData = This->Data; // Console->FrontEndIFace.Data;
544
545 /* Close the notification window */
546 DestroyWindow(TuiData->hWindow);
547
548 /*
549 * Set the active console to the next one
550 * and remove the console from the list.
551 */
552 EnterCriticalSection(&ActiveVirtConsLock);
553 ActiveConsole = GetNextConsole(TuiData);
554 RemoveEntryList(&TuiData->Entry);
555
556 // /* Switch to next console */
557 // if (ActiveConsole == TuiData)
558 // if (ActiveConsole->Console == Console)
559 // {
560 // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL);
561 // }
562
563 // if (GetNextConsole(TuiData) != TuiData)
564 // {
565 // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink;
566 // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink;
567 // }
568
569 LeaveCriticalSection(&ActiveVirtConsLock);
570
571 /* Switch to the next console */
572 if (NULL != ActiveConsole) ConioDrawConsole(ActiveConsole->Console);
573
574 // Console->FrontEndIFace.Data = NULL;
575 This->Data = NULL;
576 DeleteCriticalSection(&TuiData->Lock);
577 ConsoleFreeHeap(TuiData);
578 }
579
580 static VOID NTAPI
581 TuiDrawRegion(IN OUT PFRONTEND This,
582 SMALL_RECT* Region)
583 {
584 DWORD BytesReturned;
585 PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
586 PCONSOLE_DRAW ConsoleDraw;
587 UINT ConsoleDrawSize;
588
589 if (ActiveConsole->Console != Console || GetType(Buff) != TEXTMODE_BUFFER) return;
590
591 ConsoleDrawSize = sizeof(CONSOLE_DRAW) +
592 (ConioRectWidth(Region) * ConioRectHeight(Region)) * 2;
593 ConsoleDraw = ConsoleAllocHeap(0, ConsoleDrawSize);
594 if (NULL == ConsoleDraw)
595 {
596 DPRINT1("ConsoleAllocHeap failed\n");
597 return;
598 }
599 ConsoleDraw->X = Region->Left;
600 ConsoleDraw->Y = Region->Top;
601 ConsoleDraw->SizeX = ConioRectWidth(Region);
602 ConsoleDraw->SizeY = ConioRectHeight(Region);
603 ConsoleDraw->CursorX = Buff->CursorPosition.X;
604 ConsoleDraw->CursorY = Buff->CursorPosition.Y;
605
606 TuiCopyRect((PCHAR)(ConsoleDraw + 1), (PTEXTMODE_SCREEN_BUFFER)Buff, Region);
607
608 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_DRAW,
609 NULL, 0, ConsoleDraw, ConsoleDrawSize, &BytesReturned, NULL))
610 {
611 DPRINT1("Failed to draw console\n");
612 ConsoleFreeHeap(ConsoleDraw);
613 return;
614 }
615
616 ConsoleFreeHeap(ConsoleDraw);
617 }
618
619 static VOID NTAPI
620 TuiWriteStream(IN OUT PFRONTEND This,
621 SMALL_RECT* Region,
622 SHORT CursorStartX,
623 SHORT CursorStartY,
624 UINT ScrolledLines,
625 PWCHAR Buffer,
626 UINT Length)
627 {
628 PCONSOLE_SCREEN_BUFFER Buff = Console->ActiveBuffer;
629 PCHAR NewBuffer;
630 ULONG NewLength;
631 DWORD BytesWritten;
632
633 if (ActiveConsole->Console->ActiveBuffer != Buff) return;
634
635 NewLength = WideCharToMultiByte(Console->OutputCodePage, 0,
636 Buffer, Length,
637 NULL, 0, NULL, NULL);
638 NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength * sizeof(CHAR));
639 if (!NewBuffer) return;
640
641 WideCharToMultiByte(Console->OutputCodePage, 0,
642 Buffer, Length,
643 NewBuffer, NewLength, NULL, NULL);
644
645 if (!WriteFile(ConsoleDeviceHandle, NewBuffer, NewLength * sizeof(CHAR), &BytesWritten, NULL))
646 {
647 DPRINT1("Error writing to BlueScreen\n");
648 }
649
650 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer);
651 }
652
653 static BOOL NTAPI
654 TuiSetCursorInfo(IN OUT PFRONTEND This,
655 PCONSOLE_SCREEN_BUFFER Buff)
656 {
657 CONSOLE_CURSOR_INFO Info;
658 DWORD BytesReturned;
659
660 if (ActiveConsole->Console->ActiveBuffer != Buff) return TRUE;
661
662 Info.dwSize = ConioEffectiveCursorSize(Console, 100);
663 Info.bVisible = Buff->CursorInfo.bVisible;
664
665 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_CURSOR_INFO,
666 &Info, sizeof(Info), NULL, 0, &BytesReturned, NULL))
667 {
668 DPRINT1( "Failed to set cursor info\n" );
669 return FALSE;
670 }
671
672 return TRUE;
673 }
674
675 static BOOL NTAPI
676 TuiSetScreenInfo(IN OUT PFRONTEND This,
677 PCONSOLE_SCREEN_BUFFER Buff,
678 SHORT OldCursorX,
679 SHORT OldCursorY)
680 {
681 CONSOLE_SCREEN_BUFFER_INFO Info;
682 DWORD BytesReturned;
683
684 if (ActiveConsole->Console->ActiveBuffer != Buff) return TRUE;
685 if (GetType(Buff) != TEXTMODE_BUFFER) return FALSE;
686
687 Info.dwCursorPosition = Buff->CursorPosition;
688 Info.wAttributes = ((PTEXTMODE_SCREEN_BUFFER)Buff)->ScreenDefaultAttrib;
689
690 if (!DeviceIoControl(ConsoleDeviceHandle, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO,
691 &Info, sizeof(CONSOLE_SCREEN_BUFFER_INFO), NULL, 0,
692 &BytesReturned, NULL))
693 {
694 DPRINT1( "Failed to set cursor position\n" );
695 return FALSE;
696 }
697
698 return TRUE;
699 }
700
701 static VOID NTAPI
702 TuiResizeTerminal(IN OUT PFRONTEND This)
703 {
704 }
705
706 static VOID NTAPI
707 TuiRefreshInternalInfo(IN OUT PFRONTEND This)
708 {
709 }
710
711 static VOID NTAPI
712 TuiChangeTitle(IN OUT PFRONTEND This)
713 {
714 }
715
716 static BOOL NTAPI
717 TuiChangeIcon(IN OUT PFRONTEND This,
718 HICON IconHandle)
719 {
720 return TRUE;
721 }
722
723 static HWND NTAPI
724 TuiGetConsoleWindowHandle(IN OUT PFRONTEND This)
725 {
726 PTUI_CONSOLE_DATA TuiData = This->Data;
727 return TuiData->hWindow;
728 }
729
730 static VOID NTAPI
731 TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This,
732 PCOORD pSize)
733 {
734 if (!pSize) return;
735 *pSize = PhysicalConsoleSize;
736 }
737
738 static BOOL NTAPI
739 TuiGetSelectionInfo(IN OUT PFRONTEND This,
740 PCONSOLE_SELECTION_INFO pSelectionInfo)
741 {
742 return TRUE;
743 }
744
745 static BOOL NTAPI
746 TuiSetPalette(IN OUT PFRONTEND This,
747 HPALETTE PaletteHandle,
748 UINT PaletteUsage)
749 {
750 return TRUE;
751 }
752
753 static ULONG NTAPI
754 TuiGetDisplayMode(IN OUT PFRONTEND This)
755 {
756 return CONSOLE_FULLSCREEN_HARDWARE; // CONSOLE_FULLSCREEN;
757 }
758
759 static BOOL NTAPI
760 TuiSetDisplayMode(IN OUT PFRONTEND This,
761 ULONG NewMode)
762 {
763 // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
764 // return FALSE;
765 return TRUE;
766 }
767
768 static INT NTAPI
769 TuiShowMouseCursor(IN OUT PFRONTEND This,
770 BOOL Show)
771 {
772 return 0;
773 }
774
775 static BOOL NTAPI
776 TuiSetMouseCursor(IN OUT PFRONTEND This,
777 HCURSOR CursorHandle)
778 {
779 return TRUE;
780 }
781
782 static HMENU NTAPI
783 TuiMenuControl(IN OUT PFRONTEND This,
784 UINT CmdIdLow,
785 UINT CmdIdHigh)
786 {
787 return NULL;
788 }
789
790 static BOOL NTAPI
791 TuiSetMenuClose(IN OUT PFRONTEND This,
792 BOOL Enable)
793 {
794 return TRUE;
795 }
796
797 static FRONTEND_VTBL TuiVtbl =
798 {
799 TuiInitFrontEnd,
800 TuiDeinitFrontEnd,
801 TuiDrawRegion,
802 TuiWriteStream,
803 TuiSetCursorInfo,
804 TuiSetScreenInfo,
805 TuiResizeTerminal,
806 TuiRefreshInternalInfo,
807 TuiChangeTitle,
808 TuiChangeIcon,
809 TuiGetConsoleWindowHandle,
810 TuiGetLargestConsoleWindowSize,
811 TuiGetSelectionInfo,
812 TuiSetPalette,
813 TuiGetDisplayMode,
814 TuiSetDisplayMode,
815 TuiShowMouseCursor,
816 TuiSetMouseCursor,
817 TuiMenuControl,
818 TuiSetMenuClose,
819 };
820
821 // static BOOL
822 // DtbgIsDesktopVisible(VOID)
823 // {
824 // return !((BOOL)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE));
825 // }
826 static BOOLEAN
827 IsConsoleMode(VOID)
828 {
829 return (BOOLEAN)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE);
830 }
831
832 NTSTATUS NTAPI
833 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd,
834 IN OUT PCONSOLE_INFO ConsoleInfo,
835 IN OUT PVOID ExtraConsoleInfo,
836 IN ULONG ProcessId)
837 {
838 if (FrontEnd == NULL || ConsoleInfo == NULL)
839 return STATUS_INVALID_PARAMETER;
840
841 /* We must be in console mode already */
842 if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL;
843
844 /* Initialize the TUI terminal emulator */
845 if (!TuiInit(ConsoleInfo->CodePage)) return STATUS_UNSUCCESSFUL;
846
847 /* Finally, initialize the frontend structure */
848 FrontEnd->Vtbl = &TuiVtbl;
849 FrontEnd->Data = NULL;
850 FrontEnd->OldData = NULL;
851
852 return STATUS_SUCCESS;
853 }
854
855 NTSTATUS NTAPI
856 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd)
857 {
858 if (FrontEnd == NULL) return STATUS_INVALID_PARAMETER;
859 if (FrontEnd->Data) TuiDeinitFrontEnd(FrontEnd);
860
861 return STATUS_SUCCESS;
862 }
863
864 #endif
865
866 /* EOF */