diff options
-rw-r--r-- | dosmain.c | 7 | ||||
-rw-r--r-- | dostsr.c | 122 | ||||
-rw-r--r-- | dostsr.h | 20 | ||||
-rw-r--r-- | int2fwin.h | 35 | ||||
-rw-r--r-- | w16mouse.c | 137 |
5 files changed, 165 insertions, 156 deletions
@@ -28,11 +28,6 @@ #include "vbox.h" #include "dostsr.h" -static unsigned get_resident_size(void) -{ - return FP_OFF(&resident_end); -} - #if USE_VIRTUALBOX static int set_integration(LPTSRDATA data, bool enable) { @@ -268,7 +263,7 @@ int main(int argc, const char *argv[]) LPTSRDATA data = get_tsr_data(true); int err, argi = 1; - printf("\nVBMouse 0.x (MSMOUSE %x.%x)\n", REPORTED_VERSION_MAJOR, REPORTED_VERSION_MINOR); + printf("\nVBMouse %x.%x (like MSMOUSE %x.%x)\n", VERSION_MAJOR, VERSION_MINOR, REPORTED_VERSION_MAJOR, REPORTED_VERSION_MINOR); if (argi >= argc || stricmp(argv[argi], "install") == 0) { if (data) { @@ -22,6 +22,7 @@ #include "dlog.h" #include "ps2.h" #include "int10vga.h" +#include "int2fwin.h" #include "int33.h" #include "dostsr.h" @@ -247,6 +248,12 @@ static void refresh_cursor(void) { bool should_show = data.visible_count >= 0; +#if USE_INT2F + // Windows 386 is already rendering the cursor for us. + // Hide our own. + if (data.w386cursor) should_show = false; +#endif + #if USE_VIRTUALBOX if (data.vbwantcursor) { int err = 0; @@ -305,6 +312,8 @@ static void hide_cursor(void) } } +/** Loads the current graphic cursor, + * which in this case means uploading it to the host. */ static void load_cursor(void) { #if USE_VIRTUALBOX @@ -372,6 +381,7 @@ static void load_cursor(void) #endif } +/** Refreshes the information about the current video mode. */ static void refresh_video_info(void) { uint8_t screen_columns = bda_get_num_columns(); @@ -442,11 +452,12 @@ static void refresh_video_info(void) } } +/** Calls the application-registered event handler. */ static void call_event_handler(void (__far *handler)(), uint16_t events, uint16_t buttons, int16_t x, int16_t y, int16_t delta_x, int16_t delta_y) { -#if TRACE_EVENT +#if TRACE_EVENTS dlog_print("calling event handler events="); dlog_printx(events); dlog_print(" buttons="); @@ -474,12 +485,19 @@ static void call_event_handler(void (__far *handler)(), uint16_t events, } } +/** Process a mouse event internally. + * @param buttons currently pressed buttons as a bitfield + * @param absolute whether mouse coordinates are an absolute value + * @param x y if absolute, then absolute coordinates in screen pixels + * if relative, then relative coordinates in mickeys + * @param z relative wheel mouse movement + */ static void handle_mouse_event(uint16_t buttons, bool absolute, int x, int y, int z) { uint16_t events = 0; int i; -#if TRACE_EVENT +#if TRACE_EVENTS dlog_print("handle mouse event"); if (absolute) dlog_print(" absolute"); dlog_print(" buttons="); @@ -592,7 +610,7 @@ static void __far ps2_mouse_callback(uint8_t status, uint8_t x, uint8_t y, uint8 int sz = z; bool abs = false; -#if TRACE_EVENT +#if TRACE_EVENTS dlog_print("ps2 callback status="); dlog_printx(status); dlog_print(" sx="); @@ -958,18 +976,94 @@ void __declspec(naked) __far int33_isr(void) } #if USE_INT2F +static void windows_mouse_handler(int action, int x, int y, int buttons, int events) +#pragma aux windows_mouse_handler "*" parm [ax] [bx] [cx] [dx] [si] modify [ax bx cx dx es] +{ + switch (action) { + case VMD_ACTION_MOUSE_EVENT: + handle_mouse_event(buttons, true, x, y, 0); + break; + case VMD_ACTION_HIDE_CURSOR: + dlog_puts("VMD_ACTION_HIDE_CURSOR"); + data.w386cursor = true; + refresh_cursor(); + break; + case VMD_ACTION_SHOW_CURSOR: + dlog_puts("VMD_ACTION_SHOW_CURSOR"); + data.w386cursor = false; + refresh_cursor(); + break; + } +} + +void __declspec(naked) __far windows_mouse_callback() +{ + __asm { + pusha + push ds + push es + push fs + push gs + + mov bp, sp + push cs + pop ds + + call windows_mouse_handler + + pop gs + pop fs + pop es + pop ds + popa + + retf + } +} + static void int2f_handler(union INTPACK r) #pragma aux int2f_handler "*" parm caller [] modify [ax bx cx dx es] { + switch (r.x.ax) { + case INT2F_NOTIFY_WIN386_STARTUP: + dlog_print("Windows is starting, version="); + dlog_printx(r.x.di); + dlog_endline(); + data.w386_startup.version = 3; + data.w386_startup.next = MK_FP(r.x.es, r.x.bx); + data.w386_startup.device_driver = 0; + data.w386_startup.device_driver_data = 0; + data.w386_startup.instance_data = &data.w386_instance; + data.w386_instance[0].ptr = &data; + data.w386_instance[0].size = sizeof(data); + data.w386_instance[1].ptr = 0; + data.w386_instance[1].size = 0; + r.x.es = FP_SEG(&data.w386_startup); + r.x.bx = FP_OFF(&data.w386_startup); + break; + case INT2F_NOTIFY_DEVICE_CALLOUT: + switch (r.x.bx) { + case VMD_DEVICE_ID: + switch (r.x.cx) { + case VMD_CALLOUT_TEST: + r.x.cx = 1; // Yes, we are here! + break; + case VMD_CALLOUT_GET_DOS_MOUSE_API: + // Windows is asking our mouse driver for the hook function address + r.x.ds = FP_SEG(windows_mouse_callback); + r.x.si = FP_OFF(windows_mouse_callback); + r.x.ax = 0; // Yes, we are here! + break; + } + break; + } + break; + } } void __declspec(naked) __far int2f_isr(void) { __asm { - ; Space for the pointer to the next ISR in the chain - push dword ptr 0 - - ; Save all registers (also acts as the INTPACK paramenter later) pusha push ds push es @@ -980,16 +1074,6 @@ void __declspec(naked) __far int2f_isr(void) push cs pop ds - ; Load the address of the next ISR in the chain - ; Stack looks like sp+0: gs, fs, es, ds (4*2bytes) - ; sp+8: pusha (8 * 2bytes) - ; sp+24: dword ptr (the space we reserved to store the next ISR) - mov ax, word ptr [data + 4] ; i.e. data.prev_int2f_handler -- Watcom doesn't support structs - mov [bp + 24], ax - mov ax, word ptr [data + 6] ; i.e. data.prev_int2f_handler[2] - mov [bp + 26], ax - - ; Now call our handler call int2f_handler pop gs @@ -998,8 +1082,8 @@ void __declspec(naked) __far int2f_isr(void) pop ds popa - ; This will jump to the address of the next ISR we loaded before - retf + ; Jump to the next handler in the chain + jmp dword ptr cs:[data + 4] ; wasm doesn't support structs, this is data.prev_int2f_handler } } #endif @@ -24,16 +24,19 @@ #include <stdint.h> #include "vbox.h" +#include "int2fwin.h" #define USE_VIRTUALBOX 1 #define USE_INT2F 1 -#define TRACE_EVENT 1 +#define TRACE_EVENTS 0 #define NUM_BUTTONS 3 #define GRAPHIC_CURSOR_WIDTH 16 #define GRAPHIC_CURSOR_HEIGHT 16 +#define VERSION_MAJOR 0 +#define VERSION_MINOR 3 #define REPORTED_VERSION_MAJOR 8 #define REPORTED_VERSION_MINOR 0x20 @@ -129,6 +132,15 @@ typedef struct tsrdata { /** Events for which we should call the event handler. */ uint16_t event_mask; +#if USE_INT2F + /** Information that we pass to Windows 386 on startup. */ + win386_startup_info w386_startup; + win386_instance_item w386_instance[2]; + /** Whether Windows 386 is rendering the cursor for us, + * and therefore we should hide our own. */ + bool w386cursor : 1; +#endif + #if USE_VIRTUALBOX /** VirtualBox is available. */ bool vbavail : 1; @@ -151,4 +163,10 @@ extern LPTSRDATA __far get_tsr_data(bool installed); extern int resident_end; +/** This is not just data, but the entire segment. */ +static inline unsigned get_resident_size(void) +{ + return FP_OFF(&resident_end); +} + #endif @@ -24,26 +24,29 @@ #include <stdint.h> #include <dos.h> -struct win386_instance_item +typedef _Packed struct win386_instance_item { void __far * ptr; uint16_t size; -}; +} win386_instance_item; -struct win386_startup_info +typedef _Packed struct win386_startup_info { uint16_t version; struct win386_startup_info __far * next; char __far * device_driver; void __far * device_driver_data; - struct win386_instance_item __far *instance_data; -}; + struct win386_instance_item __far * instance_data; +} win386_startup_info; typedef void (__far *LPFN)(void); enum int2f_functions { - INT2F_NOTIFY_WIN386_STARTUP = 0x1605, + /** Notification sent when Windows386 is starting up. */ + INT2F_NOTIFY_WIN386_STARTUP = 0x1605, + /** Notification sent by a VxD that wants to invoke a function in a real-mode driver. */ + INT2F_NOTIFY_DEVICE_CALLOUT = 0x1607, INT2F_NOTIFY_BACKGROUND_SWITCH = 0x4001, INT2F_NOTIFY_FOREGROUND_SWITCH = 0x4002 @@ -78,6 +81,26 @@ enum vmd_apis { VMD_SET_MOUSE_TYPE = 0x100, }; +enum vmd_callouts +{ + /** VMD emits this to know if there is a "win386 aware" DOS mouse driver installed. + * If there is, and the driver responds with CX!=0, VMD will assume + * the driver is taking care of its own instancing + * (which we do, through win386_startup_info) + * and not try to hack around our internals. */ + VMD_CALLOUT_TEST = 0, + /** VMD emits this to know the entrypoint for the API of a "win386 aware" + * DOS mouse driver. */ + VMD_CALLOUT_GET_DOS_MOUSE_API = 0x1 +}; + +enum vmd_dos_mouse_api_actions +{ + VMD_ACTION_MOUSE_EVENT = 1, + VMD_ACTION_HIDE_CURSOR = 2, + VMD_ACTION_SHOW_CURSOR = 3 +}; + enum vmd_mouse_type { VMD_TYPE_UNDEFINED = 0, VMD_TYPE_BUS = 1, @@ -24,27 +24,16 @@ #include "int2fwin.h" #include "w16mouse.h" -#define TRACE_EVENT 1 - -/** If 1, hook int2f to detect fullscreen DOSBoxes and auto-disable this driver. */ -#define HOOK_INT2F 0 +#define TRACE_EVENTS 0 #define MOUSE_NUM_BUTTONS 2 /** The routine Windows gave us which we should use to report events. */ static LPFN_MOUSEEVENT eventproc; -/** Current status of the mouse driver (see MOUSEFLAGS_*). */ -static struct mouseflags { - bool enabled : 1; - bool haswin386 : 1; - bool int2f_hooked : 1; -} flags; +/** Current status of the mouse driver. */ +static bool enabled; /** Previous deltaX, deltaY from the int33 mouse callback (for relative motion) */ static short prev_delta_x, prev_delta_y; -#if HOOK_INT2F -/** Existing interrupt2f handler. */ -static LPFN prev_int2f_handler; -#endif /* This is how events are delivered to Windows */ @@ -52,6 +41,8 @@ static void send_event(unsigned short Status, short deltaX, short deltaY, short #pragma aux (MOUSEEVENTPROC) send_event = \ "call dword ptr [eventproc]" +/* Our "CALLBACKS" segment which is fixed and non-relocatable. */ + #pragma code_seg ( "CALLBACKS" ) #include "dlog.h" @@ -61,7 +52,7 @@ static void FAR int33_mouse_callback(uint16_t events, uint16_t buttons, int16_t { int status = 0; -#if TRACE_EVENT_IN +#if TRACE_EVENTS_IN dlog_print("w16mouse: events="); dlog_printx(events); dlog_print(" buttons="); @@ -104,7 +95,7 @@ static void FAR int33_mouse_callback(uint16_t events, uint16_t buttons, int16_t // Unused (void) buttons; -#if TRACE_EVENT +#if TRACE_EVENTS dlog_print("w16mouse: event status="); dlog_printx(status); dlog_print(" x="); @@ -117,72 +108,6 @@ static void FAR int33_mouse_callback(uint16_t events, uint16_t buttons, int16_t send_event(status, x, (uint16_t)(y), MOUSE_NUM_BUTTONS, 0, 0); } -#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 (!flags.enabled) { - return; - } - - switch (function) { - case INT2F_NOTIFY_BACKGROUND_SWITCH: - dlog_puts("Going background\n"); - break; - case INT2F_NOTIFY_FOREGROUND_SWITCH: - dlog_puts("Going foreground\n"); - 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. */ @@ -196,25 +121,8 @@ BOOL FAR PASCAL LibMain(HINSTANCE hInstance, WORD wDataSegment, WORD wHeapSize, LPSTR lpszCmdLine) #pragma pop (unreferenced); { - // 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()) { - flags.haswin386 = true; - } -#endif - -#if 0 - // When running under protected mode Windows, let's tell VMD (the mouse virtualizer) - // what type of mouse we are going to be using - if (flags.haswin386) { - LPFN vmd_entry = win_get_vxd_api_entry(VMD_DEVICE_ID); - if (vmd_entry) { - vmd_set_mouse_type(&vmd_entry, VMD_TYPE_PS2, 0x33, 0); - } - } -#endif + // We are not going to bother checking whether the int33 driver exists + // and just assume it does. return 1; } @@ -238,7 +146,7 @@ VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc) eventproc = lpEventProc; sti(); - if (!flags.enabled) { + if (!enabled) { int33_reset(); int33_set_horizontal_window(0, 0x7FFF); @@ -246,35 +154,17 @@ VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc) int33_set_event_handler(INT33_EVENT_MASK_ALL, int33_mouse_callback); - flags.enabled = true; - -#if HOOK_INT2F - if (flags.haswin386) { - cli(); - hook_int2f(&prev_int2f_handler, int2f_handler); - sti(); - flags.int2f_hooked = true; - } -#endif + enabled = true; } } /** Called by Windows to disable the mouse driver. */ VOID FAR PASCAL Disable(VOID) { - if (flags.enabled) { -#if HOOK_INT2F - if (flags.int2f_hooked) { - cli(); - unhook_int2f(prev_int2f_handler); - sti(); - flags.int2f_hooked = false; - } -#endif - + if (enabled) { int33_reset(); - flags.enabled = false; + enabled = false; } } @@ -283,4 +173,3 @@ int FAR PASCAL MouseGetIntVect(VOID) { return 0x33; } - |