- Move the mouse driver to DOS since it's our 32bit version of mouse.com, in some sense,
- Temporarily disable the mouse user callbacks because currently they went called in a parallel thread than the CPU one, that caused CPU corruption,
- In the same way we currently trigger IRQ1 interrupts, we do the same for IRQ12,
- Make the console input pump more modular (and mouse presence detection code is WIP),
- Put keyboard code into a dedicated file (as done for the mouse),
- Adapt the existing PS/2 emulation code to support two PS/2 ports controlled by 1 controller. Please note that some documentations precise that the response byte (answer to a PS/2 controller command) is written directly to the PS/2 output port.

svn path=/trunk/; revision=64168
This commit is contained in:
Hermès Bélusca-Maïto 2014-09-16 00:51:15 +00:00
parent 9c5062a147
commit 0c86291749
17 changed files with 1222 additions and 862 deletions

View file

@ -15,15 +15,17 @@ list(APPEND SOURCE
bios/rom.c
bios/vidbios.c
hardware/cmos.c
hardware/keyboard.c
hardware/mouse.c
hardware/pic.c
hardware/ps2.c
hardware/speaker.c
hardware/timer.c
hardware/vga.c
hardware/mouse.c
dos/dos32krnl/bios.c
dos/dos32krnl/dos.c
dos/dos32krnl/dosfiles.c
dos/mouse32.c
dos/dem.c
bop.c
callback.c

View file

@ -21,618 +21,24 @@
/* PRIVATE VARIABLES **********************************************************/
static BOOLEAN DriverEnabled = TRUE;
static MOUSE_DRIVER_STATE DriverState;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID PaintMouseCursor(VOID)
// Mouse IRQ 12
static VOID WINAPI BiosMouseIrq(LPWORD Stack)
{
if (Bda->VideoMode <= 3)
{
WORD Character;
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
EmulatorReadMemory(&EmulatorContext,
VideoAddress
+ (DriverState.Position.Y * Bda->ScreenColumns
+ DriverState.Position.X) * sizeof(WORD),
(LPVOID)&Character,
sizeof(WORD));
DriverState.Character = Character;
Character &= DriverState.TextCursor.ScreenMask;
Character ^= DriverState.TextCursor.CursorMask;
EmulatorWriteMemory(&EmulatorContext,
VideoAddress
+ (DriverState.Position.Y * Bda->ScreenColumns
+ DriverState.Position.X) * sizeof(WORD),
(LPVOID)&Character,
sizeof(WORD));
}
else
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
}
}
static VOID EraseMouseCursor(VOID)
{
if (Bda->VideoMode <= 3)
{
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
EmulatorWriteMemory(&EmulatorContext,
VideoAddress
+ (DriverState.Position.Y * Bda->ScreenColumns
+ DriverState.Position.X) * sizeof(WORD),
(LPVOID)&DriverState.Character,
sizeof(WORD));
}
else
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
}
}
static VOID CallMouseUserHandlers(USHORT CallMask)
{
USHORT i;
/* Call handler 0 */
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
DriverState.Handler0.Callback != (ULONG)NULL)
{
/*
* Set the parameters for the callback.
* NOTE: In text modes, the row and column will be reported
* as a multiple of the cell size, typically 8x8 pixels.
*/
setAX(CallMask);
setBX(DriverState.ButtonState);
setCX(DriverState.Position.X);
setDX(DriverState.Position.Y);
setSI(DriverState.MickeysPerCellHoriz);
setDI(DriverState.MickeysPerCellVert);
DPRINT1("Calling Handler0 0x%08x with CallMask 0x%04x\n",
DriverState.Handler0.Callback, CallMask);
/* Call the callback */
RunCallback16(&BiosContext, DriverState.Handler0.Callback);
}
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
/* Call the suitable handlers */
if ((DriverState.Handlers[i].CallMask & CallMask) != 0 &&
DriverState.Handlers[i].Callback != (ULONG)NULL)
{
/*
* Set the parameters for the callback.
* NOTE: In text modes, the row and column will be reported
* as a multiple of the cell size, typically 8x8 pixels.
*/
setAX(CallMask);
setBX(DriverState.ButtonState);
setCX(DriverState.Position.X);
setDX(DriverState.Position.Y);
setSI(DriverState.MickeysPerCellHoriz);
setDI(DriverState.MickeysPerCellVert);
DPRINT1("Calling Handler[%d] 0x%08x with CallMask 0x%04x\n",
i, DriverState.Handlers[i].Callback, CallMask);
/* Call the callback */
RunCallback16(&BiosContext, DriverState.Handlers[i].Callback);
}
}
}
static VOID WINAPI BiosMouseService(LPWORD Stack)
{
switch (getAX())
{
/* Reset Driver */
case 0x00:
{
SHORT i;
DriverEnabled = TRUE;
DriverState.ShowCount = 0;
DriverState.ButtonState = 0;
/* Set the default text cursor */
DriverState.TextCursor.ScreenMask = 0xFFFF; /* Display everything */
DriverState.TextCursor.CursorMask = 0xFF00; /* ... but with inverted attributes */
/* Set the default graphics cursor */
DriverState.GraphicsCursor.HotSpot.X = 3;
DriverState.GraphicsCursor.HotSpot.Y = 1;
DriverState.GraphicsCursor.ScreenMask[0] = 0xC3FF; // 1100001111111111
DriverState.GraphicsCursor.ScreenMask[1] = 0xC0FF; // 1100000011111111
DriverState.GraphicsCursor.ScreenMask[2] = 0xC07F; // 1100000001111111
DriverState.GraphicsCursor.ScreenMask[3] = 0xC01F; // 1100000000011111
DriverState.GraphicsCursor.ScreenMask[4] = 0xC00F; // 1100000000001111
DriverState.GraphicsCursor.ScreenMask[5] = 0xC007; // 1100000000000111
DriverState.GraphicsCursor.ScreenMask[6] = 0xC003; // 1100000000000011
DriverState.GraphicsCursor.ScreenMask[7] = 0xC007; // 1100000000000111
DriverState.GraphicsCursor.ScreenMask[8] = 0xC01F; // 1100000000011111
DriverState.GraphicsCursor.ScreenMask[9] = 0xC01F; // 1100000000011111
DriverState.GraphicsCursor.ScreenMask[10] = 0xC00F; // 1100000000001111
DriverState.GraphicsCursor.ScreenMask[11] = 0xC60F; // 1100011000001111
DriverState.GraphicsCursor.ScreenMask[12] = 0xFF07; // 1111111100000111
DriverState.GraphicsCursor.ScreenMask[13] = 0xFF07; // 1111111100000111
DriverState.GraphicsCursor.ScreenMask[14] = 0xFF87; // 1111111110000111
DriverState.GraphicsCursor.ScreenMask[15] = 0xFFCF; // 1111111111001111
DriverState.GraphicsCursor.CursorMask[0] = 0x0000; // 0000000000000000
DriverState.GraphicsCursor.CursorMask[1] = 0x1C00; // 0001110000000000
DriverState.GraphicsCursor.CursorMask[2] = 0x1F00; // 0001111100000000
DriverState.GraphicsCursor.CursorMask[3] = 0x1F80; // 0001111110000000
DriverState.GraphicsCursor.CursorMask[4] = 0x1FE0; // 0001111111100000
DriverState.GraphicsCursor.CursorMask[5] = 0x1FF0; // 0001111111110000
DriverState.GraphicsCursor.CursorMask[6] = 0x1FF8; // 0001111111111000
DriverState.GraphicsCursor.CursorMask[7] = 0x1FE0; // 0001111111100000
DriverState.GraphicsCursor.CursorMask[8] = 0x1FC0; // 0001111111000000
DriverState.GraphicsCursor.CursorMask[9] = 0x1FC0; // 0001111111000000
DriverState.GraphicsCursor.CursorMask[10] = 0x19E0; // 0001100111100000
DriverState.GraphicsCursor.CursorMask[11] = 0x00E0; // 0000000011100000
DriverState.GraphicsCursor.CursorMask[12] = 0x0070; // 0000000001110000
DriverState.GraphicsCursor.CursorMask[13] = 0x0070; // 0000000001110000
DriverState.GraphicsCursor.CursorMask[14] = 0x0030; // 0000000000110000
DriverState.GraphicsCursor.CursorMask[15] = 0x0000; // 0000000000000000
/* Initialize the counters */
DriverState.HorizCount = DriverState.VertCount = 0;
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
{
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
}
/* Initialize the resolution */
DriverState.MickeysPerCellHoriz = 8;
DriverState.MickeysPerCellVert = 16;
/* Return mouse information */
setAX(0xFFFF); // Hardware & driver installed
setBX(NUM_MOUSE_BUTTONS);
break;
}
/* Show Mouse Cursor */
case 0x01:
{
DriverState.ShowCount++;
if (DriverState.ShowCount > 0) PaintMouseCursor();
break;
}
/* Hide Mouse Cursor */
case 0x02:
{
DriverState.ShowCount--;
if (DriverState.ShowCount <= 0) EraseMouseCursor();
break;
}
/* Return Position And Button Status */
case 0x03:
{
setBX(DriverState.ButtonState);
setCX(DriverState.Position.X);
setDX(DriverState.Position.Y);
break;
}
/* Position Mouse Cursor */
case 0x04:
{
POINT Point;
Point.x = getCX();
Point.y = getDX();
ClientToScreen(GetConsoleWindow(), &Point);
SetCursorPos(Point.x, Point.y);
break;
}
/* Return Button Press Data */
case 0x05:
{
WORD Button = getBX();
setAX(DriverState.ButtonState);
setBX(DriverState.PressCount[Button]);
setCX(DriverState.LastPress[Button].X);
setDX(DriverState.LastPress[Button].Y);
/* Reset the counter */
DriverState.PressCount[Button] = 0;
break;
}
/* Return Button Release Data */
case 0x06:
{
WORD Button = getBX();
setAX(DriverState.ButtonState);
setBX(DriverState.ReleaseCount[Button]);
setCX(DriverState.LastRelease[Button].X);
setDX(DriverState.LastRelease[Button].Y);
/* Reset the counter */
DriverState.ReleaseCount[Button] = 0;
break;
}
/* Define Graphics Cursor */
case 0x09:
{
PWORD MaskBitmap = (PWORD)SEG_OFF_TO_PTR(getES(), getDX());
DriverState.GraphicsCursor.HotSpot.X = getBX();
DriverState.GraphicsCursor.HotSpot.Y = getCX();
RtlMoveMemory(DriverState.GraphicsCursor.ScreenMask,
MaskBitmap,
sizeof(DriverState.GraphicsCursor.ScreenMask));
RtlMoveMemory(DriverState.GraphicsCursor.CursorMask,
&MaskBitmap[16],
sizeof(DriverState.GraphicsCursor.CursorMask));
break;
}
/* Define Text Cursor */
case 0x0A:
{
USHORT BX = getBX();
if (BX == 0x0000)
{
/* Define software cursor */
DriverState.TextCursor.ScreenMask = getCX();
DriverState.TextCursor.CursorMask = getDX();
}
else if (BX == 0x0001)
{
/* Define hardware cursor */
DPRINT1("Defining hardware cursor is unimplemented\n");
UNIMPLEMENTED;
// CX == start scan line
// DX == end scan line
}
else
{
DPRINT1("Invalid BX value 0x%04x\n", BX);
}
break;
}
/* Read Motion Counters */
case 0x0B:
{
setCX(DriverState.HorizCount);
setDX(DriverState.VertCount);
/* Reset the counters */
DriverState.HorizCount = DriverState.VertCount = 0;
break;
}
/* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
case 0x0C:
{
DriverState.Handler0.CallMask = getCX();
DriverState.Handler0.Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
DPRINT1("Define callback 0x%04x, 0x%08x\n",
DriverState.Handler0.CallMask, DriverState.Handler0.Callback);
break;
}
/* Define Mickey/Pixel Ratio */
case 0x0F:
{
DriverState.MickeysPerCellHoriz = getCX();
DriverState.MickeysPerCellVert = getDX();
break;
}
/* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
case 0x14:
{
USHORT OldCallMask = DriverState.Handler0.CallMask;
ULONG OldCallback = DriverState.Handler0.Callback;
DriverState.Handler0.CallMask = getCX();
DriverState.Handler0.Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
/* Return old callmask in CX and callback vector in ES:DX */
setCX(OldCallMask);
setES(HIWORD(OldCallback));
setDX(LOWORD(OldCallback));
break;
}
/* Return Driver Storage Requirements */
case 0x15:
{
setBX(sizeof(MOUSE_DRIVER_STATE));
break;
}
/* Save Driver State */
case 0x16:
{
*((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState;
break;
}
/* Restore Driver State */
case 0x17:
{
DriverState = *((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX()));
break;
}
/* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
case 0x18:
{
/*
* Up to three handlers can be defined by separate calls to this
* function, each with a different combination of shift states in
* the call mask; calling this function again with a call mask of
* 0000h undefines the specified handler (official documentation);
* specifying the same call mask and an address of 0000h:0000h
* undefines the handler (real life).
* See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
* for more information.
*/
USHORT i;
USHORT CallMask = getCX();
ULONG Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
BOOLEAN Success = FALSE;
DPRINT1("Define v6.0+ callback 0x%04x, 0x%08x\n",
CallMask, Callback);
if (CallMask == 0x0000)
{
/*
* Find the handler entry corresponding to the given
* callback and undefine it.
*/
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
if (DriverState.Handlers[i].Callback == Callback)
{
/* Found it, undefine the handler */
DriverState.Handlers[i].CallMask = 0x0000;
DriverState.Handlers[i].Callback = (ULONG)NULL;
Success = TRUE;
break;
}
}
}
else if (Callback == (ULONG)NULL)
{
/*
* Find the handler entry corresponding to the given
* callmask and undefine it.
*/
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
if (DriverState.Handlers[i].CallMask == CallMask)
{
/* Found it, undefine the handler */
DriverState.Handlers[i].CallMask = 0x0000;
DriverState.Handlers[i].Callback = (ULONG)NULL;
Success = TRUE;
break;
}
}
}
else
{
/*
* Try to find a handler entry corresponding to the given
* callmask to redefine it, otherwise find an empty handler
* entry and set the new handler in there.
*/
USHORT EmptyHandler = 0xFFFF; // Invalid handler
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
/* Find the first empty handler */
if (EmptyHandler == 0xFFFF &&
DriverState.Handlers[i].CallMask == 0x0000 &&
DriverState.Handlers[i].Callback == (ULONG)NULL)
{
EmptyHandler = i;
}
if (DriverState.Handlers[i].CallMask == CallMask)
{
/* Found it, redefine the handler */
DriverState.Handlers[i].CallMask = CallMask;
DriverState.Handlers[i].Callback = Callback;
Success = TRUE;
break;
}
}
/*
* If we haven't found anything and we found
* an empty handler, set it.
*/
if (!Success && EmptyHandler != 0xFFFF
/* && EmptyHandler < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
{
DriverState.Handlers[EmptyHandler].CallMask = CallMask;
DriverState.Handlers[EmptyHandler].Callback = Callback;
Success = TRUE;
}
}
/* If we failed, set error code */
if (!Success) setAX(0xFFFF);
break;
}
/* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
case 0x19:
{
USHORT i;
USHORT CallMask = getCX();
ULONG Callback;
BOOLEAN Success = FALSE;
/*
* Find the handler entry corresponding to the given callmask.
*/
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
if (DriverState.Handlers[i].CallMask == CallMask)
{
/* Found it */
Callback = DriverState.Handlers[i].Callback;
Success = TRUE;
break;
}
}
if (Success)
{
/* Return the callback vector in BX:DX */
setBX(HIWORD(Callback));
setDX(LOWORD(Callback));
}
else
{
/* We failed, set error code */
setCX(0x0000);
}
break;
}
/* Disable Mouse Driver */
case 0x1F:
{
setES(0x0000);
setBX(0x0000);
DriverEnabled = FALSE;
break;
}
/* Enable Mouse Driver */
case 0x20:
{
DriverEnabled = TRUE;
break;
}
default:
{
DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
}
}
PicIRQComplete(Stack);
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID MouseBiosUpdatePosition(PCOORD NewPosition)
{
SHORT DeltaX = NewPosition->X - DriverState.Position.X;
SHORT DeltaY = NewPosition->Y - DriverState.Position.Y;
if (!DriverEnabled) return;
DriverState.HorizCount += (DeltaX * (SHORT)DriverState.MickeysPerCellHoriz) / 8;
DriverState.VertCount += (DeltaY * (SHORT)DriverState.MickeysPerCellVert ) / 8;
if (DriverState.ShowCount > 0)
{
EraseMouseCursor();
DriverState.Position = *NewPosition;
PaintMouseCursor();
}
/* Call the mouse handlers */
CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
}
VOID MouseBiosUpdateButtons(WORD ButtonState)
{
USHORT i;
USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format
if (!DriverEnabled) return;
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
{
BOOLEAN OldState = (DriverState.ButtonState >> i) & 1;
BOOLEAN NewState = (ButtonState >> i) & 1;
if (NewState > OldState)
{
/* Mouse press */
DriverState.PressCount[i]++;
DriverState.LastPress[i] = DriverState.Position;
CallMask |= (1 << (2 * i + 1));
}
else if (NewState < OldState)
{
/* Mouse release */
DriverState.ReleaseCount[i]++;
DriverState.LastRelease[i] = DriverState.Position;
CallMask |= (1 << (2 * i + 2));
}
}
DriverState.ButtonState = ButtonState;
/* Call the mouse handlers */
CallMouseUserHandlers(CallMask);
}
BOOLEAN MouseBios32Initialize(VOID)
{
/* Clear the state */
ZeroMemory(&DriverState, sizeof(DriverState));
/* Initialize the interrupt handler */
RegisterBiosInt32(BIOS_MOUSE_INTERRUPT, BiosMouseService);
/* Set up the HW vector interrupts */
EnableHwIRQ(12, BiosMouseIrq);
return TRUE;
}
VOID MouseBios32Cleanup(VOID)
{
if (DriverState.ShowCount > 0) EraseMouseCursor();
}

