2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: VDM Mouse 32-bit BIOS
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 #include "moubios32.h"
20 #include "hardware/mouse.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
)
86 if ((DriverState
.Handler0
.CallMask
& CallMask
) != 0 &&
87 DriverState
.Handler0
.Callback
!= (ULONG
)NULL
)
90 * Set the parameters for the callback.
91 * NOTE: In text modes, the row and column will be reported
92 * as a multiple of the cell size, typically 8x8 pixels.
95 setBX(DriverState
.ButtonState
);
96 setCX(DriverState
.Position
.X
);
97 setDX(DriverState
.Position
.Y
);
98 setSI(DriverState
.MickeysPerCellHoriz
);
99 setDI(DriverState
.MickeysPerCellVert
);
101 DPRINT1("Calling Handler0 0x%08x with CallMask 0x%04x\n",
102 DriverState
.Handler0
.Callback
, CallMask
);
104 /* Call the callback */
105 RunCallback16(&BiosContext
, DriverState
.Handler0
.Callback
);
108 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
110 /* Call the suitable handlers */
111 if ((DriverState
.Handlers
[i
].CallMask
& CallMask
) != 0 &&
112 DriverState
.Handlers
[i
].Callback
!= (ULONG
)NULL
)
115 * Set the parameters for the callback.
116 * NOTE: In text modes, the row and column will be reported
117 * as a multiple of the cell size, typically 8x8 pixels.
120 setBX(DriverState
.ButtonState
);
121 setCX(DriverState
.Position
.X
);
122 setDX(DriverState
.Position
.Y
);
123 setSI(DriverState
.MickeysPerCellHoriz
);
124 setDI(DriverState
.MickeysPerCellVert
);
126 DPRINT1("Calling Handler[%d] 0x%08x with CallMask 0x%04x\n",
127 i
, DriverState
.Handlers
[i
].Callback
, CallMask
);
129 /* Call the callback */
130 RunCallback16(&BiosContext
, DriverState
.Handlers
[i
].Callback
);
135 static VOID WINAPI
BiosMouseService(LPWORD Stack
)
144 DriverEnabled
= TRUE
;
145 DriverState
.ShowCount
= 0;
146 DriverState
.ButtonState
= 0;
148 /* Set the default text cursor */
149 DriverState
.TextCursor
.ScreenMask
= 0xFFFF; /* Display everything */
150 DriverState
.TextCursor
.CursorMask
= 0xFF00; /* ... but with inverted attributes */
152 /* Set the default graphics cursor */
153 DriverState
.GraphicsCursor
.HotSpot
.X
= 3;
154 DriverState
.GraphicsCursor
.HotSpot
.Y
= 1;
156 DriverState
.GraphicsCursor
.ScreenMask
[0] = 0xC3FF; // 1100001111111111
157 DriverState
.GraphicsCursor
.ScreenMask
[1] = 0xC0FF; // 1100000011111111
158 DriverState
.GraphicsCursor
.ScreenMask
[2] = 0xC07F; // 1100000001111111
159 DriverState
.GraphicsCursor
.ScreenMask
[3] = 0xC01F; // 1100000000011111
160 DriverState
.GraphicsCursor
.ScreenMask
[4] = 0xC00F; // 1100000000001111
161 DriverState
.GraphicsCursor
.ScreenMask
[5] = 0xC007; // 1100000000000111
162 DriverState
.GraphicsCursor
.ScreenMask
[6] = 0xC003; // 1100000000000011
163 DriverState
.GraphicsCursor
.ScreenMask
[7] = 0xC007; // 1100000000000111
164 DriverState
.GraphicsCursor
.ScreenMask
[8] = 0xC01F; // 1100000000011111
165 DriverState
.GraphicsCursor
.ScreenMask
[9] = 0xC01F; // 1100000000011111
166 DriverState
.GraphicsCursor
.ScreenMask
[10] = 0xC00F; // 1100000000001111
167 DriverState
.GraphicsCursor
.ScreenMask
[11] = 0xC60F; // 1100011000001111
168 DriverState
.GraphicsCursor
.ScreenMask
[12] = 0xFF07; // 1111111100000111
169 DriverState
.GraphicsCursor
.ScreenMask
[13] = 0xFF07; // 1111111100000111
170 DriverState
.GraphicsCursor
.ScreenMask
[14] = 0xFF87; // 1111111110000111
171 DriverState
.GraphicsCursor
.ScreenMask
[15] = 0xFFCF; // 1111111111001111
173 DriverState
.GraphicsCursor
.CursorMask
[0] = 0x0000; // 0000000000000000
174 DriverState
.GraphicsCursor
.CursorMask
[1] = 0x1C00; // 0001110000000000
175 DriverState
.GraphicsCursor
.CursorMask
[2] = 0x1F00; // 0001111100000000
176 DriverState
.GraphicsCursor
.CursorMask
[3] = 0x1F80; // 0001111110000000
177 DriverState
.GraphicsCursor
.CursorMask
[4] = 0x1FE0; // 0001111111100000
178 DriverState
.GraphicsCursor
.CursorMask
[5] = 0x1FF0; // 0001111111110000
179 DriverState
.GraphicsCursor
.CursorMask
[6] = 0x1FF8; // 0001111111111000
180 DriverState
.GraphicsCursor
.CursorMask
[7] = 0x1FE0; // 0001111111100000
181 DriverState
.GraphicsCursor
.CursorMask
[8] = 0x1FC0; // 0001111111000000
182 DriverState
.GraphicsCursor
.CursorMask
[9] = 0x1FC0; // 0001111111000000
183 DriverState
.GraphicsCursor
.CursorMask
[10] = 0x19E0; // 0001100111100000
184 DriverState
.GraphicsCursor
.CursorMask
[11] = 0x00E0; // 0000000011100000
185 DriverState
.GraphicsCursor
.CursorMask
[12] = 0x0070; // 0000000001110000
186 DriverState
.GraphicsCursor
.CursorMask
[13] = 0x0070; // 0000000001110000
187 DriverState
.GraphicsCursor
.CursorMask
[14] = 0x0030; // 0000000000110000
188 DriverState
.GraphicsCursor
.CursorMask
[15] = 0x0000; // 0000000000000000
190 /* Initialize the counters */
191 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
193 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
195 DriverState
.PressCount
[i
] = DriverState
.ReleaseCount
[i
] = 0;
198 /* Initialize the resolution */
199 DriverState
.MickeysPerCellHoriz
= 8;
200 DriverState
.MickeysPerCellVert
= 16;
202 /* Return mouse information */
203 setAX(0xFFFF); // Hardware & driver installed
204 setBX(NUM_MOUSE_BUTTONS
);
209 /* Show Mouse Cursor */
212 DriverState
.ShowCount
++;
213 if (DriverState
.ShowCount
> 0) PaintMouseCursor();
218 /* Hide Mouse Cursor */
221 DriverState
.ShowCount
--;
222 if (DriverState
.ShowCount
<= 0) EraseMouseCursor();
227 /* Return Position And Button Status */
230 setBX(DriverState
.ButtonState
);
231 setCX(DriverState
.Position
.X
);
232 setDX(DriverState
.Position
.Y
);
236 /* Position Mouse Cursor */
244 ClientToScreen(GetConsoleWindow(), &Point
);
245 SetCursorPos(Point
.x
, Point
.y
);
250 /* Return Button Press Data */
253 WORD Button
= getBX();
255 setAX(DriverState
.ButtonState
);
256 setBX(DriverState
.PressCount
[Button
]);
257 setCX(DriverState
.LastPress
[Button
].X
);
258 setDX(DriverState
.LastPress
[Button
].Y
);
260 /* Reset the counter */
261 DriverState
.PressCount
[Button
] = 0;
266 /* Return Button Release Data */
269 WORD Button
= getBX();
271 setAX(DriverState
.ButtonState
);
272 setBX(DriverState
.ReleaseCount
[Button
]);
273 setCX(DriverState
.LastRelease
[Button
].X
);
274 setDX(DriverState
.LastRelease
[Button
].Y
);
276 /* Reset the counter */
277 DriverState
.ReleaseCount
[Button
] = 0;
283 /* Define Graphics Cursor */
286 PWORD MaskBitmap
= (PWORD
)SEG_OFF_TO_PTR(getES(), getDX());
288 DriverState
.GraphicsCursor
.HotSpot
.X
= getBX();
289 DriverState
.GraphicsCursor
.HotSpot
.Y
= getCX();
291 RtlMoveMemory(DriverState
.GraphicsCursor
.ScreenMask
,
293 sizeof(DriverState
.GraphicsCursor
.ScreenMask
));
295 RtlMoveMemory(DriverState
.GraphicsCursor
.CursorMask
,
297 sizeof(DriverState
.GraphicsCursor
.CursorMask
));
302 /* Define Text Cursor */
309 /* Define software cursor */
310 DriverState
.TextCursor
.ScreenMask
= getCX();
311 DriverState
.TextCursor
.CursorMask
= getDX();
313 else if (BX
== 0x0001)
315 /* Define hardware cursor */
316 DPRINT1("Defining hardware cursor is unimplemented\n");
318 // CX == start scan line
319 // DX == end scan line
323 DPRINT1("Invalid BX value 0x%04x\n", BX
);
329 /* Read Motion Counters */
332 setCX(DriverState
.HorizCount
);
333 setDX(DriverState
.VertCount
);
335 /* Reset the counters */
336 DriverState
.HorizCount
= DriverState
.VertCount
= 0;
341 /* Define Interrupt Subroutine Parameters, compatible MS MOUSE v1.0+ */
344 DriverState
.Handler0
.CallMask
= getCX();
345 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
346 DPRINT1("Define callback 0x%04x, 0x%08x\n",
347 DriverState
.Handler0
.CallMask
, DriverState
.Handler0
.Callback
);
351 /* Define Mickey/Pixel Ratio */
354 DriverState
.MickeysPerCellHoriz
= getCX();
355 DriverState
.MickeysPerCellVert
= getDX();
359 /* Exchange Interrupt Subroutines, compatible MS MOUSE v3.0+ (see function 0x0C) */
362 USHORT OldCallMask
= DriverState
.Handler0
.CallMask
;
363 ULONG OldCallback
= DriverState
.Handler0
.Callback
;
365 DriverState
.Handler0
.CallMask
= getCX();
366 DriverState
.Handler0
.Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
368 /* Return old callmask in CX and callback vector in ES:DX */
370 setES(HIWORD(OldCallback
));
371 setDX(LOWORD(OldCallback
));
376 /* Return Driver Storage Requirements */
379 setBX(sizeof(MOUSE_DRIVER_STATE
));
383 /* Save Driver State */
386 *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX())) = DriverState
;
390 /* Restore Driver State */
393 DriverState
= *((PMOUSE_DRIVER_STATE
)SEG_OFF_TO_PTR(getES(), getDX()));
397 /* Set Alternate Mouse User Handler, compatible MS MOUSE v6.0+ */
401 * Up to three handlers can be defined by separate calls to this
402 * function, each with a different combination of shift states in
403 * the call mask; calling this function again with a call mask of
404 * 0000h undefines the specified handler (official documentation);
405 * specifying the same call mask and an address of 0000h:0000h
406 * undefines the handler (real life).
407 * See Ralf Brown: http://www.ctyme.com/intr/rb-5981.htm
408 * for more information.
412 USHORT CallMask
= getCX();
413 ULONG Callback
= MAKELONG(getDX(), getES()); // Far pointer to the callback
414 BOOLEAN Success
= FALSE
;
416 DPRINT1("Define v6.0+ callback 0x%04x, 0x%08x\n",
419 if (CallMask
== 0x0000)
422 * Find the handler entry corresponding to the given
423 * callback and undefine it.
425 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
427 if (DriverState
.Handlers
[i
].Callback
== Callback
)
429 /* Found it, undefine the handler */
430 DriverState
.Handlers
[i
].CallMask
= 0x0000;
431 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
437 else if (Callback
== (ULONG
)NULL
)
440 * Find the handler entry corresponding to the given
441 * callmask and undefine it.
443 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
445 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
447 /* Found it, undefine the handler */
448 DriverState
.Handlers
[i
].CallMask
= 0x0000;
449 DriverState
.Handlers
[i
].Callback
= (ULONG
)NULL
;
458 * Try to find a handler entry corresponding to the given
459 * callmask to redefine it, otherwise find an empty handler
460 * entry and set the new handler in there.
463 USHORT EmptyHandler
= 0xFFFF; // Invalid handler
465 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
467 /* Find the first empty handler */
468 if (EmptyHandler
== 0xFFFF &&
469 DriverState
.Handlers
[i
].CallMask
== 0x0000 &&
470 DriverState
.Handlers
[i
].Callback
== (ULONG
)NULL
)
475 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
477 /* Found it, redefine the handler */
478 DriverState
.Handlers
[i
].CallMask
= CallMask
;
479 DriverState
.Handlers
[i
].Callback
= Callback
;
486 * If we haven't found anything and we found
487 * an empty handler, set it.
489 if (!Success
&& EmptyHandler
!= 0xFFFF
490 /* && EmptyHandler < sizeof(DriverState.Handlers)/sizeof(DriverState.Handlers[0]) */)
492 DriverState
.Handlers
[EmptyHandler
].CallMask
= CallMask
;
493 DriverState
.Handlers
[EmptyHandler
].Callback
= Callback
;
498 /* If we failed, set error code */
499 if (!Success
) setAX(0xFFFF);
504 /* Return User Alternate Interrupt Vector, compatible MS MOUSE v6.0+ */
508 USHORT CallMask
= getCX();
510 BOOLEAN Success
= FALSE
;
513 * Find the handler entry corresponding to the given callmask.
515 for (i
= 0; i
< sizeof(DriverState
.Handlers
)/sizeof(DriverState
.Handlers
[0]); ++i
)
517 if (DriverState
.Handlers
[i
].CallMask
== CallMask
)
520 Callback
= DriverState
.Handlers
[i
].Callback
;
528 /* Return the callback vector in BX:DX */
529 setBX(HIWORD(Callback
));
530 setDX(LOWORD(Callback
));
534 /* We failed, set error code */
541 /* Disable Mouse Driver */
547 DriverEnabled
= FALSE
;
551 /* Enable Mouse Driver */
554 DriverEnabled
= TRUE
;
560 DPRINT1("BIOS Function INT 33h, AX = 0x%04X NOT IMPLEMENTED\n", getAX());
565 /* PUBLIC FUNCTIONS ***********************************************************/
567 VOID
MouseBiosUpdatePosition(PCOORD NewPosition
)
569 SHORT DeltaX
= NewPosition
->X
- DriverState
.Position
.X
;
570 SHORT DeltaY
= NewPosition
->Y
- DriverState
.Position
.Y
;
572 if (!DriverEnabled
) return;
574 DriverState
.HorizCount
+= (DeltaX
* (SHORT
)DriverState
.MickeysPerCellHoriz
) / 8;
575 DriverState
.VertCount
+= (DeltaY
* (SHORT
)DriverState
.MickeysPerCellVert
) / 8;
577 if (DriverState
.ShowCount
> 0)
580 DriverState
.Position
= *NewPosition
;
584 /* Call the mouse handlers */
585 CallMouseUserHandlers(0x0001); // We use MS MOUSE v1.0+ format
588 VOID
MouseBiosUpdateButtons(WORD ButtonState
)
591 USHORT CallMask
= 0x0000; // We use MS MOUSE v1.0+ format
593 if (!DriverEnabled
) return;
595 for (i
= 0; i
< NUM_MOUSE_BUTTONS
; i
++)
597 BOOLEAN OldState
= (DriverState
.ButtonState
>> i
) & 1;
598 BOOLEAN NewState
= (ButtonState
>> i
) & 1;
600 if (NewState
> OldState
)
603 DriverState
.PressCount
[i
]++;
604 DriverState
.LastPress
[i
] = DriverState
.Position
;
606 CallMask
|= (1 << (2 * i
+ 1));
608 else if (NewState
< OldState
)
611 DriverState
.ReleaseCount
[i
]++;
612 DriverState
.LastRelease
[i
] = DriverState
.Position
;
614 CallMask
|= (1 << (2 * i
+ 2));
618 DriverState
.ButtonState
= ButtonState
;
620 /* Call the mouse handlers */
621 CallMouseUserHandlers(CallMask
);
624 BOOLEAN
MouseBios32Initialize(VOID
)
626 /* Clear the state */
627 ZeroMemory(&DriverState
, sizeof(DriverState
));
629 /* Initialize the interrupt handler */
630 RegisterBiosInt32(BIOS_MOUSE_INTERRUPT
, BiosMouseService
);
635 VOID
MouseBios32Cleanup(VOID
)
637 if (DriverState
.ShowCount
> 0) EraseMouseCursor();