Author: aandrejevic Date: Fri May 2 21:17:05 2014 New Revision: 63119
URL: http://svn.reactos.org/svn/reactos?rev=63119&view=rev Log: [NTVDM] Restore the console to normal size while no DOS task is running and keep track of the cursor position. Adapted from a patch by Hermès Bélusca-Maïto.
Modified: branches/ntvdm/subsystems/ntvdm/dos/dem.c branches/ntvdm/subsystems/ntvdm/hardware/vga.c branches/ntvdm/subsystems/ntvdm/hardware/vga.h branches/ntvdm/subsystems/ntvdm/ntvdm.c
Modified: branches/ntvdm/subsystems/ntvdm/dos/dem.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos/dem.c... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/dos/dem.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/dos/dem.c [iso-8859-1] Fri May 2 21:17:05 2014 @@ -20,6 +20,9 @@ #include "dem.h" #include "bop.h"
+#include "bios/bios.h" +#include "hardware/vga.h" + /* Extra PSDK/NDK Headers */ #include <ndk/obtypes.h>
@@ -117,7 +120,7 @@ STARTUPINFOA StartupInfo; PROCESS_INFORMATION ProcessInformation;
- /* Remove return carriage character */ + /* NULL-terminate the command by removing the return carriage character */ while (*CmdPtr != '\r') CmdPtr++; *CmdPtr = '\0';
@@ -135,7 +138,8 @@
StartupInfo.cb = sizeof(StartupInfo);
- DosPrintCharacter('\n'); + VgaRefreshDisplay(); + VgaDetachFromConsole(FALSE);
Result = CreateProcessA(NULL, CommandLine, @@ -166,8 +170,10 @@ DPRINT1("Failed when launched command '%s'\n"); dwExitCode = GetLastError(); } - - DosPrintCharacter('\n'); + + VgaAttachToConsole(); + VgaRefreshDisplay(); + VidBiosSyncCursorPosition();
setAL((UCHAR)dwExitCode);
Modified: branches/ntvdm/subsystems/ntvdm/hardware/vga.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/hardware/... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/hardware/vga.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/hardware/vga.c [iso-8859-1] Fri May 2 21:17:05 2014 @@ -12,6 +12,7 @@
#include "emulator.h" #include "vga.h" +#include "../bios/vidbios.h"
#include "io.h"
@@ -189,6 +190,10 @@ static HANDLE EndEvent = NULL; static HANDLE AnotherEvent = NULL;
+static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo; +static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo; + + /* * Text mode -- we always keep a valid text mode framebuffer * even if we are in graphics mode. This is needed in order to @@ -403,8 +408,24 @@ /* PRIVATE FUNCTIONS **********************************************************/
static inline DWORD VgaGetAddressSize(VOID); - -static BOOL VgaAttachToConsole(PCOORD Resolution) +static VOID VgaUpdateTextCursor(VOID); + +static VOID VgaUpdateCursorPosition(VOID) +{ + /* + * Update the cursor position in the VGA registers. + */ + WORD Offset = ConsoleInfo.dwCursorPosition.Y * TextResolution.X + + ConsoleInfo.dwCursorPosition.X; + + VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset); + VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset); + + VidBiosSyncCursorPosition(); + VgaUpdateTextCursor(); +} + +static BOOL VgaAttachToConsoleInternal(PCOORD Resolution) { BOOL Success; ULONG Length = 0; @@ -414,12 +435,10 @@ DWORD AddressSize, ScanlineSize; DWORD Address = 0; DWORD CurrentAddr; - SMALL_RECT ScreenRect; // ConRect; + SMALL_RECT ConRect; COORD Origin = { 0, 0 };
ASSERT(TextFramebuffer == NULL); - - // ResetEvent(AnotherEvent);
TextResolution = *Resolution;
@@ -454,504 +473,9 @@ return FALSE; }
- /* Copy console data into VGA memory */ - - /* Get the data */ - AddressSize = VgaGetAddressSize(); - ScreenRect.Left = ScreenRect.Top = 0; - ScreenRect.Right = TextResolution.X; - ScreenRect.Bottom = TextResolution.Y; - - // ConRect.Left = 0; - // ConRect.Top = ConsoleSize->Y - BufferSize.Y; - // ConRect.Right = ConRect.Left + BufferSize.X - 1; - // ConRect.Bottom = ConRect.Top + BufferSize.Y - 1; - - ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2; - - /* Read the data from the console into the framebuffer... */ - ReadConsoleOutputA(TextConsoleBuffer, - CharBuff, - TextResolution, - Origin, - &ScreenRect); // &ConRect); - - /* ... and copy the framebuffer into the VGA memory */ - - /* Loop through the scanlines */ - for (i = 0; i < TextResolution.Y; i++) - { - /* Loop through the characters */ - for (j = 0; j < TextResolution.X; j++) - { - CurrentAddr = LOWORD((Address + j) * AddressSize); - - /* Store the character in plane 0 */ - VgaMemory[CurrentAddr] = CharBuff[i * TextResolution.X + j].Char.AsciiChar; - - /* Store the attribute in plane 1 */ - VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes; - } - - /* Move to the next scanline */ - Address += ScanlineSize; - } - - return TRUE; -} - -static VOID VgaDetachFromConsole(VOID) -{ - ULONG dummyLength; - PVOID dummyPtr; - COORD dummySize = {0}; - - __RegisterConsoleVDM(0, - NULL, - NULL, - NULL, - 0, - &dummyLength, - &dummyPtr, - NULL, - 0, - dummySize, - (PCHAR*)&dummyPtr); - - TextFramebuffer = NULL; -} - -static BOOL IsConsoleHandle(HANDLE hHandle) -{ - DWORD dwMode; - - /* Check whether the handle may be that of a console... */ - if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR) - return FALSE; - /* - * It may be. Perform another test... The idea comes from the - * MSDN description of the WriteConsole API: - * - * "WriteConsole fails if it is used with a standard handle - * that is redirected to a file. If an application processes - * multilingual output that can be redirected, determine whether - * the output handle is a console handle (one method is to call - * the GetConsoleMode function and check whether it succeeds). - * If the handle is a console handle, call WriteConsole. If the - * handle is not a console handle, the output is redirected and - * you should call WriteFile to perform the I/O." + * Resize the console */ - return GetConsoleMode(hHandle, &dwMode); -} - -static inline DWORD VgaGetAddressSize(VOID) -{ - if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD) - { - /* Double-word addressing */ - return 4; // sizeof(DWORD) - } - else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE) - { - /* Byte addressing */ - return 1; // sizeof(BYTE) - } - else - { - /* Word addressing */ - return 2; // sizeof(WORD) - } -} - -static inline DWORD VgaTranslateReadAddress(DWORD Address) -{ - DWORD Offset = Address - VgaGetVideoBaseAddress(); - BYTE Plane; - - /* Check for chain-4 and odd-even mode */ - if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) - { - /* The lowest two bits are the plane number */ - Plane = Offset & 3; - Offset >>= 2; - } - else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) - { - /* The LSB is the plane number */ - Plane = Offset & 1; - Offset >>= 1; - } - else - { - /* Use the read mode */ - Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03; - } - - /* Multiply the offset by the address size */ - Offset *= VgaGetAddressSize(); - - return Offset + Plane * VGA_BANK_SIZE; -} - -static inline DWORD VgaTranslateWriteAddress(DWORD Address) -{ - DWORD Offset = Address - VgaGetVideoBaseAddress(); - - /* Check for chain-4 and odd-even mode */ - if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) - { - /* Shift the offset to the right by 2 */ - Offset >>= 2; - } - else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) - { - /* Shift the offset to the right by 1 */ - Offset >>= 1; - } - - /* Multiply the offset by the address size */ - Offset *= VgaGetAddressSize(); - - /* Return the offset on plane 0 */ - return Offset; -} - -static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane) -{ - BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3; - BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG]; - - if (WriteMode == 1) - { - /* In write mode 1 just return the latch register */ - return VgaLatchRegisters[Plane]; - } - - if (WriteMode != 2) - { - /* Write modes 0 and 3 rotate the data to the right first */ - BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7; - Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount))); - } - else - { - /* Write mode 2 expands the appropriate bit to all 8 bits */ - Data = (Data & (1 << Plane)) ? 0xFF : 0x00; - } - - if (WriteMode == 0) - { - /* - * In write mode 0, the enable set/reset register decides if the - * set/reset bit should be expanded to all 8 bits. - */ - if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane)) - { - /* Copy the bit from the set/reset register to all 8 bits */ - Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00; - } - } - - if (WriteMode != 3) - { - /* Write modes 0 and 2 then perform a logical operation on the data and latch */ - BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3; - - if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane]; - else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane]; - else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane]; - } - else - { - /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */ - BitMask &= Data; - - /* Then we expand the bit in the set/reset field */ - Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00; - } - - /* Bits cleared in the bitmask are replaced with latch register bits */ - Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask)); - - /* Return the byte */ - return Data; -} - -static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column) -{ - /* Check if this is the first time the rectangle is updated */ - if (!NeedsUpdate) - { - UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT; - UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT; - } - - /* Expand the rectangle to include the point */ - UpdateRectangle.Left = min(UpdateRectangle.Left, Column); - UpdateRectangle.Right = max(UpdateRectangle.Right, Column); - UpdateRectangle.Top = min(UpdateRectangle.Top, Row); - UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row); - - /* Set the update request flag */ - NeedsUpdate = TRUE; -} - -static VOID VgaWriteSequencer(BYTE Data) -{ - ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG); - - /* Save the value */ - VgaSeqRegisters[VgaSeqIndex] = Data; -} - -static VOID VgaWriteGc(BYTE Data) -{ - ASSERT(VgaGcIndex < VGA_GC_MAX_REG); - - /* Save the value */ - VgaGcRegisters[VgaGcIndex] = Data; - - /* Check the index */ - switch (VgaGcIndex) - { - case VGA_GC_MISC_REG: - { - /* The GC misc register decides if it's text or graphics mode */ - ModeChanged = TRUE; - break; - } - } -} - -static VOID VgaWriteCrtc(BYTE Data) -{ - ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG); - - /* Save the value */ - VgaCrtcRegisters[VgaCrtcIndex] = Data; - - /* Check the index */ - switch (VgaCrtcIndex) - { - case VGA_CRTC_END_HORZ_DISP_REG: - case VGA_CRTC_VERT_DISP_END_REG: - case VGA_CRTC_OVERFLOW_REG: - { - /* The video mode has changed */ - ModeChanged = TRUE; - break; - } - - case VGA_CRTC_CURSOR_LOC_LOW_REG: - case VGA_CRTC_CURSOR_LOC_HIGH_REG: - case VGA_CRTC_CURSOR_START_REG: - case VGA_CRTC_CURSOR_END_REG: - { - /* Set the cursor moved flag */ - CursorMoved = TRUE; - break; - } - } -} - -static VOID VgaWriteDac(BYTE Data) -{ - INT PaletteIndex; - PALETTEENTRY Entry; - - /* Set the value */ - VgaDacRegisters[VgaDacIndex] = Data; - - /* Find the palette index */ - PaletteIndex = VgaDacIndex / 3; - - /* Fill the entry structure */ - Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]); - Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]); - Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]); - Entry.peFlags = 0; - - /* Update the palette entry and set the palette change flag */ - SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry); - PaletteChanged = TRUE; - - /* Update the index */ - VgaDacIndex++; - VgaDacIndex %= VGA_PALETTE_SIZE; -} - -static VOID VgaWriteAc(BYTE Data) -{ - ASSERT(VgaAcIndex < VGA_AC_MAX_REG); - - /* Save the value */ - if (VgaAcIndex <= VGA_AC_PAL_F_REG) - { - if (VgaAcPalDisable) return; - - // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex); - if (VgaAcRegisters[VgaAcIndex] != Data) - { - /* Update the AC register and set the palette change flag */ - VgaAcRegisters[VgaAcIndex] = Data; - PaletteChanged = TRUE; - } - } - else - { - VgaAcRegisters[VgaAcIndex] = Data; - } -} - -static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries) -{ - USHORT i; - - /* Copy the colors of the default palette to the DAC and console palette */ - for (i = 0; i < NumOfEntries; i++) - { - /* Set the palette entries */ - Entries[i].peRed = GetRValue(VgaDefaultPalette[i]); - Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]); - Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]); - Entries[i].peFlags = 0; - - /* Set the DAC registers */ - VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i])); - VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i])); - VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i])); - } -} - -static BOOLEAN VgaInitializePalette(VOID) -{ - LPLOGPALETTE Palette; - - /* Allocate storage space for the palette */ - Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(LOGPALETTE) + - VGA_MAX_COLORS * sizeof(PALETTEENTRY)); - if (Palette == NULL) return FALSE; - - /* Initialize the palette */ - Palette->palVersion = 0x0300; - Palette->palNumEntries = VGA_MAX_COLORS; - - /* Restore the default palette */ - VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries); - - /* Create the palette */ - PaletteHandle = CreatePalette(Palette); - - /* Free the palette */ - HeapFree(GetProcessHeap(), 0, Palette); - - /* Fail if the palette wasn't successfully created... */ - if (PaletteHandle == NULL) return FALSE; - - /* ... otherwise return success */ - return TRUE; -} - -static BOOL VgaEnterGraphicsMode(PCOORD Resolution) -{ - DWORD i; - CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo; - BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE]; - LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer; - LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors); - - LONG Width = Resolution->X; - LONG Height = Resolution->Y; - - /* Use DoubleVision mode if the resolution is too small */ - if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT) - { - DoubleVision = TRUE; - Width *= 2; - Height *= 2; - } - else - { - DoubleVision = FALSE; - } - - /* Fill the bitmap info header */ - ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER)); - BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - BitmapInfo->bmiHeader.biWidth = Width; - BitmapInfo->bmiHeader.biHeight = Height; - BitmapInfo->bmiHeader.biBitCount = 8; - BitmapInfo->bmiHeader.biPlanes = 1; - BitmapInfo->bmiHeader.biCompression = BI_RGB; - BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */; - - /* Fill the palette data */ - for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i; - - /* Fill the console graphics buffer info */ - GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE; - GraphicsBufferInfo.lpBitMapInfo = BitmapInfo; - GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS; - - /* Create the buffer */ - GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - CONSOLE_GRAPHICS_BUFFER, - &GraphicsBufferInfo); - if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE; - - /* Save the framebuffer address and mutex */ - ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap; - ConsoleMutex = GraphicsBufferInfo.hMutex; - - /* Clear the framebuffer */ - ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage); - - /* Set the active buffer */ - SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer); - - /* Set the graphics mode palette */ - SetConsolePalette(GraphicsConsoleBuffer, - PaletteHandle, - SYSPAL_NOSTATIC256); - - /* Set the screen mode flag */ - ScreenMode = GRAPHICS_MODE; - - return TRUE; -} - -static VOID VgaLeaveGraphicsMode(VOID) -{ - /* Release the console framebuffer mutex */ - ReleaseMutex(ConsoleMutex); - - /* Switch back to the default console text buffer */ - // SetConsoleActiveScreenBuffer(TextConsoleBuffer); - - /* Cleanup the video data */ - CloseHandle(ConsoleMutex); - ConsoleMutex = NULL; - ConsoleFramebuffer = NULL; - CloseHandle(GraphicsConsoleBuffer); - GraphicsConsoleBuffer = NULL; - DoubleVision = FALSE; -} - -static BOOL VgaEnterTextMode(PCOORD Resolution) -{ - SMALL_RECT ConRect; - - DPRINT1("VgaEnterTextMode\n"); - - /* Switch to the text buffer */ - SetConsoleActiveScreenBuffer(TextConsoleBuffer); - - /* Resize the console */ ConRect.Left = 0; ConRect.Top = ConsoleInfo.srWindow.Top; ConRect.Right = ConRect.Left + Resolution->X - 1; @@ -970,30 +494,551 @@ /* Update the saved console information */ GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo);
- /* Adjust the text framebuffer if we changed resolution */ + /* + * Copy console data into VGA memory + */ + + /* Get the data */ + AddressSize = VgaGetAddressSize(); + ConRect.Left = ConRect.Top = 0; + ConRect.Right = TextResolution.X; + ConRect.Bottom = TextResolution.Y; + ScanlineSize = (DWORD)VgaCrtcRegisters[VGA_CRTC_OFFSET_REG] * 2; + + /* Read the data from the console into the framebuffer... */ + ReadConsoleOutputA(TextConsoleBuffer, + CharBuff, + TextResolution, + Origin, + &ConRect); + + /* ... and copy the framebuffer into the VGA memory */ + + /* Loop through the scanlines */ + for (i = 0; i < TextResolution.Y; i++) + { + /* Loop through the characters */ + for (j = 0; j < TextResolution.X; j++) + { + CurrentAddr = LOWORD((Address + j) * AddressSize); + + /* Store the character in plane 0 */ + VgaMemory[CurrentAddr] = CharBuff[i * TextResolution.X + j].Char.AsciiChar; + + /* Store the attribute in plane 1 */ + VgaMemory[CurrentAddr + VGA_BANK_SIZE] = (BYTE)CharBuff[i * TextResolution.X + j].Attributes; + } + + /* Move to the next scanline */ + Address += ScanlineSize; + } + + VgaUpdateCursorPosition(); + + return TRUE; +} + +BOOL VgaAttachToConsole(VOID) +{ + if (TextResolution.X == 0 || TextResolution.Y == 0) + DPRINT1("VgaAttachToConsole -- TextResolution uninitialized\n"); + + if (TextResolution.X == 0) TextResolution.X = 80; + if (TextResolution.Y == 0) TextResolution.Y = 25; + + return VgaAttachToConsoleInternal(&TextResolution); +} + +VOID VgaDetachFromConsole(BOOL ChangingMode) +{ + ULONG dummyLength; + PVOID dummyPtr; + COORD dummySize = {0}; + + __RegisterConsoleVDM(0, + NULL, + NULL, + NULL, + 0, + &dummyLength, + &dummyPtr, + NULL, + 0, + dummySize, + (PCHAR*)&dummyPtr); + + TextFramebuffer = NULL; + + if (!ChangingMode) + { + SMALL_RECT ConRect; + + /* Restore the old screen buffer */ + SetConsoleActiveScreenBuffer(TextConsoleBuffer); + + /* Restore the original console size */ + ConRect.Left = 0; + ConRect.Top = 0; + ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left; + ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ; + /* + * See the following trick explanation in VgaAttachToConsoleInternal. + */ + SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize); + SetConsoleWindowInfo(TextConsoleBuffer, TRUE, &ConRect); + SetConsoleScreenBufferSize(TextConsoleBuffer, OrgConsoleBufferInfo.dwSize); + + /* Restore the original cursor shape */ + SetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo); + } +} + +static BOOL IsConsoleHandle(HANDLE hHandle) +{ + DWORD dwMode; + + /* Check whether the handle may be that of a console... */ + if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR) + return FALSE; + + /* + * It may be. Perform another test... The idea comes from the + * MSDN description of the WriteConsole API: + * + * "WriteConsole fails if it is used with a standard handle + * that is redirected to a file. If an application processes + * multilingual output that can be redirected, determine whether + * the output handle is a console handle (one method is to call + * the GetConsoleMode function and check whether it succeeds). + * If the handle is a console handle, call WriteConsole. If the + * handle is not a console handle, the output is redirected and + * you should call WriteFile to perform the I/O." + */ + return GetConsoleMode(hHandle, &dwMode); +} + +static inline DWORD VgaGetAddressSize(VOID) +{ + if (VgaCrtcRegisters[VGA_CRTC_UNDERLINE_REG] & VGA_CRTC_UNDERLINE_DWORD) + { + /* Double-word addressing */ + return 4; // sizeof(DWORD) + } + else if (VgaCrtcRegisters[VGA_CRTC_MODE_CONTROL_REG] & VGA_CRTC_MODE_CONTROL_BYTE) + { + /* Byte addressing */ + return 1; // sizeof(BYTE) + } + else + { + /* Word addressing */ + return 2; // sizeof(WORD) + } +} + +static inline DWORD VgaTranslateReadAddress(DWORD Address) +{ + DWORD Offset = Address - VgaGetVideoBaseAddress(); + BYTE Plane; + + /* Check for chain-4 and odd-even mode */ + if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) + { + /* The lowest two bits are the plane number */ + Plane = Offset & 3; + Offset >>= 2; + } + else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) + { + /* The LSB is the plane number */ + Plane = Offset & 1; + Offset >>= 1; + } + else + { + /* Use the read mode */ + Plane = VgaGcRegisters[VGA_GC_READ_MAP_SEL_REG] & 0x03; + } + + /* Multiply the offset by the address size */ + Offset *= VgaGetAddressSize(); + + return Offset + Plane * VGA_BANK_SIZE; +} + +static inline DWORD VgaTranslateWriteAddress(DWORD Address) +{ + DWORD Offset = Address - VgaGetVideoBaseAddress(); + + /* Check for chain-4 and odd-even mode */ + if (VgaSeqRegisters[VGA_SEQ_MEM_REG] & VGA_SEQ_MEM_C4) + { + /* Shift the offset to the right by 2 */ + Offset >>= 2; + } + else if (VgaGcRegisters[VGA_GC_MODE_REG] & VGA_GC_MODE_OE) + { + /* Shift the offset to the right by 1 */ + Offset >>= 1; + } + + /* Multiply the offset by the address size */ + Offset *= VgaGetAddressSize(); + + /* Return the offset on plane 0 */ + return Offset; +} + +static inline BYTE VgaTranslateByteForWriting(BYTE Data, BYTE Plane) +{ + BYTE WriteMode = VgaGcRegisters[VGA_GC_MODE_REG] & 3; + BYTE BitMask = VgaGcRegisters[VGA_GC_BITMASK_REG]; + + if (WriteMode == 1) + { + /* In write mode 1 just return the latch register */ + return VgaLatchRegisters[Plane]; + } + + if (WriteMode != 2) + { + /* Write modes 0 and 3 rotate the data to the right first */ + BYTE RotateCount = VgaGcRegisters[VGA_GC_ROTATE_REG] & 7; + Data = LOBYTE(((DWORD)Data >> RotateCount) | ((DWORD)Data << (8 - RotateCount))); + } + else + { + /* Write mode 2 expands the appropriate bit to all 8 bits */ + Data = (Data & (1 << Plane)) ? 0xFF : 0x00; + } + + if (WriteMode == 0) + { + /* + * In write mode 0, the enable set/reset register decides if the + * set/reset bit should be expanded to all 8 bits. + */ + if (VgaGcRegisters[VGA_GC_ENABLE_RESET_REG] & (1 << Plane)) + { + /* Copy the bit from the set/reset register to all 8 bits */ + Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00; + } + } + + if (WriteMode != 3) + { + /* Write modes 0 and 2 then perform a logical operation on the data and latch */ + BYTE LogicalOperation = (VgaGcRegisters[VGA_GC_ROTATE_REG] >> 3) & 3; + + if (LogicalOperation == 1) Data &= VgaLatchRegisters[Plane]; + else if (LogicalOperation == 2) Data |= VgaLatchRegisters[Plane]; + else if (LogicalOperation == 3) Data ^= VgaLatchRegisters[Plane]; + } + else + { + /* For write mode 3, we AND the bitmask with the data, which is used as the new bitmask */ + BitMask &= Data; + + /* Then we expand the bit in the set/reset field */ + Data = (VgaGcRegisters[VGA_GC_RESET_REG] & (1 << Plane)) ? 0xFF : 0x00; + } + + /* Bits cleared in the bitmask are replaced with latch register bits */ + Data = (Data & BitMask) | (VgaLatchRegisters[Plane] & (~BitMask)); + + /* Return the byte */ + return Data; +} + +static inline VOID VgaMarkForUpdate(SHORT Row, SHORT Column) +{ + /* Check if this is the first time the rectangle is updated */ + if (!NeedsUpdate) + { + UpdateRectangle.Left = UpdateRectangle.Top = MAXSHORT; + UpdateRectangle.Right = UpdateRectangle.Bottom = MINSHORT; + } + + /* Expand the rectangle to include the point */ + UpdateRectangle.Left = min(UpdateRectangle.Left, Column); + UpdateRectangle.Right = max(UpdateRectangle.Right, Column); + UpdateRectangle.Top = min(UpdateRectangle.Top, Row); + UpdateRectangle.Bottom = max(UpdateRectangle.Bottom, Row); + + /* Set the update request flag */ + NeedsUpdate = TRUE; +} + +static VOID VgaWriteSequencer(BYTE Data) +{ + ASSERT(VgaSeqIndex < VGA_SEQ_MAX_REG); + + /* Save the value */ + VgaSeqRegisters[VgaSeqIndex] = Data; +} + +static VOID VgaWriteGc(BYTE Data) +{ + ASSERT(VgaGcIndex < VGA_GC_MAX_REG); + + /* Save the value */ + VgaGcRegisters[VgaGcIndex] = Data; + + /* Check the index */ + switch (VgaGcIndex) + { + case VGA_GC_MISC_REG: + { + /* The GC misc register decides if it's text or graphics mode */ + ModeChanged = TRUE; + break; + } + } +} + +static VOID VgaWriteCrtc(BYTE Data) +{ + ASSERT(VgaGcIndex < VGA_CRTC_MAX_REG); + + /* Save the value */ + VgaCrtcRegisters[VgaCrtcIndex] = Data; + + /* Check the index */ + switch (VgaCrtcIndex) + { + case VGA_CRTC_END_HORZ_DISP_REG: + case VGA_CRTC_VERT_DISP_END_REG: + case VGA_CRTC_OVERFLOW_REG: + { + /* The video mode has changed */ + ModeChanged = TRUE; + break; + } + + case VGA_CRTC_CURSOR_LOC_LOW_REG: + case VGA_CRTC_CURSOR_LOC_HIGH_REG: + case VGA_CRTC_CURSOR_START_REG: + case VGA_CRTC_CURSOR_END_REG: + { + /* Set the cursor moved flag */ + CursorMoved = TRUE; + break; + } + } +} + +static VOID VgaWriteDac(BYTE Data) +{ + INT PaletteIndex; + PALETTEENTRY Entry; + + /* Set the value */ + VgaDacRegisters[VgaDacIndex] = Data; + + /* Find the palette index */ + PaletteIndex = VgaDacIndex / 3; + + /* Fill the entry structure */ + Entry.peRed = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3]); + Entry.peGreen = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 1]); + Entry.peBlue = VGA_DAC_TO_COLOR(VgaDacRegisters[PaletteIndex * 3 + 2]); + Entry.peFlags = 0; + + /* Update the palette entry and set the palette change flag */ + SetPaletteEntries(PaletteHandle, PaletteIndex, 1, &Entry); + PaletteChanged = TRUE; + + /* Update the index */ + VgaDacIndex++; + VgaDacIndex %= VGA_PALETTE_SIZE; +} + +static VOID VgaWriteAc(BYTE Data) +{ + ASSERT(VgaAcIndex < VGA_AC_MAX_REG); + + /* Save the value */ + if (VgaAcIndex <= VGA_AC_PAL_F_REG) + { + if (VgaAcPalDisable) return; + + // DbgPrint(" AC Palette Writing %d to index %d\n", Data, VgaAcIndex); + if (VgaAcRegisters[VgaAcIndex] != Data) + { + /* Update the AC register and set the palette change flag */ + VgaAcRegisters[VgaAcIndex] = Data; + PaletteChanged = TRUE; + } + } + else + { + VgaAcRegisters[VgaAcIndex] = Data; + } +} + +static VOID VgaRestoreDefaultPalette(PPALETTEENTRY Entries, USHORT NumOfEntries) +{ + USHORT i; + + /* Copy the colors of the default palette to the DAC and console palette */ + for (i = 0; i < NumOfEntries; i++) + { + /* Set the palette entries */ + Entries[i].peRed = GetRValue(VgaDefaultPalette[i]); + Entries[i].peGreen = GetGValue(VgaDefaultPalette[i]); + Entries[i].peBlue = GetBValue(VgaDefaultPalette[i]); + Entries[i].peFlags = 0; + + /* Set the DAC registers */ + VgaDacRegisters[i * 3] = VGA_COLOR_TO_DAC(GetRValue(VgaDefaultPalette[i])); + VgaDacRegisters[i * 3 + 1] = VGA_COLOR_TO_DAC(GetGValue(VgaDefaultPalette[i])); + VgaDacRegisters[i * 3 + 2] = VGA_COLOR_TO_DAC(GetBValue(VgaDefaultPalette[i])); + } +} + +static BOOLEAN VgaInitializePalette(VOID) +{ + LPLOGPALETTE Palette; + + /* Allocate storage space for the palette */ + Palette = (LPLOGPALETTE)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(LOGPALETTE) + + VGA_MAX_COLORS * sizeof(PALETTEENTRY)); + if (Palette == NULL) return FALSE; + + /* Initialize the palette */ + Palette->palVersion = 0x0300; + Palette->palNumEntries = VGA_MAX_COLORS; + + /* Restore the default palette */ + VgaRestoreDefaultPalette(Palette->palPalEntry, Palette->palNumEntries); + + /* Create the palette */ + PaletteHandle = CreatePalette(Palette); + + /* Free the palette */ + HeapFree(GetProcessHeap(), 0, Palette); + + /* Fail if the palette wasn't successfully created... */ + if (PaletteHandle == NULL) return FALSE; + + /* ... otherwise return success */ + return TRUE; +} + +static BOOL VgaEnterGraphicsMode(PCOORD Resolution) +{ + DWORD i; + CONSOLE_GRAPHICS_BUFFER_INFO GraphicsBufferInfo; + BYTE BitmapInfoBuffer[VGA_BITMAP_INFO_SIZE]; + LPBITMAPINFO BitmapInfo = (LPBITMAPINFO)BitmapInfoBuffer; + LPWORD PaletteIndex = (LPWORD)(BitmapInfo->bmiColors); + + LONG Width = Resolution->X; + LONG Height = Resolution->Y; + + /* Use DoubleVision mode if the resolution is too small */ + if (Width < VGA_MINIMUM_WIDTH && Height < VGA_MINIMUM_HEIGHT) + { + DoubleVision = TRUE; + Width *= 2; + Height *= 2; + } + else + { + DoubleVision = FALSE; + } + + /* Fill the bitmap info header */ + ZeroMemory(&BitmapInfo->bmiHeader, sizeof(BITMAPINFOHEADER)); + BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + BitmapInfo->bmiHeader.biWidth = Width; + BitmapInfo->bmiHeader.biHeight = Height; + BitmapInfo->bmiHeader.biBitCount = 8; + BitmapInfo->bmiHeader.biPlanes = 1; + BitmapInfo->bmiHeader.biCompression = BI_RGB; + BitmapInfo->bmiHeader.biSizeImage = Width * Height /* * 1 == biBitCount / 8 */; + + /* Fill the palette data */ + for (i = 0; i < (VGA_PALETTE_SIZE / 3); i++) PaletteIndex[i] = (WORD)i; + + /* Fill the console graphics buffer info */ + GraphicsBufferInfo.dwBitMapInfoLength = VGA_BITMAP_INFO_SIZE; + GraphicsBufferInfo.lpBitMapInfo = BitmapInfo; + GraphicsBufferInfo.dwUsage = DIB_PAL_COLORS; + + /* Create the buffer */ + GraphicsConsoleBuffer = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + CONSOLE_GRAPHICS_BUFFER, + &GraphicsBufferInfo); + if (GraphicsConsoleBuffer == INVALID_HANDLE_VALUE) return FALSE; + + /* Save the framebuffer address and mutex */ + ConsoleFramebuffer = GraphicsBufferInfo.lpBitMap; + ConsoleMutex = GraphicsBufferInfo.hMutex; + + /* Clear the framebuffer */ + ZeroMemory(ConsoleFramebuffer, BitmapInfo->bmiHeader.biSizeImage); + + /* Set the active buffer */ + SetConsoleActiveScreenBuffer(GraphicsConsoleBuffer); + + /* Set the graphics mode palette */ + SetConsolePalette(GraphicsConsoleBuffer, + PaletteHandle, + SYSPAL_NOSTATIC256); + + /* Set the screen mode flag */ + ScreenMode = GRAPHICS_MODE; + + return TRUE; +} + +static VOID VgaLeaveGraphicsMode(VOID) +{ + /* Release the console framebuffer mutex */ + ReleaseMutex(ConsoleMutex); + + /* Switch back to the default console text buffer */ + // SetConsoleActiveScreenBuffer(TextConsoleBuffer); + + /* Cleanup the video data */ + CloseHandle(ConsoleMutex); + ConsoleMutex = NULL; + ConsoleFramebuffer = NULL; + CloseHandle(GraphicsConsoleBuffer); + GraphicsConsoleBuffer = NULL; + DoubleVision = FALSE; +} + +static BOOL VgaEnterTextMode(PCOORD Resolution) +{ + DPRINT1("VgaEnterTextMode\n"); + + /* Switch to the text buffer */ + SetConsoleActiveScreenBuffer(TextConsoleBuffer); + + /* Adjust the text framebuffer if we changed the resolution */ if (TextResolution.X != Resolution->X || TextResolution.Y != Resolution->Y) { - WORD Offset; - - VgaDetachFromConsole(); - - /* VgaAttachToConsole sets TextResolution to the new resolution */ - if (!VgaAttachToConsole(Resolution)) + VgaDetachFromConsole(TRUE); + + /* + * VgaAttachToConsoleInternal sets TextResolution to the + * new resolution and updates ConsoleInfo. + */ + if (!VgaAttachToConsoleInternal(Resolution)) { DisplayMessage(L"An unexpected error occurred!\n"); EmulatorTerminate(); return FALSE; } - - /* Update the cursor position in the registers */ - Offset = ConsoleInfo.dwCursorPosition.Y * Resolution->X + - ConsoleInfo.dwCursorPosition.X; - DPRINT1("X = %d ; Y = %d\n", ConsoleInfo.dwCursorPosition.X, ConsoleInfo.dwCursorPosition.Y); - VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_LOW_REG] = LOBYTE(Offset); - VgaCrtcRegisters[VGA_CRTC_CURSOR_LOC_HIGH_REG] = HIBYTE(Offset); - CursorMoved = TRUE; - } + } + else VgaUpdateCursorPosition();
/* The active framebuffer is now the text framebuffer */ ConsoleFramebuffer = TextFramebuffer; @@ -1825,11 +1870,13 @@ if (!IsConsoleHandle(TextHandle)) return FALSE; TextConsoleBuffer = TextHandle;
- /* Save the console information */ - if (!GetConsoleScreenBufferInfo(TextConsoleBuffer, &ConsoleInfo)) + /* Save the original cursor and console screen buffer information */ + if (!GetConsoleCursorInfo(TextConsoleBuffer, &OrgConsoleCursorInfo) || + !GetConsoleScreenBufferInfo(TextConsoleBuffer, &OrgConsoleBufferInfo)) { return FALSE; } + ConsoleInfo = OrgConsoleBufferInfo;
/* Initialize the VGA palette and fail if it isn't successfully created */ if (!VgaInitializePalette()) return FALSE; @@ -1873,7 +1920,7 @@ VgaLeaveTextMode(); }
- VgaDetachFromConsole(); + VgaDetachFromConsole(FALSE);
CloseHandle(AnotherEvent); CloseHandle(EndEvent);
Modified: branches/ntvdm/subsystems/ntvdm/hardware/vga.h URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/hardware/... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/hardware/vga.h [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/hardware/vga.h [iso-8859-1] Fri May 2 21:17:05 2014 @@ -250,6 +250,9 @@
/* FUNCTIONS ******************************************************************/
+BOOL VgaAttachToConsole(VOID); +VOID VgaDetachFromConsole(BOOL ChangeMode); + DWORD VgaGetVideoBaseAddress(VOID); DWORD VgaGetVideoLimitAddress(VOID); COORD VgaGetDisplayResolution(VOID);
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.c?r... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] Fri May 2 21:17:05 2014 @@ -32,8 +32,6 @@ static HANDLE ConsoleInput = INVALID_HANDLE_VALUE; static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE; static DWORD OrgConsoleInputMode, OrgConsoleOutputMode; -static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo; -static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo; static BOOLEAN AcceptCommands = TRUE; static HANDLE CommandThread = NULL;
@@ -344,16 +342,6 @@ return FALSE; }
- /* Save the original cursor and console screen buffer information */ - if (!GetConsoleCursorInfo(ConsoleOutput, &OrgConsoleCursorInfo) || - !GetConsoleScreenBufferInfo(ConsoleOutput, &OrgConsoleBufferInfo)) - { - CloseHandle(ConsoleOutput); - CloseHandle(ConsoleInput); - wprintf(L"FATAL: Cannot save console cursor/screen-buffer info\n"); - return FALSE; - } - /* Initialize the UI */ ConsoleInitUI();
@@ -362,26 +350,6 @@
VOID ConsoleCleanup(VOID) { - SMALL_RECT ConRect; - - /* Restore the old screen buffer */ - SetConsoleActiveScreenBuffer(ConsoleOutput); - - /* Restore the original console size */ - ConRect.Left = 0; - ConRect.Top = 0; - ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left; - ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ; - /* - * See the following trick explanation in vga.c:VgaEnterTextMode() . - */ - SetConsoleScreenBufferSize(ConsoleOutput, OrgConsoleBufferInfo.dwSize); - SetConsoleWindowInfo(ConsoleOutput, TRUE, &ConRect); - SetConsoleScreenBufferSize(ConsoleOutput, OrgConsoleBufferInfo.dwSize); - - /* Restore the original cursor shape */ - SetConsoleCursorInfo(ConsoleOutput, &OrgConsoleCursorInfo); - /* Restore the original input and output console modes */ SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode); SetConsoleMode(ConsoleInput , OrgConsoleInputMode ); @@ -428,11 +396,7 @@ CommandInfo.Env = Env; CommandInfo.EnvLen = sizeof(Env);
- if (First) - { - CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK; - First = FALSE; - } + if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
/* Wait for the next available VDM */ if (!GetNextVDMCommand(&CommandInfo)) break; @@ -446,6 +410,12 @@ DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result); break; } + + /* Attach to the console */ + if (!First) VgaAttachToConsole(); + + /* Perform a screen refresh */ + VgaRefreshDisplay();
/* Start simulation */ SetEvent(VdmTaskEvent); @@ -453,6 +423,11 @@
/* Perform another screen refresh */ VgaRefreshDisplay(); + + /* Detach from the console */ + VgaDetachFromConsole(FALSE); + + First = FALSE; }
return 0;