View file

@ -37,7 +37,8 @@
/* Processor speed */
#define STEPS_PER_CYCLE 256
#define KBD_INT_CYCLES 16
#define IRQ1_CYCLES 16
#define IRQ12_CYCLES 16
/* VARIABLES ******************************************************************/
@ -48,7 +49,9 @@ LONGLONG TimerTicks;
DWORD StartTickCount, CurrentTickCount;
DWORD LastClockUpdate;
DWORD LastVerticalRefresh;
INT KeyboardIntCounter = 0;
UINT Irq1Counter = 0;
UINT Irq12Counter = 0;
#ifdef IPS_DISPLAY
DWORD LastCyclePrintout;
@ -118,10 +121,16 @@ VOID ClockUpdate(VOID)
LastVerticalRefresh = CurrentTickCount;
}
if (++KeyboardIntCounter == KBD_INT_CYCLES)
if (++Irq1Counter == IRQ1_CYCLES)
{
GenerateKeyboardInterrupts();
KeyboardIntCounter = 0;
GenerateIrq1();
Irq1Counter = 0;
}
if (++Irq12Counter == IRQ12_CYCLES)
{
GenerateIrq12();
Irq12Counter = 0;
}
/* Horizontal retrace occurs as fast as possible */

View file

@ -21,6 +21,7 @@
#include "bop.h"
#include "bios/bios.h"
#include "mouse32.h"
/* Extra PSDK/NDK Headers */
#include <ndk/obtypes.h>
@ -234,6 +235,7 @@ BOOLEAN DosInitialize(IN LPCSTR DosKernelFileName)
BOOLEAN Result;
Result = DosBIOSInitialize();
DosMouseInitialize(); // FIXME: Should be done by the DOS BIOS
// Result &= DosKRNLInitialize();
return Result;

