3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: subsys/csrss/win32csr/tuiconsole.c
6 * PURPOSE: Implementation of text-mode consoles
14 CRITICAL_SECTION ActiveConsoleLock
;
15 static COORD PhysicalConsoleSize
;
16 static HANDLE ConsoleDeviceHandle
;
17 static PCSRSS_CONSOLE ActiveConsole
;
19 static BOOL ConsInitialized
= FALSE
;
21 static LRESULT CALLBACK
22 TuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
24 if (msg
== WM_ACTIVATE
)
27 if (LOWORD(wParam
) != WA_INACTIVE
)
31 ConioDrawConsole(ActiveConsole
);
34 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
40 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
44 ConsoleDeviceHandle
= CreateFileW(L
"\\\\.\\BlueScreen", FILE_ALL_ACCESS
, 0, NULL
,
45 OPEN_EXISTING
, 0, NULL
);
46 if (INVALID_HANDLE_VALUE
== ConsoleDeviceHandle
)
48 DPRINT1("Failed to open BlueScreen.\n");
53 InitializeCriticalSection(&ActiveConsoleLock
);
54 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
,
55 NULL
, 0, &ScrInfo
, sizeof(ScrInfo
), &BytesReturned
, NULL
))
57 DPRINT1("Failed to get console info\n");
60 PhysicalConsoleSize
= ScrInfo
.dwSize
;
62 RtlZeroMemory(&wc
, sizeof(WNDCLASSEXW
));
63 wc
.cbSize
= sizeof(WNDCLASSEXW
);
64 wc
.lpszClassName
= L
"TuiConsoleWindowClass";
65 wc
.lpfnWndProc
= TuiConsoleWndProc
;
66 wc
.hInstance
= (HINSTANCE
) GetModuleHandleW(NULL
);
67 if (RegisterClassExW(&wc
) == 0)
69 DPRINT1("Failed to register console wndproc\n");
77 TuiInitScreenBuffer(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buffer
)
79 Buffer
->DefaultAttrib
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
| BACKGROUND_BLUE
;
83 TuiCopyRect(char *Dest
, PCSRSS_SCREEN_BUFFER Buff
, RECT
*Region
)
85 UINT SrcDelta
, DestDelta
;
89 Src
= Buff
->Buffer
+ (((Region
->top
+ Buff
->ShowY
) % Buff
->MaxY
) * Buff
->MaxX
90 + Region
->left
+ Buff
->ShowX
) * 2;
91 SrcDelta
= Buff
->MaxX
* 2;
92 SrcEnd
= Buff
->Buffer
+ Buff
->MaxY
* Buff
->MaxX
* 2;
93 DestDelta
= ConioRectWidth(Region
) * 2;
94 for (i
= Region
->top
; i
<= Region
->bottom
; i
++)
96 memcpy(Dest
, Src
, DestDelta
);
100 Src
-= Buff
->MaxY
* Buff
->MaxX
* 2;
107 TuiDrawRegion(PCSRSS_CONSOLE Console
, RECT
*Region
)
110 PCSRSS_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
111 LONG CursorX
, CursorY
;
112 PCONSOLE_DRAW ConsoleDraw
;
113 UINT ConsoleDrawSize
;
115 if (ActiveConsole
!= Console
)
120 ConsoleDrawSize
= sizeof(CONSOLE_DRAW
) +
121 (ConioRectWidth(Region
) * ConioRectHeight(Region
)) * 2;
122 ConsoleDraw
= HeapAlloc(Win32CsrApiHeap
, 0, ConsoleDrawSize
);
123 if (NULL
== ConsoleDraw
)
125 DPRINT1("HeapAlloc failed\n");
128 ConioPhysicalToLogical(Buff
, Buff
->CurrentX
, Buff
->CurrentY
, &CursorX
, &CursorY
);
129 ConsoleDraw
->X
= Region
->left
;
130 ConsoleDraw
->Y
= Region
->top
;
131 ConsoleDraw
->SizeX
= ConioRectWidth(Region
);
132 ConsoleDraw
->SizeY
= ConioRectHeight(Region
);
133 ConsoleDraw
->CursorX
= CursorX
;
134 ConsoleDraw
->CursorY
= CursorY
;
136 TuiCopyRect((char *) (ConsoleDraw
+ 1), Buff
, Region
);
138 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_DRAW
,
139 NULL
, 0, ConsoleDraw
, ConsoleDrawSize
, &BytesReturned
, NULL
))
141 DPRINT1("Failed to draw console\n");
142 HeapFree(Win32CsrApiHeap
, 0, ConsoleDraw
);
146 HeapFree(Win32CsrApiHeap
, 0, ConsoleDraw
);
150 TuiWriteStream(PCSRSS_CONSOLE Console
, RECT
*Region
, LONG CursorStartX
, LONG CursorStartY
,
151 UINT ScrolledLines
, CHAR
*Buffer
, UINT Length
)
154 PCSRSS_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
156 if (ActiveConsole
->ActiveBuffer
!= Buff
)
161 if (! WriteFile(ConsoleDeviceHandle
, Buffer
, Length
, &BytesWritten
, NULL
))
163 DPRINT1("Error writing to BlueScreen\n");
168 TuiSetCursorInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
)
172 if (ActiveConsole
->ActiveBuffer
!= Buff
)
177 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_CURSOR_INFO
,
178 &Buff
->CursorInfo
, sizeof(Buff
->CursorInfo
), NULL
, 0,
179 &BytesReturned
, NULL
))
181 DPRINT1( "Failed to set cursor info\n" );
189 TuiSetScreenInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
, UINT OldCursorX
, UINT OldCursorY
)
191 CONSOLE_SCREEN_BUFFER_INFO Info
;
192 LONG CursorX
, CursorY
;
195 if (ActiveConsole
->ActiveBuffer
!= Buff
)
200 ConioPhysicalToLogical(Buff
, Buff
->CurrentX
, Buff
->CurrentY
, &CursorX
, &CursorY
);
201 Info
.dwCursorPosition
.X
= CursorX
;
202 Info
.dwCursorPosition
.Y
= CursorY
;
203 Info
.wAttributes
= Buff
->DefaultAttrib
;
205 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
,
206 &Info
, sizeof(CONSOLE_SCREEN_BUFFER_INFO
), NULL
, 0,
207 &BytesReturned
, NULL
))
209 DPRINT1( "Failed to set cursor position\n" );
217 TuiUpdateScreenInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
)
223 TuiChangeTitle(PCSRSS_CONSOLE Console
)
229 TuiCleanupConsole(PCSRSS_CONSOLE Console
)
231 DestroyWindow(Console
->hWindow
);
233 EnterCriticalSection(&ActiveConsoleLock
);
235 /* Switch to next console */
236 if (ActiveConsole
== Console
)
238 ActiveConsole
= Console
->Next
!= Console
? Console
->Next
: NULL
;
241 if (Console
->Next
!= Console
)
243 Console
->Prev
->Next
= Console
->Next
;
244 Console
->Next
->Prev
= Console
->Prev
;
246 LeaveCriticalSection(&ActiveConsoleLock
);
248 if (NULL
!= ActiveConsole
)
250 ConioDrawConsole(ActiveConsole
);
255 TuiConsoleThread (PVOID Data
)
257 PCSRSS_CONSOLE Console
= (PCSRSS_CONSOLE
) Data
;
261 NewWindow
= CreateWindowW(L
"TuiConsoleWindowClass",
262 Console
->Title
.Buffer
,
264 -32000, -32000, 0, 0,
266 (HINSTANCE
) GetModuleHandleW(NULL
),
268 Console
->hWindow
= NewWindow
;
269 if (NULL
== NewWindow
)
271 DPRINT1("CSR: Unable to create console window\n");
275 SetForegroundWindow(Console
->hWindow
);
279 GetMessageW(&msg
, 0, 0, 0);
280 DispatchMessage(&msg
);
281 TranslateMessage(&msg
);
283 if (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
||
284 msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_KEYUP
||
285 msg
.message
== WM_SYSKEYDOWN
|| msg
.message
== WM_SYSKEYUP
)
287 ConioProcessKey(&msg
, Console
, TRUE
);
294 static CSRSS_CONSOLE_VTBL TuiVtbl
=
307 TuiInitConsole(PCSRSS_CONSOLE Console
)
311 if (! ConsInitialized
)
313 ConsInitialized
= TRUE
;
316 ConsInitialized
= FALSE
;
317 return STATUS_UNSUCCESSFUL
;
321 Console
->Vtbl
= &TuiVtbl
;
322 Console
->hWindow
= NULL
;
323 Console
->Size
= PhysicalConsoleSize
;
324 Console
->ActiveBuffer
->MaxX
= PhysicalConsoleSize
.X
;
325 Console
->ActiveBuffer
->MaxY
= PhysicalConsoleSize
.Y
;
327 ThreadHandle
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
) TuiConsoleThread
,
329 if (NULL
== ThreadHandle
)
331 DPRINT1("CSR: Unable to create console thread\n");
332 return STATUS_UNSUCCESSFUL
;
334 CloseHandle(ThreadHandle
);
336 EnterCriticalSection(&ActiveConsoleLock
);
337 if (NULL
!= ActiveConsole
)
339 Console
->Prev
= ActiveConsole
;
340 Console
->Next
= ActiveConsole
->Next
;
341 ActiveConsole
->Next
->Prev
= Console
;
342 ActiveConsole
->Next
= Console
;
346 Console
->Prev
= Console
;
347 Console
->Next
= Console
;
349 ActiveConsole
= Console
;
350 LeaveCriticalSection(&ActiveConsoleLock
);
352 return STATUS_SUCCESS
;
355 PCSRSS_CONSOLE FASTCALL
356 TuiGetFocusConsole(VOID
)
358 return ActiveConsole
;
362 TuiSwapConsole(int Next
)
364 static PCSRSS_CONSOLE SwapConsole
= NULL
; /* console we are thinking about swapping with */
372 /* alt-tab, swap consoles */
373 /* move SwapConsole to next console, and print its title */
374 EnterCriticalSection(&ActiveConsoleLock
);
377 SwapConsole
= ActiveConsole
;
380 SwapConsole
= (0 < Next
? SwapConsole
->Next
: SwapConsole
->Prev
);
381 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize(&SwapConsole
->Title
);
383 Buffer
= HeapAlloc(Win32CsrApiHeap
,
385 sizeof(COORD
) + Title
.MaximumLength
);
386 pos
= (COORD
*)Buffer
;
387 Title
.Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof( COORD
));
389 RtlUnicodeStringToAnsiString(&Title
, &SwapConsole
->Title
, FALSE
);
390 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
391 pos
->X
= (PhysicalConsoleSize
.X
- Title
.Length
) / 2;
392 /* redraw the console to clear off old title */
393 ConioDrawConsole(ActiveConsole
);
394 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
395 NULL
, 0, Buffer
, sizeof(COORD
) + Title
.Length
,
396 &BytesReturned
, NULL
))
398 DPRINT1( "Error writing to console\n" );
400 HeapFree(Win32CsrApiHeap
, 0, Buffer
);
401 LeaveCriticalSection(&ActiveConsoleLock
);
405 else if (NULL
!= SwapConsole
)
407 EnterCriticalSection(&ActiveConsoleLock
);
408 if (SwapConsole
!= ActiveConsole
)
410 /* first remove swapconsole from the list */
411 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
412 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
413 /* now insert before activeconsole */
414 SwapConsole
->Next
= ActiveConsole
;
415 SwapConsole
->Prev
= ActiveConsole
->Prev
;
416 ActiveConsole
->Prev
->Next
= SwapConsole
;
417 ActiveConsole
->Prev
= SwapConsole
;
419 ActiveConsole
= SwapConsole
;
421 ConioDrawConsole(ActiveConsole
);
422 LeaveCriticalSection(&ActiveConsoleLock
);