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