2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/video/console.c
5 * PURPOSE: Console driver for the video subsystem
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
29 /* PRIVATE VARIABLES **********************************************************/
31 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
32 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
35 static HANDLE ScreenBufferHandle
= NULL
;
36 static PVOID OldConsoleFramebuffer
= NULL
;
40 * Text mode -- we always keep a valid text mode framebuffer
41 * even if we are in graphics mode. This is needed in order
42 * to keep a consistent VGA state. However, each time the VGA
43 * detaches from the console (and reattaches to it later on),
44 * this text mode framebuffer is recreated.
46 static HANDLE TextConsoleBuffer
= NULL
;
47 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
48 static COORD TextResolution
= {0};
49 /// static PCHAR_CELL TextFramebuffer = NULL;
54 static HANDLE GraphicsConsoleBuffer
= NULL
;
55 /// static PVOID GraphicsFramebuffer = NULL;
56 static HANDLE ConsoleMutex
= NULL
;
57 /* DoubleVision support */
58 static BOOLEAN DoubleWidth
= FALSE
;
59 static BOOLEAN DoubleHeight
= FALSE
;
64 * Activate this line if you want to use the real
65 * RegisterConsoleVDM API of ReactOS/Windows.
67 // #define USE_REAL_REGISTERCONSOLEVDM
69 static HANDLE StartEvent
= NULL
;
70 static HANDLE EndEvent
= NULL
;
71 static HANDLE AnotherEvent
= NULL
;
73 /* RegisterConsoleVDM EMULATION ***********************************************/
77 #ifdef USE_REAL_REGISTERCONSOLEVDM
79 #define __RegisterConsoleVDM RegisterConsoleVDM
80 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
85 * This private buffer, per-console, is used by
86 * RegisterConsoleVDM and InvalidateConsoleDIBits.
88 static COORD VDMBufferSize
= {0};
89 static PCHAR_CELL VDMBuffer
= NULL
;
91 static PCHAR_INFO CharBuff
= NULL
; // This is a hack, which is unneeded
92 // for the real RegisterConsoleVDM and
93 // InvalidateConsoleDIBits
97 __RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
98 IN HANDLE hStartHardwareEvent
,
99 IN HANDLE hEndHardwareEvent
,
100 IN HANDLE hErrorHardwareEvent
,
101 IN DWORD dwUnusedVar
,
102 OUT LPDWORD lpVideoStateLength
,
103 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
104 IN PVOID lpUnusedBuffer
,
105 IN DWORD dwUnusedBufferLength
,
106 IN COORD dwVDMBufferSize
,
107 OUT PVOID
* lpVDMBuffer
)
109 UNREFERENCED_PARAMETER(hErrorHardwareEvent
);
110 UNREFERENCED_PARAMETER(dwUnusedVar
);
111 UNREFERENCED_PARAMETER(lpVideoStateLength
);
112 UNREFERENCED_PARAMETER(lpVideoState
);
113 UNREFERENCED_PARAMETER(lpUnusedBuffer
);
114 UNREFERENCED_PARAMETER(dwUnusedBufferLength
);
117 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags
);
119 if (lpVDMBuffer
== NULL
) return FALSE
;
121 if (dwRegisterFlags
!= 0)
123 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
124 if (VDMBuffer
!= NULL
) return FALSE
;
126 VDMBufferSize
= dwVDMBufferSize
;
128 /* HACK: Cache -- to be removed in the real implementation */
129 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
131 VDMBufferSize
.X
* VDMBufferSize
.Y
132 * sizeof(*CharBuff
));
135 VDMBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
137 VDMBufferSize
.X
* VDMBufferSize
.Y
138 * sizeof(*VDMBuffer
));
139 *lpVDMBuffer
= VDMBuffer
;
140 return (VDMBuffer
!= NULL
);
144 /* HACK: Cache -- to be removed in the real implementation */
145 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
148 if (VDMBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer
);
151 VDMBufferSize
.X
= VDMBufferSize
.Y
= 0;
158 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput
,
159 IN PSMALL_RECT lpRect
)
161 if ((hConsoleOutput
== TextConsoleBuffer
) && (VDMBuffer
!= NULL
))
163 /* HACK: Write the cached data to the console */
165 COORD Origin
= { lpRect
->Left
, lpRect
->Top
};
170 for (i
= 0; i
< VDMBufferSize
.Y
; i
++)
172 for (j
= 0; j
< VDMBufferSize
.X
; j
++)
174 CharBuff
[i
* VDMBufferSize
.X
+ j
].Char
.AsciiChar
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Char
;
175 CharBuff
[i
* VDMBufferSize
.X
+ j
].Attributes
= VDMBuffer
[i
* VDMBufferSize
.X
+ j
].Attributes
;
179 WriteConsoleOutputA(hConsoleOutput
,
186 return InvalidateConsoleDIBits(hConsoleOutput
, lpRect
);
192 /* PRIVATE FUNCTIONS **********************************************************/
196 static VOID
VgaUpdateTextCursor(VOID
);
197 static inline DWORD
VgaGetAddressSize(VOID
);
203 static VOID
ResizeTextConsole(PCOORD Resolution
, PSMALL_RECT WindowSize OPTIONAL
)
207 SHORT oldWidth
, oldHeight
;
210 * Use this trick to effectively resize the console buffer and window,
212 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
213 * is smaller than the current console window size, and:
214 * - SetConsoleWindowInfo fails if the new console window size is larger
215 * than the current console screen buffer size.
219 /* Retrieve the latest console information */
220 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
222 oldWidth
= ConsoleInfo
.srWindow
.Right
- ConsoleInfo
.srWindow
.Left
+ 1;
223 oldHeight
= ConsoleInfo
.srWindow
.Bottom
- ConsoleInfo
.srWindow
.Top
+ 1;
226 * If the current console window is too large to hold the full contents
227 * of the new screen buffer, resize it first.
229 if (oldWidth
> Resolution
->X
|| oldHeight
> Resolution
->Y
)
232 // NOTE: This is not a problem if we move the window back to (0,0)
233 // because when we resize the screen buffer, the window will move back
234 // to where the cursor is. Or, if the screen buffer is not resized,
235 // when we readjust again the window, we will move back to a correct
236 // position. This is what we wanted after all...
239 ConRect
.Left
= ConRect
.Top
= 0;
240 ConRect
.Right
= ConRect
.Left
+ min(oldWidth
, Resolution
->X
) - 1;
241 ConRect
.Bottom
= ConRect
.Top
+ min(oldHeight
, Resolution
->Y
) - 1;
243 Success
= SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
244 if (!Success
) DPRINT1("(resize) SetConsoleWindowInfo(1) failed with error %d\n", GetLastError());
247 /* Resize the screen buffer if needed */
248 if (Resolution
->X
!= ConsoleInfo
.dwSize
.X
|| Resolution
->Y
!= ConsoleInfo
.dwSize
.Y
)
251 * SetConsoleScreenBufferSize automatically takes into account the current
252 * cursor position when it computes starting which row it should copy text
253 * when resizing the sceenbuffer, and scrolls the console window such that
254 * the cursor is placed in it again. We therefore do not need to care about
255 * the cursor position and do the maths ourselves.
257 Success
= SetConsoleScreenBufferSize(TextConsoleBuffer
, *Resolution
);
258 if (!Success
) DPRINT1("(resize) SetConsoleScreenBufferSize failed with error %d\n", GetLastError());
261 * Setting a new screen buffer size can change other information,
262 * so update the saved console information.
264 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
270 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
271 ConRect
.Bottom
= max(ConsoleInfo
.dwCursorPosition
.Y
, Resolution
->Y
- 1);
272 ConRect
.Top
= ConRect
.Bottom
- Resolution
->Y
+ 1;
274 // NOTE: We may take ConsoleInfo.dwMaximumWindowSize into account
278 ConRect
.Left
= ConRect
.Top
= 0;
279 ConRect
.Right
= ConRect
.Left
+ WindowSize
->Right
- WindowSize
->Left
;
280 ConRect
.Bottom
= ConRect
.Top
+ WindowSize
->Bottom
- WindowSize
->Top
;
283 Success
= SetConsoleWindowInfo(TextConsoleBuffer
, TRUE
, &ConRect
);
284 if (!Success
) DPRINT1("(resize) SetConsoleWindowInfo(2) failed with error %d\n", GetLastError());
286 /* Update the saved console information */
287 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
290 static VOID
UpdateCursorPosition(VOID
)
293 * Update the cursor position in the VGA registers.
295 WORD Offset
= ConsoleInfo
.dwCursorPosition
.Y
* TextResolution
.X
+
296 ConsoleInfo
.dwCursorPosition
.X
;
298 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_LOW_REG
] = LOBYTE(Offset
);
299 VgaCrtcRegisters
[VGA_CRTC_CURSOR_LOC_HIGH_REG
] = HIBYTE(Offset
);
301 VgaUpdateTextCursor();
304 static BOOL
AttachToConsoleInternal(PCOORD Resolution
)
308 PVIDEO_HARDWARE_STATE_HEADER State
;
310 #ifdef USE_REAL_REGISTERCONSOLEVDM
311 PCHAR_INFO CharBuff
= NULL
;
314 DWORD AddressSize
, ScanlineSize
;
318 COORD Origin
= { 0, 0 };
320 ASSERT(TextFramebuffer
== NULL
);
322 TextResolution
= *Resolution
;
325 * Windows 2k3 winsrv.dll calls NtVdmControl(VdmQueryVdmProcess == 14, &ConsoleHandle);
326 * in the two following APIs:
327 * SrvRegisterConsoleVDM (corresponding Win32 API: RegisterConsoleVDM)
328 * SrvVDMConsoleOperation (corresponding Win32 API: VDMConsoleOperation)
329 * to check whether the current process is a VDM process, and fails otherwise
330 * with the error 0xC0000022 (STATUS_ACCESS_DENIED).
332 * It is worth it to notice that also basesrv.dll does the same only for the
333 * BaseSrvIsFirstVDM API...
336 /* Register with the console server */
338 __RegisterConsoleVDM(1,
341 AnotherEvent
, // NULL,
343 &Length
, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
344 (PVOID
*)&State
, // NULL,
348 (PVOID
*)&TextFramebuffer
);
351 DisplayMessage(L
"RegisterConsoleVDM failed with error %d\n", GetLastError());
356 #ifdef USE_REAL_REGISTERCONSOLEVDM
357 CharBuff
= RtlAllocateHeap(RtlGetProcessHeap(),
359 TextResolution
.X
* TextResolution
.Y
360 * sizeof(*CharBuff
));
364 /* Resize the console */
365 ResizeTextConsole(Resolution
, NULL
);
367 /* Update the saved console information */
368 GetConsoleScreenBufferInfo(TextConsoleBuffer
, &ConsoleInfo
);
371 * Copy console data into VGA memory
374 /* Read the data from the console into the framebuffer... */
375 ConRect
.Left
= ConRect
.Top
= 0;
376 ConRect
.Right
= TextResolution
.X
;
377 ConRect
.Bottom
= TextResolution
.Y
;
379 ReadConsoleOutputA(TextConsoleBuffer
,
385 /* ... and copy the framebuffer into the VGA memory */
386 AddressSize
= VgaGetAddressSize();
387 ScanlineSize
= (DWORD
)VgaCrtcRegisters
[VGA_CRTC_OFFSET_REG
] * 2;
389 /* Loop through the scanlines */
390 for (i
= 0; i
< TextResolution
.Y
; i
++)
392 /* Loop through the characters */
393 for (j
= 0; j
< TextResolution
.X
; j
++)
395 CurrentAddr
= LOWORD((Address
+ j
) * AddressSize
);
397 /* Store the character in plane 0 */
398 VgaMemory
[CurrentAddr
* VGA_NUM_BANKS
] = CharBuff
[i
* TextResolution
.X
+ j
].Char
.AsciiChar
;
400 /* Store the attribute in plane 1 */
401 VgaMemory
[CurrentAddr
* VGA_NUM_BANKS
+ 1] = (BYTE
)CharBuff
[i
* TextResolution
.X
+ j
].Attributes
;
404 /* Move to the next scanline */
405 Address
+= ScanlineSize
;
408 #ifdef USE_REAL_REGISTERCONSOLEVDM
409 if (CharBuff
) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff
);
412 UpdateCursorPosition();
417 static VOID
DetachFromConsoleInternal(VOID
)
421 COORD dummySize
= {0};
423 /* Deregister with the console server */
424 __RegisterConsoleVDM(0,
436 TextFramebuffer
= NULL
;
439 static VOID
SetActiveScreenBuffer(HANDLE ScreenBuffer
)
441 ASSERT(ScreenBuffer
);
443 /* Set the active buffer and reattach the VDM UI to it */
444 SetConsoleActiveScreenBuffer(ScreenBuffer
);
445 ConsoleReattach(ScreenBuffer
);
448 VOID
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent
)
451 * This function monitors and allows console resizings only if they are triggered by us.
452 * User-driven resizings via the console properties, or programmatical console resizings
453 * made by explicit calls to SetConsoleScreenBufferSize by external applications, are forbidden.
454 * In that case only a console window resize is done in case the size is reduced.
455 * This protection is enabled in CONSRV side when NTVDM registers as a VDM to CONSRV,
456 * but we also implement it there in case we are running in STANDALONE mode without
457 * CONSRV registration.
459 * The only potential problem we have is that, when this handler is called,
460 * the console is already resized. In case this corresponds to a forbidden resize,
461 * we resize the console back to its original size from inside the handler.
462 * This will trigger a recursive call to the handler, that should be detected.
465 if (CurrResolution
.X
== ScreenEvent
->dwSize
.X
&&
466 CurrResolution
.Y
== ScreenEvent
->dwSize
.Y
)
468 /* Allowed resize, we are OK */
472 DPRINT1("ScreenEventHandler - Detected forbidden resize! Reset console screenbuffer size back to (X = %d ; Y = %d)\n", CurrResolution
.X
, CurrResolution
.Y
);
474 // FIXME: If we're detaching, then stop monitoring for changes!!
476 /* Restore the original console size */
477 ResizeTextConsole(&CurrResolution
, NULL
);
479 /* Force refresh of all the screen */
481 UpdateRectangle
.Left
= 0;
482 UpdateRectangle
.Top
= 0;
483 UpdateRectangle
.Right
= CurrResolution
.X
;
484 UpdateRectangle
.Bottom
= CurrResolution
.Y
;
488 BOOLEAN
VgaGetDoubleVisionState(PBOOLEAN Horizontal
, PBOOLEAN Vertical
)
490 if (GraphicsConsoleBuffer
== NULL
) return FALSE
;
491 if (Horizontal
) *Horizontal
= DoubleWidth
;
492 if (Vertical
) *Vertical
= DoubleHeight
;
496 BOOL
VgaAttachToConsole(VOID
)
498 if (TextResolution
.X
== 0 || TextResolution
.Y
== 0)
499 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
501 if (TextResolution
.X
== 0) TextResolution
.X
= 80;
502 if (TextResolution
.Y
== 0) TextResolution
.Y
= 25;
504 // DetachFromConsoleInternal();
507 * AttachToConsoleInternal sets TextResolution
508 * to the new resolution and updates ConsoleInfo.
510 if (!AttachToConsoleInternal(&TextResolution
))
512 DisplayMessage(L
"An unexpected error occurred!\n");
517 /* Restore the original screen buffer */
518 SetActiveScreenBuffer(ScreenBufferHandle
);
519 ScreenBufferHandle
= NULL
;
521 /* Restore the screen state */
522 if (ScreenMode
== TEXT_MODE
)
524 /* The text mode framebuffer was recreated */
525 ActiveFramebuffer
= TextFramebuffer
;
529 /* The graphics mode framebuffer is unchanged */
530 ActiveFramebuffer
= OldConsoleFramebuffer
;
532 OldConsoleFramebuffer
= NULL
;
537 VOID
VgaDetachFromConsole(VOID
)
539 DetachFromConsoleInternal();
541 /* Save the screen state */
542 if (ScreenMode
== TEXT_MODE
)
543 ScreenBufferHandle
= TextConsoleBuffer
;
545 ScreenBufferHandle
= GraphicsConsoleBuffer
;
547 /* Reset the active framebuffer */
548 OldConsoleFramebuffer
= ActiveFramebuffer
;
549 ActiveFramebuffer
= NULL
;
551 /* Restore the original console size */
552 ResizeTextConsole(&OrgConsoleBufferInfo
.dwSize
, &OrgConsoleBufferInfo
.srWindow
);
554 /* Restore the original cursor shape */
555 SetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
);
557 // FIXME: Should we copy back the screen data to the screen buffer??
558 // WriteConsoleOutputA(...);
560 // FIXME: Should we change cursor POSITION??
561 // VgaUpdateTextCursor();
563 ///* Update the physical cursor */
564 //SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
565 //SetConsoleCursorPosition(TextConsoleBuffer, Position /*OrgConsoleBufferInfo.dwCursorPosition*/);
567 /* Restore the old text-mode screen buffer */
568 SetActiveScreenBuffer(TextConsoleBuffer
);
575 VgaConsoleUpdateTextCursor(BOOL CursorVisible
,
583 CONSOLE_CURSOR_INFO CursorInfo
;
585 if (CursorStart
< CursorEnd
)
588 CursorInfo
.bVisible
= CursorVisible
;
589 CursorInfo
.dwSize
= (100 * (CursorEnd
- CursorStart
)) / TextSize
;
594 CursorInfo
.bVisible
= FALSE
;
595 CursorInfo
.dwSize
= 1; // The size needs to be non-zero for SetConsoleCursorInfo to succeed.
598 /* Find the coordinates of the new position */
599 Position
.X
= (SHORT
)(Location
% ScanlineSize
);
600 Position
.Y
= (SHORT
)(Location
/ ScanlineSize
);
602 DPRINT("VgaConsoleUpdateTextCursor: (X = %d ; Y = %d)\n", Position
.X
, Position
.Y
);
604 /* Update the physical cursor */
605 SetConsoleCursorInfo(TextConsoleBuffer
, &CursorInfo
);
606 SetConsoleCursorPosition(TextConsoleBuffer
, Position
);
610 VgaConsoleCreateGraphicsScreen(// OUT PBYTE* GraphicsFramebuffer,
611 IN PCOORD Resolution
,
612 IN HANDLE PaletteHandle
)
615 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo
;
616 BYTE BitmapInfoBuffer
[VGA_BITMAP_INFO_SIZE
];
617 LPBITMAPINFO BitmapInfo
= (LPBITMAPINFO
)BitmapInfoBuffer
;
618 LPWORD PaletteIndex
= (LPWORD
)(BitmapInfo
->bmiColors
);
620 LONG Width
= Resolution
->X
;
621 LONG Height
= Resolution
->Y
;
623 /* Use DoubleVision mode if the resolution is too small */
624 DoubleWidth
= (Width
< VGA_MINIMUM_WIDTH
);
625 if (DoubleWidth
) Width
*= 2;
626 DoubleHeight
= (Height
< VGA_MINIMUM_HEIGHT
);
627 if (DoubleHeight
) Height
*= 2;
629 /* Fill the bitmap info header */
630 RtlZeroMemory(&BitmapInfo
->bmiHeader
, sizeof(BitmapInfo
->bmiHeader
));
631 BitmapInfo
->bmiHeader
.biSize
= sizeof(BitmapInfo
->bmiHeader
);
632 BitmapInfo
->bmiHeader
.biWidth
= Width
;
633 BitmapInfo
->bmiHeader
.biHeight
= Height
;
634 BitmapInfo
->bmiHeader
.biBitCount
= 8;
635 BitmapInfo
->bmiHeader
.biPlanes
= 1;
636 BitmapInfo
->bmiHeader
.biCompression
= BI_RGB
;
637 BitmapInfo
->bmiHeader
.biSizeImage
= Width
* Height
/* * 1 == biBitCount / 8 */;
639 /* Fill the palette data */
640 for (i
= 0; i
< (VGA_PALETTE_SIZE
/ 3); i
++) PaletteIndex
[i
] = (WORD
)i
;
642 /* Fill the console graphics buffer info */
643 GraphicsBufferInfo
.dwBitMapInfoLength
= VGA_BITMAP_INFO_SIZE
;
644 GraphicsBufferInfo
.lpBitMapInfo
= BitmapInfo
;
645 GraphicsBufferInfo
.dwUsage
= DIB_PAL_COLORS
;
647 /* Create the buffer */
648 GraphicsConsoleBuffer
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
649 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
651 CONSOLE_GRAPHICS_BUFFER
,
652 &GraphicsBufferInfo
);
653 if (GraphicsConsoleBuffer
== INVALID_HANDLE_VALUE
) return FALSE
;
655 /* Save the framebuffer address and mutex */
656 // *GraphicsFramebuffer = GraphicsBufferInfo.lpBitMap;
657 GraphicsFramebuffer
= GraphicsBufferInfo
.lpBitMap
;
658 ConsoleMutex
= GraphicsBufferInfo
.hMutex
;
660 /* Clear the framebuffer */
661 // RtlZeroMemory(*GraphicsFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
662 RtlZeroMemory(GraphicsFramebuffer
, BitmapInfo
->bmiHeader
.biSizeImage
);
664 /* Set the graphics mode palette */
665 SetConsolePalette(GraphicsConsoleBuffer
,
669 /* Set the active buffer */
670 SetActiveScreenBuffer(GraphicsConsoleBuffer
);
675 VOID
VgaConsoleDestroyGraphicsScreen(VOID
)
677 /* Release the console framebuffer mutex */
678 ReleaseMutex(ConsoleMutex
);
680 /* Switch back to the default console text buffer */
681 // SetActiveScreenBuffer(TextConsoleBuffer);
683 /* Cleanup the video data */
684 CloseHandle(ConsoleMutex
);
686 // GraphicsFramebuffer = NULL;
687 CloseHandle(GraphicsConsoleBuffer
);
688 GraphicsConsoleBuffer
= NULL
;
690 // /* Reset the active framebuffer */
691 // ActiveFramebuffer = NULL;
694 DoubleHeight
= FALSE
;
698 VgaConsoleCreateTextScreen(// OUT PCHAR_CELL* TextFramebuffer,
699 IN PCOORD Resolution
,
700 IN HANDLE PaletteHandle
)
702 /* Switch to the text buffer */
703 // FIXME: Wouldn't it be preferrable to switch to it AFTER we reset everything??
704 SetActiveScreenBuffer(TextConsoleBuffer
);
706 /* Adjust the text framebuffer if we changed the resolution */
707 if (TextResolution
.X
!= Resolution
->X
||
708 TextResolution
.Y
!= Resolution
->Y
)
710 DetachFromConsoleInternal();
713 * AttachToConsoleInternal sets TextResolution
714 * to the new resolution and updates ConsoleInfo.
716 if (!AttachToConsoleInternal(Resolution
))
718 DisplayMessage(L
"An unexpected error occurred!\n");
725 UpdateCursorPosition();
729 * Set the text mode palette.
731 * INFORMATION: This call should fail on Windows (and therefore
732 * we get the default palette and our external behaviour is
733 * just like Windows' one), but it should success on ReactOS
734 * (so that we get console palette changes even for text-mode
735 * screen buffers, which is a new feature on ReactOS).
737 SetConsolePalette(TextConsoleBuffer
,
744 VOID
VgaConsoleDestroyTextScreen(VOID
)
750 VOID
VgaConsoleRepaintScreen(PSMALL_RECT Rect
)
752 HANDLE ConsoleBufferHandle
= NULL
;
753 SMALL_RECT UpdateRectangle
= *Rect
;
755 /* Check if we are in text or graphics mode */
756 if (ScreenMode
== GRAPHICS_MODE
)
759 ConsoleBufferHandle
= GraphicsConsoleBuffer
;
761 /* In DoubleVision mode, scale the update rectangle */
764 UpdateRectangle
.Left
*= 2;
765 UpdateRectangle
.Right
= UpdateRectangle
.Right
* 2 + 1;
769 UpdateRectangle
.Top
*= 2;
770 UpdateRectangle
.Bottom
= UpdateRectangle
.Bottom
* 2 + 1;
776 ConsoleBufferHandle
= TextConsoleBuffer
;
779 /* Redraw the screen */
780 __InvalidateConsoleDIBits(ConsoleBufferHandle
, &UpdateRectangle
);
783 BOOLEAN
VgaConsoleInitialize(HANDLE TextHandle
)
786 * Initialize the console video by saving the default
787 * text-mode console output handle, if it is valid.
789 if (!IsConsoleHandle(TextHandle
)) return FALSE
;
790 TextConsoleBuffer
= TextHandle
;
792 /* Save the original cursor and console screen buffer information */
793 if (!GetConsoleCursorInfo(TextConsoleBuffer
, &OrgConsoleCursorInfo
) ||
794 !GetConsoleScreenBufferInfo(TextConsoleBuffer
, &OrgConsoleBufferInfo
))
796 TextConsoleBuffer
= NULL
;
799 ConsoleInfo
= OrgConsoleBufferInfo
;
801 /* Switch to the text buffer, but do not enter into a text mode */
802 SetActiveScreenBuffer(TextConsoleBuffer
);
807 VOID
VgaConsoleCleanup(VOID
)
809 /* If the console video was not initialized, just return */
810 if (!TextConsoleBuffer
)
813 VgaDetachFromConsole();
815 // TODO: We need to initialize those events before using them!
816 CloseHandle(AnotherEvent
);
817 CloseHandle(EndEvent
);
818 CloseHandle(StartEvent
);