2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VDM 32-bit compatible MOUSE.COM driver
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
17 #include "bios/bios.h"
20 #include "dos32krnl/dos.h"
22 /* PRIVATE VARIABLES **********************************************************/
24 static BOOLEAN DriverEnabled
= TRUE
;
25 static MOUSE_DRIVER_STATE DriverState
;
27 /* PRIVATE FUNCTIONS **********************************************************/
29 static VOID
PaintMouseCursor(VOID
)
31 if (Bda
->VideoMode
<= 3)
34 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
36 EmulatorReadMemory(&EmulatorContext
,
38 + (DriverState
.Position
.Y
* Bda
->ScreenColumns
39 + DriverState
.Position
.X
) * sizeof(WORD
),
43 DriverState
.Character
= Character
;
44 Character
&= DriverState
.TextCursor
.ScreenMask
;
45 Character
^= DriverState
.TextCursor
.CursorMask
;
47 EmulatorWriteMemory(&EmulatorContext
,
49 + (DriverState
.Position
.Y
* Bda
->ScreenColumns
50 + DriverState
.Position
.X
) * sizeof(WORD
),
56 // TODO: NOT IMPLEMENTED
61 static VOID
EraseMouseCursor(VOID
)
63 if (Bda
->VideoMode
<= 3)
65 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
67 EmulatorWriteMemory(&EmulatorContext
,
69 + (DriverState
.Position
.Y
* Bda
->ScreenColumns
70 + DriverState
.Position
.X
) * sizeof(WORD
),
71 (LPVOID
)&DriverState
.Character
,
76 // TODO: NOT IMPLEMENTED
81 static VOID
CallMouseUserHandlers(USHORT CallMask
)
85 USHORT AX
, BX
, CX
, DX
, SI
, DI
;
88 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
89 DriverState
.Handler0
.Callback
!= (ULONG
)NULL
)
92 * Set the parameters for the callback.
93 * NOTE: In text modes, the row and column will be reported
94 * as a multiple of the cell size, typically 8x8 pixels.
105 setBX(DriverState
.ButtonState
);
106 setCX(DriverState
.Position
.X
);
107 setDX(DriverState
.Position
.Y
);
108 setSI(DriverState
.MickeysPerCellHoriz
);
109 setDI(DriverState
.MickeysPerCellVert
);
111 DPRINT1("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
112 HIWORD(DriverState
.Handler0
.Callback
),
113 LOWORD(DriverState
.Handler0
.Callback
),
116 /* Call the callback */
117 RunCallback16(&DosContext
, DriverState
.Handler0
.Callback
);
127 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
129 /* Call the suitable handlers */
130 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
131 DriverState
.Handlers
[i
].Callback
!= (ULONG
)NULL
)
134 * Set the parameters for the callback.
135 * NOTE: In text modes, the row and column will be reported
136 * as a multiple of the cell size, typically 8x8 pixels.
147 setBX(DriverState
.ButtonState
);
148 setCX(DriverState
.Position
.X
);
149 setDX(DriverState
.Position
.Y
);
150 setSI(DriverState
.MickeysPerCellHoriz
);
151 setDI(DriverState
.MickeysPerCellVert
);
153 DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
155 HIWORD(DriverState
.Handlers
[i
].Callback
),
156 LOWORD(DriverState
.Handlers
[i
].Callback
),
159 /* Call the callback */
160 RunCallback16(&DosContext
, DriverState
.Handlers
[i
].Callback
);
173 static VOID WINAPI
BiosMouseService(LPWORD Stack
)
182 DriverEnabled
= TRUE
;
183 DriverState
.ShowCount
= 0;
184 DriverState
.ButtonState
= 0;
186 /* Set the default text cursor */
187 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
188 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
190 /* Set the default graphics cursor */
191 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
192 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
194 DriverState
.GraphicsCursor
.ScreenMask
[0] = 0xC3FF; // 1100001111111111
195 DriverState
.GraphicsCursor
.ScreenMask
[1] = 0xC0FF; // 1100000011111111
196 DriverState
.GraphicsCursor
.ScreenMask
[2] = 0xC07F; // 1100000001111111
197 DriverState
.GraphicsCursor
.ScreenMask
[3] = 0xC01F; // 1100000000011111
198 DriverState
.GraphicsCursor
.ScreenMask
[4] = 0xC00F; // 1100000000001111
199 DriverState
.GraphicsCursor
.ScreenMask
[5] = 0xC007; // 1100000000000111
200 DriverState
.GraphicsCursor
.ScreenMask
[6] = 0xC003; // 1100000000000011
201 DriverState
.GraphicsCursor
.ScreenMask
[7] = 0xC007; // 1100000000000111
202 DriverState
.GraphicsCursor
.ScreenMask
[8] = 0xC01F; // 1100000000011111
203 DriverState
.GraphicsCursor
.ScreenMask
[9] = 0xC01F; // 1100000000011111
204 DriverState
.GraphicsCursor
.ScreenMask
[10] = 0xC00F; // 1100000000001111
205 DriverState
.GraphicsCursor
.ScreenMask
[11] = 0xC60F; // 1100011000001111
206 DriverState
.GraphicsCursor
.ScreenMask
[12] = 0xFF07; // 1111111100000111
207 DriverState
.GraphicsCursor
.ScreenMask
[13] = 0xFF07; // 1111111100000111
208 DriverState
.GraphicsCursor
.ScreenMask
[14] = 0xFF87; // 1111111110000111
209 DriverState
.GraphicsCursor
.ScreenMask
[15] = 0xFFCF; // 1111111111001111
211 DriverState
.GraphicsCursor
.CursorMask
[0] = 0x0000; // 0000000000000000
212 DriverState
.GraphicsCursor
.CursorMask
[1] = 0x1C00; // 0001110000000000
213 DriverState
.GraphicsCursor
.CursorMask
[2] = 0x1F00; // 0001111100000000
214 DriverState
.GraphicsCursor
.CursorMask
[3] = 0x1F80; // 0001111110000000
215 DriverState
.GraphicsCursor
.CursorMask
[4] = 0x1FE0; // 0001111111100000
216 DriverState
.GraphicsCursor
.CursorMask
[5] = 0x1FF0; // 0001111111110000
217 DriverState
.GraphicsCursor
.CursorMask
[6] = 0x1FF8; // 0001111111111000
218 DriverState
.GraphicsCursor
.CursorMask
[7] = 0x1FE0; // 0001111111100000
219 DriverState
.GraphicsCursor
.CursorMask
[8] = 0x1FC0; // 0001111111000000
220 DriverState
.GraphicsCursor
.CursorMask
[9] = 0x1FC0; // 0001111111000000
221 DriverState
.GraphicsCursor
.CursorMask
[10] = 0x19E0; // 0001100111100000
222 DriverState
.GraphicsCursor
.CursorMask
[11] = 0x00E0; // 0000000011100000
223 DriverState
.GraphicsCursor
.CursorMask
[12] = 0x0070; // 0000000001110000
224 DriverState
.GraphicsCursor
.CursorMask
[13] = 0x0070; // 0000000001110000
225 DriverState
.GraphicsCursor
.CursorMask
[14] = 0x0030; // 0000000000110000
226 DriverState
.GraphicsCursor
.CursorMask
[15] = 0x0000; // 0000000000000000
228 /* Initialize the counters */
229 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
231 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
233 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
236 /* Initialize the resolution */
237 DriverState
.MickeysPerCellHoriz
= 8;
238 DriverState
.MickeysPerCellVert
= 16;
240 /* Return mouse information */
241 setAX(0xFFFF); // Hardware & driver installed
242 setBX(NUM_MOUSE_BUTTONS
);
247 /* Show Mouse Cursor */
250 DriverState
.ShowCount
++;
251 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
256 /* Hide Mouse Cursor */
259 DriverState
.ShowCount
--;
260 if (DriverState
.ShowCount
<= 0) EraseMouseCursor();
265 /* Return Position And Button Status */
268 setBX(DriverState
.ButtonState
);
269 setCX(DriverState
.Position
.X
);
270 setDX(DriverState
.Position
.Y
);
274 /* Position Mouse Cursor */
282 ClientToScreen(GetConsoleWindow(), &Point
);
283 SetCursorPos(Point
.x
, Point
.y
);
288 /* Return Button Press Data */
291 WORD Button
= getBX();
293 setAX(DriverState
.ButtonState
);
294 setBX(DriverState
.PressCount
[Button
]);
295 setCX(DriverState
.LastPress
[Button
].X
);
296 setDX(DriverState
.LastPress
[Button
].Y
);
298 /* Reset the counter */
299 DriverState
.PressCount
[Button
] = 0;
304 /* Return Button Release Data */
307 WORD Button
= getBX();
309 setAX(DriverState
.ButtonState
);
310 setBX(DriverState
.ReleaseCount
[Button
]);
311 setCX(DriverState
.LastRelease
[Button
].X
);
312 setDX(DriverState
.LastRelease
[Button
].Y
);
314 /* Reset the counter */
315 DriverState
.ReleaseCount
[Button
] = 0;
321 /* Define Graphics Cursor */
324 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
326 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
327 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
329 RtlMoveMemory(DriverState
.GraphicsCursor
.ScreenMask
,
331 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
333 RtlMoveMemory(DriverState
.GraphicsCursor
.CursorMask
,
335 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
340 /* Define Text Cursor */
347 /* Define software cursor */
348 DriverState
.TextCursor
.ScreenMask
= getCX();
349 DriverState
.TextCursor
.CursorMask
= getDX();
351 else if (BX
== 0x0001)
353 /* Define hardware cursor */
354 DPRINT1("Defining hardware cursor is unimplemented\n");
356 // CX == start scan line
357 // DX == end scan line
361 DPRINT1("Invalid BX value 0x%04X\n", BX
);
367 /* Read Motion Counters */
370 setCX(DriverState
.HorizCount
);
371 setDX(DriverState
.VertCount
);
373 /* Reset the counters */
374 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
379 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
382 DriverState
.Handler0
.CallMask
= getCX();
383 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
384 DPRINT1("Define callback 0x%04X, %04X:%04X\n",
385 DriverState
.Handler0
.CallMask
,
386 HIWORD(DriverState
.Handler0
.Callback
),
387 LOWORD(DriverState
.Handler0
.Callback
));
391 /* Define Mickey/Pixel Ratio */
394 DriverState
.MickeysPerCellHoriz
= getCX();
395 DriverState
.MickeysPerCellVert
= getDX();
399 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
402 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
403 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
405 DriverState
.Handler0
.CallMask
= getCX();
406 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
408 /* Return old callmask in CX and callback vector in ES:DX */
410 setES(HIWORD(OldCallback
));
411 setDX(LOWORD(OldCallback
));
416 /* Return Driver Storage Requirements */
419 setBX(sizeof(MOUSE_DRIVER_STATE
));
423 /* Save Driver State */
426 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
430 /* Restore Driver State */
433 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
437 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
441 * Up to three handlers can be defined by separate calls to this
442 * function, each with a different combination of shift states in
443 * the call mask; calling this function again with a call mask of
444 * 0000h undefines the specified handler (official documentation);
445 * specifying the same call mask and an address of 0000h:0000h
446 * undefines the handler (real life).
447 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
448 * for more information.
452 USHORT CallMask
= getCX();
453 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
454 BOOLEAN Success
= FALSE
;
456 DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
457 CallMask
, HIWORD(Callback
), LOWORD(Callback
));
459 if (CallMask
== 0x0000)
462 * Find the handler entry corresponding to the given
463 * callback and undefine it.
465 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
467 if (DriverState
.Handlers
[i
].Callback
== Callback
)
469 /* Found it, undefine the handler */
470 DriverState
.Handlers
[i
].CallMask
= 0x0000;
471 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
477 else if (Callback
== (ULONG
)NULL
)
480 * Find the handler entry corresponding to the given
481 * callmask and undefine it.
483 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
485 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
487 /* Found it, undefine the handler */
488 DriverState
.Handlers
[i
].CallMask
= 0x0000;
489 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
498 * Try to find a handler entry corresponding to the given
499 * callmask to redefine it, otherwise find an empty handler
500 * entry and set the new handler in there.
503 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
505 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
507 /* Find the first empty handler */
508 if (EmptyHandler
== 0xFFFF &&
509 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
510 DriverState
.Handlers
[i
].Callback
== (ULONG
)NULL
)
515 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
517 /* Found it, redefine the handler */
518 DriverState
.Handlers
[i
].CallMask
= CallMask
;
519 DriverState
.Handlers
[i
].Callback
= Callback
;
526 * If we haven't found anything and we found
527 * an empty handler, set it.
529 if (!Success
&& EmptyHandler
!= 0xFFFF
530 /* && EmptyHandler < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
532 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
533 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
538 /* If we failed, set error code */
539 if (!Success
) setAX(0xFFFF);
544 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
548 USHORT CallMask
= getCX();
550 BOOLEAN Success
= FALSE
;
553 * Find the handler entry corresponding to the given callmask.
555 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
557 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
560 Callback
= DriverState
.Handlers
[i
].Callback
;
568 /* Return the callback vector in BX:DX */
569 setBX(HIWORD(Callback
));
570 setDX(LOWORD(Callback
));
574 /* We failed, set error code */
581 /* Disable Mouse Driver */
587 DriverEnabled
= FALSE
;
591 /* Enable Mouse Driver */
594 DriverEnabled
= TRUE
;
600 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
605 /* PUBLIC FUNCTIONS ***********************************************************/
607 VOID
MouseBiosUpdatePosition(PCOORD NewPosition
)
609 SHORT DeltaX
= NewPosition
->X
- DriverState
.Position
.X
;
610 SHORT DeltaY
= NewPosition
->Y
- DriverState
.Position
.Y
;
612 if (!DriverEnabled
) return;
614 DriverState
.HorizCount
+= (DeltaX
* (SHORT
)DriverState
.MickeysPerCellHoriz
) / 8;
615 DriverState
.VertCount
+= (DeltaY
* (SHORT
)DriverState
.MickeysPerCellVert
) / 8;
617 if (DriverState
.ShowCount
> 0)
620 DriverState
.Position
= *NewPosition
;
624 /* Call the mouse handlers */
625 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
628 VOID
MouseBiosUpdateButtons(WORD ButtonState
)
631 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
633 if (!DriverEnabled
) return;
635 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
637 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
638 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
640 if (NewState
> OldState
)
643 DriverState
.PressCount
[i
]++;
644 DriverState
.LastPress
[i
] = DriverState
.Position
;
646 CallMask
|= (1 << (2 * i
+ 1));
648 else if (NewState
< OldState
)
651 DriverState
.ReleaseCount
[i
]++;
652 DriverState
.LastRelease
[i
] = DriverState
.Position
;
654 CallMask
|= (1 << (2 * i
+ 2));
658 DriverState
.ButtonState
= ButtonState
;
660 /* Call the mouse handlers */
661 CallMouseUserHandlers(CallMask
);
664 BOOLEAN
DosMouseInitialize(VOID
)
666 /* Clear the state */
667 ZeroMemory(&DriverState
, sizeof(DriverState
));
669 /* Initialize the interrupt handler */
670 RegisterDosInt32(BIOS_MOUSE_INTERRUPT
, BiosMouseService
);
675 VOID
DosMouseCleanup(VOID
)
677 if (DriverState
.ShowCount
> 0) EraseMouseCursor();