View file

@ -0,0 +1,671 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: mouse32.c
* PURPOSE: VDM 32-bit compatible MOUSE.COM driver
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "emulator.h"
#include "callback.h"
#include "mouse32.h"
#include "bios/bios.h"
#include "io.h"
#include "dos32krnl/dos.h"
/* PRIVATE VARIABLES **********************************************************/
static BOOLEAN DriverEnabled = TRUE;
static MOUSE_DRIVER_STATE DriverState;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID PaintMouseCursor(VOID)
{
if (Bda->VideoMode <= 3)
{
WORD Character;
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
EmulatorReadMemory(&EmulatorContext,
VideoAddress
+ (DriverState.Position.Y * Bda->ScreenColumns
+ DriverState.Position.X) * sizeof(WORD),
(LPVOID)&Character,
sizeof(WORD));
DriverState.Character = Character;
Character &= DriverState.TextCursor.ScreenMask;
Character ^= DriverState.TextCursor.CursorMask;
EmulatorWriteMemory(&EmulatorContext,
VideoAddress
+ (DriverState.Position.Y * Bda->ScreenColumns
+ DriverState.Position.X) * sizeof(WORD),
(LPVOID)&Character,
sizeof(WORD));
}
else
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
}
}
static VOID EraseMouseCursor(VOID)
{
if (Bda->VideoMode <= 3)
{
DWORD VideoAddress = TO_LINEAR(TEXT_VIDEO_SEG, Bda->VideoPage * Bda->VideoPageSize);
EmulatorWriteMemory(&EmulatorContext,
VideoAddress
+ (DriverState.Position.Y * Bda->ScreenColumns
+ DriverState.Position.X) * sizeof(WORD),
(LPVOID)&DriverState.Character,
sizeof(WORD));
}
else
{
// TODO: NOT IMPLEMENTED
UNIMPLEMENTED;
}
}
static VOID CallMouseUserHandlers(USHORT CallMask)
{
#if 0
USHORT i;
USHORT AX, BX, CX, DX, SI, DI;
/* Call handler 0 */
if ((DriverState.Handler0.CallMask & CallMask) != 0 &&
DriverState.Handler0.Callback != (ULONG)NULL)
{
/*
* Set the parameters for the callback.
* NOTE: In text modes, the row and column will be reported
* as a multiple of the cell size, typically 8x8 pixels.
*/
AX = getAX();
BX = getBX();
CX = getCX();
DX = getDX();
SI = getSI();
DI = getDI();
setAX(CallMask);
setBX(DriverState.ButtonState);
setCX(DriverState.Position.X);
setDX(DriverState.Position.Y);
setSI(DriverState.MickeysPerCellHoriz);
setDI(DriverState.MickeysPerCellVert);
DPRINT1("Calling Handler0 0x%08x with CallMask 0x%04x\n",
DriverState.Handler0.Callback, CallMask);
/* Call the callback */
RunCallback16(&DosContext, DriverState.Handler0.Callback);
setAX(AX);
setBX(BX);
setCX(CX);
setDX(DX);
setSI(SI);
setDI(DI);
}
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
/* Call the suitable handlers */
if ((DriverState.Handlers[i].CallMask & CallMask) != 0 &&
DriverState.Handlers[i].Callback != (ULONG)NULL)
{
/*
* Set the parameters for the callback.
* NOTE: In text modes, the row and column will be reported
* as a multiple of the cell size, typically 8x8 pixels.
*/
AX = getAX();
BX = getBX();
CX = getCX();
DX = getDX();
SI = getSI();
DI = getDI();
setAX(CallMask);
setBX(DriverState.ButtonState);
setCX(DriverState.Position.X);
setDX(DriverState.Position.Y);
setSI(DriverState.MickeysPerCellHoriz);
setDI(DriverState.MickeysPerCellVert);
DPRINT1("Calling Handler[%d] 0x%08x with CallMask 0x%04x\n",
i, DriverState.Handlers[i].Callback, CallMask);
/* Call the callback */
RunCallback16(&DosContext, DriverState.Handlers[i].Callback);
setAX(AX);
setBX(BX);
setCX(CX);
setDX(DX);
setSI(SI);
setDI(DI);
}
}
#endif
}
static VOID WINAPI BiosMouseService(LPWORD Stack)
{
switch (getAX())
{
/* Reset Driver */
case 0x00:
{
SHORT i;
DriverEnabled = TRUE;
DriverState.ShowCount = 0;
DriverState.ButtonState = 0;
/* Set the default text cursor */
DriverState.TextCursor.ScreenMask = 0xFFFF; /* Display everything */
DriverState.TextCursor.CursorMask = 0xFF00; /* ... but with inverted attributes */
/* Set the default graphics cursor */
DriverState.GraphicsCursor.HotSpot.X = 3;
DriverState.GraphicsCursor.HotSpot.Y = 1;
DriverState.GraphicsCursor.ScreenMask[0] = 0xC3FF; // 1100001111111111
DriverState.GraphicsCursor.ScreenMask[1] = 0xC0FF; // 1100000011111111
DriverState.GraphicsCursor.ScreenMask[2] = 0xC07F; // 1100000001111111
DriverState.GraphicsCursor.ScreenMask[3] = 0xC01F; // 1100000000011111
DriverState.GraphicsCursor.ScreenMask[4] = 0xC00F; // 1100000000001111
DriverState.GraphicsCursor.ScreenMask[5] = 0xC007; // 1100000000000111
DriverState.GraphicsCursor.ScreenMask[6] = 0xC003; // 1100000000000011
DriverState.GraphicsCursor.ScreenMask[7] = 0xC007; // 1100000000000111
DriverState.GraphicsCursor.ScreenMask[8] = 0xC01F; // 1100000000011111
DriverState.GraphicsCursor.ScreenMask[9] = 0xC01F; // 1100000000011111
DriverState.GraphicsCursor.ScreenMask[10] = 0xC00F; // 1100000000001111
DriverState.GraphicsCursor.ScreenMask[11] = 0xC60F; // 1100011000001111
DriverState.GraphicsCursor.ScreenMask[12] = 0xFF07; // 1111111100000111
DriverState.GraphicsCursor.ScreenMask[13] = 0xFF07; // 1111111100000111
DriverState.GraphicsCursor.ScreenMask[14] = 0xFF87; // 1111111110000111
DriverState.GraphicsCursor.ScreenMask[15] = 0xFFCF; // 1111111111001111
DriverState.GraphicsCursor.CursorMask[0] = 0x0000; // 0000000000000000
DriverState.GraphicsCursor.CursorMask[1] = 0x1C00; // 0001110000000000
DriverState.GraphicsCursor.CursorMask[2] = 0x1F00; // 0001111100000000
DriverState.GraphicsCursor.CursorMask[3] = 0x1F80; // 0001111110000000
DriverState.GraphicsCursor.CursorMask[4] = 0x1FE0; // 0001111111100000
DriverState.GraphicsCursor.CursorMask[5] = 0x1FF0; // 0001111111110000
DriverState.GraphicsCursor.CursorMask[6] = 0x1FF8; // 0001111111111000
DriverState.GraphicsCursor.CursorMask[7] = 0x1FE0; // 0001111111100000
DriverState.GraphicsCursor.CursorMask[8] = 0x1FC0; // 0001111111000000
DriverState.GraphicsCursor.CursorMask[9] = 0x1FC0; // 0001111111000000
DriverState.GraphicsCursor.CursorMask[10] = 0x19E0; // 0001100111100000
DriverState.GraphicsCursor.CursorMask[11] = 0x00E0; // 0000000011100000
DriverState.GraphicsCursor.CursorMask[12] = 0x0070; // 0000000001110000
DriverState.GraphicsCursor.CursorMask[13] = 0x0070; // 0000000001110000
DriverState.GraphicsCursor.CursorMask[14] = 0x0030; // 0000000000110000
DriverState.GraphicsCursor.CursorMask[15] = 0x0000; // 0000000000000000
/* Initialize the counters */
DriverState.HorizCount = DriverState.VertCount = 0;
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
{
DriverState.PressCount[i] = DriverState.ReleaseCount[i] = 0;
}
/* Initialize the resolution */
DriverState.MickeysPerCellHoriz = 8;
DriverState.MickeysPerCellVert = 16;
/* Return mouse information */
setAX(0xFFFF); // Hardware & driver installed
setBX(NUM_MOUSE_BUTTONS);
break;
}
/* Show Mouse Cursor */
case 0x01:
{
DriverState.ShowCount++;
if (DriverState.ShowCount > 0) PaintMouseCursor();
break;
}
/* Hide Mouse Cursor */
case 0x02:
{
DriverState.ShowCount--;
if (DriverState.ShowCount <= 0) EraseMouseCursor();
break;
}
/* Return Position And Button Status */
case 0x03:
{
setBX(DriverState.ButtonState);
setCX(DriverState.Position.X);
setDX(DriverState.Position.Y);
break;
}
/* Position Mouse Cursor */
case 0x04:
{
POINT Point;
Point.x = getCX();
Point.y = getDX();
ClientToScreen(GetConsoleWindow(), &Point);
SetCursorPos(Point.x, Point.y);
break;
}
/* Return Button Press Data */
case 0x05:
{
WORD Button = getBX();
setAX(DriverState.ButtonState);
setBX(DriverState.PressCount[Button]);
setCX(DriverState.LastPress[Button].X);
setDX(DriverState.LastPress[Button].Y);
/* Reset the counter */
DriverState.PressCount[Button] = 0;
break;
}
/* Return Button Release Data */
case 0x06:
{
WORD Button = getBX();
setAX(DriverState.ButtonState);
setBX(DriverState.ReleaseCount[Button]);
setCX(DriverState.LastRelease[Button].X);
setDX(DriverState.LastRelease[Button].Y);
/* Reset the counter */
DriverState.ReleaseCount[Button] = 0;
break;
}
/* Define Graphics Cursor */
case 0x09:
{
PWORD MaskBitmap = (PWORD)SEG_OFF_TO_PTR(getES(), getDX());
DriverState.GraphicsCursor.HotSpot.X = getBX();
DriverState.GraphicsCursor.HotSpot.Y = getCX();
RtlMoveMemory(DriverState.GraphicsCursor.ScreenMask,
MaskBitmap,
sizeof(DriverState.GraphicsCursor.ScreenMask));
RtlMoveMemory(DriverState.GraphicsCursor.CursorMask,
&MaskBitmap[16],
sizeof(DriverState.GraphicsCursor.CursorMask));
break;
}
/* Define Text Cursor */
case 0x0A:
{
USHORT BX = getBX();
if (BX == 0x0000)
{
/* Define software cursor */
DriverState.TextCursor.ScreenMask = getCX();
DriverState.TextCursor.CursorMask = getDX();
}
else if (BX == 0x0001)
{
/* Define hardware cursor */
DPRINT1("Defining hardware cursor is unimplemented\n");
UNIMPLEMENTED;
// CX == start scan line
// DX == end scan line
}
else
{
DPRINT1("Invalid BX value 0x%04x\n", BX);
}
break;
}
/* Read Motion Counters */
case 0x0B:
{
setCX(DriverState.HorizCount);
setDX(DriverState.VertCount);
/* Reset the counters */
DriverState.HorizCount = DriverState.VertCount = 0;
break;
}
/* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
case 0x0C:
{
DriverState.Handler0.CallMask = getCX();
DriverState.Handler0.Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
DPRINT1("Define callback 0x%04x, 0x%08x\n",
DriverState.Handler0.CallMask, DriverState.Handler0.Callback);
break;
}
/* Define Mickey/Pixel Ratio */
case 0x0F:
{
DriverState.MickeysPerCellHoriz = getCX();
DriverState.MickeysPerCellVert = getDX();
break;
}
/* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
case 0x14:
{
USHORT OldCallMask = DriverState.Handler0.CallMask;
ULONG OldCallback = DriverState.Handler0.Callback;
DriverState.Handler0.CallMask = getCX();
DriverState.Handler0.Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
/* Return old callmask in CX and callback vector in ES:DX */
setCX(OldCallMask);
setES(HIWORD(OldCallback));
setDX(LOWORD(OldCallback));
break;
}
/* Return Driver Storage Requirements */
case 0x15:
{
setBX(sizeof(MOUSE_DRIVER_STATE));
break;
}
/* Save Driver State */
case 0x16:
{
*((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState;
break;
}
/* Restore Driver State */
case 0x17:
{
DriverState = *((PMOUSE_DRIVER_STATE)SEG_OFF_TO_PTR(getES(), getDX()));
break;
}
/* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
case 0x18:
{
/*
* Up to three handlers can be defined by separate calls to this
* function, each with a different combination of shift states in
* the call mask; calling this function again with a call mask of
* 0000h undefines the specified handler (official documentation);
* specifying the same call mask and an address of 0000h:0000h
* undefines the handler (real life).
* See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
* for more information.
*/
USHORT i;
USHORT CallMask = getCX();
ULONG Callback = MAKELONG(getDX(), getES()); // Far pointer to the callback
BOOLEAN Success = FALSE;
DPRINT1("Define v6.0+ callback 0x%04x, 0x%08x\n",
CallMask, Callback);
if (CallMask == 0x0000)
{
/*
* Find the handler entry corresponding to the given
* callback and undefine it.
*/
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
if (DriverState.Handlers[i].Callback == Callback)
{
/* Found it, undefine the handler */
DriverState.Handlers[i].CallMask = 0x0000;
DriverState.Handlers[i].Callback = (ULONG)NULL;
Success = TRUE;
break;
}
}
}
else if (Callback == (ULONG)NULL)
{
/*
* Find the handler entry corresponding to the given
* callmask and undefine it.
*/
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
if (DriverState.Handlers[i].CallMask == CallMask)
{
/* Found it, undefine the handler */
DriverState.Handlers[i].CallMask = 0x0000;
DriverState.Handlers[i].Callback = (ULONG)NULL;
Success = TRUE;
break;
}
}
}
else
{
/*
* Try to find a handler entry corresponding to the given
* callmask to redefine it, otherwise find an empty handler
* entry and set the new handler in there.
*/
USHORT EmptyHandler = 0xFFFF; // Invalid handler
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
/* Find the first empty handler */
if (EmptyHandler == 0xFFFF &&
DriverState.Handlers[i].CallMask == 0x0000 &&
DriverState.Handlers[i].Callback == (ULONG)NULL)
{
EmptyHandler = i;
}
if (DriverState.Handlers[i].CallMask == CallMask)
{
/* Found it, redefine the handler */
DriverState.Handlers[i].CallMask = CallMask;
DriverState.Handlers[i].Callback = Callback;
Success = TRUE;
break;
}
}
/*
* If we haven't found anything and we found
* an empty handler, set it.
*/
if (!Success && EmptyHandler != 0xFFFF
/* && EmptyHandler < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
{
DriverState.Handlers[EmptyHandler].CallMask = CallMask;
DriverState.Handlers[EmptyHandler].Callback = Callback;
Success = TRUE;
}
}
/* If we failed, set error code */
if (!Success) setAX(0xFFFF);
break;
}
/* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
case 0x19:
{
USHORT i;
USHORT CallMask = getCX();
ULONG Callback;
BOOLEAN Success = FALSE;
/*
* Find the handler entry corresponding to the given callmask.
*/
for (i = 0; i < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]); ++i)
{
if (DriverState.Handlers[i].CallMask == CallMask)
{
/* Found it */
Callback = DriverState.Handlers[i].Callback;
Success = TRUE;
break;
}
}
if (Success)
{
/* Return the callback vector in BX:DX */
setBX(HIWORD(Callback));
setDX(LOWORD(Callback));
}
else
{
/* We failed, set error code */
setCX(0x0000);
}
break;
}
/* Disable Mouse Driver */
case 0x1F:
{
setES(0x0000);
setBX(0x0000);
DriverEnabled = FALSE;
break;
}
/* Enable Mouse Driver */
case 0x20:
{
DriverEnabled = TRUE;
break;
}
default:
{
DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
}
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID MouseBiosUpdatePosition(PCOORD NewPosition)
{
SHORT DeltaX = NewPosition->X - DriverState.Position.X;
SHORT DeltaY = NewPosition->Y - DriverState.Position.Y;
if (!DriverEnabled) return;
DriverState.HorizCount += (DeltaX * (SHORT)DriverState.MickeysPerCellHoriz) / 8;
DriverState.VertCount += (DeltaY * (SHORT)DriverState.MickeysPerCellVert ) / 8;
if (DriverState.ShowCount > 0)
{
EraseMouseCursor();
DriverState.Position = *NewPosition;
PaintMouseCursor();
}
/* Call the mouse handlers */
CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
}
VOID MouseBiosUpdateButtons(WORD ButtonState)
{
USHORT i;
USHORT CallMask = 0x0000; // We use MS MOUSE v1.0+ format
if (!DriverEnabled) return;
for (i = 0; i < NUM_MOUSE_BUTTONS; i++)
{
BOOLEAN OldState = (DriverState.ButtonState >> i) & 1;
BOOLEAN NewState = (ButtonState >> i) & 1;
if (NewState > OldState)
{
/* Mouse press */
DriverState.PressCount[i]++;
DriverState.LastPress[i] = DriverState.Position;
CallMask |= (1 << (2 * i + 1));
}
else if (NewState < OldState)
{
/* Mouse release */
DriverState.ReleaseCount[i]++;
DriverState.LastRelease[i] = DriverState.Position;
CallMask |= (1 << (2 * i + 2));
}
}
DriverState.ButtonState = ButtonState;
/* Call the mouse handlers */
CallMouseUserHandlers(CallMask);
}
BOOLEAN DosMouseInitialize(VOID)
{
/* Clear the state */
ZeroMemory(&DriverState, sizeof(DriverState));
/* Initialize the interrupt handler */
RegisterDosInt32(BIOS_MOUSE_INTERRUPT, BiosMouseService);
return TRUE;
}
VOID DosMouseCleanup(VOID)
{
if (DriverState.ShowCount > 0) EraseMouseCursor();
}

