2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/consrv/tuiconsole.c
5 * PURPOSE: Interface to text-mode consoles
10 #include "tuiconsole.h"
11 #include <drivers/blue/ntddblue.h>
17 /* TUI Console Window Class name */
18 #define TUI_CONSOLE_WINDOW_CLASS L"TuiConsoleWindowClass"
21 CRITICAL_SECTION ActiveConsoleLock
;
22 static COORD PhysicalConsoleSize
;
23 static HANDLE ConsoleDeviceHandle
;
24 static PCONSOLE ActiveConsole
;
26 static BOOL ConsInitialized
= FALSE
;
28 static LRESULT CALLBACK
29 TuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
31 if (msg
== WM_ACTIVATE
)
33 if (LOWORD(wParam
) != WA_INACTIVE
)
36 ConioDrawConsole(ActiveConsole
);
39 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
43 TuiStartService(LPCWSTR lpServiceName
)
45 SC_HANDLE hSCManager
= NULL
;
46 SC_HANDLE hService
= NULL
;
49 hSCManager
= OpenSCManagerW(NULL
, NULL
, 0);
50 if (hSCManager
== NULL
)
53 hService
= OpenServiceW(hSCManager
, lpServiceName
, SERVICE_START
);
57 ret
= StartServiceW(hService
, 0, NULL
);
64 if (hSCManager
!= NULL
)
65 CloseServiceHandle(hSCManager
);
67 CloseServiceHandle(hService
);
74 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
77 ATOM ConsoleClassAtom
;
78 USHORT TextAttribute
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
80 TuiStartService(L
"Blue");
82 ConsoleDeviceHandle
= CreateFileW(L
"\\\\.\\BlueScreen", FILE_ALL_ACCESS
, 0, NULL
,
83 OPEN_EXISTING
, 0, NULL
);
84 if (INVALID_HANDLE_VALUE
== ConsoleDeviceHandle
)
86 DPRINT1("Failed to open BlueScreen.\n");
90 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_LOADFONT
,
91 &OemCP
, sizeof(OemCP
), NULL
, 0,
92 &BytesReturned
, NULL
))
94 DPRINT1("Failed to load the font for codepage %d\n", OemCP
);
95 /* Let's suppose the font is good enough to continue */
98 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE
,
99 &TextAttribute
, sizeof(TextAttribute
), NULL
, 0,
100 &BytesReturned
, NULL
))
102 DPRINT1("Failed to set text attribute\n");
105 ActiveConsole
= NULL
;
106 InitializeCriticalSection(&ActiveConsoleLock
);
107 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
,
108 NULL
, 0, &ScrInfo
, sizeof(ScrInfo
), &BytesReturned
, NULL
))
110 DPRINT1("Failed to get console info\n");
113 PhysicalConsoleSize
= ScrInfo
.dwSize
;
115 RtlZeroMemory(&wc
, sizeof(WNDCLASSEXW
));
116 wc
.cbSize
= sizeof(WNDCLASSEXW
);
117 wc
.lpszClassName
= TUI_CONSOLE_WINDOW_CLASS
;
118 wc
.lpfnWndProc
= TuiConsoleWndProc
;
119 wc
.cbWndExtra
= GWLP_CONSOLEWND_ALLOC
;
120 wc
.hInstance
= (HINSTANCE
)GetModuleHandleW(NULL
);
122 ConsoleClassAtom
= RegisterClassExW(&wc
);
123 if (ConsoleClassAtom
== 0)
125 DPRINT1("Failed to register TUI console wndproc\n");
130 NtUserConsoleControl(TuiConsoleWndClassAtom
, &ConsoleClassAtom
, sizeof(ATOM
));
137 TuiInitScreenBuffer(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buffer
)
139 Buffer
->DefaultAttrib
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
143 TuiCopyRect(char *Dest
, PCONSOLE_SCREEN_BUFFER Buff
, SMALL_RECT
*Region
)
145 UINT SrcDelta
, DestDelta
;
149 Src
= ConioCoordToPointer(Buff
, Region
->Left
, Region
->Top
);
150 SrcDelta
= Buff
->MaxX
* 2;
151 SrcEnd
= Buff
->Buffer
+ Buff
->MaxY
* Buff
->MaxX
* 2;
152 DestDelta
= ConioRectWidth(Region
) * 2;
153 for (i
= Region
->Top
; i
<= Region
->Bottom
; i
++)
155 memcpy(Dest
, Src
, DestDelta
);
159 Src
-= Buff
->MaxY
* Buff
->MaxX
* 2;
166 TuiDrawRegion(PCONSOLE Console
, SMALL_RECT
*Region
)
169 PCONSOLE_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
170 PCONSOLE_DRAW ConsoleDraw
;
171 UINT ConsoleDrawSize
;
173 if (ActiveConsole
!= Console
)
178 ConsoleDrawSize
= sizeof(CONSOLE_DRAW
) +
179 (ConioRectWidth(Region
) * ConioRectHeight(Region
)) * 2;
180 ConsoleDraw
= HeapAlloc(ConSrvHeap
, 0, ConsoleDrawSize
);
181 if (NULL
== ConsoleDraw
)
183 DPRINT1("HeapAlloc failed\n");
186 ConsoleDraw
->X
= Region
->Left
;
187 ConsoleDraw
->Y
= Region
->Top
;
188 ConsoleDraw
->SizeX
= ConioRectWidth(Region
);
189 ConsoleDraw
->SizeY
= ConioRectHeight(Region
);
190 ConsoleDraw
->CursorX
= Buff
->CurrentX
;
191 ConsoleDraw
->CursorY
= Buff
->CurrentY
;
193 TuiCopyRect((char *) (ConsoleDraw
+ 1), Buff
, Region
);
195 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_DRAW
,
196 NULL
, 0, ConsoleDraw
, ConsoleDrawSize
, &BytesReturned
, NULL
))
198 DPRINT1("Failed to draw console\n");
199 HeapFree(ConSrvHeap
, 0, ConsoleDraw
);
203 HeapFree(ConSrvHeap
, 0, ConsoleDraw
);
207 TuiWriteStream(PCONSOLE Console
, SMALL_RECT
*Region
, LONG CursorStartX
, LONG CursorStartY
,
208 UINT ScrolledLines
, CHAR
*Buffer
, UINT Length
)
211 PCONSOLE_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
213 if (ActiveConsole
->ActiveBuffer
!= Buff
)
218 if (! WriteFile(ConsoleDeviceHandle
, Buffer
, Length
, &BytesWritten
, NULL
))
220 DPRINT1("Error writing to BlueScreen\n");
225 TuiSetCursorInfo(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
)
227 CONSOLE_CURSOR_INFO Info
;
230 if (ActiveConsole
->ActiveBuffer
!= Buff
)
235 Info
.dwSize
= ConioEffectiveCursorSize(Console
, 100);
236 Info
.bVisible
= Buff
->CursorInfo
.bVisible
;
238 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_CURSOR_INFO
,
239 &Info
, sizeof(Info
), NULL
, 0, &BytesReturned
, NULL
))
241 DPRINT1( "Failed to set cursor info\n" );
249 TuiSetScreenInfo(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
, UINT OldCursorX
, UINT OldCursorY
)
251 CONSOLE_SCREEN_BUFFER_INFO Info
;
254 if (ActiveConsole
->ActiveBuffer
!= Buff
)
259 Info
.dwCursorPosition
.X
= Buff
->CurrentX
;
260 Info
.dwCursorPosition
.Y
= Buff
->CurrentY
;
261 Info
.wAttributes
= Buff
->DefaultAttrib
;
263 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
,
264 &Info
, sizeof(CONSOLE_SCREEN_BUFFER_INFO
), NULL
, 0,
265 &BytesReturned
, NULL
))
267 DPRINT1( "Failed to set cursor position\n" );
275 TuiUpdateScreenInfo(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER Buff
)
281 TuiChangeTitle(PCONSOLE Console
)
287 TuiCleanupConsole(PCONSOLE Console
)
289 DestroyWindow(Console
->hWindow
);
291 EnterCriticalSection(&ActiveConsoleLock
);
293 /* Switch to next console */
294 if (ActiveConsole
== Console
)
296 ActiveConsole
= Console
->Next
!= Console
? Console
->Next
: NULL
;
299 if (Console
->Next
!= Console
)
301 Console
->Prev
->Next
= Console
->Next
;
302 Console
->Next
->Prev
= Console
->Prev
;
304 LeaveCriticalSection(&ActiveConsoleLock
);
306 if (NULL
!= ActiveConsole
)
308 ConioDrawConsole(ActiveConsole
);
313 TuiChangeIcon(PCONSOLE Console
, HICON hWindowIcon
)
318 static NTSTATUS WINAPI
319 TuiResizeBuffer(PCONSOLE Console
, PCONSOLE_SCREEN_BUFFER ScreenBuffer
, COORD Size
)
322 return STATUS_NOT_IMPLEMENTED
;
326 TuiConsoleThread(PVOID Data
)
328 PCONSOLE Console
= (PCONSOLE
) Data
;
332 NewWindow
= CreateWindowW(TUI_CONSOLE_WINDOW_CLASS
,
333 Console
->Title
.Buffer
,
335 -32000, -32000, 0, 0,
337 (HINSTANCE
)GetModuleHandleW(NULL
),
339 if (NULL
== NewWindow
)
341 DPRINT1("CSR: Unable to create console window\n");
344 Console
->hWindow
= NewWindow
;
345 SetConsoleWndConsoleLeaderCID(Console
);
347 SetForegroundWindow(Console
->hWindow
);
351 GetMessageW(&msg
, 0, 0, 0);
352 DispatchMessage(&msg
);
353 TranslateMessage(&msg
);
355 if (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
||
356 msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_KEYUP
||
357 msg
.message
== WM_SYSKEYDOWN
|| msg
.message
== WM_SYSKEYUP
)
359 ConioProcessKey(&msg
, Console
, TRUE
);
366 static CONSOLE_VTBL TuiVtbl
=
381 TuiInitConsole(PCONSOLE Console
)
385 if (!ConsInitialized
)
387 ConsInitialized
= TRUE
;
388 if (!TuiInit(Console
->CodePage
))
390 ConsInitialized
= FALSE
;
391 return STATUS_UNSUCCESSFUL
;
395 Console
->Vtbl
= &TuiVtbl
;
396 Console
->hWindow
= NULL
;
397 Console
->Size
= PhysicalConsoleSize
;
398 Console
->ActiveBuffer
->MaxX
= PhysicalConsoleSize
.X
;
399 Console
->ActiveBuffer
->MaxY
= PhysicalConsoleSize
.Y
;
401 ThreadHandle
= CreateThread(NULL
,
407 if (NULL
== ThreadHandle
)
409 DPRINT1("CSR: Unable to create console thread\n");
410 return STATUS_UNSUCCESSFUL
;
412 CloseHandle(ThreadHandle
);
414 EnterCriticalSection(&ActiveConsoleLock
);
415 if (NULL
!= ActiveConsole
)
417 Console
->Prev
= ActiveConsole
;
418 Console
->Next
= ActiveConsole
->Next
;
419 ActiveConsole
->Next
->Prev
= Console
;
420 ActiveConsole
->Next
= Console
;
424 Console
->Prev
= Console
;
425 Console
->Next
= Console
;
427 ActiveConsole
= Console
;
428 LeaveCriticalSection(&ActiveConsoleLock
);
430 return STATUS_SUCCESS
;
434 TuiGetFocusConsole(VOID
)
436 return ActiveConsole
;
440 TuiSwapConsole(int Next
)
442 static PCONSOLE SwapConsole
= NULL
; /* console we are thinking about swapping with */
450 /* alt-tab, swap consoles */
451 /* move SwapConsole to next console, and print its title */
452 EnterCriticalSection(&ActiveConsoleLock
);
455 SwapConsole
= ActiveConsole
;
458 SwapConsole
= (0 < Next
? SwapConsole
->Next
: SwapConsole
->Prev
);
459 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize(&SwapConsole
->Title
);
461 Buffer
= HeapAlloc(ConSrvHeap
,
463 sizeof(COORD
) + Title
.MaximumLength
);
464 pos
= (COORD
*)Buffer
;
465 Title
.Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof( COORD
));
467 RtlUnicodeStringToAnsiString(&Title
, &SwapConsole
->Title
, FALSE
);
468 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
469 pos
->X
= (PhysicalConsoleSize
.X
- Title
.Length
) / 2;
470 /* redraw the console to clear off old title */
471 ConioDrawConsole(ActiveConsole
);
472 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
473 NULL
, 0, Buffer
, sizeof(COORD
) + Title
.Length
,
474 &BytesReturned
, NULL
))
476 DPRINT1( "Error writing to console\n" );
478 HeapFree(ConSrvHeap
, 0, Buffer
);
479 LeaveCriticalSection(&ActiveConsoleLock
);
483 else if (NULL
!= SwapConsole
)
485 EnterCriticalSection(&ActiveConsoleLock
);
486 if (SwapConsole
!= ActiveConsole
)
488 /* first remove swapconsole from the list */
489 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
490 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
491 /* now insert before activeconsole */
492 SwapConsole
->Next
= ActiveConsole
;
493 SwapConsole
->Prev
= ActiveConsole
->Prev
;
494 ActiveConsole
->Prev
->Next
= SwapConsole
;
495 ActiveConsole
->Prev
= SwapConsole
;
497 ActiveConsole
= SwapConsole
;
499 ConioDrawConsole(ActiveConsole
);
500 LeaveCriticalSection(&ActiveConsoleLock
);