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