[NTVDM]
[reactos.git] / reactos / subsystems / ntvdm / hardware / mouse.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: mouse.c
5 * PURPOSE: Mouse emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "mouse.h"
14 #include "ps2.h"
15
16 /* PRIVATE VARIABLES **********************************************************/
17
18 static MOUSE_MODE Mode, PreviousMode;
19 static COORD Position;
20 static ULONG WidthMm, HeightMm, WidthPixels, HeightPixels;
21 static ULONG SampleRate;
22 static ULONG Resolution;
23 static BOOLEAN Scaling;
24 static BOOLEAN Reporting;
25 static BYTE MouseId;
26 static ULONG ButtonState;
27 static SHORT HorzCounter;
28 static SHORT VertCounter;
29 static CHAR ScrollCounter;
30
31 /* PRIVATE FUNCTIONS **********************************************************/
32
33 static VOID MouseResetConfig(VOID)
34 {
35 /* Reset the configuration to defaults */
36 SampleRate = 100;
37 Resolution = 4;
38 Scaling = FALSE;
39 Reporting = FALSE;
40 }
41
42 static VOID MouseResetCounters(VOID)
43 {
44 /* Reset all flags and counters */
45 ButtonState = HorzCounter = VertCounter = ScrollCounter = 0;
46 }
47
48 static VOID MouseReset(VOID)
49 {
50 /* Reset everything */
51 MouseResetConfig();
52 MouseResetCounters();
53
54 /* Enter streaming mode and the reset the mouse ID */
55 Mode = MOUSE_STREAMING_MODE;
56 MouseId = 0;
57
58 /* Send the Basic Assurance Test success code and the device ID */
59 KeyboardQueuePush(MOUSE_BAT_SUCCESS);
60 KeyboardQueuePush(MouseId);
61 }
62
63 #if 0
64 static VOID MouseGetPacket(PMOUSE_PACKET Packet)
65 {
66 /* Clear the packet */
67 ZeroMemory(Packet, sizeof(MOUSE_PACKET));
68
69 Packet->Flags |= MOUSE_ALWAYS_SET;
70
71 /* Check for horizontal overflows */
72 if ((HorzCounter < MOUSE_MIN) || (HorzCounter > MOUSE_MAX))
73 {
74 if (HorzCounter > MOUSE_MAX) HorzCounter = MOUSE_MAX;
75 if (HorzCounter < MOUSE_MIN) HorzCounter = MOUSE_MIN;
76
77 Packet->Flags |= MOUSE_X_OVERFLOW;
78 }
79
80 /* Check for vertical overflows */
81 if ((VertCounter < MOUSE_MIN) || (VertCounter > MOUSE_MAX))
82 {
83 if (VertCounter > MOUSE_MIN) VertCounter = MOUSE_MIN;
84 if (VertCounter < MOUSE_MIN) VertCounter = MOUSE_MIN;
85
86 Packet->Flags |= MOUSE_Y_OVERFLOW;
87 }
88
89 /* Set the sign flags */
90 if (HorzCounter & MOUSE_SIGN_BIT) Packet->Flags |= MOUSE_X_SIGN;
91 if (HorzCounter & MOUSE_SIGN_BIT) Packet->Flags |= MOUSE_Y_SIGN;
92
93 /* Set the button flags */
94 if (ButtonState & FROM_LEFT_1ST_BUTTON_PRESSED) Packet->Flags |= MOUSE_LEFT_BUTTON;
95 if (ButtonState & FROM_LEFT_2ND_BUTTON_PRESSED) Packet->Flags |= MOUSE_MIDDLE_BUTTON;
96 if (ButtonState & RIGHTMOST_BUTTON_PRESSED) Packet->Flags |= MOUSE_RIGHT_BUTTON;
97
98 if (MouseId == 4)
99 {
100 if (ButtonState & FROM_LEFT_3RD_BUTTON_PRESSED) Packet->Extra |= MOUSE_4TH_BUTTON;
101 if (ButtonState & FROM_LEFT_4TH_BUTTON_PRESSED) Packet->Extra |= MOUSE_5TH_BUTTON;
102 }
103
104 if (MouseId >= 3)
105 {
106 /* Set the scroll counter */
107 Packet->Extra |= (UCHAR)ScrollCounter & 0x0F;
108 }
109
110 /* Store the counters in the packet */
111 Packet->HorzCounter = LOBYTE(HorzCounter);
112 Packet->VertCounter = LOBYTE(VertCounter);
113
114 /* Reset the counters */
115 MouseResetCounters();
116 }
117 #endif
118
119 /* PUBLIC FUNCTIONS ***********************************************************/
120
121 VOID MouseUpdatePosition(PCOORD NewPosition)
122 {
123 /* Update the counters */
124 HorzCounter += ((NewPosition->X - Position.X) * WidthMm * Resolution) / WidthPixels;
125 VertCounter += ((NewPosition->Y - Position.Y) * HeightMm * Resolution) / HeightPixels;
126
127 /* Update the position */
128 Position = *NewPosition;
129 }
130
131 VOID MouseUpdateButtons(ULONG NewButtonState)
132 {
133 ButtonState = NewButtonState;
134 }
135
136 VOID MouseScroll(LONG Direction)
137 {
138 ScrollCounter += Direction;
139 }
140
141 COORD MouseGetPosition(VOID)
142 {
143 return Position;
144 }
145
146 VOID MouseCommand(BYTE Command)
147 {
148 switch (Command)
149 {
150 /* Set 1:1 Scaling */
151 case 0xE6:
152 {
153 Scaling = FALSE;
154 KeyboardQueuePush(MOUSE_ACK);
155 break;
156 }
157
158 /* Set 2:1 Scaling */
159 case 0xE7:
160 {
161 Scaling = TRUE;
162 KeyboardQueuePush(MOUSE_ACK);
163 break;
164 }
165
166 /* Set Resolution */
167 case 0xE8:
168 {
169 // TODO: NOT IMPLEMENTED
170 UNIMPLEMENTED;
171 break;
172 }
173
174 /* Read Status */
175 case 0xE9:
176 {
177 // TODO: NOT IMPLEMENTED
178 UNIMPLEMENTED;
179 break;
180 }
181
182 /* Enter Streaming Mode */
183 case 0xEA:
184 {
185 MouseResetCounters();
186 Mode = MOUSE_STREAMING_MODE;
187
188 KeyboardQueuePush(MOUSE_ACK);
189 break;
190 }
191
192 /* Read Packet */
193 case 0xEB:
194 {
195 // TODO: NOT IMPLEMENTED
196 UNIMPLEMENTED;
197 break;
198 }
199
200 /* Return From Wrap Mode */
201 case 0xEC:
202 {
203 if (Mode == MOUSE_WRAP_MODE)
204 {
205 /* Restore the previous mode */
206 MouseResetCounters();
207 Mode = PreviousMode;
208 KeyboardQueuePush(MOUSE_ACK);
209 }
210 else KeyboardQueuePush(MOUSE_ERROR);
211
212 break;
213 }
214
215 /* Enter Wrap Mode */
216 case 0xEE:
217 {
218 if (Mode != MOUSE_WRAP_MODE)
219 {
220 /* Save the previous mode */
221 PreviousMode = Mode;
222 }
223
224 MouseResetCounters();
225 Mode = MOUSE_WRAP_MODE;
226
227 KeyboardQueuePush(MOUSE_ACK);
228 break;
229 }
230
231 /* Enter Remote Mode */
232 case 0xF0:
233 {
234 MouseResetCounters();
235 Mode = MOUSE_REMOTE_MODE;
236
237 KeyboardQueuePush(MOUSE_ACK);
238 break;
239 }
240
241 /* Get Mouse ID */
242 case 0xF2:
243 {
244 KeyboardQueuePush(MOUSE_ACK);
245 KeyboardQueuePush(MouseId);
246 break;
247 }
248
249 /* Set Sample Rate */
250 case 0xF3:
251 {
252 // TODO: NOT IMPLEMENTED
253 UNIMPLEMENTED;
254 break;
255 }
256
257 /* Enable Reporting */
258 case 0xF4:
259 {
260 Reporting = TRUE;
261 KeyboardQueuePush(MOUSE_ACK);
262 break;
263 }
264
265 /* Disable Reporting */
266 case 0xF5:
267 {
268 Reporting = FALSE;
269 KeyboardQueuePush(MOUSE_ACK);
270 break;
271 }
272
273 /* Set Defaults */
274 case 0xF6:
275 {
276 /* Reset the configuration and counters */
277 MouseResetConfig();
278 MouseResetCounters();
279 break;
280 }
281
282 /* Resend */
283 case 0xFE:
284 {
285 // TODO: NOT IMPLEMENTED
286 UNIMPLEMENTED;
287 break;
288 }
289
290 /* Reset */
291 case 0xFF:
292 {
293 MouseReset();
294 break;
295 }
296
297 /* Unknown command */
298 default:
299 {
300 KeyboardQueuePush(MOUSE_ERROR);
301 }
302 }
303 }
304
305 BOOLEAN MouseInit(VOID)
306 {
307 HWND hWnd;
308 HDC hDC;
309
310 /* Get the console window */
311 hWnd = GetConsoleWindow();
312 if (hWnd == NULL) return FALSE;
313
314 /* Get the console window's device context */
315 hDC = GetWindowDC(hWnd);
316 if (hDC == NULL) return FALSE;
317
318 /* Get the parameters */
319 WidthMm = (ULONG)GetDeviceCaps(hDC, HORZSIZE);
320 HeightMm = (ULONG)GetDeviceCaps(hDC, VERTSIZE);
321 WidthPixels = (ULONG)GetDeviceCaps(hDC, HORZRES);
322 HeightPixels = (ULONG)GetDeviceCaps(hDC, VERTRES);
323
324 /* Release the device context */
325 ReleaseDC(hWnd, hDC);
326
327 MouseReset();
328 return TRUE;
329 }