From 0561b7fabde7a4e2a32437217f8dd85912c89c05 Mon Sep 17 00:00:00 2001 From: Javier Date: Sat, 12 Mar 2022 13:24:01 +0100 Subject: use int2f to detect fullscreen dosboxes in protected mode --- mousew16.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 2 deletions(-) (limited to 'mousew16.c') 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. */ } -- cgit v1.2.3