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
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
12 #ifdef TUITERM_COMPILE
16 // #include "include/conio.h"
17 #include "include/console.h"
18 #include "include/settings.h"
21 #include <ndk/iofuncs.h>
22 #include <ndk/setypes.h>
23 #include <drivers/blue/ntddblue.h>
29 /* CAB FILE STRUCTURES ******************************************************/
31 typedef struct _CFHEADER
33 ULONG Signature
; // File signature 'MSCF' (CAB_SIGNATURE)
34 ULONG Reserved1
; // Reserved field
35 ULONG CabinetSize
; // Cabinet file size
36 ULONG Reserved2
; // Reserved field
37 ULONG FileTableOffset
; // Offset of first CFFILE
38 ULONG Reserved3
; // Reserved field
39 USHORT Version
; // Cabinet version (CAB_VERSION)
40 USHORT FolderCount
; // Number of folders
41 USHORT FileCount
; // Number of files
42 USHORT Flags
; // Cabinet flags (CAB_FLAG_*)
43 USHORT SetID
; // Cabinet set id
44 USHORT CabinetNumber
; // Zero-based cabinet number
45 } CFHEADER
, *PCFHEADER
;
47 typedef struct _CFFILE
49 ULONG FileSize
; // Uncompressed file size in bytes
50 ULONG FileOffset
; // Uncompressed offset of file in the folder
51 USHORT FileControlID
; // File control ID (CAB_FILE_*)
52 USHORT FileDate
; // File date stamp, as used by DOS
53 USHORT FileTime
; // File time stamp, as used by DOS
54 USHORT Attributes
; // File attributes (CAB_ATTRIB_*)
55 /* After this is the NULL terminated filename */
56 // CHAR FileName[ANYSIZE_ARRAY];
59 #define CAB_SIGNATURE 0x4643534D // "MSCF"
60 #define CAB_VERSION 0x0103
63 /* GLOBALS ******************************************************************/
65 #define ConsoleOutputUnicodeToAnsiChar(Console, dChar, sWChar) \
67 ASSERT((ULONG_PTR)(dChar) != (ULONG_PTR)(sWChar)); \
68 WideCharToMultiByte((Console)->OutputCodePage, 0, (sWChar), 1, (dChar), 1, NULL, NULL); \
71 /* TUI Console Window Class name */
72 #define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass"
74 typedef struct _TUI_CONSOLE_DATA
76 CRITICAL_SECTION Lock
;
77 LIST_ENTRY Entry
; /* Entry in the list of virtual consoles */
78 // HANDLE hTuiInitEvent;
79 // HANDLE hTuiTermEvent;
81 HWND hWindow
; /* Handle to the console's window (used for the window's procedure) */
83 PCONSRV_CONSOLE Console
; /* Pointer to the owned console */
84 PCONSOLE_SCREEN_BUFFER ActiveBuffer
; /* Pointer to the active screen buffer (then maybe the previous Console member is redundant?? Or not...) */
85 // TUI_CONSOLE_INFO TuiInfo; /* TUI terminal settings */
86 } TUI_CONSOLE_DATA
, *PTUI_CONSOLE_DATA
;
88 #define GetNextConsole(Console) \
89 CONTAINING_RECORD(Console->Entry.Flink, TUI_CONSOLE_DATA, Entry)
91 #define GetPrevConsole(Console) \
92 CONTAINING_RECORD(Console->Entry.Blink, TUI_CONSOLE_DATA, Entry)
95 /* List of the maintained virtual consoles and its lock */
96 static LIST_ENTRY VirtConsList
;
97 static PTUI_CONSOLE_DATA ActiveConsole
; /* The active console on screen */
98 static CRITICAL_SECTION ActiveVirtConsLock
;
100 static COORD PhysicalConsoleSize
;
101 static HANDLE ConsoleDeviceHandle
;
103 static BOOL ConsInitialized
= FALSE
;
105 /******************************************************************************\
106 |** BlueScreen Driver management **|
108 /* Code taken and adapted from base/system/services/driver.c */
110 ScmLoadDriver(LPCWSTR lpServiceName
)
112 NTSTATUS Status
= STATUS_SUCCESS
;
113 BOOLEAN WasPrivilegeEnabled
= FALSE
;
115 UNICODE_STRING DriverPath
;
117 /* Build the driver path */
118 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
119 pszDriverPath
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
120 (52 + wcslen(lpServiceName
) + 1) * sizeof(WCHAR
));
121 if (pszDriverPath
== NULL
)
122 return ERROR_NOT_ENOUGH_MEMORY
;
124 wcscpy(pszDriverPath
,
125 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
126 wcscat(pszDriverPath
,
129 RtlInitUnicodeString(&DriverPath
,
132 DPRINT(" Path: %wZ\n", &DriverPath
);
134 /* Acquire driver-loading privilege */
135 Status
= RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE
,
138 &WasPrivilegeEnabled
);
139 if (!NT_SUCCESS(Status
))
141 /* We encountered a failure, exit properly */
142 DPRINT1("CONSRV: Cannot acquire driver-loading privilege, Status = 0x%08lx\n", Status
);
146 Status
= NtLoadDriver(&DriverPath
);
148 /* Release driver-loading privilege */
149 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE
,
152 &WasPrivilegeEnabled
);
155 ConsoleFreeHeap(pszDriverPath
);
156 return RtlNtStatusToDosError(Status
);
159 #ifdef BLUESCREEN_DRIVER_UNLOADING
161 ScmUnloadDriver(LPCWSTR lpServiceName
)
163 NTSTATUS Status
= STATUS_SUCCESS
;
164 BOOLEAN WasPrivilegeEnabled
= FALSE
;
166 UNICODE_STRING DriverPath
;
168 /* Build the driver path */
169 /* 52 = wcslen(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") */
170 pszDriverPath
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
,
171 (52 + wcslen(lpServiceName
) + 1) * sizeof(WCHAR
));
172 if (pszDriverPath
== NULL
)
173 return ERROR_NOT_ENOUGH_MEMORY
;
175 wcscpy(pszDriverPath
,
176 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
177 wcscat(pszDriverPath
,
180 RtlInitUnicodeString(&DriverPath
,
183 DPRINT(" Path: %wZ\n", &DriverPath
);
185 /* Acquire driver-unloading privilege */
186 Status
= RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE
,
189 &WasPrivilegeEnabled
);
190 if (!NT_SUCCESS(Status
))
192 /* We encountered a failure, exit properly */
193 DPRINT1("CONSRV: Cannot acquire driver-unloading privilege, Status = 0x%08lx\n", Status
);
197 Status
= NtUnloadDriver(&DriverPath
);
199 /* Release driver-unloading privilege */
200 RtlAdjustPrivilege(SE_LOAD_DRIVER_PRIVILEGE
,
203 &WasPrivilegeEnabled
);
206 ConsoleFreeHeap(pszDriverPath
);
207 return RtlNtStatusToDosError(Status
);
211 \******************************************************************************/
215 TuiSwapConsole(INT Next
)
217 static PTUI_CONSOLE_DATA SwapConsole
= NULL
; /* Console we are thinking about swapping with */
226 * Alt-Tab, swap consoles.
227 * move SwapConsole to next console, and print its title.
229 EnterCriticalSection(&ActiveVirtConsLock
);
230 if (!SwapConsole
) SwapConsole
= ActiveConsole
;
232 SwapConsole
= (0 < Next
? GetNextConsole(SwapConsole
) : GetPrevConsole(SwapConsole
));
233 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize(&SwapConsole
->Console
->Title
);
235 Buffer
= ConsoleAllocHeap(0, sizeof(COORD
) + Title
.MaximumLength
);
236 pos
= (PCOORD
)Buffer
;
237 Title
.Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof(COORD
));
239 RtlUnicodeStringToAnsiString(&Title
, &SwapConsole
->Console
->Title
, FALSE
);
240 pos
->X
= (PhysicalConsoleSize
.X
- Title
.Length
) / 2;
241 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
242 /* Redraw the console to clear off old title */
243 ConioDrawConsole(ActiveConsole
->Console
);
244 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
245 NULL
, 0, Buffer
, sizeof(COORD
) + Title
.Length
,
246 &BytesReturned
, NULL
))
248 DPRINT1( "Error writing to console\n" );
250 ConsoleFreeHeap(Buffer
);
251 LeaveCriticalSection(&ActiveVirtConsLock
);
255 else if (NULL
!= SwapConsole
)
257 EnterCriticalSection(&ActiveVirtConsLock
);
258 if (SwapConsole
!= ActiveConsole
)
260 /* First remove swapconsole from the list */
261 SwapConsole
->Entry
.Blink
->Flink
= SwapConsole
->Entry
.Flink
;
262 SwapConsole
->Entry
.Flink
->Blink
= SwapConsole
->Entry
.Blink
;
263 /* Now insert before activeconsole */
264 SwapConsole
->Entry
.Flink
= &ActiveConsole
->Entry
;
265 SwapConsole
->Entry
.Blink
= ActiveConsole
->Entry
.Blink
;
266 ActiveConsole
->Entry
.Blink
->Flink
= &SwapConsole
->Entry
;
267 ActiveConsole
->Entry
.Blink
= &SwapConsole
->Entry
;
269 ActiveConsole
= SwapConsole
;
271 ConioDrawConsole(ActiveConsole
->Console
);
272 LeaveCriticalSection(&ActiveVirtConsLock
);
283 TuiCopyRect(PCHAR Dest
, PTEXTMODE_SCREEN_BUFFER Buff
, SMALL_RECT
* Region
)
285 UINT SrcDelta
, DestDelta
;
287 PCHAR_INFO Src
, SrcEnd
;
289 Src
= ConioCoordToPointer(Buff
, Region
->Left
, Region
->Top
);
290 SrcDelta
= Buff
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
);
291 SrcEnd
= Buff
->Buffer
+ Buff
->ScreenBufferSize
.Y
* Buff
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
);
292 DestDelta
= ConioRectWidth(Region
) * 2 /* 2 == sizeof(CHAR) + sizeof(BYTE) */;
293 for (i
= Region
->Top
; i
<= Region
->Bottom
; i
++)
295 ConsoleOutputUnicodeToAnsiChar(Buff
->Header
.Console
, (PCHAR
)Dest
, &Src
->Char
.UnicodeChar
);
296 *(PBYTE
)(Dest
+ 1) = (BYTE
)Src
->Attributes
;
301 Src
-= Buff
->ScreenBufferSize
.Y
* Buff
->ScreenBufferSize
.X
* sizeof(CHAR_INFO
);
307 static LRESULT CALLBACK
308 TuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
311 PTUI_CONSOLE_DATA TuiData = NULL;
312 PCONSRV_CONSOLE Console = NULL;
314 TuiData = TuiGetGuiData(hWnd);
315 if (TuiData == NULL) return 0;
328 if ((HIWORD(lParam
) & KF_ALTDOWN
) && wParam
== VK_TAB
)
330 // if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT)
331 TuiSwapConsole(ShiftState
& SHIFT_PRESSED
? -1 : 1);
335 else if (wParam
== VK_MENU
/* && !Down */)
342 if (ConDrvValidateConsoleUnsafe((PCONSOLE
)ActiveConsole
->Console
, CONSOLE_RUNNING
, TRUE
))
346 Message
.message
= msg
;
347 Message
.wParam
= wParam
;
348 Message
.lParam
= lParam
;
350 ConioProcessKey(ActiveConsole
->Console
, &Message
);
351 LeaveCriticalSection(&ActiveConsole
->Console
->Lock
);
358 if (ConDrvValidateConsoleUnsafe((PCONSOLE
)ActiveConsole
->Console
, CONSOLE_RUNNING
, TRUE
))
360 if (LOWORD(wParam
) != WA_INACTIVE
)
363 ConioDrawConsole(ActiveConsole
->Console
);
365 LeaveCriticalSection(&ActiveConsole
->Console
->Lock
);
374 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
378 TuiConsoleThread(PVOID Param
)
380 PTUI_CONSOLE_DATA TuiData
= (PTUI_CONSOLE_DATA
)Param
;
381 PCONSRV_CONSOLE Console
= TuiData
->Console
;
385 NewWindow
= CreateWindowW(TUI_CONSOLE_WINDOW_CLASS
,
386 Console
->Title
.Buffer
,
388 -32000, -32000, 0, 0,
392 if (NULL
== NewWindow
)
394 DPRINT1("CONSRV: Unable to create console window\n");
397 TuiData
->hWindow
= NewWindow
;
399 SetForegroundWindow(TuiData
->hWindow
);
400 NtUserConsoleControl(ConsoleAcquireDisplayOwnership
, NULL
, 0);
402 while (GetMessageW(&msg
, NULL
, 0, 0))
404 TranslateMessage(&msg
);
405 DispatchMessageW(&msg
);
412 TuiSetConsoleOutputCP(
413 IN HANDLE hNtConddHandle
,
416 static UINT LastLoadedCodepage
= 0;
417 UNICODE_STRING FontFile
= RTL_CONSTANT_STRING(L
"\\SystemRoot\\vgafonts.cab");
422 OBJECT_ATTRIBUTES ObjectAttributes
;
423 IO_STATUS_BLOCK IoStatusBlock
;
425 PUCHAR FontBitField
= NULL
;
427 /* CAB-specific data */
428 HANDLE FileSectionHandle
;
429 PUCHAR FileBuffer
= NULL
;
431 PCFHEADER CabFileHeader
;
437 PCFFILE FoundFile
= NULL
;
441 if (CodePage
== LastLoadedCodepage
)
445 * Open the *uncompressed* fonts archive file.
447 InitializeObjectAttributes(&ObjectAttributes
,
449 OBJ_CASE_INSENSITIVE
,
453 Status
= NtOpenFile(&FileHandle
,
454 GENERIC_READ
| SYNCHRONIZE
,
458 FILE_SYNCHRONOUS_IO_NONALERT
);
459 if (!NT_SUCCESS(Status
))
461 DPRINT1("Error: Cannot open '%wZ' (0x%lx)\n", &FontFile
, Status
);
468 Status
= NtCreateSection(&FileSectionHandle
,
474 if (!NT_SUCCESS(Status
))
476 DPRINT1("NtCreateSection failed (0x%lx)\n", Status
);
480 Status
= NtMapViewOfSection(FileSectionHandle
,
488 if (!NT_SUCCESS(Status
))
490 DPRINT1("NtMapViewOfSection failed (0x%lx)\n", Status
);
494 /* Wrap in SEH to protect against ill-formed file */
497 DPRINT("Cabinet file '%wZ' opened and mapped to 0x%p\n",
498 &FontFile
, FileBuffer
);
500 CabFileHeader
= (PCFHEADER
)FileBuffer
;
502 /* Validate the CAB file */
503 if (FileSize
<= sizeof(CFHEADER
) ||
504 CabFileHeader
->Signature
!= CAB_SIGNATURE
||
505 CabFileHeader
->Version
!= CAB_VERSION
||
506 CabFileHeader
->FolderCount
== 0 ||
507 CabFileHeader
->FileCount
== 0 ||
508 CabFileHeader
->FileTableOffset
< sizeof(CFHEADER
))
510 DPRINT1("Cabinet file '%wZ' has an invalid header\n", &FontFile
);
511 Status
= STATUS_UNSUCCESSFUL
;
512 _SEH2_YIELD(goto Exit
);
516 * Find the font file within the archive.
518 RtlStringCbPrintfA(FontName
, sizeof(FontName
),
519 "%u-8x8.bin", CodePage
);
521 /* Read the file table, find the file of interest and the end of the table */
522 Data
.CabFile
= (PCFFILE
)(FileBuffer
+ CabFileHeader
->FileTableOffset
);
523 for (Index
= 0; Index
< CabFileHeader
->FileCount
; ++Index
)
525 FileName
= (PSTR
)(Data
.CabFile
+ 1);
529 // Status = RtlCharToInteger(FileName, 0, &ReadCP);
530 // if (NT_SUCCESS(Status) && (ReadCP == CodePage))
531 if (_stricmp(FontName
, FileName
) == 0)
533 /* We've got the correct file. Save the offset and
534 * loop through the rest of the file table to find
535 * the position, where the actual data starts. */
536 FoundFile
= Data
.CabFile
;
540 /* Move to the next file (go past the filename NULL terminator) */
541 Data
.CabFile
= (PCFFILE
)(strchr(FileName
, 0) + 1);
546 DPRINT("File '%S' not found in cabinet '%wZ'\n",
547 FontName
, &FontFile
);
548 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
549 _SEH2_YIELD(goto Exit
);
553 * Extract the font file.
555 /* Verify the font file size; we only support a fixed 256-char 8-bit font */
556 if (FoundFile
->FileSize
!= 256 * 8)
558 DPRINT1("File of size %lu is not of the expected size %lu\n",
559 FoundFile
->FileSize
, 256 * 8);
560 Status
= STATUS_INVALID_BUFFER_SIZE
;
561 _SEH2_YIELD(goto Exit
);
564 FontBitField
= RtlAllocateHeap(RtlGetProcessHeap(), 0, FoundFile
->FileSize
);
567 DPRINT1("ExAllocatePoolWithTag(%lu) failed\n", FoundFile
->FileSize
);
568 Status
= STATUS_NO_MEMORY
;
569 _SEH2_YIELD(goto Exit
);
572 /* 8 = Size of a CFFOLDER structure (see cabman). As we don't need
573 * the values of that structure, just increase the offset here. */
574 Data
.Buffer
= (PVOID
)((ULONG_PTR
)Data
.Buffer
+ 8); // sizeof(CFFOLDER);
575 Data
.Buffer
= (PVOID
)((ULONG_PTR
)Data
.Buffer
+ FoundFile
->FileOffset
);
577 /* Data.Buffer now points to the actual data of the RAW font */
578 RtlCopyMemory(FontBitField
, Data
.Buffer
, FoundFile
->FileSize
);
579 Status
= STATUS_SUCCESS
;
581 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
583 Status
= _SEH2_GetExceptionCode();
584 DPRINT1("TuiSetConsoleOutputCP - Caught an exception, Status = 0x%08lx\n", Status
);
591 if (NT_SUCCESS(Status
))
594 ASSERT(FontBitField
);
595 Status
= NtDeviceIoControlFile(hNtConddHandle
,
600 IOCTL_CONSOLE_LOADFONT
,
608 RtlFreeHeap(RtlGetProcessHeap(), 0, FontBitField
);
612 NtUnmapViewOfSection(NtCurrentProcess(), FileBuffer
);
614 if (FileSectionHandle
)
615 NtClose(FileSectionHandle
);
619 if (NT_SUCCESS(Status
))
620 LastLoadedCodepage
= CodePage
;
622 return NT_SUCCESS(Status
);
626 TuiInit(IN UINT OemCP
)
629 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
632 ATOM ConsoleClassAtom
;
633 USHORT TextAttribute
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
635 /* Exit if we were already initialized */
636 if (ConsInitialized
) return TRUE
;
639 * Initialize the TUI front-end:
640 * - load the console driver,
641 * - open BlueScreen device and enable it,
642 * - set default screen attributes,
643 * - grab the console size.
645 ScmLoadDriver(L
"Blue");
647 ConsoleDeviceHandle
= CreateFileW(L
"\\\\.\\BlueScreen",
652 if (ConsoleDeviceHandle
== INVALID_HANDLE_VALUE
)
654 DPRINT1("Failed to open BlueScreen.\n");
659 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_RESET_SCREEN
,
660 &Success
, sizeof(Success
), NULL
, 0,
661 &BytesReturned
, NULL
))
663 DPRINT1("Failed to enable the screen.\n");
664 CloseHandle(ConsoleDeviceHandle
);
668 if (!TuiSetConsoleOutputCP(ConsoleDeviceHandle
, OemCP
))
670 DPRINT1("Failed to load the font for codepage %d\n", OemCP
);
671 /* Let's suppose the font is good enough to continue */
674 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE
,
675 &TextAttribute
, sizeof(TextAttribute
), NULL
, 0,
676 &BytesReturned
, NULL
))
678 DPRINT1("Failed to set text attribute.\n");
681 ActiveConsole
= NULL
;
682 InitializeListHead(&VirtConsList
);
683 InitializeCriticalSection(&ActiveVirtConsLock
);
685 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
,
686 NULL
, 0, &ScrInfo
, sizeof(ScrInfo
), &BytesReturned
, NULL
))
688 DPRINT1("Failed to get console info.\n");
692 PhysicalConsoleSize
= ScrInfo
.dwSize
;
694 /* Register the TUI notification window class */
695 RtlZeroMemory(&wc
, sizeof(WNDCLASSEXW
));
696 wc
.cbSize
= sizeof(WNDCLASSEXW
);
697 wc
.lpszClassName
= TUI_CONSOLE_WINDOW_CLASS
;
698 wc
.lpfnWndProc
= TuiConsoleWndProc
;
700 wc
.hInstance
= ConSrvDllInstance
;
702 ConsoleClassAtom
= RegisterClassExW(&wc
);
703 if (ConsoleClassAtom
== 0)
705 DPRINT1("Failed to register TUI console wndproc.\n");
716 DeleteCriticalSection(&ActiveVirtConsLock
);
717 CloseHandle(ConsoleDeviceHandle
);
720 ConsInitialized
= Success
;
726 /******************************************************************************
727 * TUI Console Driver *
728 ******************************************************************************/
731 TuiDeinitFrontEnd(IN OUT PFRONTEND This
/*,
732 IN PCONSRV_CONSOLE Console */);
734 static NTSTATUS NTAPI
735 TuiInitFrontEnd(IN OUT PFRONTEND This
,
736 IN PCONSRV_CONSOLE Console
)
738 PTUI_CONSOLE_DATA TuiData
;
741 if (This
== NULL
|| Console
== NULL
)
742 return STATUS_INVALID_PARAMETER
;
744 if (GetType(Console
->ActiveBuffer
) != TEXTMODE_BUFFER
)
745 return STATUS_INVALID_PARAMETER
;
747 TuiData
= ConsoleAllocHeap(HEAP_ZERO_MEMORY
, sizeof(TUI_CONSOLE_DATA
));
750 DPRINT1("CONSRV: Failed to create TUI_CONSOLE_DATA\n");
751 return STATUS_UNSUCCESSFUL
;
753 // Console->FrontEndIFace.Context = (PVOID)TuiData;
754 TuiData
->Console
= Console
;
755 TuiData
->ActiveBuffer
= Console
->ActiveBuffer
;
756 TuiData
->hWindow
= NULL
;
758 InitializeCriticalSection(&TuiData
->Lock
);
761 * HACK: Resize the console since we don't support for now changing
762 * the console size when we display it with the hardware.
764 // Console->ConsoleSize = PhysicalConsoleSize;
765 // ConioResizeBuffer(Console, (PTEXTMODE_SCREEN_BUFFER)(Console->ActiveBuffer), PhysicalConsoleSize);
767 // /* The console cannot be resized anymore */
768 // Console->FixedSize = TRUE; // MUST be placed AFTER the call to ConioResizeBuffer !!
769 // // TermResizeTerminal(Console);
772 * Contrary to what we do in the GUI front-end, here we create
773 * an input thread for each console. It will dispatch all the
774 * input messages to the proper console (on the GUI it is done
775 * via the default GUI dispatch thread).
777 ThreadHandle
= CreateThread(NULL
,
783 if (NULL
== ThreadHandle
)
785 DPRINT1("CONSRV: Unable to create console thread\n");
786 // TuiDeinitFrontEnd(Console);
787 TuiDeinitFrontEnd(This
);
788 return STATUS_UNSUCCESSFUL
;
790 CloseHandle(ThreadHandle
);
793 * Insert the newly created console in the list of virtual consoles
794 * and activate it (give it the focus).
796 EnterCriticalSection(&ActiveVirtConsLock
);
797 InsertTailList(&VirtConsList
, &TuiData
->Entry
);
798 ActiveConsole
= TuiData
;
799 LeaveCriticalSection(&ActiveVirtConsLock
);
801 /* Finally, initialize the frontend structure */
802 This
->Context
= TuiData
;
803 This
->Context2
= NULL
;
805 return STATUS_SUCCESS
;
809 TuiDeinitFrontEnd(IN OUT PFRONTEND This
)
811 // PCONSRV_CONSOLE Console = This->Console;
812 PTUI_CONSOLE_DATA TuiData
= This
->Context
;
814 /* Close the notification window */
815 DestroyWindow(TuiData
->hWindow
);
818 * Set the active console to the next one
819 * and remove the console from the list.
821 EnterCriticalSection(&ActiveVirtConsLock
);
822 ActiveConsole
= GetNextConsole(TuiData
);
823 RemoveEntryList(&TuiData
->Entry
);
825 // /* Switch to next console */
826 // if (ActiveConsole == TuiData)
827 // if (ActiveConsole->Console == Console)
829 // ActiveConsole = (TuiData->Entry.Flink != TuiData->Entry ? GetNextConsole(TuiData) : NULL);
832 // if (GetNextConsole(TuiData) != TuiData)
834 // TuiData->Entry.Blink->Flink = TuiData->Entry.Flink;
835 // TuiData->Entry.Flink->Blink = TuiData->Entry.Blink;
838 LeaveCriticalSection(&ActiveVirtConsLock
);
840 /* Switch to the next console */
841 if (NULL
!= ActiveConsole
) ConioDrawConsole(ActiveConsole
->Console
);
843 This
->Context
= NULL
;
844 DeleteCriticalSection(&TuiData
->Lock
);
845 ConsoleFreeHeap(TuiData
);
849 TuiDrawRegion(IN OUT PFRONTEND This
,
852 PTUI_CONSOLE_DATA TuiData
= This
->Context
;
853 PCONSOLE_SCREEN_BUFFER Buff
= TuiData
->Console
->ActiveBuffer
;
854 PCONSOLE_DRAW ConsoleDraw
;
856 UINT ConsoleDrawSize
;
858 if (TuiData
!= ActiveConsole
) return;
859 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
861 ConsoleDrawSize
= sizeof(CONSOLE_DRAW
) +
862 (ConioRectWidth(Region
) * ConioRectHeight(Region
)) * 2;
863 ConsoleDraw
= ConsoleAllocHeap(0, ConsoleDrawSize
);
864 if (NULL
== ConsoleDraw
)
866 DPRINT1("ConsoleAllocHeap failed\n");
869 ConsoleDraw
->X
= Region
->Left
;
870 ConsoleDraw
->Y
= Region
->Top
;
871 ConsoleDraw
->SizeX
= ConioRectWidth(Region
);
872 ConsoleDraw
->SizeY
= ConioRectHeight(Region
);
873 ConsoleDraw
->CursorX
= Buff
->CursorPosition
.X
;
874 ConsoleDraw
->CursorY
= Buff
->CursorPosition
.Y
;
876 TuiCopyRect((PCHAR
)(ConsoleDraw
+ 1), (PTEXTMODE_SCREEN_BUFFER
)Buff
, Region
);
878 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_DRAW
,
879 NULL
, 0, ConsoleDraw
, ConsoleDrawSize
, &BytesReturned
, NULL
))
881 DPRINT1("Failed to draw console\n");
882 ConsoleFreeHeap(ConsoleDraw
);
886 ConsoleFreeHeap(ConsoleDraw
);
890 TuiWriteStream(IN OUT PFRONTEND This
,
898 PTUI_CONSOLE_DATA TuiData
= This
->Context
;
899 PCONSOLE_SCREEN_BUFFER Buff
= TuiData
->Console
->ActiveBuffer
;
904 if (TuiData
!= ActiveConsole
) return;
905 if (GetType(Buff
) != TEXTMODE_BUFFER
) return;
907 NewLength
= WideCharToMultiByte(TuiData
->Console
->OutputCodePage
, 0,
909 NULL
, 0, NULL
, NULL
);
910 NewBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, NewLength
* sizeof(CHAR
));
911 if (!NewBuffer
) return;
913 WideCharToMultiByte(TuiData
->Console
->OutputCodePage
, 0,
915 NewBuffer
, NewLength
, NULL
, NULL
);
917 if (!WriteFile(ConsoleDeviceHandle
, NewBuffer
, NewLength
* sizeof(CHAR
), &BytesWritten
, NULL
))
919 DPRINT1("Error writing to BlueScreen\n");
922 RtlFreeHeap(RtlGetProcessHeap(), 0, NewBuffer
);
926 TuiRingBell(IN OUT PFRONTEND This
)
932 TuiSetCursorInfo(IN OUT PFRONTEND This
,
933 PCONSOLE_SCREEN_BUFFER Buff
)
935 PTUI_CONSOLE_DATA TuiData
= This
->Context
;
936 CONSOLE_CURSOR_INFO Info
;
939 if (TuiData
!= ActiveConsole
) return TRUE
;
940 if (TuiData
->Console
->ActiveBuffer
!= Buff
) return TRUE
;
941 if (GetType(Buff
) != TEXTMODE_BUFFER
) return FALSE
;
943 Info
.dwSize
= ConioEffectiveCursorSize(TuiData
->Console
, 100);
944 Info
.bVisible
= Buff
->CursorInfo
.bVisible
;
946 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_CURSOR_INFO
,
947 &Info
, sizeof(Info
), NULL
, 0, &BytesReturned
, NULL
))
949 DPRINT1( "Failed to set cursor info\n" );
957 TuiSetScreenInfo(IN OUT PFRONTEND This
,
958 PCONSOLE_SCREEN_BUFFER Buff
,
962 PTUI_CONSOLE_DATA TuiData
= This
->Context
;
963 CONSOLE_SCREEN_BUFFER_INFO Info
;
966 if (TuiData
!= ActiveConsole
) return TRUE
;
967 if (TuiData
->Console
->ActiveBuffer
!= Buff
) return TRUE
;
968 if (GetType(Buff
) != TEXTMODE_BUFFER
) return FALSE
;
970 Info
.dwCursorPosition
= Buff
->CursorPosition
;
971 Info
.wAttributes
= ((PTEXTMODE_SCREEN_BUFFER
)Buff
)->ScreenDefaultAttrib
;
973 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
,
974 &Info
, sizeof(CONSOLE_SCREEN_BUFFER_INFO
), NULL
, 0,
975 &BytesReturned
, NULL
))
977 DPRINT1( "Failed to set cursor position\n" );
985 TuiResizeTerminal(IN OUT PFRONTEND This
)
990 TuiSetActiveScreenBuffer(IN OUT PFRONTEND This
)
992 // PGUI_CONSOLE_DATA GuiData = This->Context;
993 // PCONSOLE_SCREEN_BUFFER ActiveBuffer;
994 // HPALETTE hPalette;
996 // EnterCriticalSection(&GuiData->Lock);
997 // GuiData->WindowSizeLock = TRUE;
999 // InterlockedExchangePointer(&GuiData->ActiveBuffer,
1000 // ConDrvGetActiveScreenBuffer(GuiData->Console));
1002 // GuiData->WindowSizeLock = FALSE;
1003 // LeaveCriticalSection(&GuiData->Lock);
1005 // ActiveBuffer = GuiData->ActiveBuffer;
1007 // /* Change the current palette */
1008 // if (ActiveBuffer->PaletteHandle == NULL)
1010 // hPalette = GuiData->hSysPalette;
1014 // hPalette = ActiveBuffer->PaletteHandle;
1017 // DPRINT("GuiSetActiveScreenBuffer using palette 0x%p\n", hPalette);
1019 // /* Set the new palette for the framebuffer */
1020 // SelectPalette(GuiData->hMemDC, hPalette, FALSE);
1022 // /* Specify the use of the system palette for the framebuffer */
1023 // SetSystemPaletteUse(GuiData->hMemDC, ActiveBuffer->PaletteUsage);
1025 // /* Realize the (logical) palette */
1026 // RealizePalette(GuiData->hMemDC);
1028 // GuiResizeTerminal(This);
1029 // // ConioDrawConsole(Console);
1033 TuiReleaseScreenBuffer(IN OUT PFRONTEND This
,
1034 IN PCONSOLE_SCREEN_BUFFER ScreenBuffer
)
1036 // PGUI_CONSOLE_DATA GuiData = This->Context;
1039 // * If we were notified to release a screen buffer that is not actually
1040 // * ours, then just ignore the notification...
1042 // if (ScreenBuffer != GuiData->ActiveBuffer) return;
1045 // * ... else, we must release our active buffer. Two cases are present:
1046 // * - If ScreenBuffer (== GuiData->ActiveBuffer) IS NOT the console
1047 // * active screen buffer, then we can safely switch to it.
1048 // * - If ScreenBuffer IS the console active screen buffer, we must release
1052 // /* Release the old active palette and set the default one */
1053 // if (GetCurrentObject(GuiData->hMemDC, OBJ_PAL) == ScreenBuffer->PaletteHandle)
1055 // /* Set the new palette */
1056 // SelectPalette(GuiData->hMemDC, GuiData->hSysPalette, FALSE);
1059 // /* Set the adequate active screen buffer */
1060 // if (ScreenBuffer != GuiData->Console->ActiveBuffer)
1062 // GuiSetActiveScreenBuffer(This);
1066 // EnterCriticalSection(&GuiData->Lock);
1067 // GuiData->WindowSizeLock = TRUE;
1069 // InterlockedExchangePointer(&GuiData->ActiveBuffer, NULL);
1071 // GuiData->WindowSizeLock = FALSE;
1072 // LeaveCriticalSection(&GuiData->Lock);
1077 TuiRefreshInternalInfo(IN OUT PFRONTEND This
)
1082 TuiChangeTitle(IN OUT PFRONTEND This
)
1087 TuiChangeIcon(IN OUT PFRONTEND This
,
1094 TuiGetThreadConsoleDesktop(IN OUT PFRONTEND This
)
1096 // PTUI_CONSOLE_DATA TuiData = This->Context;
1101 TuiGetConsoleWindowHandle(IN OUT PFRONTEND This
)
1103 PTUI_CONSOLE_DATA TuiData
= This
->Context
;
1104 return TuiData
->hWindow
;
1108 TuiGetLargestConsoleWindowSize(IN OUT PFRONTEND This
,
1112 *pSize
= PhysicalConsoleSize
;
1116 TuiGetSelectionInfo(IN OUT PFRONTEND This
,
1117 PCONSOLE_SELECTION_INFO pSelectionInfo
)
1123 TuiSetPalette(IN OUT PFRONTEND This
,
1124 HPALETTE PaletteHandle
,
1131 TuiSetCodePage(IN OUT PFRONTEND This
,
1134 // PTUI_CONSOLE_DATA TuiData = This->Context;
1136 // TODO: Verify that the console is the visible one.
1137 // Only then can we change the output code page font.
1139 if (!TuiSetConsoleOutputCP(ConsoleDeviceHandle
, CodePage
))
1141 DPRINT1("Failed to load the font for codepage %d\n", CodePage
);
1142 /* Let's suppose the font is good enough to continue */
1150 TuiGetDisplayMode(IN OUT PFRONTEND This
)
1152 return CONSOLE_FULLSCREEN_HARDWARE
; // CONSOLE_FULLSCREEN;
1156 TuiSetDisplayMode(IN OUT PFRONTEND This
,
1159 // if (NewMode & ~(CONSOLE_FULLSCREEN_MODE | CONSOLE_WINDOWED_MODE))
1165 TuiShowMouseCursor(IN OUT PFRONTEND This
,
1172 TuiSetMouseCursor(IN OUT PFRONTEND This
,
1173 HCURSOR CursorHandle
)
1179 TuiMenuControl(IN OUT PFRONTEND This
,
1187 TuiSetMenuClose(IN OUT PFRONTEND This
,
1193 static FRONTEND_VTBL TuiVtbl
=
1203 TuiSetActiveScreenBuffer
,
1204 TuiReleaseScreenBuffer
,
1205 TuiRefreshInternalInfo
,
1208 TuiGetThreadConsoleDesktop
,
1209 TuiGetConsoleWindowHandle
,
1210 TuiGetLargestConsoleWindowSize
,
1211 TuiGetSelectionInfo
,
1225 return (BOOLEAN
)NtUserCallNoParam(NOPARAM_ROUTINE_ISCONSOLEMODE
);
1229 TuiLoadFrontEnd(IN OUT PFRONTEND FrontEnd
,
1230 IN OUT PCONSOLE_STATE_INFO ConsoleInfo
,
1231 IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo
,
1232 IN HANDLE ConsoleLeaderProcessHandle
)
1234 if (FrontEnd
== NULL
|| ConsoleInfo
== NULL
)
1235 return STATUS_INVALID_PARAMETER
;
1237 /* We must be in console mode already */
1238 if (!IsConsoleMode()) return STATUS_UNSUCCESSFUL
;
1240 /* Initialize the TUI terminal emulator */
1241 if (!TuiInit(ConsoleInfo
->CodePage
)) return STATUS_UNSUCCESSFUL
;
1243 /* Finally, initialize the frontend structure */
1244 FrontEnd
->Vtbl
= &TuiVtbl
;
1245 FrontEnd
->Context
= NULL
;
1246 FrontEnd
->Context2
= NULL
;
1248 return STATUS_SUCCESS
;
1252 TuiUnloadFrontEnd(IN OUT PFRONTEND FrontEnd
)
1254 if (FrontEnd
== NULL
) return STATUS_INVALID_PARAMETER
;
1255 if (FrontEnd
->Context
) TuiDeinitFrontEnd(FrontEnd
);
1257 return STATUS_SUCCESS
;