View file

@ -0,0 +1,83 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: mouse32.h
* PURPOSE: VDM 32-bit compatible MOUSE.COM driver
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
#ifndef _MOUSE32_H_
#define _MOUSE32_H_
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
/* DEFINES ********************************************************************/
#define BIOS_MOUSE_INTERRUPT 0x33
enum
{
MOUSE_BUTTON_LEFT,
MOUSE_BUTTON_RIGHT,
MOUSE_BUTTON_MIDDLE,
NUM_MOUSE_BUTTONS
};
typedef struct _MOUSE_USER_HANDLER
{
/*
* CallMask format: see table: http://www.ctyme.com/intr/rb-5968.htm#Table3171
* Alternatively, see table: http://www.ctyme.com/intr/rb-5981.htm#Table3174
*/
USHORT CallMask;
ULONG Callback; // Far pointer to the callback
} MOUSE_USER_HANDLER, *PMOUSE_USER_HANDLER;
typedef struct _MOUSE_DRIVER_STATE
{
SHORT ShowCount;
COORD Position;
WORD Character;
WORD ButtonState;
WORD PressCount[NUM_MOUSE_BUTTONS];
COORD LastPress[NUM_MOUSE_BUTTONS];
WORD ReleaseCount[NUM_MOUSE_BUTTONS];
COORD LastRelease[NUM_MOUSE_BUTTONS];
SHORT HorizCount;
SHORT VertCount;
WORD MickeysPerCellHoriz;
WORD MickeysPerCellVert;
/*
* User Subroutine Handlers called on mouse events
*/
MOUSE_USER_HANDLER Handler0; // Handler compatible MS MOUSE v1.0+
MOUSE_USER_HANDLER Handlers[3]; // Handlers compatible MS MOUSE v6.0+
struct
{
WORD ScreenMask;
WORD CursorMask;
} TextCursor;
struct
{
COORD HotSpot;
WORD ScreenMask[16];
WORD CursorMask[16];
} GraphicsCursor;
} MOUSE_DRIVER_STATE, *PMOUSE_DRIVER_STATE;
/* FUNCTIONS ******************************************************************/
VOID MouseBiosUpdatePosition(PCOORD NewPosition);
VOID MouseBiosUpdateButtons(WORD ButtonStatus);
BOOLEAN DosMouseInitialize(VOID);
VOID DosMouseCleanup(VOID);
#endif // _MOUSE32_H_
/* EOF */

