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 *******************************************************************/
18 #include "bios/bios.h"
21 #include "dos32krnl/dos.h"
23 /* PRIVATE VARIABLES **********************************************************/
25 static BOOLEAN DriverEnabled
= TRUE
;
26 static MOUSE_DRIVER_STATE DriverState
;
33 /* PRIVATE FUNCTIONS **********************************************************/
35 static VOID
PaintMouseCursor(VOID
)
37 if (Bda
->VideoMode
<= 3)
40 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
42 EmulatorReadMemory(&EmulatorContext
,
44 + (DriverState
.Position
.Y
* Bda
->ScreenColumns
45 + DriverState
.Position
.X
) * sizeof(WORD
),
49 DriverState
.Character
= Character
;
50 Character
&= DriverState
.TextCursor
.ScreenMask
;
51 Character
^= DriverState
.TextCursor
.CursorMask
;
53 EmulatorWriteMemory(&EmulatorContext
,
55 + (DriverState
.Position
.Y
* Bda
->ScreenColumns
56 + DriverState
.Position
.X
) * sizeof(WORD
),
62 // TODO: NOT IMPLEMENTED
67 static VOID
EraseMouseCursor(VOID
)
69 if (Bda
->VideoMode
<= 3)
71 DWORD VideoAddress
= TO_LINEAR(TEXT_VIDEO_SEG
, Bda
->VideoPage
* Bda
->VideoPageSize
);
73 EmulatorWriteMemory(&EmulatorContext
,
75 + (DriverState
.Position
.Y
* Bda
->ScreenColumns
76 + DriverState
.Position
.X
) * sizeof(WORD
),
77 (LPVOID
)&DriverState
.Character
,
82 // TODO: NOT IMPLEMENTED
87 static VOID
CallMouseUserHandlers(USHORT CallMask
)
90 USHORT AX
, BX
, CX
, DX
, SI
, DI
;
93 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
94 DriverState
.Handler0
.Callback
!= (ULONG
)NULL
)
97 * Set the parameters for the callback.
98 * NOTE: In text modes, the row and column will be reported
99 * as a multiple of the cell size, typically 8x8 pixels.
110 setBX(DriverState
.ButtonState
);
111 setCX(DriverState
.Position
.X
);
112 setDX(DriverState
.Position
.Y
);
113 setSI(DriverState
.MickeysPerCellHoriz
);
114 setDI(DriverState
.MickeysPerCellVert
);
116 DPRINT("Calling Handler0 %04X:%04X with CallMask 0x%04X\n",
117 HIWORD(DriverState
.Handler0
.Callback
),
118 LOWORD(DriverState
.Handler0
.Callback
),
121 /* Call the callback */
122 RunCallback16(&DosContext
, DriverState
.Handler0
.Callback
);
132 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
134 /* Call the suitable handlers */
135 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
136 DriverState
.Handlers
[i
].Callback
!= (ULONG
)NULL
)
139 * Set the parameters for the callback.
140 * NOTE: In text modes, the row and column will be reported
141 * as a multiple of the cell size, typically 8x8 pixels.
152 setBX(DriverState
.ButtonState
);
153 setCX(DriverState
.Position
.X
);
154 setDX(DriverState
.Position
.Y
);
155 setSI(DriverState
.MickeysPerCellHoriz
);
156 setDI(DriverState
.MickeysPerCellVert
);
158 DPRINT1("Calling Handler[%d] %04X:%04X with CallMask 0x%04X\n",
160 HIWORD(DriverState
.Handlers
[i
].Callback
),
161 LOWORD(DriverState
.Handlers
[i
].Callback
),
164 /* Call the callback */
165 RunCallback16(&DosContext
, DriverState
.Handlers
[i
].Callback
);
177 static VOID WINAPI
DosMouseService(LPWORD Stack
)
186 DriverEnabled
= TRUE
;
187 DriverState
.ShowCount
= 0;
188 DriverState
.ButtonState
= 0;
190 /* Set the default text cursor */
191 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
192 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
194 /* Set the default graphics cursor */
195 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
196 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
198 DriverState
.GraphicsCursor
.ScreenMask
[0] = 0xC3FF; // 1100001111111111
199 DriverState
.GraphicsCursor
.ScreenMask
[1] = 0xC0FF; // 1100000011111111
200 DriverState
.GraphicsCursor
.ScreenMask
[2] = 0xC07F; // 1100000001111111
201 DriverState
.GraphicsCursor
.ScreenMask
[3] = 0xC01F; // 1100000000011111
202 DriverState
.GraphicsCursor
.ScreenMask
[4] = 0xC00F; // 1100000000001111
203 DriverState
.GraphicsCursor
.ScreenMask
[5] = 0xC007; // 1100000000000111
204 DriverState
.GraphicsCursor
.ScreenMask
[6] = 0xC003; // 1100000000000011
205 DriverState
.GraphicsCursor
.ScreenMask
[7] = 0xC007; // 1100000000000111
206 DriverState
.GraphicsCursor
.ScreenMask
[8] = 0xC01F; // 1100000000011111
207 DriverState
.GraphicsCursor
.ScreenMask
[9] = 0xC01F; // 1100000000011111
208 DriverState
.GraphicsCursor
.ScreenMask
[10] = 0xC00F; // 1100000000001111
209 DriverState
.GraphicsCursor
.ScreenMask
[11] = 0xC60F; // 1100011000001111
210 DriverState
.GraphicsCursor
.ScreenMask
[12] = 0xFF07; // 1111111100000111
211 DriverState
.GraphicsCursor
.ScreenMask
[13] = 0xFF07; // 1111111100000111
212 DriverState
.GraphicsCursor
.ScreenMask
[14] = 0xFF87; // 1111111110000111
213 DriverState
.GraphicsCursor
.ScreenMask
[15] = 0xFFCF; // 1111111111001111
215 DriverState
.GraphicsCursor
.CursorMask
[0] = 0x0000; // 0000000000000000
216 DriverState
.GraphicsCursor
.CursorMask
[1] = 0x1C00; // 0001110000000000
217 DriverState
.GraphicsCursor
.CursorMask
[2] = 0x1F00; // 0001111100000000
218 DriverState
.GraphicsCursor
.CursorMask
[3] = 0x1F80; // 0001111110000000
219 DriverState
.GraphicsCursor
.CursorMask
[4] = 0x1FE0; // 0001111111100000
220 DriverState
.GraphicsCursor
.CursorMask
[5] = 0x1FF0; // 0001111111110000
221 DriverState
.GraphicsCursor
.CursorMask
[6] = 0x1FF8; // 0001111111111000
222 DriverState
.GraphicsCursor
.CursorMask
[7] = 0x1FE0; // 0001111111100000
223 DriverState
.GraphicsCursor
.CursorMask
[8] = 0x1FC0; // 0001111111000000
224 DriverState
.GraphicsCursor
.CursorMask
[9] = 0x1FC0; // 0001111111000000
225 DriverState
.GraphicsCursor
.CursorMask
[10] = 0x19E0; // 0001100111100000
226 DriverState
.GraphicsCursor
.CursorMask
[11] = 0x00E0; // 0000000011100000
227 DriverState
.GraphicsCursor
.CursorMask
[12] = 0x0070; // 0000000001110000
228 DriverState
.GraphicsCursor
.CursorMask
[13] = 0x0070; // 0000000001110000
229 DriverState
.GraphicsCursor
.CursorMask
[14] = 0x0030; // 0000000000110000
230 DriverState
.GraphicsCursor
.CursorMask
[15] = 0x0000; // 0000000000000000
232 /* Initialize the counters */
233 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
235 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
237 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
240 /* Initialize the resolution */
241 DriverState
.MickeysPerCellHoriz
= 8;
242 DriverState
.MickeysPerCellVert
= 16;
244 /* Return mouse information */
245 setAX(0xFFFF); // Hardware & driver installed
246 setBX(NUM_MOUSE_BUTTONS
);
251 /* Show Mouse Cursor */
254 DriverState
.ShowCount
++;
255 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
260 /* Hide Mouse Cursor */
263 DriverState
.ShowCount
--;
264 if (DriverState
.ShowCount
<= 0) EraseMouseCursor();
269 /* Return Position And Button Status */
272 setBX(DriverState
.ButtonState
);
273 setCX(DriverState
.Position
.X
);
274 setDX(DriverState
.Position
.Y
);
278 /* Position Mouse Cursor */
286 ClientToScreen(GetConsoleWindow(), &Point
);
287 SetCursorPos(Point
.x
, Point
.y
);
292 /* Return Button Press Data */
295 WORD Button
= getBX();
297 setAX(DriverState
.ButtonState
);
298 setBX(DriverState
.PressCount
[Button
]);
299 setCX(DriverState
.LastPress
[Button
].X
);
300 setDX(DriverState
.LastPress
[Button
].Y
);
302 /* Reset the counter */
303 DriverState
.PressCount
[Button
] = 0;
308 /* Return Button Release Data */
311 WORD Button
= getBX();
313 setAX(DriverState
.ButtonState
);
314 setBX(DriverState
.ReleaseCount
[Button
]);
315 setCX(DriverState
.LastRelease
[Button
].X
);
316 setDX(DriverState
.LastRelease
[Button
].Y
);
318 /* Reset the counter */
319 DriverState
.ReleaseCount
[Button
] = 0;
325 /* Define Graphics Cursor */
328 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
330 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
331 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
333 RtlCopyMemory(DriverState
.GraphicsCursor
.ScreenMask
,
335 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
337 RtlCopyMemory(DriverState
.GraphicsCursor
.CursorMask
,
339 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
344 /* Define Text Cursor */
351 /* Define software cursor */
352 DriverState
.TextCursor
.ScreenMask
= getCX();
353 DriverState
.TextCursor
.CursorMask
= getDX();
355 else if (BX
== 0x0001)
357 /* Define hardware cursor */
358 DPRINT1("Defining hardware cursor is unimplemented\n");
360 // CX == start scan line
361 // DX == end scan line
365 DPRINT1("Invalid BX value 0x%04X\n", BX
);
371 /* Read Motion Counters */
374 setCX(DriverState
.HorizCount
);
375 setDX(DriverState
.VertCount
);
377 /* Reset the counters */
378 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
383 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
386 DriverState
.Handler0
.CallMask
= getCX();
387 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
388 DPRINT1("Define callback 0x%04X, %04X:%04X\n",
389 DriverState
.Handler0
.CallMask
,
390 HIWORD(DriverState
.Handler0
.Callback
),
391 LOWORD(DriverState
.Handler0
.Callback
));
395 /* Define Mickey/Pixel Ratio */
398 DriverState
.MickeysPerCellHoriz
= getCX();
399 DriverState
.MickeysPerCellVert
= getDX();
403 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
406 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
407 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
409 DriverState
.Handler0
.CallMask
= getCX();
410 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
412 /* Return old callmask in CX and callback vector in ES:DX */
414 setES(HIWORD(OldCallback
));
415 setDX(LOWORD(OldCallback
));
420 /* Return Driver Storage Requirements */
423 setBX(sizeof(MOUSE_DRIVER_STATE
));
427 /* Save Driver State */
430 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
434 /* Restore Driver State */
437 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
441 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
445 * Up to three handlers can be defined by separate calls to this
446 * function, each with a different combination of shift states in
447 * the call mask; calling this function again with a call mask of
448 * 0000h undefines the specified handler (official documentation);
449 * specifying the same call mask and an address of 0000h:0000h
450 * undefines the handler (real life).
451 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
452 * for more information.
456 USHORT CallMask
= getCX();
457 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
458 BOOLEAN Success
= FALSE
;
460 DPRINT1("Define v6.0+ callback 0x%04X, %04X:%04X\n",
461 CallMask
, HIWORD(Callback
), LOWORD(Callback
));
463 if (CallMask
== 0x0000)
466 * Find the handler entry corresponding to the given
467 * callback and undefine it.
469 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
471 if (DriverState
.Handlers
[i
].Callback
== Callback
)
473 /* Found it, undefine the handler */
474 DriverState
.Handlers
[i
].CallMask
= 0x0000;
475 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
481 else if (Callback
== (ULONG
)NULL
)
484 * Find the handler entry corresponding to the given
485 * callmask and undefine it.
487 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
489 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
491 /* Found it, undefine the handler */
492 DriverState
.Handlers
[i
].CallMask
= 0x0000;
493 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
502 * Try to find a handler entry corresponding to the given
503 * callmask to redefine it, otherwise find an empty handler
504 * entry and set the new handler in there.
507 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
509 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
511 /* Find the first empty handler */
512 if (EmptyHandler
== 0xFFFF &&
513 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
514 DriverState
.Handlers
[i
].Callback
== (ULONG
)NULL
)
519 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
521 /* Found it, redefine the handler */
522 DriverState
.Handlers
[i
].CallMask
= CallMask
;
523 DriverState
.Handlers
[i
].Callback
= Callback
;
530 * If we haven't found anything and we found
531 * an empty handler, set it.
533 if (!Success
&& EmptyHandler
!= 0xFFFF
534 /* && EmptyHandler < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
536 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
537 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
542 /* If we failed, set error code */
543 if (!Success
) setAX(0xFFFF);
548 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
552 USHORT CallMask
= getCX();
554 BOOLEAN Success
= FALSE
;
557 * Find the handler entry corresponding to the given callmask.
559 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
561 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
564 Callback
= DriverState
.Handlers
[i
].Callback
;
572 /* Return the callback vector in BX:DX */
573 setBX(HIWORD(Callback
));
574 setDX(LOWORD(Callback
));
578 /* We failed, set error code */
585 /* Disable Mouse Driver */
591 DriverEnabled
= FALSE
;
595 /* Enable Mouse Driver */
598 DriverEnabled
= TRUE
;
604 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
609 /* PUBLIC FUNCTIONS ***********************************************************/
611 VOID
DosMouseUpdatePosition(PCOORD NewPosition
)
613 SHORT DeltaX
= NewPosition
->X
- DriverState
.Position
.X
;
614 SHORT DeltaY
= NewPosition
->Y
- DriverState
.Position
.Y
;
616 if (!DriverEnabled
) return;
618 DriverState
.HorizCount
+= (DeltaX
* (SHORT
)DriverState
.MickeysPerCellHoriz
) / 8;
619 DriverState
.VertCount
+= (DeltaY
* (SHORT
)DriverState
.MickeysPerCellVert
) / 8;
621 if (DriverState
.ShowCount
> 0) EraseMouseCursor();
622 DriverState
.Position
= *NewPosition
;
623 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
625 /* Call the mouse handlers */
626 // if (DeltaX || DeltaY)
627 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
630 VOID
DosMouseUpdateButtons(WORD ButtonState
)
633 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
635 if (!DriverEnabled
) return;
637 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
639 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
640 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
642 if (NewState
> OldState
)
645 DriverState
.PressCount
[i
]++;
646 DriverState
.LastPress
[i
] = DriverState
.Position
;
648 CallMask
|= (1 << (2 * i
+ 1));
650 else if (NewState
< OldState
)
653 DriverState
.ReleaseCount
[i
]++;
654 DriverState
.LastRelease
[i
] = DriverState
.Position
;
656 CallMask
|= (1 << (2 * i
+ 2));
660 DriverState
.ButtonState
= ButtonState
;
662 /* Call the mouse handlers */
663 CallMouseUserHandlers(CallMask
);
666 BOOLEAN
DosMouseInitialize(VOID
)
668 /* Clear the state */
669 RtlZeroMemory(&DriverState
, sizeof(DriverState
));
671 /* Initialize the interrupt handler */
672 RegisterDosInt32(DOS_MOUSE_INTERRUPT
, DosMouseService
);
677 VOID
DosMouseCleanup(VOID
)
679 if (DriverState
.ShowCount
> 0) EraseMouseCursor();