2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Mouse emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
17 // HACK: For the PS/2 bypass and MOUSE.COM driver direct call
18 #include "dos/mouse32.h"
20 /* PRIVATE VARIABLES **********************************************************/
22 static MOUSE_MODE Mode
, PreviousMode
;
23 static COORD Position
;
24 static ULONG WidthMm
, HeightMm
, WidthPixels
, HeightPixels
;
25 static ULONG SampleRate
;
26 static ULONG Resolution
;
27 static BOOLEAN Scaling
;
28 static BOOLEAN Reporting
;
30 static ULONG ButtonState
;
31 static SHORT HorzCounter
;
32 static SHORT VertCounter
;
33 static CHAR ScrollCounter
;
35 static BYTE PS2Port
= 1;
37 /* PRIVATE FUNCTIONS **********************************************************/
39 static VOID
MouseResetConfig(VOID
)
41 /* Reset the configuration to defaults */
48 static VOID
MouseResetCounters(VOID
)
50 /* Reset all flags and counters */
51 ButtonState
= HorzCounter
= VertCounter
= ScrollCounter
= 0;
54 static VOID
MouseReset(VOID
)
56 /* Reset everything */
60 /* Enter streaming mode and the reset the mouse ID */
61 Mode
= MOUSE_STREAMING_MODE
;
64 /* Send the Basic Assurance Test success code and the device ID */
65 PS2QueuePush(PS2Port
, MOUSE_BAT_SUCCESS
);
66 PS2QueuePush(PS2Port
, MouseId
);
70 static VOID
MouseGetPacket(PMOUSE_PACKET Packet
)
72 /* Clear the packet */
73 RtlZeroMemory(Packet
, sizeof(*Packet
));
75 Packet
->Flags
|= MOUSE_ALWAYS_SET
;
77 /* Check for horizontal overflows */
78 if ((HorzCounter
< MOUSE_MIN
) || (HorzCounter
> MOUSE_MAX
))
80 if (HorzCounter
> MOUSE_MAX
) HorzCounter
= MOUSE_MAX
;
81 if (HorzCounter
< MOUSE_MIN
) HorzCounter
= MOUSE_MIN
;
83 Packet
->Flags
|= MOUSE_X_OVERFLOW
;
86 /* Check for vertical overflows */
87 if ((VertCounter
< MOUSE_MIN
) || (VertCounter
> MOUSE_MAX
))
89 if (VertCounter
> MOUSE_MIN
) VertCounter
= MOUSE_MIN
;
90 if (VertCounter
< MOUSE_MIN
) VertCounter
= MOUSE_MIN
;
92 Packet
->Flags
|= MOUSE_Y_OVERFLOW
;
95 /* Set the sign flags */
96 if (HorzCounter
& MOUSE_SIGN_BIT
) Packet
->Flags
|= MOUSE_X_SIGN
;
97 if (HorzCounter
& MOUSE_SIGN_BIT
) Packet
->Flags
|= MOUSE_Y_SIGN
;
99 /* Set the button flags */
100 if (ButtonState
& FROM_LEFT_1ST_BUTTON_PRESSED
) Packet
->Flags
|= MOUSE_LEFT_BUTTON
;
101 if (ButtonState
& FROM_LEFT_2ND_BUTTON_PRESSED
) Packet
->Flags
|= MOUSE_MIDDLE_BUTTON
;
102 if (ButtonState
& RIGHTMOST_BUTTON_PRESSED
) Packet
->Flags
|= MOUSE_RIGHT_BUTTON
;
106 if (ButtonState
& FROM_LEFT_3RD_BUTTON_PRESSED
) Packet
->Extra
|= MOUSE_4TH_BUTTON
;
107 if (ButtonState
& FROM_LEFT_4TH_BUTTON_PRESSED
) Packet
->Extra
|= MOUSE_5TH_BUTTON
;
112 /* Set the scroll counter */
113 Packet
->Extra
|= (UCHAR
)ScrollCounter
& 0x0F;
116 /* Store the counters in the packet */
117 Packet
->HorzCounter
= LOBYTE(HorzCounter
);
118 Packet
->VertCounter
= LOBYTE(VertCounter
);
120 /* Reset the counters */
121 MouseResetCounters();
125 /*static*/ VOID
MouseUpdatePosition(PCOORD NewPosition
)
127 /* Update the counters */
128 HorzCounter
+= ((NewPosition
->X
- Position
.X
) * WidthMm
* Resolution
) / WidthPixels
;
129 VertCounter
+= ((NewPosition
->Y
- Position
.Y
) * HeightMm
* Resolution
) / HeightPixels
;
131 /* Update the position */
132 Position
= *NewPosition
;
135 /*static*/ VOID
MouseUpdateButtons(ULONG NewButtonState
)
137 ButtonState
= NewButtonState
;
140 /*static*/ VOID
MouseScroll(LONG Direction
)
142 ScrollCounter
+= Direction
;
145 /*static*/ COORD
MouseGetPosition(VOID
)
150 static VOID WINAPI
MouseCommand(LPVOID Param
, BYTE Command
)
154 /* Set 1:1 Scaling */
158 PS2QueuePush(PS2Port
, MOUSE_ACK
);
162 /* Set 2:1 Scaling */
166 PS2QueuePush(PS2Port
, MOUSE_ACK
);
173 // TODO: NOT IMPLEMENTED
181 // TODO: NOT IMPLEMENTED
186 /* Enter Streaming Mode */
189 MouseResetCounters();
190 Mode
= MOUSE_STREAMING_MODE
;
192 PS2QueuePush(PS2Port
, MOUSE_ACK
);
199 // TODO: NOT IMPLEMENTED
204 /* Return From Wrap Mode */
207 if (Mode
== MOUSE_WRAP_MODE
)
209 /* Restore the previous mode */
210 MouseResetCounters();
212 PS2QueuePush(PS2Port
, MOUSE_ACK
);
214 else PS2QueuePush(PS2Port
, MOUSE_ERROR
);
219 /* Enter Wrap Mode */
222 if (Mode
!= MOUSE_WRAP_MODE
)
224 /* Save the previous mode */
228 MouseResetCounters();
229 Mode
= MOUSE_WRAP_MODE
;
231 PS2QueuePush(PS2Port
, MOUSE_ACK
);
235 /* Enter Remote Mode */
238 MouseResetCounters();
239 Mode
= MOUSE_REMOTE_MODE
;
241 PS2QueuePush(PS2Port
, MOUSE_ACK
);
248 PS2QueuePush(PS2Port
, MOUSE_ACK
);
249 PS2QueuePush(PS2Port
, MouseId
);
253 /* Set Sample Rate */
256 // TODO: NOT IMPLEMENTED
261 /* Enable Reporting */
265 PS2QueuePush(PS2Port
, MOUSE_ACK
);
269 /* Disable Reporting */
273 PS2QueuePush(PS2Port
, MOUSE_ACK
);
280 /* Reset the configuration and counters */
282 MouseResetCounters();
289 // TODO: NOT IMPLEMENTED
301 /* Unknown command */
304 PS2QueuePush(PS2Port
, MOUSE_ERROR
);
309 /* PUBLIC FUNCTIONS ***********************************************************/
311 VOID
MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent
)
313 // FIXME: Sync our private data
315 // HACK: Bypass PS/2 and instead, notify the MOUSE.COM driver directly
316 MouseBiosUpdatePosition(&MouseEvent
->dwMousePosition
);
317 MouseBiosUpdateButtons(LOWORD(MouseEvent
->dwButtonState
));
319 // PS2QueuePush(PS2Port, Data);
322 BOOLEAN
MouseInit(BYTE PS2Connector
)
327 /* Get the console window */
328 hWnd
= GetConsoleWindow();
329 if (hWnd
== NULL
) return FALSE
;
331 /* Get the console window's device context */
332 hDC
= GetWindowDC(hWnd
);
333 if (hDC
== NULL
) return FALSE
;
335 /* Get the parameters */
336 WidthMm
= (ULONG
)GetDeviceCaps(hDC
, HORZSIZE
);
337 HeightMm
= (ULONG
)GetDeviceCaps(hDC
, VERTSIZE
);
338 WidthPixels
= (ULONG
)GetDeviceCaps(hDC
, HORZRES
);
339 HeightPixels
= (ULONG
)GetDeviceCaps(hDC
, VERTRES
);
341 /* Release the device context */
342 ReleaseDC(hWnd
, hDC
);
344 /* Finish to plug the mouse to the specified PS/2 port */
345 PS2Port
= PS2Connector
;
346 PS2SetDeviceCmdProc(PS2Port
, NULL
, MouseCommand
);