View file

@ -16,6 +16,8 @@
#include "clock.h"
#include "bios/rom.h"
#include "hardware/cmos.h"
#include "hardware/keyboard.h"
#include "hardware/mouse.h"
#include "hardware/pic.h"
#include "hardware/ps2.h"
#include "hardware/speaker.h"
@ -335,6 +337,95 @@ static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
// SpeakerChange();
}
static DWORD
WINAPI
PumpConsoleInput(LPVOID Parameter)
{
HANDLE ConsoleInput = (HANDLE)Parameter;
INPUT_RECORD InputRecord;
DWORD Count;
while (VdmRunning)
{
/* Make sure the task event is signaled */
WaitForSingleObject(VdmTaskEvent, INFINITE);
/* Wait for an input record */
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
{
DWORD LastError = GetLastError();
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
return LastError;
}
ASSERT(Count != 0);
/* Check the event type */
switch (InputRecord.EventType)
{
/*
* Hardware events
*/
case KEY_EVENT:
KeyboardEventHandler(&InputRecord.Event.KeyEvent);
break;
case MOUSE_EVENT:
MouseEventHandler(&InputRecord.Event.MouseEvent);
break;
case WINDOW_BUFFER_SIZE_EVENT:
ScreenEventHandler(&InputRecord.Event.WindowBufferSizeEvent);
break;
/*
* Interface events
*/
case MENU_EVENT:
MenuEventHandler(&InputRecord.Event.MenuEvent);
break;
case FOCUS_EVENT:
FocusEventHandler(&InputRecord.Event.FocusEvent);
break;
default:
break;
}
}
return 0;
}
static VOID EnableExtraHardware(HANDLE ConsoleInput)
{
DWORD ConInMode;
if (GetConsoleMode(ConsoleInput, &ConInMode))
{
#if 0
// GetNumberOfConsoleMouseButtons();
// GetSystemMetrics(SM_CMOUSEBUTTONS);
// GetSystemMetrics(SM_MOUSEPRESENT);
if (MousePresent)
{
#endif
/* Support mouse input events if there is a mouse on the system */
ConInMode |= ENABLE_MOUSE_INPUT;
#if 0
}
else
{
/* Do not support mouse input events if there is no mouse on the system */
ConInMode &= ~ENABLE_MOUSE_INPUT;
}
#endif
SetConsoleMode(ConsoleInput, ConInMode);
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID DumpMemory(VOID)
@ -421,8 +512,6 @@ VOID DumpMemory(VOID)
DPRINT1("Memory dump done\n");
}
DWORD WINAPI PumpConsoleInput(LPVOID Parameter);
BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
{
/* Allocate memory for the 16-bit address space */
@ -476,8 +565,14 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
SetConsoleMode(ConsoleInput, ENABLE_PROCESSED_INPUT /* | ENABLE_WINDOW_INPUT */);
// SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
/* Initialize the PS2 port */
PS2Initialize(ConsoleInput);
/**/EnableExtraHardware(ConsoleInput);/**/
/* Initialize the PS/2 port */
PS2Initialize();
/* Initialize the keyboard and mouse and connect them to their PS/2 ports */
KeyboardInit(0);
MouseInit(1);
/**************** ATTACH INPUT WITH CONSOLE *****************/
/* Start the input thread */

View file

@ -0,0 +1,46 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: keyboard.c
* PURPOSE: Keyboard emulation
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
/* INCLUDES *******************************************************************/
#define NDEBUG
#include "keyboard.h"
#include "ps2.h"
static BYTE PS2Port = 0;
/* PUBLIC FUNCTIONS ***********************************************************/
VOID KeyboardEventHandler(PKEY_EVENT_RECORD KeyEvent)
{
WORD i;
BYTE ScanCode = (BYTE)KeyEvent->wVirtualScanCode;
/* If this is a key release, set the highest bit in the scan code */
if (!KeyEvent->bKeyDown) ScanCode |= 0x80;
/* Push the scan code into the PS/2 queue */
for (i = 0; i < KeyEvent->wRepeatCount; i++)
{
PS2QueuePush(PS2Port, ScanCode);
}
// PicInterruptRequest(1);
}
VOID KeyboardCommand(BYTE Command)
{
UNIMPLEMENTED;
}
BOOLEAN KeyboardInit(BYTE PS2Connector)
{
PS2Port = PS2Connector;
return TRUE;
}

View file

@ -0,0 +1,28 @@
/*
* COPYRIGHT: GPL - See COPYING in the top level directory
* PROJECT: ReactOS Virtual DOS Machine
* FILE: keyboard.h
* PURPOSE: Keyboard emulation
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
#ifndef _KEYBOARD_H_
#define _KEYBOARD_H_
/* INCLUDES *******************************************************************/
#include "ntvdm.h"
/* DEFINES ********************************************************************/
/* Command responses */
#define KEYBOARD_ACK 0xFA
#define KEYBOARD_RESEND 0xFE
/* FUNCTIONS ******************************************************************/
VOID KeyboardEventHandler(PKEY_EVENT_RECORD KeyEvent);
VOID KeyboardCommand(BYTE Command);
BOOLEAN KeyboardInit(BYTE PS2Connector);
#endif // _KEYBOARD_H_

View file

@ -13,6 +13,9 @@
#include "mouse.h"
#include "ps2.h"
// HACK: For the PS/2 bypass and MOUSE.COM driver direct call
#include "dos/mouse32.h"
/* PRIVATE VARIABLES **********************************************************/
static MOUSE_MODE Mode, PreviousMode;
@ -28,6 +31,8 @@ static SHORT HorzCounter;
static SHORT VertCounter;
static CHAR ScrollCounter;
static BYTE PS2Port = 1;
/* PRIVATE FUNCTIONS **********************************************************/
static VOID MouseResetConfig(VOID)
@ -56,8 +61,8 @@ static VOID MouseReset(VOID)
MouseId = 0;
/* Send the Basic Assurance Test success code and the device ID */
KeyboardQueuePush(MOUSE_BAT_SUCCESS);
KeyboardQueuePush(MouseId);
PS2QueuePush(PS2Port, MOUSE_BAT_SUCCESS);
PS2QueuePush(PS2Port, MouseId);
}
#if 0
@ -116,9 +121,7 @@ static VOID MouseGetPacket(PMOUSE_PACKET Packet)
}
#endif
/* PUBLIC FUNCTIONS ***********************************************************/
VOID MouseUpdatePosition(PCOORD NewPosition)
/*static*/ VOID MouseUpdatePosition(PCOORD NewPosition)
{
/* Update the counters */
HorzCounter += ((NewPosition->X - Position.X) * WidthMm * Resolution) / WidthPixels;
@ -128,11 +131,25 @@ VOID MouseUpdatePosition(PCOORD NewPosition)
Position = *NewPosition;
}
VOID MouseUpdateButtons(ULONG NewButtonState)
/*static*/ VOID MouseUpdateButtons(ULONG NewButtonState)
{
ButtonState = NewButtonState;
}
/* PUBLIC FUNCTIONS ***********************************************************/
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent)
{
// FIXME: Sync our private data
// HACK: Bypass PS/2 and instead, notify the MOUSE.COM driver directly
MouseBiosUpdatePosition(&MouseEvent->dwMousePosition);
MouseBiosUpdateButtons(LOWORD(MouseEvent->dwButtonState));
// PS2QueuePush(PS2Port, Data);
// PicInterruptRequest(12);
}
VOID MouseScroll(LONG Direction)
{
ScrollCounter += Direction;
@ -151,7 +168,7 @@ VOID MouseCommand(BYTE Command)
case 0xE6:
{
Scaling = FALSE;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
break;
}
@ -159,7 +176,7 @@ VOID MouseCommand(BYTE Command)
case 0xE7:
{
Scaling = TRUE;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
break;
}
@ -185,7 +202,7 @@ VOID MouseCommand(BYTE Command)
MouseResetCounters();
Mode = MOUSE_STREAMING_MODE;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
break;
}
@ -205,9 +222,9 @@ VOID MouseCommand(BYTE Command)
/* Restore the previous mode */
MouseResetCounters();
Mode = PreviousMode;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
}
else KeyboardQueuePush(MOUSE_ERROR);
else PS2QueuePush(PS2Port, MOUSE_ERROR);
break;
}
@ -224,7 +241,7 @@ VOID MouseCommand(BYTE Command)
MouseResetCounters();
Mode = MOUSE_WRAP_MODE;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
break;
}
@ -234,15 +251,15 @@ VOID MouseCommand(BYTE Command)
MouseResetCounters();
Mode = MOUSE_REMOTE_MODE;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
break;
}
/* Get Mouse ID */
case 0xF2:
{
KeyboardQueuePush(MOUSE_ACK);
KeyboardQueuePush(MouseId);
PS2QueuePush(PS2Port, MOUSE_ACK);
PS2QueuePush(PS2Port, MouseId);
break;
}
@ -258,7 +275,7 @@ VOID MouseCommand(BYTE Command)
case 0xF4:
{
Reporting = TRUE;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
break;
}
@ -266,7 +283,7 @@ VOID MouseCommand(BYTE Command)
case 0xF5:
{
Reporting = FALSE;
KeyboardQueuePush(MOUSE_ACK);
PS2QueuePush(PS2Port, MOUSE_ACK);
break;
}
@ -297,12 +314,12 @@ VOID MouseCommand(BYTE Command)
/* Unknown command */
default:
{
KeyboardQueuePush(MOUSE_ERROR);
PS2QueuePush(PS2Port, MOUSE_ERROR);
}
}
}
BOOLEAN MouseInit(VOID)
BOOLEAN MouseInit(BYTE PS2Connector)
{
HWND hWnd;
HDC hDC;
@ -324,6 +341,8 @@ BOOLEAN MouseInit(VOID)
/* Release the device context */
ReleaseDC(hWnd, hDC);
PS2Port = PS2Connector;
MouseReset();
return TRUE;
}

