1 /* $Id: tuiconsole.c 47693 2010-06-08 06:38:14Z jmorlan $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: win32ss/user/consrv/tuiconsole.c
6 * PURPOSE: Implementation of text-mode consoles
13 CRITICAL_SECTION ActiveConsoleLock
;
14 static COORD PhysicalConsoleSize
;
15 static HANDLE ConsoleDeviceHandle
;
16 static PCSRSS_CONSOLE ActiveConsole
;
18 static BOOL ConsInitialized
= FALSE
;
20 static LRESULT CALLBACK
21 TuiConsoleWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
23 if (msg
== WM_ACTIVATE
)
25 if (LOWORD(wParam
) != WA_INACTIVE
)
28 ConioDrawConsole(ActiveConsole
);
31 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
35 TuiStartService(LPCWSTR lpServiceName
)
37 SC_HANDLE hSCManager
= NULL
;
38 SC_HANDLE hService
= NULL
;
41 hSCManager
= OpenSCManagerW(NULL
, NULL
, 0);
42 if (hSCManager
== NULL
)
45 hService
= OpenServiceW(hSCManager
, lpServiceName
, SERVICE_START
);
49 ret
= StartServiceW(hService
, 0, NULL
);
56 if (hSCManager
!= NULL
)
57 CloseServiceHandle(hSCManager
);
59 CloseServiceHandle(hService
);
66 CONSOLE_SCREEN_BUFFER_INFO ScrInfo
;
69 USHORT TextAttribute
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
71 TuiStartService(L
"Blue");
73 ConsoleDeviceHandle
= CreateFileW(L
"\\\\.\\BlueScreen", FILE_ALL_ACCESS
, 0, NULL
,
74 OPEN_EXISTING
, 0, NULL
);
75 if (INVALID_HANDLE_VALUE
== ConsoleDeviceHandle
)
77 DPRINT1("Failed to open BlueScreen.\n");
81 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_LOADFONT
,
82 &OemCP
, sizeof(OemCP
), NULL
, 0,
83 &BytesReturned
, NULL
))
85 DPRINT1("Failed to load the font for codepage %d\n", OemCP
);
86 /* Let's suppose the font is good enough to continue */
89 if (!DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_TEXT_ATTRIBUTE
,
90 &TextAttribute
, sizeof(TextAttribute
), NULL
, 0,
91 &BytesReturned
, NULL
))
93 DPRINT1("Failed to set text attribute\n");
97 InitializeCriticalSection(&ActiveConsoleLock
);
98 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_GET_SCREEN_BUFFER_INFO
,
99 NULL
, 0, &ScrInfo
, sizeof(ScrInfo
), &BytesReturned
, NULL
))
101 DPRINT1("Failed to get console info\n");
104 PhysicalConsoleSize
= ScrInfo
.dwSize
;
106 RtlZeroMemory(&wc
, sizeof(WNDCLASSEXW
));
107 wc
.cbSize
= sizeof(WNDCLASSEXW
);
108 wc
.lpszClassName
= L
"TuiConsoleWindowClass";
109 wc
.lpfnWndProc
= TuiConsoleWndProc
;
110 wc
.hInstance
= (HINSTANCE
) GetModuleHandleW(NULL
);
111 if (RegisterClassExW(&wc
) == 0)
113 DPRINT1("Failed to register console wndproc\n");
121 TuiInitScreenBuffer(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buffer
)
123 Buffer
->DefaultAttrib
= FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
;
127 TuiCopyRect(char *Dest
, PCSRSS_SCREEN_BUFFER Buff
, SMALL_RECT
*Region
)
129 UINT SrcDelta
, DestDelta
;
133 Src
= ConioCoordToPointer(Buff
, Region
->Left
, Region
->Top
);
134 SrcDelta
= Buff
->MaxX
* 2;
135 SrcEnd
= Buff
->Buffer
+ Buff
->MaxY
* Buff
->MaxX
* 2;
136 DestDelta
= ConioRectWidth(Region
) * 2;
137 for (i
= Region
->Top
; i
<= Region
->Bottom
; i
++)
139 memcpy(Dest
, Src
, DestDelta
);
143 Src
-= Buff
->MaxY
* Buff
->MaxX
* 2;
150 TuiDrawRegion(PCSRSS_CONSOLE Console
, SMALL_RECT
*Region
)
153 PCSRSS_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
154 PCONSOLE_DRAW ConsoleDraw
;
155 UINT ConsoleDrawSize
;
157 if (ActiveConsole
!= Console
)
162 ConsoleDrawSize
= sizeof(CONSOLE_DRAW
) +
163 (ConioRectWidth(Region
) * ConioRectHeight(Region
)) * 2;
164 ConsoleDraw
= HeapAlloc(ConSrvHeap
, 0, ConsoleDrawSize
);
165 if (NULL
== ConsoleDraw
)
167 DPRINT1("HeapAlloc failed\n");
170 ConsoleDraw
->X
= Region
->Left
;
171 ConsoleDraw
->Y
= Region
->Top
;
172 ConsoleDraw
->SizeX
= ConioRectWidth(Region
);
173 ConsoleDraw
->SizeY
= ConioRectHeight(Region
);
174 ConsoleDraw
->CursorX
= Buff
->CurrentX
;
175 ConsoleDraw
->CursorY
= Buff
->CurrentY
;
177 TuiCopyRect((char *) (ConsoleDraw
+ 1), Buff
, Region
);
179 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_DRAW
,
180 NULL
, 0, ConsoleDraw
, ConsoleDrawSize
, &BytesReturned
, NULL
))
182 DPRINT1("Failed to draw console\n");
183 HeapFree(ConSrvHeap
, 0, ConsoleDraw
);
187 HeapFree(ConSrvHeap
, 0, ConsoleDraw
);
191 TuiWriteStream(PCSRSS_CONSOLE Console
, SMALL_RECT
*Region
, LONG CursorStartX
, LONG CursorStartY
,
192 UINT ScrolledLines
, CHAR
*Buffer
, UINT Length
)
195 PCSRSS_SCREEN_BUFFER Buff
= Console
->ActiveBuffer
;
197 if (ActiveConsole
->ActiveBuffer
!= Buff
)
202 if (! WriteFile(ConsoleDeviceHandle
, Buffer
, Length
, &BytesWritten
, NULL
))
204 DPRINT1("Error writing to BlueScreen\n");
209 TuiSetCursorInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
)
211 CONSOLE_CURSOR_INFO Info
;
214 if (ActiveConsole
->ActiveBuffer
!= Buff
)
219 Info
.dwSize
= ConioEffectiveCursorSize(Console
, 100);
220 Info
.bVisible
= Buff
->CursorInfo
.bVisible
;
222 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_CURSOR_INFO
,
223 &Info
, sizeof(Info
), NULL
, 0, &BytesReturned
, NULL
))
225 DPRINT1( "Failed to set cursor info\n" );
233 TuiSetScreenInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
, UINT OldCursorX
, UINT OldCursorY
)
235 CONSOLE_SCREEN_BUFFER_INFO Info
;
238 if (ActiveConsole
->ActiveBuffer
!= Buff
)
243 Info
.dwCursorPosition
.X
= Buff
->CurrentX
;
244 Info
.dwCursorPosition
.Y
= Buff
->CurrentY
;
245 Info
.wAttributes
= Buff
->DefaultAttrib
;
247 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_SET_SCREEN_BUFFER_INFO
,
248 &Info
, sizeof(CONSOLE_SCREEN_BUFFER_INFO
), NULL
, 0,
249 &BytesReturned
, NULL
))
251 DPRINT1( "Failed to set cursor position\n" );
259 TuiUpdateScreenInfo(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER Buff
)
265 TuiChangeTitle(PCSRSS_CONSOLE Console
)
271 TuiCleanupConsole(PCSRSS_CONSOLE Console
)
273 DestroyWindow(Console
->hWindow
);
275 EnterCriticalSection(&ActiveConsoleLock
);
277 /* Switch to next console */
278 if (ActiveConsole
== Console
)
280 ActiveConsole
= Console
->Next
!= Console
? Console
->Next
: NULL
;
283 if (Console
->Next
!= Console
)
285 Console
->Prev
->Next
= Console
->Next
;
286 Console
->Next
->Prev
= Console
->Prev
;
288 LeaveCriticalSection(&ActiveConsoleLock
);
290 if (NULL
!= ActiveConsole
)
292 ConioDrawConsole(ActiveConsole
);
297 TuiChangeIcon(PCSRSS_CONSOLE Console
, HICON hWindowIcon
)
302 static NTSTATUS WINAPI
303 TuiResizeBuffer(PCSRSS_CONSOLE Console
, PCSRSS_SCREEN_BUFFER ScreenBuffer
, COORD Size
)
306 return STATUS_NOT_IMPLEMENTED
;
310 TuiConsoleThread (PVOID Data
)
312 PCSRSS_CONSOLE Console
= (PCSRSS_CONSOLE
) Data
;
316 NewWindow
= CreateWindowW(L
"TuiConsoleWindowClass",
317 Console
->Title
.Buffer
,
319 -32000, -32000, 0, 0,
321 (HINSTANCE
) GetModuleHandleW(NULL
),
323 Console
->hWindow
= NewWindow
;
324 if (NULL
== NewWindow
)
326 DPRINT1("CSR: Unable to create console window\n");
330 SetForegroundWindow(Console
->hWindow
);
334 GetMessageW(&msg
, 0, 0, 0);
335 DispatchMessage(&msg
);
336 TranslateMessage(&msg
);
338 if (msg
.message
== WM_CHAR
|| msg
.message
== WM_SYSCHAR
||
339 msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_KEYUP
||
340 msg
.message
== WM_SYSKEYDOWN
|| msg
.message
== WM_SYSKEYUP
)
342 ConioProcessKey(&msg
, Console
, TRUE
);
349 static CSRSS_CONSOLE_VTBL TuiVtbl
=
364 TuiInitConsole(PCSRSS_CONSOLE Console
)
368 if (! ConsInitialized
)
370 ConsInitialized
= TRUE
;
371 if (! TuiInit(Console
->CodePage
))
373 ConsInitialized
= FALSE
;
374 return STATUS_UNSUCCESSFUL
;
378 Console
->Vtbl
= &TuiVtbl
;
379 Console
->hWindow
= NULL
;
380 Console
->Size
= PhysicalConsoleSize
;
381 Console
->ActiveBuffer
->MaxX
= PhysicalConsoleSize
.X
;
382 Console
->ActiveBuffer
->MaxY
= PhysicalConsoleSize
.Y
;
384 ThreadHandle
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
) TuiConsoleThread
,
386 if (NULL
== ThreadHandle
)
388 DPRINT1("CSR: Unable to create console thread\n");
389 return STATUS_UNSUCCESSFUL
;
391 CloseHandle(ThreadHandle
);
393 EnterCriticalSection(&ActiveConsoleLock
);
394 if (NULL
!= ActiveConsole
)
396 Console
->Prev
= ActiveConsole
;
397 Console
->Next
= ActiveConsole
->Next
;
398 ActiveConsole
->Next
->Prev
= Console
;
399 ActiveConsole
->Next
= Console
;
403 Console
->Prev
= Console
;
404 Console
->Next
= Console
;
406 ActiveConsole
= Console
;
407 LeaveCriticalSection(&ActiveConsoleLock
);
409 return STATUS_SUCCESS
;
412 PCSRSS_CONSOLE FASTCALL
413 TuiGetFocusConsole(VOID
)
415 return ActiveConsole
;
419 TuiSwapConsole(int Next
)
421 static PCSRSS_CONSOLE SwapConsole
= NULL
; /* console we are thinking about swapping with */
429 /* alt-tab, swap consoles */
430 /* move SwapConsole to next console, and print its title */
431 EnterCriticalSection(&ActiveConsoleLock
);
434 SwapConsole
= ActiveConsole
;
437 SwapConsole
= (0 < Next
? SwapConsole
->Next
: SwapConsole
->Prev
);
438 Title
.MaximumLength
= RtlUnicodeStringToAnsiSize(&SwapConsole
->Title
);
440 Buffer
= HeapAlloc(ConSrvHeap
,
442 sizeof(COORD
) + Title
.MaximumLength
);
443 pos
= (COORD
*)Buffer
;
444 Title
.Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof( COORD
));
446 RtlUnicodeStringToAnsiString(&Title
, &SwapConsole
->Title
, FALSE
);
447 pos
->Y
= PhysicalConsoleSize
.Y
/ 2;
448 pos
->X
= (PhysicalConsoleSize
.X
- Title
.Length
) / 2;
449 /* redraw the console to clear off old title */
450 ConioDrawConsole(ActiveConsole
);
451 if (! DeviceIoControl(ConsoleDeviceHandle
, IOCTL_CONSOLE_WRITE_OUTPUT_CHARACTER
,
452 NULL
, 0, Buffer
, sizeof(COORD
) + Title
.Length
,
453 &BytesReturned
, NULL
))
455 DPRINT1( "Error writing to console\n" );
457 HeapFree(ConSrvHeap
, 0, Buffer
);
458 LeaveCriticalSection(&ActiveConsoleLock
);
462 else if (NULL
!= SwapConsole
)
464 EnterCriticalSection(&ActiveConsoleLock
);
465 if (SwapConsole
!= ActiveConsole
)
467 /* first remove swapconsole from the list */
468 SwapConsole
->Prev
->Next
= SwapConsole
->Next
;
469 SwapConsole
->Next
->Prev
= SwapConsole
->Prev
;
470 /* now insert before activeconsole */
471 SwapConsole
->Next
= ActiveConsole
;
472 SwapConsole
->Prev
= ActiveConsole
->Prev
;
473 ActiveConsole
->Prev
->Next
= SwapConsole
;
474 ActiveConsole
->Prev
= SwapConsole
;
476 ActiveConsole
= SwapConsole
;
478 ConioDrawConsole(ActiveConsole
);
479 LeaveCriticalSection(&ActiveConsoleLock
);