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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 744 VOID VgaConsoleDestroyTextScreen(VOID) 745 { 746 } 747 748 749 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 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 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