Author: aandrejevic
Date: Sat Aug 9 01:39:28 2014
New Revision: 63842
URL:
http://svn.reactos.org/svn/reactos?rev=63842&view=rev
Log:
[NTVDM]
Start implementing mouse support.
Added:
trunk/reactos/subsystems/ntvdm/hardware/mouse.c (with props)
trunk/reactos/subsystems/ntvdm/hardware/mouse.h (with props)
Modified:
trunk/reactos/subsystems/ntvdm/CMakeLists.txt
trunk/reactos/subsystems/ntvdm/hardware/ps2.c
trunk/reactos/subsystems/ntvdm/hardware/ps2.h
Modified: trunk/reactos/subsystems/ntvdm/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/ntvdm/CMakeList…
==============================================================================
--- trunk/reactos/subsystems/ntvdm/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/subsystems/ntvdm/CMakeLists.txt [iso-8859-1] Sat Aug 9 01:39:28 2014
@@ -19,6 +19,7 @@
hardware/speaker.c
hardware/timer.c
hardware/vga.c
+ hardware/mouse.c
dos/dos32krnl/bios.c
dos/dos32krnl/dos.c
dos/dos32krnl/dosfiles.c
Added: trunk/reactos/subsystems/ntvdm/hardware/mouse.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/ntvdm/hardware/…
==============================================================================
--- trunk/reactos/subsystems/ntvdm/hardware/mouse.c (added)
+++ trunk/reactos/subsystems/ntvdm/hardware/mouse.c [iso-8859-1] Sat Aug 9 01:39:28 2014
@@ -0,0 +1,329 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: mouse.c
+ * PURPOSE: Mouse emulation
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#define NDEBUG
+
+#include "mouse.h"
+#include "ps2.h"
+
+/* PRIVATE VARIABLES **********************************************************/
+
+static MOUSE_MODE Mode, PreviousMode;
+static COORD Position;
+static ULONG WidthMm, HeightMm, WidthPixels, HeightPixels;
+static ULONG SampleRate;
+static ULONG Resolution;
+static BOOLEAN Scaling;
+static BOOLEAN Reporting;
+static BYTE MouseId;
+static ULONG ButtonState;
+static SHORT HorzCounter;
+static SHORT VertCounter;
+static CHAR ScrollCounter;
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static VOID MouseResetConfig(VOID)
+{
+ /* Reset the configuration to defaults */
+ SampleRate = 100;
+ Resolution = 4;
+ Scaling = FALSE;
+ Reporting = FALSE;
+}
+
+static VOID MouseResetCounters(VOID)
+{
+ /* Reset all flags and counters */
+ ButtonState = HorzCounter = VertCounter = ScrollCounter = 0;
+}
+
+static VOID MouseReset(VOID)
+{
+ /* Reset everything */
+ MouseResetConfig();
+ MouseResetCounters();
+
+ /* Enter streaming mode and the reset the mouse ID */
+ Mode = MOUSE_STREAMING_MODE;
+ MouseId = 0;
+
+ /* Send the Basic Assurance Test success code and the device ID */
+ KeyboardQueuePush(MOUSE_BAT_SUCCESS);
+ KeyboardQueuePush(MouseId);
+}
+
+#if 0
+static VOID MouseGetPacket(PMOUSE_PACKET Packet)
+{
+ /* Clear the packet */
+ ZeroMemory(Packet, sizeof(MOUSE_PACKET));
+
+ Packet->Flags |= MOUSE_ALWAYS_SET;
+
+ /* Check for horizontal overflows */
+ if ((HorzCounter < MOUSE_MIN) || (HorzCounter > MOUSE_MAX))
+ {
+ if (HorzCounter > MOUSE_MAX) HorzCounter = MOUSE_MAX;
+ if (HorzCounter < MOUSE_MIN) HorzCounter = MOUSE_MIN;
+
+ Packet->Flags |= MOUSE_X_OVERFLOW;
+ }
+
+ /* Check for vertical overflows */
+ if ((VertCounter < MOUSE_MIN) || (VertCounter > MOUSE_MAX))
+ {
+ if (VertCounter > MOUSE_MIN) VertCounter = MOUSE_MIN;
+ if (VertCounter < MOUSE_MIN) VertCounter = MOUSE_MIN;
+
+ Packet->Flags |= MOUSE_Y_OVERFLOW;
+ }
+
+ /* Set the sign flags */
+ if (HorzCounter & MOUSE_SIGN_BIT) Packet->Flags |= MOUSE_X_SIGN;
+ if (HorzCounter & MOUSE_SIGN_BIT) Packet->Flags |= MOUSE_Y_SIGN;
+
+ /* Set the button flags */
+ if (ButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) Packet->Flags |=
MOUSE_LEFT_BUTTON;
+ if (ButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) Packet->Flags |=
MOUSE_MIDDLE_BUTTON;
+ if (ButtonState & RIGHTMOST_BUTTON_PRESSED) Packet->Flags |=
MOUSE_RIGHT_BUTTON;
+
+ if (MouseId == 4)
+ {
+ if (ButtonState & FROM_LEFT_3RD_BUTTON_PRESSED) Packet->Extra |=
MOUSE_4TH_BUTTON;
+ if (ButtonState & FROM_LEFT_4TH_BUTTON_PRESSED) Packet->Extra |=
MOUSE_5TH_BUTTON;
+ }
+
+ if (MouseId >= 3)
+ {
+ /* Set the scroll counter */
+ Packet->Extra |= (UCHAR)ScrollCounter & 0x0F;
+ }
+
+ /* Store the counters in the packet */
+ Packet->HorzCounter = LOBYTE(HorzCounter);
+ Packet->VertCounter = LOBYTE(VertCounter);
+
+ /* Reset the counters */
+ MouseResetCounters();
+}
+#endif
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID MouseUpdatePosition(PCOORD NewPosition)
+{
+ /* Update the counters */
+ HorzCounter += ((NewPosition->X - Position.X) * WidthMm * Resolution) /
WidthPixels;
+ VertCounter += ((NewPosition->Y - Position.Y) * HeightMm * Resolution) /
HeightPixels;
+
+ /* Update the position */
+ Position = *NewPosition;
+}
+
+VOID MouseUpdateButtons(ULONG NewButtonState)
+{
+ ButtonState = NewButtonState;
+}
+
+VOID MouseScroll(LONG Direction)
+{
+ ScrollCounter += Direction;
+}
+
+COORD MouseGetPosition(VOID)
+{
+ return Position;
+}
+
+VOID MouseCommand(BYTE Command)
+{
+ switch (Command)
+ {
+ /* Set 1:1 Scaling */
+ case 0xE6:
+ {
+ Scaling = FALSE;
+ KeyboardQueuePush(MOUSE_ACK);
+ break;
+ }
+
+ /* Set 2:1 Scaling */
+ case 0xE7:
+ {
+ Scaling = TRUE;
+ KeyboardQueuePush(MOUSE_ACK);
+ break;
+ }
+
+ /* Set Resolution */
+ case 0xE8:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Read Status */
+ case 0xE9:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Enter Streaming Mode */
+ case 0xEA:
+ {
+ MouseResetCounters();
+ Mode = MOUSE_STREAMING_MODE;
+
+ KeyboardQueuePush(MOUSE_ACK);
+ break;
+ }
+
+ /* Read Packet */
+ case 0xEB:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Return From Wrap Mode */
+ case 0xEC:
+ {
+ if (Mode == MOUSE_WRAP_MODE)
+ {
+ /* Restore the previous mode */
+ MouseResetCounters();
+ Mode = PreviousMode;
+ KeyboardQueuePush(MOUSE_ACK);
+ }
+ else KeyboardQueuePush(MOUSE_ERROR);
+
+ break;
+ }
+
+ /* Enter Wrap Mode */
+ case 0xEE:
+ {
+ if (Mode != MOUSE_WRAP_MODE)
+ {
+ /* Save the previous mode */
+ PreviousMode = Mode;
+ }
+
+ MouseResetCounters();
+ Mode = MOUSE_WRAP_MODE;
+
+ KeyboardQueuePush(MOUSE_ACK);
+ break;
+ }
+
+ /* Enter Remote Mode */
+ case 0xF0:
+ {
+ MouseResetCounters();
+ Mode = MOUSE_REMOTE_MODE;
+
+ KeyboardQueuePush(MOUSE_ACK);
+ break;
+ }
+
+ /* Get Mouse ID */
+ case 0xF2:
+ {
+ KeyboardQueuePush(MOUSE_ACK);
+ KeyboardQueuePush(MouseId);
+ break;
+ }
+
+ /* Set Sample Rate */
+ case 0xF3:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Enable Reporting */
+ case 0xF4:
+ {
+ Reporting = TRUE;
+ KeyboardQueuePush(MOUSE_ACK);
+ break;
+ }
+
+ /* Disable Reporting */
+ case 0xF5:
+ {
+ Reporting = FALSE;
+ KeyboardQueuePush(MOUSE_ACK);
+ break;
+ }
+
+ /* Set Defaults */
+ case 0xF6:
+ {
+ /* Reset the configuration and counters */
+ MouseResetConfig();
+ MouseResetCounters();
+ break;
+ }
+
+ /* Resend */
+ case 0xFE:
+ {
+ // TODO: NOT IMPLEMENTED
+ UNIMPLEMENTED;
+ break;
+ }
+
+ /* Reset */
+ case 0xFF:
+ {
+ MouseReset();
+ break;
+ }
+
+ /* Unknown command */
+ default:
+ {
+ KeyboardQueuePush(MOUSE_ERROR);
+ }
+ }
+}
+
+BOOLEAN MouseInit(VOID)
+{
+ HWND hWnd;
+ HDC hDC;
+
+ /* Get the console window */
+ hWnd = GetConsoleWindow();
+ if (hWnd == NULL) return FALSE;
+
+ /* Get the console window's device context */
+ hDC = GetWindowDC(hWnd);
+ if (hDC == NULL) return FALSE;
+
+ /* Get the parameters */
+ WidthMm = (ULONG)GetDeviceCaps(hDC, HORZSIZE);
+ HeightMm = (ULONG)GetDeviceCaps(hDC, VERTSIZE);
+ WidthPixels = (ULONG)GetDeviceCaps(hDC, HORZRES);
+ HeightPixels = (ULONG)GetDeviceCaps(hDC, VERTRES);
+
+ /* Release the device context */
+ ReleaseDC(hWnd, hDC);
+
+ MouseReset();
+ return TRUE;
+}
Propchange: trunk/reactos/subsystems/ntvdm/hardware/mouse.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/subsystems/ntvdm/hardware/mouse.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/ntvdm/hardware/…
==============================================================================
--- trunk/reactos/subsystems/ntvdm/hardware/mouse.h (added)
+++ trunk/reactos/subsystems/ntvdm/hardware/mouse.h [iso-8859-1] Sat Aug 9 01:39:28 2014
@@ -0,0 +1,78 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: mouse.h
+ * PURPOSE: Mouse emulation
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+#ifndef _MOUSE_H_
+#define _MOUSE_H_
+
+/* INCLUDES *******************************************************************/
+
+#include "ntvdm.h"
+
+/* DEFINES ********************************************************************/
+
+/* Mouse packet constants */
+#define MOUSE_MIN -256
+#define MOUSE_MAX 255
+#define MOUSE_SIGN_BIT (1 << 8)
+
+/* Mouse packet flags */
+#define MOUSE_LEFT_BUTTON (1 << 0)
+#define MOUSE_RIGHT_BUTTON (1 << 1)
+#define MOUSE_MIDDLE_BUTTON (1 << 2)
+#define MOUSE_ALWAYS_SET (1 << 3)
+#define MOUSE_X_SIGN (1 << 4)
+#define MOUSE_Y_SIGN (1 << 5)
+#define MOUSE_X_OVERFLOW (1 << 6)
+#define MOUSE_Y_OVERFLOW (1 << 7)
+
+/* Mouse packet extra flags */
+#define MOUSE_4TH_BUTTON (1 << 4)
+#define MOUSE_5TH_BUTTON (1 << 5)
+
+/* Command responses */
+#define MOUSE_BAT_SUCCESS 0xAA
+#define MOUSE_ACK 0xFA
+#define MOUSE_ERROR 0xFC
+
+/*
+ * Scrolling directions
+ *
+ * It may seem odd that the directions are implemented this way, but
+ * this is how it's done on real hardware. It works because the two
+ * scroll wheels can't be used at the same time.
+ */
+#define MOUSE_SCROLL_UP 1
+#define MOUSE_SCROLL_DOWN -1
+#define MOUSE_SCROLL_RIGHT 2
+#define MOUSE_SCROLL_LET -2
+
+typedef enum _MOUSE_MODE
+{
+ MOUSE_STREAMING_MODE,
+ MOUSE_REMOTE_MODE,
+ MOUSE_WRAP_MODE,
+} MOUSE_MODE, *PMOUSE_MODE;
+
+typedef struct _MOUSE_PACKET
+{
+ BYTE Flags;
+ BYTE HorzCounter;
+ BYTE VertCounter;
+ BYTE Extra;
+} MOUSE_PACKET, *PMOUSE_PACKET;
+
+/* FUNCTIONS ******************************************************************/
+
+VOID MouseUpdatePosition(PCOORD NewPosition);
+VOID MouseUpdateButtons(ULONG NewButtonState);
+VOID MouseScroll(LONG Direction);
+COORD MouseGetPosition(VOID);
+VOID MouseCommand(BYTE Command);
+BOOLEAN MouseInit(VOID);
+
+#endif // _MOUSE_H_
Propchange: trunk/reactos/subsystems/ntvdm/hardware/mouse.h
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/subsystems/ntvdm/hardware/ps2.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/ntvdm/hardware/…
==============================================================================
--- trunk/reactos/subsystems/ntvdm/hardware/ps2.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/ntvdm/hardware/ps2.c [iso-8859-1] Sat Aug 9 01:39:28 2014
@@ -14,6 +14,7 @@
#include "io.h"
#include "ps2.h"
#include "pic.h"
+#include "mouse.h"
/* PRIVATE VARIABLES **********************************************************/
@@ -27,69 +28,6 @@
static HANDLE QueueMutex = NULL;
/* PRIVATE FUNCTIONS **********************************************************/
-
-static BOOLEAN KeyboardQueuePush(BYTE ScanCode)
-{
- BOOLEAN Result = TRUE;
-
- WaitForSingleObject(QueueMutex, INFINITE);
-
- /* Check if the keyboard queue is full */
- if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd))
- {
- Result = FALSE;
- goto Done;
- }
-
- /* Insert the value in the queue */
- KeyboardQueue[KeyboardQueueEnd] = ScanCode;
- KeyboardQueueEnd++;
- KeyboardQueueEnd %= KEYBOARD_BUFFER_SIZE;
-
- /* Since we inserted a value, it's not empty anymore */
- KeyboardQueueEmpty = FALSE;
-
-Done:
- ReleaseMutex(QueueMutex);
- return Result;
-}
-
-static BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
-{
- 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)
- {
- 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;
-}
static BYTE WINAPI PS2ReadPort(ULONG Port)
{
@@ -156,14 +94,14 @@
/* Disable mouse */
case 0xA7:
{
- // TODO: Mouse support
+ // TODO: Not implemented
break;
}
/* Enable mouse */
case 0xA8:
{
- // TODO: Mouse support
+ // TODO: Not implemented
break;
}
@@ -268,7 +206,7 @@
case 0xD4:
{
- // TODO: Mouse support
+ MouseCommand(Data);
break;
}
}
@@ -281,6 +219,69 @@
}
/* PUBLIC FUNCTIONS ***********************************************************/
+
+BOOLEAN KeyboardQueuePush(BYTE ScanCode)
+{
+ BOOLEAN Result = TRUE;
+
+ WaitForSingleObject(QueueMutex, INFINITE);
+
+ /* Check if the keyboard queue is full */
+ if (!KeyboardQueueEmpty && (KeyboardQueueStart == KeyboardQueueEnd))
+ {
+ Result = FALSE;
+ goto Done;
+ }
+
+ /* Insert the value in the queue */
+ KeyboardQueue[KeyboardQueueEnd] = ScanCode;
+ KeyboardQueueEnd++;
+ KeyboardQueueEnd %= KEYBOARD_BUFFER_SIZE;
+
+ /* Since we inserted a value, it's not empty anymore */
+ KeyboardQueueEmpty = FALSE;
+
+Done:
+ ReleaseMutex(QueueMutex);
+ return Result;
+}
+
+BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
+{
+ 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)
+ {
+ 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)
{
Modified: trunk/reactos/subsystems/ntvdm/hardware/ps2.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/ntvdm/hardware/…
==============================================================================
--- trunk/reactos/subsystems/ntvdm/hardware/ps2.h [iso-8859-1] (original)
+++ trunk/reactos/subsystems/ntvdm/hardware/ps2.h [iso-8859-1] Sat Aug 9 01:39:28 2014
@@ -24,6 +24,8 @@
/* FUNCTIONS ******************************************************************/
+BOOLEAN KeyboardQueuePush(BYTE ScanCode);
+BOOLEAN KeyboardQueuePop(BYTE *ScanCode);
VOID PS2Dispatch(PINPUT_RECORD InputRecord);
VOID GenerateKeyboardInterrupts(VOID);