aboutsummaryrefslogtreecommitdiff
path: root/mousew16.c
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2022-03-12 13:24:01 +0100
committerJavier <dev.git@javispedro.com>2022-03-12 13:24:01 +0100
commit0561b7fabde7a4e2a32437217f8dd85912c89c05 (patch)
treeedfc9f1388c4fb5560291027dfdeacfd57d2d46c /mousew16.c
parenta5ae81421c666fe55bbd8c6272cc94da9acd830b (diff)
downloadvbmouse-0561b7fabde7a4e2a32437217f8dd85912c89c05.tar.gz
vbmouse-0561b7fabde7a4e2a32437217f8dd85912c89c05.zip
use int2f to detect fullscreen dosboxes in protected mode
Diffstat (limited to 'mousew16.c')
-rw-r--r--mousew16.c107
1 files changed, 105 insertions, 2 deletions
diff --git a/mousew16.c b/mousew16.c
index c017133..f2e22ab 100644
--- a/mousew16.c
+++ b/mousew16.c
@@ -22,10 +22,14 @@
#include "vbox.h"
#include "vboxdev.h"
#include "ps2.h"
+#include "int2fwin.h"
#include "mousew16.h"
-/** If this is 0, this should behave like a plain PS/2 mouse driver. */
+/** If 1, actually call VBox services.
+ * Thus, if 0, this should behave like a plain PS/2 mouse driver. */
#define ENABLE_VBOX 1
+/** If 1, hook int2f to detect fullscreen DOSBoxes and auto-disable this driver. */
+#define HOOK_INT2F 1
/** Logging through the virtualbox backdoor. */
#define log(...) vbox_logs(__VA_ARGS__)
@@ -40,9 +44,13 @@ enum {
MOUSEFLAGS_ENABLED = 1 << 0,
MOUSEFLAGS_HAS_VBOX = 1 << 1,
MOUSEFLAGS_VBOX_ENABLED = 1 << 2,
+ MOUSEFLAGS_HAS_WIN386 = 1 << 3,
+ MOUSEFLAGS_INT2F_HOOKED = 1 << 4
};
/** Last received pressed button status (to compare and see which buttons have been pressed). */
static unsigned char mousebtnstatus;
+/** Existing interrupt2f handler. */
+static LPFN prev_int2f_handler;
/* This is how events are delivered to Windows */
@@ -104,6 +112,74 @@ static void FAR ps2_mouse_callback(uint8_t status, uint8_t x, uint8_t y, uint8_t
}
}
+#if HOOK_INT2F
+
+static void display_switch_handler(int function)
+#pragma aux display_switch_handler parm caller [ax] modify [ax bx cx dx si di]
+{
+ if (!(mouseflags & MOUSEFLAGS_ENABLED) || !(mouseflags & MOUSEFLAGS_VBOX_ENABLED)) {
+ return;
+ }
+
+ switch (function) {
+ case INT2F_NOTIFY_BACKGROUND_SWITCH:
+ vbox_logs("Going background\n");
+ vbox_set_mouse_locked(false);
+ break;
+ case INT2F_NOTIFY_FOREGROUND_SWITCH:
+ vbox_logs("Going foreground\n");
+ vbox_set_mouse_locked(true);
+ break;
+ }
+}
+
+/** Interrupt 2F handler, which will be called on some Windows 386 mode events.
+ * This is more complicated than it should be becaused we have to fetch our DS
+ * without clobbering any registers whatsoever, and chain back to the previous handler.
+ * @todo OpenWatcom 2.x insists on calling GETDS from a different code segment, so we can't use __interrupt. */
+static void __declspec(naked) __far int2f_handler(void)
+{
+ _asm {
+ ; Preserve data segment
+ push ds
+
+ ; Load our data segment
+ push ax
+ mov ax, SEG prev_int2f_handler ; Let's hope that Windows relocates segments with interrupts disabled
+ mov ds, ax
+ pop ax
+
+ ; Check functions we are interested in hooking
+ cmp ax, 0x4001 ; Notify Background Switch
+ je handle_it
+ cmp ax, 0x4002 ; Notify Foreground Switch
+ je handle_it
+
+ ; Otherwise directly jump to next handler
+ jmp next_handler
+
+ handle_it:
+ pushad ; Save and restore 32-bit registers, we may clobber them from C
+ call display_switch_handler
+ popad
+
+ next_handler:
+ ; Store the address of the previous handler
+ push dword ptr [prev_int2f_handler]
+
+ ; Restore original data segment without touching the stack,
+ ; since we want to keep the prev handler address at the top
+ push bp
+ mov bp, sp
+ mov ds, [bp + 6] ; Stack looks like 0: bp, 2: prev_int2f_handler, 6: ds
+ pop bp
+
+ retf 2
+ }
+}
+
+#endif /* HOOK_INT2F */
+
#pragma code_seg ()
/* Driver exported functions. */
@@ -119,6 +195,13 @@ BOOL FAR PASCAL LibMain(HINSTANCE hInstance, WORD wDataSegment,
{
// We are not going to bother checking whether a PS2 mouse exists and just assume it does
+#if HOOK_INT2F
+ // Check now whether we are running under protected mode windows
+ if (windows_386_enhanced_mode()) {
+ mouseflags |= MOUSEFLAGS_HAS_WIN386;
+ }
+#endif
+
#if ENABLE_VBOX
// However we will check whether VirtualBox exists:
if (vbox_init() == 0) {
@@ -187,6 +270,16 @@ VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc)
mouseflags |= MOUSEFLAGS_VBOX_ENABLED;
}
#endif
+
+#if HOOK_INT2F
+ if ((mouseflags & MOUSEFLAGS_HAS_WIN386) && (mouseflags & MOUSEFLAGS_VBOX_ENABLED)) {
+ cli();
+ hook_int2f(&prev_int2f_handler, int2f_handler);
+ sti();
+ vbox_logs("int2F hooked!\n");
+ mouseflags |= MOUSEFLAGS_INT2F_HOOKED;
+ }
+#endif
}
}
@@ -194,6 +287,16 @@ VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc)
VOID FAR PASCAL Disable(VOID)
{
if (mouseflags & MOUSEFLAGS_ENABLED) {
+#if HOOK_INT2F
+ if (mouseflags & MOUSEFLAGS_INT2F_HOOKED) {
+ cli();
+ unhook_int2f(prev_int2f_handler);
+ sti();
+ vbox_logs("int2F unhooked!\n");
+ mouseflags &= ~MOUSEFLAGS_INT2F_HOOKED;
+ }
+#endif
+
ps2_enable(false);
ps2_set_callback(NULL);
vbox_logs("PS2 Disabled!\n");
@@ -214,6 +317,6 @@ VOID FAR PASCAL Disable(VOID)
/** Called by Window to retrieve the interrupt vector number used by this driver, or -1. */
int FAR PASCAL MouseGetIntVect(VOID)
{
- return -1;
+ return 0x74; /* This corresponds to IRQ12, the PS/2 IRQ. At least in VirtualBox. */
}