aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2022-04-14 00:00:19 +0200
committerJavier <dev.git@javispedro.com>2022-04-14 00:00:19 +0200
commitb11d085f98465aae2b5a861066b963fce5aeaae3 (patch)
tree85ce02217e85d913fbbb827945e593d1d53b1845
parenta77ce98811ba6040dafec8f75b5387ae5b2813aa (diff)
downloadvbados-b11d085f98465aae2b5a861066b963fce5aeaae3.tar.gz
vbados-b11d085f98465aae2b5a861066b963fce5aeaae3.zip
add wheel support to win16 mouse driver
-rw-r--r--int21dos.h21
-rw-r--r--int33.h11
-rw-r--r--mousew16.c142
3 files changed, 165 insertions, 9 deletions
diff --git a/int21dos.h b/int21dos.h
index 0a04ac0..a76c2c5 100644
--- a/int21dos.h
+++ b/int21dos.h
@@ -67,6 +67,25 @@ enum dos_error {
DOS_ERROR_CANNOT_MAKE = 82,
};
+// General functions
+static inline void dos_print_string(const char *s);
+#pragma aux dos_print_string = \
+ "mov ah, 0x09" \
+ "int 0x21" \
+ __parm [dx] \
+ __modify [ah]
+
+static inline uint8_t dos_read_character(void);
+#pragma aux dos_read_character = \
+ "mov ah, 0x08" \
+ "int 0x21" \
+ __value [al] \
+ __modify [ax]
+
+// Memory manipulation functions
+
+typedef __segment segment_t;
+
enum dos_allocation_strategy {
DOS_FIT_FIRST = 0,
DOS_FIT_BEST = 1,
@@ -76,8 +95,6 @@ enum dos_allocation_strategy {
DOS_FIT_HIGHONLY = 0x40,
};
-typedef __segment segment_t;
-
/** Converts bytes to paragraphs (16 bytes), rounding up. */
static inline unsigned get_paragraphs(unsigned bytes)
{
diff --git a/int33.h b/int33.h
index bb975a3..7cd7aa5 100644
--- a/int33.h
+++ b/int33.h
@@ -248,4 +248,15 @@ static bool int33_get_max_coordinates(int16_t *x, int16_t *y);
__value [al] \
__modify [ax bx cx dx]
+static uint16_t int33_get_capabilities(void);
+#pragma aux int33_get_capabilities = \
+ "mov ax, 0x11" \
+ "int 0x33" \
+ "cmp ax, 0x574D" /* Compare against the INT33_WHEEL_API_MAGIC number. */ \
+ "je end" \
+ "xor cx, cx" /* If magic not correct, assume not supported and return 0. */ \
+ "end:" \
+ __value [cx] \
+ __modify [ax bx cx]
+
#endif /* INT33_H */
diff --git a/mousew16.c b/mousew16.c
index 6e70371..11324aa 100644
--- a/mousew16.c
+++ b/mousew16.c
@@ -17,24 +17,49 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include <windows.h>
+#include <string.h>
#include <limits.h>
+#include <windows.h>
#include "utils.h"
#include "int33.h"
+#include "int21dos.h"
#include "int2fwin.h"
#include "mousew16.h"
+/** Whether to enable wheel mouse handling. */
+#define USE_WHEEL 1
+/** Verbosely log events as they happen. */
#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. */
-static bool enabled;
+/** Current status of the driver. */
+static struct {
+ /** Whether the driver is currently enabled. */
+ bool enabled : 1;
+#if USE_WHEEL
+ /** Whether a mouse wheel was detected. */
+ bool wheel : 1;
+#endif
+} flags;
/** Previous deltaX, deltaY from the int33 mouse callback (for relative motion) */
static short prev_delta_x, prev_delta_y;
+#if USE_WHEEL
+/** Some delay-loaded functions from USER.EXE to provide wheel mouse events. */
+static struct {
+ HINSTANCE hUser;
+ void WINAPI (*GetCursorPos)( POINT FAR * );
+ HWND WINAPI (*WindowFromPoint)( POINT );
+ HWND WINAPI (*GetParent)( HWND );
+ int WINAPI (*GetClassName)( HWND, LPSTR, int );
+ LONG WINAPI (*GetWindowLong)( HWND, int );
+ BOOL WINAPI (*EnumChildWindows)( HWND, WNDENUMPROC, LPARAM );
+ BOOL WINAPI (*PostMessage)( HWND, UINT, WPARAM, LPARAM );
+} userapi;
+#endif
/* This is how events are delivered to Windows */
@@ -48,6 +73,81 @@ static void send_event(unsigned short Status, short deltaX, short deltaY, short
#include "dlog.h"
+#if USE_WHEEL
+typedef struct {
+ HWND scrollbar;
+} FINDSCROLLBARDATA, FAR * LPFINDSCROLLBARDATA;
+
+static BOOL CALLBACK __loadds find_scrollbar(HWND hWnd, LPARAM lParam)
+{
+ LPFINDSCROLLBARDATA data = (LPFINDSCROLLBARDATA) lParam;
+ char buffer[16];
+
+ userapi.GetClassName(hWnd, &buffer, sizeof(buffer));
+
+ if (_fstrcmp(buffer, "ScrollBar") == 0) {
+ data->scrollbar = hWnd;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void send_wheel_movement(int8_t z)
+{
+ POINT point;
+ HWND hWnd;
+ WPARAM wParam;
+
+#if TRACE_EVENTS
+ dlog_print("w16mouse: wheel=");
+ dlog_printd(z);
+ dlog_endline();
+#endif
+
+ // TODO It's highly unlikely that we can call this many functions from
+ // an interrupt handler without causing a re-entrancy issue somewhere.
+ // Likely it would be better to just move all of this into a hook .DLL
+
+ userapi.GetCursorPos(&point);
+
+ hWnd = userapi.WindowFromPoint(point);
+
+ while (hWnd) {
+ LONG style = userapi.GetWindowLong(hWnd, GWL_STYLE);
+
+ if (style & WS_VSCROLL) {
+ wParam = z < 0 ? SB_LINEUP : SB_LINEDOWN;
+ userapi.PostMessage(hWnd, WM_VSCROLL, wParam, 0);
+ break;
+ } else if (style & WS_HSCROLL) {
+ wParam = z < 0 ? SB_LINELEFT : SB_LINERIGHT;
+ userapi.PostMessage(hWnd, WM_HSCROLL, wParam, 0);
+ break;
+ } else {
+ FINDSCROLLBARDATA data = {0};
+
+ // Let's check if we can find a scroll bar in this window..
+ userapi.EnumChildWindows(hWnd, find_scrollbar, (LONG) (LPVOID) &data);
+ if (data.scrollbar) {
+ // Assume vertical scrolling
+ wParam = z < 0 ? SB_LINEUP : SB_LINEDOWN;
+ userapi.PostMessage(hWnd, WM_VSCROLL, wParam, 0);
+ break;
+ }
+
+ if (style & WS_CHILD) {
+ // Otherwise try again with a parent window
+ hWnd = userapi.GetParent(hWnd);
+ } else {
+ // This was already a topmost
+ break;
+ }
+ }
+ }
+}
+#endif /* USE_WHEEL */
+
static void FAR int33_mouse_callback(uint16_t events, uint16_t buttons, int16_t x, int16_t y, int16_t delta_x, int16_t delta_y)
#pragma aux (INT33_CB) int33_mouse_callback
{
@@ -78,6 +178,16 @@ static void FAR int33_mouse_callback(uint16_t events, uint16_t buttons, int16_t
status |= SF_MOVEMENT;
}
+#if USE_WHEEL
+ if (flags.wheel && (events & INT33_EVENT_MASK_WHEEL_MOVEMENT)) {
+ // If wheel API is enabled, higher byte of buttons contains wheel movement
+ int8_t z = (buttons & 0xFF00) >> 8;
+ if (z) {
+ send_wheel_movement(z);
+ }
+ }
+#endif
+
if (events & INT33_EVENT_MASK_ABSOLUTE) {
status |= SF_ABSOLUTE;
@@ -129,6 +239,9 @@ BOOL FAR PASCAL LibMain(HINSTANCE hInstance, WORD wDataSegment,
// For now we just check for the presence of any int33 driver version
if (version == 0) {
// No one responded to our request, we can assume no driver
+ dos_print_string("To use VBMOUSE.DRV you have to run/install VBMOUSE.EXE first\r\n(or at least any other DOS mouse driver).\r\n\n$");
+ dos_print_string("Press any key to terminate.$");
+ dos_read_character();
// This will cause a "can't load .drv" message from Windows
return 0;
}
@@ -155,9 +268,24 @@ VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc)
eventproc = lpEventProc;
_enable();
- if (!enabled) {
+ if (!flags.enabled) {
int33_reset();
+#if USE_WHEEL
+ // Detect whether the int33 driver has wheel support
+ flags.wheel = int33_get_capabilities() & 1;
+ if (flags.wheel) {
+ userapi.hUser = (HINSTANCE) GetModuleHandle("USER");
+ userapi.GetCursorPos = (LPVOID) GetProcAddress(userapi.hUser, "GetCursorPos");
+ userapi.WindowFromPoint = (LPVOID) GetProcAddress(userapi.hUser, "WindowFromPoint");
+ userapi.GetParent = (LPVOID) GetProcAddress(userapi.hUser, "GetParent");
+ userapi.GetClassName = (LPVOID) GetProcAddress(userapi.hUser, "GetClassName");
+ userapi.GetWindowLong = (LPVOID) GetProcAddress(userapi.hUser, "GetWindowLong");
+ userapi.EnumChildWindows = (LPVOID) GetProcAddress(userapi.hUser, "EnumChildWindows");
+ userapi.PostMessage = (LPVOID) GetProcAddress(userapi.hUser, "PostMessage");
+ }
+#endif
+
// Since the mouse driver will likely not know the Windows resolution,
// let's manually set up a large window of coordinates so as to have
// as much precision as possible.
@@ -167,16 +295,16 @@ VOID FAR PASCAL Enable(LPFN_MOUSEEVENT lpEventProc)
int33_set_event_handler(INT33_EVENT_MASK_ALL, int33_mouse_callback);
- enabled = true;
+ flags.enabled = true;
}
}
/** Called by Windows to disable the mouse driver. */
VOID FAR PASCAL Disable(VOID)
{
- if (enabled) {
+ if (flags.enabled) {
int33_reset(); // This removes our handler and all other settings
- enabled = false;
+ flags.enabled = false;
}
}