View file

@ -68,11 +68,12 @@ typedef struct _MOUSE_PACKET
/* FUNCTIONS ******************************************************************/
VOID MouseUpdatePosition(PCOORD NewPosition);
VOID MouseUpdateButtons(ULONG NewButtonState);
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent);
VOID MouseScroll(LONG Direction);
COORD MouseGetPosition(VOID);
VOID MouseCommand(BYTE Command);
BOOLEAN MouseInit(VOID);
BOOLEAN MouseInit(BYTE PS2Connector);
#endif // _MOUSE_H_

View file

@ -4,6 +4,7 @@
* FILE: ps2.c
* PURPOSE: PS/2 controller emulation
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
@ -14,19 +15,39 @@
#include "io.h"
#include "ps2.h"
#include "pic.h"
#include "keyboard.h"
#include "mouse.h"
#include "../bios/bios32/moubios32.h"
/* PRIVATE VARIABLES **********************************************************/
static BYTE KeyboardQueue[KEYBOARD_BUFFER_SIZE];
static BOOLEAN KeyboardQueueEmpty = TRUE;
static UINT KeyboardQueueStart = 0;
static UINT KeyboardQueueEnd = 0;
static BYTE KeyboardData = 0, KeyboardResponse = 0;
static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE;
static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG;
static HANDLE QueueMutex = NULL;
#define BUFFER_SIZE 32
typedef struct _PS2_PORT
{
BOOLEAN IsEnabled;
BOOLEAN QueueEmpty;
BYTE Queue[BUFFER_SIZE];
UINT QueueStart;
UINT QueueEnd;
HANDLE QueueMutex;
} PS2_PORT, *PPS2_PORT;
/*
* Port 1: Keyboard
* Port 2: Mouse
*/
#define PS2_PORTS 2
static PS2_PORT Ports[PS2_PORTS];
#define PS2_DEFAULT_CONFIG 0x47
static BYTE ControllerConfig = PS2_DEFAULT_CONFIG;
static BYTE ControllerCommand = 0x00;
static BYTE StatusRegister = 0x00;
// static BYTE InputBuffer = 0x00; // PS/2 Input Buffer
static BYTE OutputBuffer = 0x00; // PS/2 Output Buffer
/* PRIVATE FUNCTIONS **********************************************************/
@ -34,31 +55,28 @@ static BYTE WINAPI PS2ReadPort(ULONG Port)
{
if (Port == PS2_CONTROL_PORT)
{
BYTE Status = 0;
/* Be sure bit 2 is always set */
StatusRegister |= 1 << 2;
/* Set the first bit if the data can be read */
if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0;
// FIXME: Should clear bits 6 and 7 because there are
// no timeouts and no parity errors.
/* Always set bit 2 */
Status |= 1 << 2;
/* Set bit 3 if the next byte goes to the controller */
if (KeyboardWriteResponse) Status |= 1 << 3;
return Status;
return StatusRegister;
}
else if (Port == PS2_DATA_PORT)
{
/* If there was a response byte from the controller, return it */
if (KeyboardReadResponse)
{
KeyboardReadResponse = FALSE;
KeyboardData = KeyboardResponse;
}
/*
* If there is something to read (response byte from the
* controller or data from a PS/2 device), read it.
*/
if (StatusRegister & (1 << 0)) // || StatusRegister & (1 << 5) for second PS/2 port
StatusRegister &= ~(1 << 0); // StatusRegister &= ~(1 << 5);
return KeyboardData;
/* Always return the available byte stored in the output buffer */
return OutputBuffer;
}
else return 0;
return 0;
}
static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
@ -70,8 +88,8 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
/* Read configuration byte */
case 0x20:
{
KeyboardResponse = KeyboardConfig;
KeyboardReadResponse = TRUE;
OutputBuffer = ControllerConfig;
StatusRegister |= (1 << 0); // There is something to read
break;
}
@ -79,60 +97,68 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
case 0x60:
/* Write controller output port */
case 0xD1:
/* Write keyboard output buffer */
/* Write to the first PS/2 port output buffer */
case 0xD2:
/* Write mouse output buffer */
/* Write to the second PS/2 port output buffer */
case 0xD3:
/* Write mouse input buffer */
/* Write to the second PS/2 port input buffer */
case 0xD4:
{
/* These commands require a response */
KeyboardResponse = Data;
KeyboardWriteResponse = TRUE;
ControllerCommand = Data;
StatusRegister |= (1 << 3); // This is a controller command
break;
}
/* Disable mouse */
/* Disable second PS/2 port */
case 0xA7:
{
// TODO: Not implemented
Ports[1].IsEnabled = FALSE;
break;
}
/* Enable mouse */
/* Enable second PS/2 port */
case 0xA8:
{
// TODO: Not implemented
Ports[1].IsEnabled = TRUE;
break;
}
/* Test mouse port */
/* Test second PS/2 port */
case 0xA9:
{
KeyboardResponse = 0;
KeyboardReadResponse = TRUE;
OutputBuffer = 0x00; // Success code
StatusRegister |= (1 << 0); // There is something to read
break;
}
/* Test PS/2 controller */
case 0xAA:
{
KeyboardResponse = 0x55;
KeyboardReadResponse = TRUE;
OutputBuffer = 0x55; // Success code
StatusRegister |= (1 << 0); // There is something to read
break;
}
/* Disable keyboard */
/* Test first PS/2 port */
case 0xAB:
{
OutputBuffer = 0x00; // Success code
StatusRegister |= (1 << 0); // There is something to read
break;
}
/* Disable first PS/2 port */
case 0xAD:
{
// TODO: Not implemented
Ports[0].IsEnabled = FALSE;
break;
}
/* Enable keyboard */
/* Enable first PS/2 port */
case 0xAE:
{
// TODO: Not implemented
Ports[0].IsEnabled = TRUE;
break;
}
@ -162,17 +188,17 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
else if (Port == PS2_DATA_PORT)
{
/* Check if the controller is waiting for a response */
if (KeyboardWriteResponse)
if (StatusRegister & (1 << 3)) // If we have data for the controller
{
KeyboardWriteResponse = FALSE;
StatusRegister &= ~(1 << 3);
/* Check which command it was */
switch (KeyboardResponse)
switch (ControllerCommand)
{
/* Write configuration byte */
case 0x60:
{
KeyboardConfig = Data;
ControllerConfig = Data;
break;
}
@ -191,23 +217,31 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
break;
}
/* Push the data byte into the first PS/2 port queue */
case 0xD2:
{
/* Push the data byte to the keyboard queue */
KeyboardQueuePush(Data);
PS2QueuePush(0, Data);
break;
}
/* Push the data byte into the second PS/2 port queue */
case 0xD3:
{
// TODO: Mouse support
PS2QueuePush(1, Data);
break;
}
/*
* Send a command to the second PS/2 port (by default
* it is a command for the first PS/2 port)
*/
case 0xD4:
{
MouseCommand(Data);
if (Ports[1].IsEnabled)
// Ports[1].Function
MouseCommand(Data);
break;
}
}
@ -216,156 +250,148 @@ static VOID WINAPI PS2WritePort(ULONG Port, BYTE Data)
}
// TODO: Implement PS/2 device commands
if (Ports[0].IsEnabled)
// Ports[0].Function
KeyboardCommand(Data);
}
}
static BOOLEAN PS2PortQueueRead(BYTE PS2Port)
{
BOOLEAN Result = TRUE;
PPS2_PORT Port;
if (PS2Port >= PS2_PORTS) return FALSE;
Port = &Ports[PS2Port];
if (!Port->IsEnabled) return FALSE;
/* Make sure the queue is not empty (fast check) */
if (Port->QueueEmpty) return FALSE;
WaitForSingleObject(Port->QueueMutex, INFINITE);
/*
* Recheck whether the queue is not empty (it may
* have changed after having grabbed the mutex).
*/
if (Port->QueueEmpty)
{
Result = FALSE;
goto Done;
}
/* Get the data */
OutputBuffer = Port->Queue[Port->QueueStart];
StatusRegister |= (1 << 0); // There is something to read
// Sometimes StatusRegister |= (1 << 5); for the second PS/2 port
/* Remove the value from the queue */
Port->QueueStart++;
Port->QueueStart %= BUFFER_SIZE;
/* Check if the queue is now empty */
if (Port->QueueStart == Port->QueueEnd)
Port->QueueEmpty = TRUE;
Done:
ReleaseMutex(Port->QueueMutex);
return Result;
}
/* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN KeyboardQueuePush(BYTE ScanCode)
// PS2SendToPort
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data)
{
BOOLEAN Result = TRUE;
PPS2_PORT Port;
WaitForSingleObject(QueueMutex, INFINITE);
if (PS2Port >= PS2_PORTS) return FALSE;
Port = &Ports[PS2Port];
/* Check if the keyboard queue is full */
if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd))
if (!Port->IsEnabled) return FALSE;
WaitForSingleObject(Port->QueueMutex, INFINITE);
/* Check if the queue is full */
if (!Port->QueueEmpty && (Port->QueueStart == Port->QueueEnd))
{
Result = FALSE;
goto Done;
}
/* Insert the value in the queue */
KeyboardQueue[KeyboardQueueEnd] = ScanCode;
KeyboardQueueEnd++;
KeyboardQueueEnd %= KEYBOARD_BUFFER_SIZE;
Port->Queue[Port->QueueEnd] = Data;
Port->QueueEnd++;
Port->QueueEnd %= BUFFER_SIZE;
/* Since we inserted a value, it's not empty anymore */
KeyboardQueueEmpty = FALSE;
Port->QueueEmpty = FALSE;
/*
// Get the data
OutputBuffer = Port->Queue[Port->QueueStart];
StatusRegister |= (1 << 0); // There is something to read
// FIXME: Sometimes StatusRegister |= (1 << 5); for the second PS/2 port
if (PS2Port == 0)
PicInterruptRequest(1);
else if (PS2Port == 1)
PicInterruptRequest(12);
*/
Done:
ReleaseMutex(QueueMutex);
ReleaseMutex(Port->QueueMutex);
return Result;
}
BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
VOID GenerateIrq1(VOID)
{
BOOLEAN Result = TRUE;
/* Make sure the keyboard queue is not empty (fast check) */
if (KeyboardQueueEmpty) return FALSE;
WaitForSingleObject(QueueMutex, INFINITE);
/*
* Recheck whether keyboard queue is not empty (it
* may have changed after having grabbed the mutex).
*/
if (KeyboardQueueEmpty)
/* Generate an interrupt if interrupts for the first PS/2 port are enabled */
if (ControllerConfig & 0x01)
{
Result = FALSE;
goto Done;
}
/* Get the scan code */
*ScanCode = KeyboardQueue[KeyboardQueueStart];
/* Remove the value from the queue */
KeyboardQueueStart++;
KeyboardQueueStart %= KEYBOARD_BUFFER_SIZE;
/* Check if the queue is now empty */
if (KeyboardQueueStart == KeyboardQueueEnd)
{
KeyboardQueueEmpty = TRUE;
}
Done:
ReleaseMutex(QueueMutex);
return Result;
}
VOID PS2Dispatch(PINPUT_RECORD InputRecord)
{
/* Check the event type */
switch (InputRecord->EventType)
{
case KEY_EVENT:
{
WORD i;
BYTE ScanCode = (BYTE)InputRecord->Event.KeyEvent.wVirtualScanCode;
/* If this is a key release, set the highest bit in the scan code */
if (!InputRecord->Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
/* Push the scan code onto the keyboard queue */
for (i = 0; i < InputRecord->Event.KeyEvent.wRepeatCount; i++)
{
KeyboardQueuePush(ScanCode);
}
break;
}
case MOUSE_EVENT:
{
/* Notify the BIOS driver */
MouseBiosUpdatePosition(&InputRecord->Event.MouseEvent.dwMousePosition);
MouseBiosUpdateButtons(LOWORD(InputRecord->Event.MouseEvent.dwButtonState));
// TODO: PS/2, other stuff
break;
}
/* We ignore all the rest */
default:
break;
/* Generate an IRQ 1 if there is data ready in the output queue */
if (PS2PortQueueRead(0)) PicInterruptRequest(1);
}
}
VOID GenerateKeyboardInterrupts(VOID)
VOID GenerateIrq12(VOID)
{
/* Generate an IRQ 1 if there is a key ready in the queue */
if (KeyboardQueuePop(&KeyboardData)) PicInterruptRequest(1);
/* Generate an interrupt if interrupts for the second PS/2 port are enabled */
if (ControllerConfig & 0x02)
{
/* Generate an IRQ 12 if there is data ready in the output queue */
if (PS2PortQueueRead(1)) PicInterruptRequest(12);
}
}
BOOLEAN PS2Initialize(HANDLE ConsoleInput)
BOOLEAN PS2Initialize(VOID)
{
DWORD ConInMode;
/* Initialize the PS/2 ports */
Ports[0].IsEnabled = TRUE;
Ports[0].QueueEmpty = TRUE;
Ports[0].QueueStart = 0;
Ports[0].QueueEnd = 0;
Ports[0].QueueMutex = CreateMutex(NULL, FALSE, NULL);
/* Create the mutex */
QueueMutex = CreateMutex(NULL, FALSE, NULL);
Ports[1].IsEnabled = TRUE;
Ports[1].QueueEmpty = TRUE;
Ports[1].QueueStart = 0;
Ports[1].QueueEnd = 0;
Ports[1].QueueMutex = CreateMutex(NULL, FALSE, NULL);
/* Register the I/O Ports */
RegisterIoPort(PS2_CONTROL_PORT, PS2ReadPort, PS2WritePort);
RegisterIoPort(PS2_DATA_PORT , PS2ReadPort, PS2WritePort);
if (GetConsoleMode(ConsoleInput, &ConInMode))
{
#if 0
if (MousePresent)
{
#endif
/* Support mouse input events if there is a mouse on the system */
ConInMode |= ENABLE_MOUSE_INPUT;
#if 0
}
else
{
/* Do not support mouse input events if there is no mouse on the system */
ConInMode &= ~ENABLE_MOUSE_INPUT;
}
#endif
SetConsoleMode(ConsoleInput, ConInMode);
}
return TRUE;
}
VOID PS2Cleanup(VOID)
{
CloseHandle(QueueMutex);
CloseHandle(Ports[1].QueueMutex);
CloseHandle(Ports[0].QueueMutex);
}
/* EOF */

View file

@ -4,6 +4,7 @@
* FILE: ps2.h
* PURPOSE: PS/2 controller emulation
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
#ifndef _PS2_H_
@ -15,21 +16,17 @@
/* DEFINES ********************************************************************/
#define KEYBOARD_BUFFER_SIZE 32
#define PS2_DATA_PORT 0x60
#define PS2_CONTROL_PORT 0x64
#define PS2_DEFAULT_CONFIG 0x05
#define KEYBOARD_ACK 0xFA
#define KEYBOARD_RESEND 0xFE
#define PS2_DATA_PORT 0x60
#define PS2_CONTROL_PORT 0x64
/* FUNCTIONS ******************************************************************/
BOOLEAN KeyboardQueuePush(BYTE ScanCode);
BOOLEAN KeyboardQueuePop(BYTE *ScanCode);
VOID PS2Dispatch(PINPUT_RECORD InputRecord);
VOID GenerateKeyboardInterrupts(VOID);
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data);
BOOLEAN PS2Initialize(HANDLE ConsoleInput);
VOID GenerateIrq1(VOID);
VOID GenerateIrq12(VOID);
BOOLEAN PS2Initialize(VOID);
VOID PS2Cleanup(VOID);
#endif // _PS2_H_

