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>
16 CRITICAL_SECTION ActiveConsoleLock
;
17 static COORD PhysicalConsoleSize
;
18 static HANDLE ConsoleDeviceHandle
;
19 static PCSRSS_CONSOLE ActiveConsole
;
21 static BOOL ConsInitialized
= FALSE
;
23 static LRESULT CALLBACK
24 TuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
26 if (msg
== WM_ACTIVATE
)
28 if (LOWORD(wParam
) != WA_INACTIVE
)
31 ConioDrawConsole(ActiveConsole
);
34 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
38 TuiStartService(LPCWSTR lpServiceName
)
40 SC_HANDLE hSCManager
= NULL
;
41 SC_HANDLE hService
= NULL
;
44 hSCManager
= OpenSCManagerW(NULL
, NULL
, 0);
45 if (hSCManager
== NULL
)
48 hService
= OpenServiceW(hSCManager
, lpServiceName
, SERVICE_START
);
52 ret
= StartServiceW(hService
, 0, NULL
);
59 if (hSCManager
!= NULL
)
60 CloseServiceHandle(hSCManager
);
62 CloseServiceHandle(hService
);
69 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
72 USHORT TextAttribute
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
74 TuiStartService(L
"Blue");
76 ConsoleDeviceHandle
= CreateFileW(L
"\\\\.\\BlueScreen", FILE_ALL_ACCESS
, 0, NULL
,
77 OPEN_EXISTING
, 0, NULL
);
78 if (INVALID_HANDLE_VALUE
== ConsoleDeviceHandle
)
80 DPRINT1("Failed to open BlueScreen.\n");
84 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_LOADFONT
,
85 &OemCP
, sizeof(OemCP
), NULL
, 0,
86 &BytesReturned
, NULL
))
88 DPRINT1("Failed to load the font for codepage %d\n", OemCP
);
89 /* Let's suppose the font is good enough to continue */
92 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE
,
93 &TextAttribute
, sizeof(TextAttribute
), NULL
, 0,
94 &BytesReturned
, NULL
))
96 DPRINT1("Failed to set text attribute\n");
100 InitializeCriticalSection(&ActiveConsoleLock
);
101 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
,
102 NULL
, 0, &ScrInfo
, sizeof(ScrInfo
), &BytesReturned
, NULL
))
104 DPRINT1("Failed to get console info\n");
107 PhysicalConsoleSize
= ScrInfo
.dwSize
;
109 RtlZeroMemory(&wc
, sizeof(WNDCLASSEXW
));
110 wc
.cbSize
= sizeof(WNDCLASSEXW
);
111 wc
.lpszClassName
= L
"TuiConsoleWindowClass";
112 wc
.lpfnWndProc
= TuiConsoleWndProc
;
113 wc
.hInstance
= (HINSTANCE
) GetModuleHandleW(NULL
);
114 if (RegisterClassExW(&wc
) == 0)
116 DPRINT1("Failed to register console wndproc\n");
124 TuiInitScreenBuffer(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buffer
)
126 Buffer
->DefaultAttrib
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
130 TuiCopyRect(char *Dest
, PCSRSS_SCREEN_BUFFER Buff
, SMALL_RECT
*Region
)
132 UINT SrcDelta
, DestDelta
;
136 Src
= ConioCoordToPointer(Buff
, Region
->Left
, Region
->Top
);
137 SrcDelta
= Buff
->MaxX
* 2;
138 SrcEnd
= Buff
->Buffer
+ Buff
->MaxY
* Buff
->MaxX
* 2;
139 DestDelta
= ConioRectWidth(Region
) * 2;
140 for (i
= Region
->Top
; i
<= Region
->Bottom
; i
++)
142 memcpy(Dest
, Src
, DestDelta
);
146 Src
-= Buff
->MaxY
* Buff
->MaxX
* 2;
153 TuiDrawRegion(PCSRSS_CONSOLE Console
, SMALL_RECT
*Region
)
156 PCSRSS_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
157 PCONSOLE_DRAW ConsoleDraw
;
158 UINT ConsoleDrawSize
;
160 if (ActiveConsole
!= Console
)
165 ConsoleDrawSize
= sizeof(CONSOLE_DRAW
) +
166 (ConioRectWidth(Region
) * ConioRectHeight(Region
)) * 2;
167 ConsoleDraw
= HeapAlloc(ConSrvHeap
, 0, ConsoleDrawSize
);
168 if (NULL
== ConsoleDraw
)
170 DPRINT1("HeapAlloc failed\n");
173 ConsoleDraw
->X
= Region
->Left
;
174 ConsoleDraw
->Y
= Region
->Top
;
175 ConsoleDraw
->SizeX
= ConioRectWidth(Region
);
176 ConsoleDraw
->SizeY
= ConioRectHeight(Region
);
177 ConsoleDraw
->CursorX
= Buff
->CurrentX
;
178 ConsoleDraw
->CursorY
= Buff
->CurrentY
;
180 TuiCopyRect((char *) (ConsoleDraw
+ 1), Buff
, Region
);
182 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_DRAW
,
183 NULL
, 0, ConsoleDraw
, ConsoleDrawSize
, &BytesReturned
, NULL
))
185 DPRINT1("Failed to draw console\n");
186 HeapFree(ConSrvHeap
, 0, ConsoleDraw
);
190 HeapFree(ConSrvHeap
, 0, ConsoleDraw
);
194 TuiWriteStream(PCSRSS_CONSOLE Console
, SMALL_RECT
*Region
, LONG CursorStartX
, LONG CursorStartY
,
195 UINT ScrolledLines
, CHAR
*Buffer
, UINT Length
)
198 PCSRSS_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
200 if (ActiveConsole
->ActiveBuffer
!= Buff
)
205 if (! WriteFile(ConsoleDeviceHandle
, Buffer
, Length
, &BytesWritten
, NULL
))
207 DPRINT1("Error writing to BlueScreen\n");
212 TuiSetCursorInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
)
214 CONSOLE_CURSOR_INFO Info
;
217 if (ActiveConsole
->ActiveBuffer
!= Buff
)
222 Info
.dwSize
= ConioEffectiveCursorSize(Console
, 100);
223 Info
.bVisible
= Buff
->CursorInfo
.bVisible
;
225 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_CURSOR_INFO
,
226 &Info
, sizeof(Info
), NULL
, 0, &BytesReturned
, NULL
))
228 DPRINT1( "Failed to set cursor info\n" );
236 TuiSetScreenInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
, UINT OldCursorX
, UINT OldCursorY
)
238 CONSOLE_SCREEN_BUFFER_INFO Info
;
241 if (ActiveConsole
->ActiveBuffer
!= Buff
)
246 Info
.dwCursorPosition
.X
= Buff
->CurrentX
;
247 Info
.dwCursorPosition
.Y
= Buff
->CurrentY
;
248 Info
.wAttributes
= Buff
->DefaultAttrib
;
250 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
,
251 &Info
, sizeof(CONSOLE_SCREEN_BUFFER_INFO
), NULL
, 0,
252 &BytesReturned
, NULL
))
254 DPRINT1( "Failed to set cursor position\n" );
262 TuiUpdateScreenInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
)
268 TuiChangeTitle(PCSRSS_CONSOLE Console
)
274 TuiCleanupConsole(PCSRSS_CONSOLE Console
)
276 DestroyWindow(Console
->hWindow
);
278 EnterCriticalSection(&ActiveConsoleLock
);
280 /* Switch to next console */
281 if (ActiveConsole
== Console
)
283 ActiveConsole
= Console
->Next
!= Console
? Console
->Next
: NULL
;
286 if (Console
->Next
!= Console
)
288 Console
->Prev
->Next
= Console
->Next
;
289 Console
->Next
->Prev
= Console
->Prev
;
291 LeaveCriticalSection(&ActiveConsoleLock
);
293 if (NULL
!= ActiveConsole
)
295 ConioDrawConsole(ActiveConsole
);
300 TuiChangeIcon(PCSRSS_CONSOLE Console
, HICON hWindowIcon
)
305 static NTSTATUS WINAPI
306 TuiResizeBuffer(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER ScreenBuffer
, COORD Size
)
309 return STATUS_NOT_IMPLEMENTED
;
313 TuiConsoleThread(PVOID Data
)
315 PCSRSS_CONSOLE Console
= (PCSRSS_CONSOLE
) Data
;
319 NewWindow
= CreateWindowW(L
"TuiConsoleWindowClass",
320 Console
->Title
.Buffer
,
322 -32000, -32000, 0, 0,
324 (HINSTANCE
) GetModuleHandleW(NULL
),
326 Console
->hWindow
= NewWindow
;
327 if (NULL
== NewWindow
)
329 DPRINT1("CSR: Unable to create console window\n");
333 SetForegroundWindow(Console
->hWindow
);
337 GetMessageW(&msg
, 0, 0, 0);
338 DispatchMessage(&msg
);
339 TranslateMessage(&msg
);
341 if (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
||
342 msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_KEYUP
||
343 msg
.message
== WM_SYSKEYDOWN
|| msg
.message
== WM_SYSKEYUP
)
345 ConioProcessKey(&msg
, Console
, TRUE
);
352 static CSRSS_CONSOLE_VTBL TuiVtbl
=
367 TuiInitConsole(PCSRSS_CONSOLE Console
)
371 if (! ConsInitialized
)
373 ConsInitialized
= TRUE
;
374 if (! TuiInit(Console
->CodePage
))
376 ConsInitialized
= FALSE
;
377 return STATUS_UNSUCCESSFUL
;
381 Console
->Vtbl
= &TuiVtbl
;
382 Console
->hWindow
= NULL
;
383 Console
->Size
= PhysicalConsoleSize
;
384 Console
->ActiveBuffer
->MaxX
= PhysicalConsoleSize
.X
;
385 Console
->ActiveBuffer
->MaxY
= PhysicalConsoleSize
.Y
;
387 ThreadHandle
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
)TuiConsoleThread
,
389 if (NULL
== ThreadHandle
)
391 DPRINT1("CSR: Unable to create console thread\n");
392 return STATUS_UNSUCCESSFUL
;
394 CloseHandle(ThreadHandle
);
396 EnterCriticalSection(&ActiveConsoleLock
);
397 if (NULL
!= ActiveConsole
)
399 Console
->Prev
= ActiveConsole
;
400 Console
->Next
= ActiveConsole
->Next
;
401 ActiveConsole
->Next
->Prev
= Console
;
402 ActiveConsole
->Next
= Console
;
406 Console
->Prev
= Console
;
407 Console
->Next
= Console
;
409 ActiveConsole
= Console
;
410 LeaveCriticalSection(&ActiveConsoleLock
);
412 return STATUS_SUCCESS
;
415 PCSRSS_CONSOLE FASTCALL
416 TuiGetFocusConsole(VOID
)
418 return ActiveConsole
;
422 TuiSwapConsole(int Next
)
424 static PCSRSS_CONSOLE SwapConsole
= NULL
; /* console we are thinking about swapping with */
432 /* alt-tab, swap consoles */
433 /* move SwapConsole to next console, and print its title */
434 EnterCriticalSection(&ActiveConsoleLock
);
437 SwapConsole
= ActiveConsole
;
440 SwapConsole
= (0 < Next
? SwapConsole
->Next
: SwapConsole
->Prev
);
441 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize(&SwapConsole
->Title
);
443 Buffer
= HeapAlloc(ConSrvHeap
,
445 sizeof(COORD
) + Title
.MaximumLength
);
446 pos
= (COORD
*)Buffer
;
447 Title
.Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof( COORD
));
449 RtlUnicodeStringToAnsiString(&Title
, &SwapConsole
->Title
, FALSE
);
450 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
451 pos
->X
= (PhysicalConsoleSize
.X
- Title
.Length
) / 2;
452 /* redraw the console to clear off old title */
453 ConioDrawConsole(ActiveConsole
);
454 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
455 NULL
, 0, Buffer
, sizeof(COORD
) + Title
.Length
,
456 &BytesReturned
, NULL
))
458 DPRINT1( "Error writing to console\n" );
460 HeapFree(ConSrvHeap
, 0, Buffer
);
461 LeaveCriticalSection(&ActiveConsoleLock
);
465 else if (NULL
!= SwapConsole
)
467 EnterCriticalSection(&ActiveConsoleLock
);
468 if (SwapConsole
!= ActiveConsole
)
470 /* first remove swapconsole from the list */
471 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
472 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
473 /* now insert before activeconsole */
474 SwapConsole
->Next
= ActiveConsole
;
475 SwapConsole
->Prev
= ActiveConsole
->Prev
;
476 ActiveConsole
->Prev
->Next
= SwapConsole
;
477 ActiveConsole
->Prev
= SwapConsole
;
479 ActiveConsole
= SwapConsole
;
481 ConioDrawConsole(ActiveConsole
);
482 LeaveCriticalSection(&ActiveConsoleLock
);