ReactOS  0.4.13-dev-235-g7373cb3
mouse.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: GPL - See COPYING in the top level directory
3  * PROJECT: ReactOS Virtual DOS Machine
4  * FILE: subsystems/mvdm/ntvdm/hardware/mouse.c
5  * PURPOSE: PS/2 Mouse emulation
6  * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "ntvdm.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 #include "mouse.h"
17 #include "ps2.h"
18 
19 #include "clock.h"
20 #include "video/svga.h"
21 
22 #include "../console/video.h"
23 
24 
25 /* PRIVATE VARIABLES **********************************************************/
26 
27 static const BYTE ScrollMagic[3] = { 200, 100, 80 };
28 static const BYTE ExtraButtonMagic[3] = { 200, 200, 80 };
29 
34 static COORD Position;
35 static BYTE Resolution; /* Completely ignored */
36 static BOOLEAN Scaling; /* Completely ignored */
38 static BYTE MouseId;
46 
47 static UINT MouseCycles = 10;
48 
49 static BYTE MousePS2Port = 1;
50 
51 /* PUBLIC VARIABLES ***********************************************************/
52 
53 /* PRIVATE FUNCTIONS **********************************************************/
54 
56 {
57  /* Reset the configuration to defaults */
58  MouseCycles = 10;
59  Resolution = 4;
60  Scaling = FALSE;
62 }
63 
65 {
66  /* Reset all flags and counters */
68 }
69 
71 {
72  /* Reset everything */
75 
76  /* Enter streaming mode and the reset the mouse ID */
78  MouseId = 0;
80 }
81 
83 {
84  /* Clear the packet */
85  RtlZeroMemory(Packet, sizeof(*Packet));
86 
87  /* Acquire the mutex */
89 
90  Packet->Flags |= MOUSE_ALWAYS_SET;
91 
92  /* Set the sign flags */
93  if (HorzCounter < 0)
94  {
95  Packet->Flags |= MOUSE_X_SIGN;
97  }
98 
99  if (VertCounter < 0)
100  {
101  Packet->Flags |= MOUSE_Y_SIGN;
103  }
104 
105  /* Check for horizontal overflows */
106  if (HorzCounter > MOUSE_MAX)
107  {
109  Packet->Flags |= MOUSE_X_OVERFLOW;
110  }
111 
112  /* Check for vertical overflows */
113  if (VertCounter > MOUSE_MAX)
114  {
116  Packet->Flags |= MOUSE_Y_OVERFLOW;
117  }
118 
119  /* Set the button flags */
123 
124  if (MouseId == 4)
125  {
128  }
129 
130  if (MouseId >= 3)
131  {
132  /* Set the scroll counter */
133  Packet->Extra |= ((UCHAR)ScrollCounter & 0x0F);
134  }
135 
136  /* Store the counters in the packet */
137  Packet->HorzCounter = LOBYTE(HorzCounter);
138  Packet->VertCounter = LOBYTE(VertCounter);
139 
140  /* Reset the counters */
142 
143  /* Release the mutex */
145 }
146 
148 {
150  PS2QueuePush(MousePS2Port, Packet->HorzCounter);
151  PS2QueuePush(MousePS2Port, Packet->VertCounter);
152  if (MouseId >= 3) PS2QueuePush(MousePS2Port, Packet->Extra);
153 }
154 
156 {
157  /* Check if we were waiting for a data byte */
158  if (MouseDataByteWait)
159  {
161 
162  switch (MouseDataByteWait)
163  {
164  /* Set Resolution */
165  case 0xE8:
166  {
168  break;
169  }
170 
171  /* Set Sample Rate */
172  case 0xF3:
173  {
174  /* Check for the scroll wheel enabling sequence */
175  if (MouseId == 0)
176  {
178  {
180  if (ScrollMagicCounter == 3) MouseId = 3;
181  }
182  else
183  {
184  ScrollMagicCounter = 0;
185  }
186  }
187 
188  /* Check for the 5-button enabling sequence */
189  if (MouseId == 3)
190  {
192  {
194  if (ExtraButtonMagicCounter == 3) MouseId = 4;
195  }
196  else
197  {
199  }
200  }
201 
202  MouseCycles = 1000 / (UINT)Command;
203  break;
204  }
205 
206  default:
207  {
208  /* Shouldn't happen */
209  ASSERT(FALSE);
210  }
211  }
212 
213  MouseDataByteWait = 0;
214  return;
215  }
216 
217  /* Check if we're in wrap mode */
218  if (Mode == MOUSE_WRAP_MODE)
219  {
220  /*
221  * In this mode, we just echo whatever byte we get,
222  * except for the 0xEC and 0xFF commands.
223  */
224  if (Command != 0xEC && Command != 0xFF)
225  {
227  return;
228  }
229  }
230 
231  switch (Command)
232  {
233  /* Set 1:1 Scaling */
234  case 0xE6:
235  {
236  Scaling = FALSE;
238  break;
239  }
240 
241  /* Set 2:1 Scaling */
242  case 0xE7:
243  {
244  Scaling = TRUE;
246  break;
247  }
248 
249  /* Set Resolution */
250  case 0xE8:
251  /* Set Sample Rate */
252  case 0xF3:
253  {
256  break;
257  }
258 
259  /* Read Status */
260  case 0xE9:
261  {
262  BYTE Status = ButtonState & 7;
263 
264  if (Scaling) Status |= 1 << 4;
265  if (MouseReporting) Status |= 1 << 5;
266  if (Mode == MOUSE_REMOTE_MODE) Status |= 1 << 6;
267 
272  break;
273  }
274 
275  /* Enter Streaming Mode */
276  case 0xEA:
277  {
280 
282  break;
283  }
284 
285  /* Read Packet */
286  case 0xEB:
287  {
291  break;
292  }
293 
294  /* Return from Wrap Mode */
295  case 0xEC:
296  {
297  if (Mode == MOUSE_WRAP_MODE)
298  {
299  /* Restore the previous mode */
301  Mode = PreviousMode;
303  }
304  else
305  {
307  }
308 
309  break;
310  }
311 
312  /* Enter Wrap Mode */
313  case 0xEE:
314  {
315  if (Mode != MOUSE_WRAP_MODE)
316  {
317  /* Save the previous mode */
318  PreviousMode = Mode;
319  }
320 
323 
325  break;
326  }
327 
328  /* Enter Remote Mode */
329  case 0xF0:
330  {
333 
335  break;
336  }
337 
338  /* Get Mouse ID */
339  case 0xF2:
340  {
343  break;
344  }
345 
346  /* Enable Reporting */
347  case 0xF4:
348  {
352  break;
353  }
354 
355  /* Disable Reporting */
356  case 0xF5:
357  {
361  break;
362  }
363 
364  /* Set Defaults */
365  case 0xF6:
366  {
367  /* Reset the configuration and counters */
371  break;
372  }
373 
374  /* Resend */
375  case 0xFE:
376  {
379  break;
380  }
381 
382  /* Reset */
383  case 0xFF:
384  {
385  /* Send ACKnowledge */
387 
388  MouseReset();
389 
390  /* Send the Basic Assurance Test success code and the device ID */
393  break;
394  }
395 
396  /* Unknown command */
397  default:
398  {
400  }
401  }
402 }
403 
405 {
406  UNREFERENCED_PARAMETER(ElapsedTime);
407 
408  /* Check if we're not in streaming mode, not reporting, or there's nothing to report */
410 
413 
415 }
416 
417 /* PUBLIC FUNCTIONS ***********************************************************/
418 
420 {
423  *CurrentButtonState = LOBYTE(ButtonState);
425 }
426 
428 {
429  COORD NewPosition = MouseEvent->dwMousePosition;
431 
433  {
434  /* Text mode */
435  NewPosition.X *= 8;
436  NewPosition.Y *= 8;
437  }
438 
439  /* Adjust for double vision */
440  if (DoubleWidth) NewPosition.X /= 2;
441  if (DoubleHeight) NewPosition.Y /= 2;
442 
444 
445  /* Update the counters */
446  HorzCounter += (NewPosition.X - Position.X) << DoubleWidth;
447  VertCounter += (NewPosition.Y - Position.Y) << DoubleHeight;
448 
449  /* Update the position */
450  Position = NewPosition;
451 
452  /* Update the button state */
453  ButtonState = MouseEvent->dwButtonState;
454 
455  if (MouseEvent->dwEventFlags & MOUSE_WHEELED)
456  {
457  ScrollCounter += (SHORT)HIWORD(MouseEvent->dwButtonState);
458  }
459 
462 }
463 
464 BOOLEAN MouseInit(BYTE PS2Connector)
465 {
466  /* Finish to plug the mouse to the specified PS/2 port */
467  MousePS2Port = PS2Connector;
469 
471  if (MouseMutex == NULL) return FALSE;
472 
474  HZ_TO_NS(100),
476 
477  MouseReset();
478  return TRUE;
479 }
#define FROM_LEFT_1ST_BUTTON_PRESSED
Definition: wincon.h:144
#define TRUE
Definition: types.h:120
DWORD dwEventFlags
Definition: wincon.h:245
static BYTE MouseId
Definition: mouse.c:38
_In_ NDIS_HANDLE _In_ PNDIS_PACKET Packet
Definition: ndis.h:1548
static MOUSE_MODE PreviousMode
Definition: mouse.c:33
#define LOBYTE(W)
Definition: jmemdos.c:487
#define RIGHTMOST_BUTTON_PRESSED
Definition: wincon.h:145
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define MOUSE_BAT_SUCCESS
Definition: mouse.h:32
static COORD Position
Definition: mouse.c:34
static VOID MouseDispatchPacket(PMOUSE_PACKET Packet)
Definition: mouse.c:147
char CHAR
Definition: xmlstorage.h:175
#define MOUSE_Y_SIGN
Definition: mouse.h:23
#define FROM_LEFT_2ND_BUTTON_PRESSED
Definition: wincon.h:146
static VOID MouseGetPacket(PMOUSE_PACKET Packet)
Definition: mouse.c:82
static MOUSE_MODE Mode
Definition: mouse.c:33
static BYTE MousePS2Port
Definition: mouse.c:49
#define MOUSE_RIGHT_BUTTON
Definition: mouse.h:19
BOOLEAN PS2QueuePush(BYTE PS2Port, BYTE Data)
Definition: ps2.c:486
Definition: shell.h:41
static PHARDWARE_TIMER StreamTimer
Definition: mouse.c:31
#define FASTCALL
Definition: nt_native.h:50
DWORD dwButtonState
Definition: wincon.h:243
static SHORT HorzCounter
Definition: mouse.c:40
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
#define MOUSE_5TH_BUTTON
Definition: mouse.h:29
#define MOUSE_MAX
Definition: mouse.h:15
static BOOLEAN Scaling
Definition: mouse.c:36
short SHORT
Definition: pedump.c:59
ULONG CurrentPosition
Definition: patchapi.h:57
static BYTE ScrollMagicCounter
Definition: mouse.c:45
ButtonState
Definition: button.c:143
COORD dwMousePosition
Definition: wincon.h:242
unsigned char BOOLEAN
PHARDWARE_TIMER CreateHardwareTimer(ULONG Flags, ULONGLONG Delay, PHARDWARE_TIMER_PROC Callback)
Definition: clock.c:144
smooth NULL
Definition: ftsmooth.c:416
#define MOUSE_LEFT_BUTTON
Definition: mouse.h:18
static BYTE ExtraButtonMagicCounter
Definition: mouse.c:45
ULONG X
Definition: bl.h:1340
#define FROM_LEFT_3RD_BUTTON_PRESSED
Definition: wincon.h:147
VOID MouseEventHandler(PMOUSE_EVENT_RECORD MouseEvent)
Definition: mouse.c:427
static ULONG ButtonState
Definition: mouse.c:39
#define MOUSE_ALWAYS_SET
Definition: mouse.h:21
#define CreateMutex
Definition: winbase.h:3570
BOOLEAN VgaGetDoubleVisionState(PBOOLEAN Horizontal, PBOOLEAN Vertical)
Definition: video.c:488
struct Command Command
uint64_t ULONGLONG
Definition: typedefs.h:65
#define MOUSE_X_OVERFLOW
Definition: mouse.h:24
static BOOLEAN DoubleHeight
Definition: video.c:59
#define WINAPI
Definition: msvc.h:8
#define HARDWARE_TIMER_ENABLED
Definition: clock.h:15
#define MOUSE_ERROR
Definition: i8042prt.h:286
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseMutex(IN HANDLE hMutex)
Definition: synch.c:564
unsigned char UCHAR
Definition: xmlstorage.h:181
enum _MOUSE_MODE MOUSE_MODE
#define MOUSE_X_SIGN
Definition: mouse.h:22
static BYTE MouseDataByteWait
Definition: mouse.c:44
#define MOUSE_ACK
Definition: i8042prt.h:285
static BOOLEAN DoubleWidth
Definition: video.c:58
static BOOLEAN MouseReporting
Definition: mouse.c:37
unsigned char BYTE
Definition: mem.h:68
static BOOLEAN EventsOccurred
Definition: mouse.c:43
#define MOUSE_MIDDLE_BUTTON
Definition: mouse.h:20
static CHAR ScrollCounter
Definition: mouse.c:42
static SHORT VertCounter
Definition: mouse.c:41
Definition: bl.h:1338
Status
Definition: gdiplustypes.h:24
static const BYTE ExtraButtonMagic[3]
Definition: mouse.c:28
static VOID MouseResetCounters(VOID)
Definition: mouse.c:64
static const BYTE ScrollMagic[3]
Definition: mouse.c:27
static VOID MouseReset(VOID)
Definition: mouse.c:70
VOID MouseGetDataFast(PCOORD CurrentPosition, PBYTE CurrentButtonState)
Definition: mouse.c:419
static UINT MouseCycles
Definition: mouse.c:47
unsigned int UINT
Definition: ndis.h:50
static VOID MouseResetConfig(VOID)
Definition: mouse.c:55
static VOID WINAPI MouseCommand(LPVOID Param, BYTE Command)
Definition: mouse.c:155
static HANDLE MouseMutex
Definition: mouse.c:30
static VOID FASTCALL MouseStreamingCallback(ULONGLONG ElapsedTime)
Definition: mouse.c:404
VOID PS2SetDeviceCmdProc(BYTE PS2Port, LPVOID Param, PS2_DEVICE_CMDPROC DeviceCommand)
Definition: ps2.c:478
#define HZ_TO_NS(Freq)
Definition: clock.h:20
static BYTE Resolution
Definition: mouse.c:35
#define HIWORD(l)
Definition: typedefs.h:246
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
BOOLEAN MouseInit(BYTE PS2Connector)
Definition: mouse.c:464
#define MOUSE_WHEELED
Definition: wincon.h:155
#define FROM_LEFT_4TH_BUTTON_PRESSED
Definition: wincon.h:148
static MOUSE_PACKET LastPacket
Definition: mouse.c:32
#define INFINITE
Definition: serial.h:102
ULONG Y
Definition: bl.h:1341
BYTE * PBYTE
Definition: pedump.c:66
#define MOUSE_4TH_BUTTON
Definition: mouse.h:28
#define MOUSE_Y_OVERFLOW
Definition: mouse.h:25