View file

@ -1917,6 +1917,11 @@ VOID VgaResetPalette(VOID)
VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent)
{
DPRINT1("Screen events not handled\n");
}
BOOL VgaAttachToConsole(VOID)
{
//

View file

@ -250,6 +250,7 @@ typedef struct _VGA_REGISTERS
/* FUNCTIONS ******************************************************************/
VOID ScreenEventHandler(PWINDOW_BUFFER_SIZE_RECORD ScreenEvent);
BOOL VgaAttachToConsole(VOID);
VOID VgaDetachFromConsole(BOOL ChangeMode);

View file

@ -328,69 +328,32 @@ ConsoleCleanup(VOID)
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
}
DWORD
WINAPI
PumpConsoleInput(LPVOID Parameter)
VOID MenuEventHandler(PMENU_EVENT_RECORD MenuEvent)
{
HANDLE ConsoleInput = (HANDLE)Parameter;
INPUT_RECORD InputRecord;
DWORD Count;
while (VdmRunning)
switch (MenuEvent->dwCommandId)
{
/* Make sure the task event is signaled */
WaitForSingleObject(VdmTaskEvent, INFINITE);
case ID_SHOWHIDE_MOUSE:
ShowHideMousePointer(ConsoleOutput, ShowPointer);
ShowPointer = !ShowPointer;
break;
/* Wait for an input record */
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
{
DWORD LastError = GetLastError();
DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
return LastError;
}
case ID_VDM_DUMPMEM:
DumpMemory();
break;
ASSERT(Count != 0);
case ID_VDM_QUIT:
/* Stop the VDM */
EmulatorTerminate();
break;
/* Check the event type */
switch (InputRecord.EventType)
{
case KEY_EVENT:
case MOUSE_EVENT:
/* Send it to the PS/2 controller */
PS2Dispatch(&InputRecord);
break;
case MENU_EVENT:
{
switch (InputRecord.Event.MenuEvent.dwCommandId)
{
case ID_SHOWHIDE_MOUSE:
ShowHideMousePointer(ConsoleOutput, ShowPointer);
ShowPointer = !ShowPointer;
break;
case ID_VDM_DUMPMEM:
DumpMemory();
break;
case ID_VDM_QUIT:
/* Stop the VDM */
EmulatorTerminate();
break;
default:
break;
}
break;
}
default:
break;
}
default:
break;
}
}
return 0;
VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent)
{
DPRINT1("Focus events not handled\n");
}
#ifndef STANDALONE

View file

@ -46,6 +46,9 @@ extern ULONG SessionId;
extern HANDLE VdmTaskEvent;
/*
* Interface functions
*/
VOID DisplayMessage(LPCWSTR Format, ...);
/*static*/ VOID
@ -53,6 +56,9 @@ CreateVdmMenu(HANDLE ConOutHandle);
/*static*/ VOID
DestroyVdmMenu(VOID);
VOID MenuEventHandler(PMENU_EVENT_RECORD MenuEvent);
VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent);
#endif // _NTVDM_H_
/* EOF */