1 /*
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)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 /** HACK!! **/
13 #if 0
14
15 #include "ntvdm.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20 #include "emulator.h"
21 #include "svga.h"
22
23 #include "console.h"
24
25 #endif
26 /** HACK!! **/
27
28
29 /* PRIVATE VARIABLES **********************************************************/
30
31 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
32 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
33
34
35 static HANDLE ScreenBufferHandle = NULL;
36 static PVOID OldConsoleFramebuffer = NULL;
37
38
39 /*
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.
45 */
46 static HANDLE TextConsoleBuffer = NULL;
47 static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
48 static COORD TextResolution = {0};
49 /// static PCHAR_CELL TextFramebuffer = NULL;
50
51 /*
52 * Graphics mode
53 */
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;
60
61
62
63 /*
64 * Activate this line if you want to use the real
65 * RegisterConsoleVDM API of ReactOS/Windows.
66 */
67 // #define USE_REAL_REGISTERCONSOLEVDM
68
69 static HANDLE StartEvent = NULL;
70 static HANDLE EndEvent = NULL;
71 static HANDLE AnotherEvent = NULL;
72
73 /* RegisterConsoleVDM EMULATION ***********************************************/
74
75 #include <ntddvdeo.h>
76
77 #ifdef USE_REAL_REGISTERCONSOLEVDM
78
79 #define __RegisterConsoleVDM RegisterConsoleVDM
80 #define __InvalidateConsoleDIBits InvalidateConsoleDIBits
81
82 #else
83
84 /*
85 * This private buffer, per-console, is used by
86 * RegisterConsoleVDM and InvalidateConsoleDIBits.
87 */
88 static COORD VDMBufferSize = {0};
89 static PCHAR_CELL VDMBuffer = NULL;
90
91 static PCHAR_INFO CharBuff = NULL; // This is a hack, which is unneeded
92 // for the real RegisterConsoleVDM and
93 // InvalidateConsoleDIBits
94
95 BOOL
96 WINAPI
__RegisterConsoleVDM(IN DWORD dwRegisterFlags,IN HANDLE hStartHardwareEvent,IN HANDLE hEndHardwareEvent,IN HANDLE hErrorHardwareEvent,IN DWORD dwUnusedVar,OUT LPDWORD lpVideoStateLength,OUT PVOID * lpVideoState,IN PVOID lpUnusedBuffer,IN DWORD dwUnusedBufferLength,IN COORD dwVDMBufferSize,OUT PVOID * lpVDMBuffer)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)
108 {
109 UNREFERENCED_PARAMETER(hErrorHardwareEvent);
110 UNREFERENCED_PARAMETER(dwUnusedVar);
111 UNREFERENCED_PARAMETER(lpVideoStateLength);
112 UNREFERENCED_PARAMETER(lpVideoState);
113 UNREFERENCED_PARAMETER(lpUnusedBuffer);
114 UNREFERENCED_PARAMETER(dwUnusedBufferLength);
115
116 SetLastError(0);
117 DPRINT1("__RegisterConsoleVDM(%d)\n", dwRegisterFlags);
118
119 if (lpVDMBuffer == NULL) return FALSE;
120
121 if (dwRegisterFlags != 0)
122 {
123 // if (hStartHardwareEvent == NULL || hEndHardwareEvent == NULL) return FALSE;
124 if (VDMBuffer != NULL) return FALSE;
125
126 VDMBufferSize = dwVDMBufferSize;
127
128 /* HACK: Cache -- to be removed in the real implementation */
129 CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
130 HEAP_ZERO_MEMORY,
131 VDMBufferSize.X * VDMBufferSize.Y
132 * sizeof(*CharBuff));
133 ASSERT(CharBuff);
134
135 VDMBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
136 HEAP_ZERO_MEMORY,
137 VDMBufferSize.X * VDMBufferSize.Y
138 * sizeof(*VDMBuffer));
139 *lpVDMBuffer = VDMBuffer;
140 return (VDMBuffer != NULL);
141 }
142 else
143 {
144 /* HACK: Cache -- to be removed in the real implementation */
145 if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
146 CharBuff = NULL;
147
148 if (VDMBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VDMBuffer);
149 VDMBuffer = NULL;
150
151 VDMBufferSize.X = VDMBufferSize.Y = 0;
152
153 return TRUE;
154 }
155 }
156
157 BOOL
__InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,IN PSMALL_RECT lpRect)158 __InvalidateConsoleDIBits(IN HANDLE hConsoleOutput,
159 IN PSMALL_RECT lpRect)
160 {
161 if ((hConsoleOutput == TextConsoleBuffer) && (VDMBuffer != NULL))
162 {
163 /* HACK: Write the cached data to the console */
164
165 COORD Origin = { lpRect->Left, lpRect->Top };
166 SHORT i, j;
167
168 ASSERT(CharBuff);
169
170 for (i = 0; i < VDMBufferSize.Y; i++)
171 {
172 for (j = 0; j < VDMBufferSize.X; j++)
173 {
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;
176 }
177 }
178
179 WriteConsoleOutputA(hConsoleOutput,
180 CharBuff,
181 VDMBufferSize,
182 Origin,
183 lpRect);
184 }
185
186 return InvalidateConsoleDIBits(hConsoleOutput, lpRect);
187 }
188
189 #endif
190
191
192 /* PRIVATE FUNCTIONS **********************************************************/
193
194
195 /*********/
196 static VOID VgaUpdateTextCursor(VOID);
197 static inline DWORD VgaGetAddressSize(VOID);
198 /*********/
199
200
201
202
ResizeTextConsole(PCOORD Resolution,PSMALL_RECT WindowSize OPTIONAL)203 static VOID ResizeTextConsole(PCOORD Resolution, PSMALL_RECT WindowSize OPTIONAL)
204 {
205 BOOL Success;
206 SMALL_RECT ConRect;
207 SHORT oldWidth, oldHeight;
208
209 /*
210 * Use this trick to effectively resize the console buffer and window,
211 * because:
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.
216 */
217
218
219 /* Retrieve the latest console information */
220 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
221
222 oldWidth = ConsoleInfo.srWindow.Right - ConsoleInfo.srWindow.Left + 1;
223 oldHeight = ConsoleInfo.srWindow.Bottom - ConsoleInfo.srWindow.Top + 1;
224
225 /*
226 * If the current console window is too large to hold the full contents
227 * of the new screen buffer, resize it first.
228 */
229 if (oldWidth > Resolution->X || oldHeight > Resolution->Y)
230 {
231 //
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...
237 //
238
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;
242
243 Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
244 if (!Success) DPRINT1("(resize) SetConsoleWindowInfo(1) failed with error %d\n", GetLastError());
245 }
246
247 /* Resize the screen buffer if needed */
248 if (Resolution->X != ConsoleInfo.dwSize.X || Resolution->Y != ConsoleInfo.dwSize.Y)
249 {
250 /*
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.
256 */
257 Success = SetConsoleScreenBufferSize(TextConsoleBuffer, *Resolution);
258 if (!Success) DPRINT1("(resize) SetConsoleScreenBufferSize failed with error %d\n", GetLastError());
259
260 /*
261 * Setting a new screen buffer size can change other information,
262 * so update the saved console information.
263 */
264 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
265 }
266
267 if (!WindowSize)
268 {
269 ConRect.Left = 0;
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;
273
274 // NOTE: We may take ConsoleInfo.dwMaximumWindowSize into account
275 }
276 else
277 {
278 ConRect.Left = ConRect.Top = 0;
279 ConRect.Right = ConRect.Left + WindowSize->Right - WindowSize->Left;
280 ConRect.Bottom = ConRect.Top + WindowSize->Bottom - WindowSize->Top ;
281 }
282
283 Success = SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect);
284 if (!Success) DPRINT1("(resize) SetConsoleWindowInfo(2) failed with error %d\n", GetLastError());
285
286 /* Update the saved console information */
287 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
288 }
289
UpdateCursorPosition(VOID)290 static VOID UpdateCursorPosition(VOID)
291 {
292 /*
293 * Update the cursor position in the VGA registers.
294 */
295 WORD Offset = ConsoleInfo.dwCursorPosition.Y * TextResolution.X +
296 ConsoleInfo.dwCursorPosition.X;
297
298 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset);
299 VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset);
300
301 VgaUpdateTextCursor();
302 }
303
AttachToConsoleInternal(PCOORD Resolution)304 static BOOL AttachToConsoleInternal(PCOORD Resolution)
305 {
306 BOOL Success;
307 ULONG Length = 0;
308 PVIDEO_HARDWARE_STATE_HEADER State;
309
310 #ifdef USE_REAL_REGISTERCONSOLEVDM
311 PCHAR_INFO CharBuff = NULL;
312 #endif
313 SHORT i, j;
314 DWORD AddressSize, ScanlineSize;
315 DWORD Address = 0;
316 DWORD CurrentAddr;
317 SMALL_RECT ConRect;
318 COORD Origin = { 0, 0 };
319
320 ASSERT(TextFramebuffer == NULL);
321
322 TextResolution = *Resolution;
323
324 /*
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).
331 *
332 * It is worth it to notice that also basesrv.dll does the same only for the
333 * BaseSrvIsFirstVDM API...
334 */
335
336 /* Register with the console server */
337 Success =
338 __RegisterConsoleVDM(1,
339 StartEvent,
340 EndEvent,
341 AnotherEvent, // NULL,
342 0,
343 &Length, // NULL, <-- putting this (and null in the next var) makes the API returning error 12 "ERROR_INVALID_ACCESS"
344 (PVOID*)&State, // NULL,
345 NULL,
346 0,
347 TextResolution,
348 (PVOID*)&TextFramebuffer);
349 if (!Success)
350 {
351 DisplayMessage(L"RegisterConsoleVDM failed with error %d\n", GetLastError());
352 EmulatorTerminate();
353 return FALSE;
354 }
355
356 #ifdef USE_REAL_REGISTERCONSOLEVDM
357 CharBuff = RtlAllocateHeap(RtlGetProcessHeap(),
358 HEAP_ZERO_MEMORY,
359 TextResolution.X * TextResolution.Y
360 * sizeof(*CharBuff));
361 ASSERT(CharBuff);
362 #endif
363
364 /* Resize the console */
365 ResizeTextConsole(Resolution, NULL);
366
367 /* Update the saved console information */
368 GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
369
370 /*
371 * Copy console data into VGA memory
372 */
373
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;
378
379 ReadConsoleOutputA(TextConsoleBuffer,
380 CharBuff,
381 TextResolution,
382 Origin,
383 &ConRect);
384
385 /* ... and copy the framebuffer into the VGA memory */
386 AddressSize = VgaGetAddressSize();
387 ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2;
388
389 /* Loop through the scanlines */
390 for (i = 0; i < TextResolution.Y; i++)
391 {
392 /* Loop through the characters */
393 for (j = 0; j < TextResolution.X; j++)
394 {
395 CurrentAddr = LOWORD((Address + j) * AddressSize);
396
397 /* Store the character in plane 0 */
398 VgaMemory[CurrentAddr * VGA_NUM_BANKS] = CharBuff[i * TextResolution.X + j].Char.AsciiChar;
399
400 /* Store the attribute in plane 1 */
401 VgaMemory[CurrentAddr * VGA_NUM_BANKS + 1] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes;
402 }
403
404 /* Move to the next scanline */
405 Address += ScanlineSize;
406 }
407
408 #ifdef USE_REAL_REGISTERCONSOLEVDM
409 if (CharBuff) RtlFreeHeap(RtlGetProcessHeap(), 0, CharBuff);
410 #endif
411
412 UpdateCursorPosition();
413
414 return TRUE;
415 }
416
DetachFromConsoleInternal(VOID)417 static VOID DetachFromConsoleInternal(VOID)
418 {
419 ULONG dummyLength;
420 PVOID dummyPtr;
421 COORD dummySize = {0};
422
423 /* Deregister with the console server */
424 __RegisterConsoleVDM(0,
425 NULL,
426 NULL,
427 NULL,
428 0,
429 &dummyLength,
430 &dummyPtr,
431 NULL,
432 0,
433 dummySize,
434 &dummyPtr);
435
436 TextFramebuffer = NULL;
437 }
438
SetActiveScreenBuffer(HANDLE ScreenBuffer)439 static VOID SetActiveScreenBuffer(HANDLE ScreenBuffer)
440 {
441 ASSERT(ScreenBuffer);
442
443 /* Set the active buffer and reattach the VDM UI to it */
444 SetConsoleActiveScreenBuffer(ScreenBuffer);
445 ConsoleReattach(ScreenBuffer);
446 }
447
ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)448 VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
449 {
450 /*
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.
458 *
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.
463 */
464
465 if (CurrResolution.X == ScreenEvent->dwSize.X &&
466 CurrResolution.Y == ScreenEvent->dwSize.Y)
467 {
468 /* Allowed resize, we are OK */
469 return;
470 }
471
472 DPRINT1("ScreenEventHandler - Detected forbidden resize! Reset console screenbuffer size back to (X = %d ; Y = %d)\n", CurrResolution.X, CurrResolution.Y);
473
474 // FIXME: If we're detaching, then stop monitoring for changes!!
475
476 /* Restore the original console size */
477 ResizeTextConsole(&CurrResolution, NULL);
478
479 /* Force refresh of all the screen */
480 NeedsUpdate = TRUE;
481 UpdateRectangle.Left = 0;
482 UpdateRectangle.Top = 0;
483 UpdateRectangle.Right = CurrResolution.X;
484 UpdateRectangle.Bottom = CurrResolution.Y;
485 VgaRefreshDisplay();
486 }
487
VgaGetDoubleVisionState(PBOOLEAN Horizontal,PBOOLEAN Vertical)488 BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Horizontal, PBOOLEAN Vertical)
489 {
490 if (GraphicsConsoleBuffer == NULL) return FALSE;
491 if (Horizontal) *Horizontal = DoubleWidth;
492 if (Vertical) *Vertical = DoubleHeight;
493 return TRUE;
494 }
495
VgaAttachToConsole(VOID)496 BOOL VgaAttachToConsole(VOID)
497 {
498 if (TextResolution.X == 0 || TextResolution.Y == 0)
499 DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n");
500
501 if (TextResolution.X == 0) TextResolution.X = 80;
502 if (TextResolution.Y == 0) TextResolution.Y = 25;
503
504 // DetachFromConsoleInternal();
505
506 /*
507 * AttachToConsoleInternal sets TextResolution
508 * to the new resolution and updates ConsoleInfo.
509 */
510 if (!AttachToConsoleInternal(&TextResolution))
511 {
512 DisplayMessage(L"An unexpected error occurred!\n");
513 EmulatorTerminate();
514 return FALSE;
515 }
516
517 /* Restore the original screen buffer */
518 SetActiveScreenBuffer(ScreenBufferHandle);
519 ScreenBufferHandle = NULL;
520
521 /* Restore the screen state */
522 if (ScreenMode == TEXT_MODE)
523 {
524 /* The text mode framebuffer was recreated */
525 ActiveFramebuffer = TextFramebuffer;
526 }
527 else
528 {
529 /* The graphics mode framebuffer is unchanged */
530 ActiveFramebuffer = OldConsoleFramebuffer;
531 }
532 OldConsoleFramebuffer = NULL;
533
534 return TRUE;
535 }
536
VgaDetachFromConsole(VOID)537 VOID VgaDetachFromConsole(VOID)
538 {
539 DetachFromConsoleInternal();
540
541 /* Save the screen state */
542 if (ScreenMode == TEXT_MODE)
543 ScreenBufferHandle = TextConsoleBuffer;
544 else
545 ScreenBufferHandle = GraphicsConsoleBuffer;
546
547 /* Reset the active framebuffer */
548 OldConsoleFramebuffer = ActiveFramebuffer;
549 ActiveFramebuffer = NULL;
550
551 /* Restore the original console size */
552 ResizeTextConsole(&OrgConsoleBufferInfo.dwSize, &OrgConsoleBufferInfo.srWindow);
553
554 /* Restore the original cursor shape */
555 SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo);
556
557 // FIXME: Should we copy back the screen data to the screen buffer??
558 // WriteConsoleOutputA(...);
559
560 // FIXME: Should we change cursor POSITION??
561 // VgaUpdateTextCursor();
562
563 ///* Update the physical cursor */
564 //SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
565 //SetConsoleCursorPosition(TextConsoleBuffer, Position /*OrgConsoleBufferInfo.dwCursorPosition*/);
566
567 /* Restore the old text-mode screen buffer */
568 SetActiveScreenBuffer(TextConsoleBuffer);
569 }
570
571
572
573
574 VOID
VgaConsoleUpdateTextCursor(BOOL CursorVisible,BYTE CursorStart,BYTE CursorEnd,BYTE TextSize,DWORD ScanlineSize,WORD Location)575 VgaConsoleUpdateTextCursor(BOOL CursorVisible,
576 BYTE CursorStart,
577 BYTE CursorEnd,
578 BYTE TextSize,
579 DWORD ScanlineSize,
580 WORD Location)
581 {
582 COORD Position;
583 CONSOLE_CURSOR_INFO CursorInfo;
584
585 if (CursorStart < CursorEnd)
586 {
587 /* Visible cursor */
588 CursorInfo.bVisible = CursorVisible;
589 CursorInfo.dwSize = (100 * (CursorEnd - CursorStart)) / TextSize;
590 }
591 else
592 {
593 /* Hidden cursor */
594 CursorInfo.bVisible = FALSE;
595 CursorInfo.dwSize = 1; // The size needs to be non-zero for SetConsoleCursorInfo to succeed.
596 }
597
598 /* Find the coordinates of the new position */
599 Position.X = (SHORT)(Location % ScanlineSize);
600 Position.Y = (SHORT)(Location / ScanlineSize);
601
602 DPRINT("VgaConsoleUpdateTextCursor: (X = %d ; Y = %d)\n", Position.X, Position.Y);
603
604 /* Update the physical cursor */
605 SetConsoleCursorInfo(TextConsoleBuffer, &CursorInfo);
606 SetConsoleCursorPosition(TextConsoleBuffer, Position);
607 }
608
609 BOOL
VgaConsoleCreateGraphicsScreen(IN PCOORD Resolution,IN HANDLE PaletteHandle)610 VgaConsoleCreateGraphicsScreen(// OUT PBYTE* GraphicsFramebuffer,
611 IN PCOORD Resolution,
612 IN HANDLE PaletteHandle)
613 {
614 DWORD i;
615 CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo;
616 BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE];
617 LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer;
618 LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors);
619
620 LONG Width = Resolution->X;
621 LONG Height = Resolution->Y;
622
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;
628
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 */;
638
639 /* Fill the palette data */
640 for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i;
641
642 /* Fill the console graphics buffer info */
643 GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE;
644 GraphicsBufferInfo.lpBitMapInfo = BitmapInfo;
645 GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS;
646
647 /* Create the buffer */
648 GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
649 FILE_SHARE_READ | FILE_SHARE_WRITE,
650 NULL,
651 CONSOLE_GRAPHICS_BUFFER,
652 &GraphicsBufferInfo);
653 if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE;
654
655 /* Save the framebuffer address and mutex */
656 // *GraphicsFramebuffer = GraphicsBufferInfo.lpBitMap;
657 GraphicsFramebuffer = GraphicsBufferInfo.lpBitMap;
658 ConsoleMutex = GraphicsBufferInfo.hMutex;
659
660 /* Clear the framebuffer */
661 // RtlZeroMemory(*GraphicsFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
662 RtlZeroMemory(GraphicsFramebuffer, BitmapInfo->bmiHeader.biSizeImage);
663
664 /* Set the graphics mode palette */
665 SetConsolePalette(GraphicsConsoleBuffer,
666 PaletteHandle,
667 SYSPAL_NOSTATIC256);
668
669 /* Set the active buffer */
670 SetActiveScreenBuffer(GraphicsConsoleBuffer);
671
672 return TRUE;
673 }
674
VgaConsoleDestroyGraphicsScreen(VOID)675 VOID VgaConsoleDestroyGraphicsScreen(VOID)
676 {
677 /* Release the console framebuffer mutex */
678 ReleaseMutex(ConsoleMutex);
679
680 /* Switch back to the default console text buffer */
681 // SetActiveScreenBuffer(TextConsoleBuffer);
682
683 /* Cleanup the video data */
684 CloseHandle(ConsoleMutex);
685 ConsoleMutex = NULL;
686 // GraphicsFramebuffer = NULL;
687 CloseHandle(GraphicsConsoleBuffer);
688 GraphicsConsoleBuffer = NULL;
689
690 // /* Reset the active framebuffer */
691 // ActiveFramebuffer = NULL;
692
693 DoubleWidth = FALSE;
694 DoubleHeight = FALSE;
695 }
696
697 BOOL
VgaConsoleCreateTextScreen(IN PCOORD Resolution,IN HANDLE PaletteHandle)698 VgaConsoleCreateTextScreen(// OUT PCHAR_CELL* TextFramebuffer,
699 IN PCOORD Resolution,
700 IN HANDLE PaletteHandle)
701 {
702 /* Switch to the text buffer */
703 // FIXME: Wouldn't it be preferrable to switch to it AFTER we reset everything??
704 SetActiveScreenBuffer(TextConsoleBuffer);
705
706 /* Adjust the text framebuffer if we changed the resolution */
707 if (TextResolution.X != Resolution->X ||
708 TextResolution.Y != Resolution->Y)
709 {
710 DetachFromConsoleInternal();
711
712 /*
713 * AttachToConsoleInternal sets TextResolution
714 * to the new resolution and updates ConsoleInfo.
715 */
716 if (!AttachToConsoleInternal(Resolution))
717 {
718 DisplayMessage(L"An unexpected error occurred!\n");
719 EmulatorTerminate();
720 return FALSE;
721 }
722 }
723 else
724 {
725 UpdateCursorPosition();
726 }
727
728 /*
729 * Set the text mode palette.
730 *
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).
736 */
737 SetConsolePalette(TextConsoleBuffer,
738 PaletteHandle,
739 SYSPAL_NOSTATIC256);
740
741 return TRUE;
742 }
743
VgaConsoleDestroyTextScreen(VOID)744 VOID VgaConsoleDestroyTextScreen(VOID)
745 {
746 }
747
748
749
VgaConsoleRepaintScreen(PSMALL_RECT Rect)750 VOID VgaConsoleRepaintScreen(PSMALL_RECT Rect)
751 {
752 HANDLE ConsoleBufferHandle = NULL;
753 SMALL_RECT UpdateRectangle = *Rect;
754
755 /* Check if we are in text or graphics mode */
756 if (ScreenMode == GRAPHICS_MODE)
757 {
758 /* Graphics mode */
759 ConsoleBufferHandle = GraphicsConsoleBuffer;
760
761 /* In DoubleVision mode, scale the update rectangle */
762 if (DoubleWidth)
763 {
764 UpdateRectangle.Left *= 2;
765 UpdateRectangle.Right = UpdateRectangle.Right * 2 + 1;
766 }
767 if (DoubleHeight)
768 {
769 UpdateRectangle.Top *= 2;
770 UpdateRectangle.Bottom = UpdateRectangle.Bottom * 2 + 1;
771 }
772 }
773 else
774 {
775 /* Text mode */
776 ConsoleBufferHandle = TextConsoleBuffer;
777 }
778
779 /* Redraw the screen */
780 __InvalidateConsoleDIBits(ConsoleBufferHandle, &UpdateRectangle);
781 }
782
VgaConsoleInitialize(HANDLE TextHandle)783 BOOLEAN VgaConsoleInitialize(HANDLE TextHandle)
784 {
785 /*
786 * Initialize the console video by saving the default
787 * text-mode console output handle, if it is valid.
788 */
789 if (!IsConsoleHandle(TextHandle)) return FALSE;
790 TextConsoleBuffer = TextHandle;
791
792 /* Save the original cursor and console screen buffer information */
793 if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) ||
794 !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo))
795 {
796 TextConsoleBuffer = NULL;
797 return FALSE;
798 }
799 ConsoleInfo = OrgConsoleBufferInfo;
800
801 /* Switch to the text buffer, but do not enter into a text mode */
802 SetActiveScreenBuffer(TextConsoleBuffer);
803
804 return TRUE;
805 }
806
VgaConsoleCleanup(VOID)807 VOID VgaConsoleCleanup(VOID)
808 {
809 /* If the console video was not initialized, just return */
810 if (!TextConsoleBuffer)
811 return;
812
813 VgaDetachFromConsole();
814
815 // TODO: We need to initialize those events before using them!
816 CloseHandle(AnotherEvent);
817 CloseHandle(EndEvent);
818 CloseHandle(StartEvent);
819 }
820