diff --git a/dvx/dvxApp.c b/dvx/dvxApp.c index eeee3b4..d99e9ce 100644 --- a/dvx/dvxApp.c +++ b/dvx/dvxApp.c @@ -1096,6 +1096,39 @@ static void dispatchEvents(AppContextT *ctx) { win->onMouse(win, relX, relY, buttons); } } + + // Mouse wheel — scroll the focused window's vertical scrollbar. + // Each notch moves MOUSE_WHEEL_STEP lines. If no vertical scrollbar, + // try horizontal (for windows with only horizontal scroll). + if (ctx->mouseWheel != 0 && ctx->stack.focusedIdx >= 0) { + WindowT *win = ctx->stack.windows[ctx->stack.focusedIdx]; + ScrollbarT *sb = win->vScroll ? win->vScroll : win->hScroll; + + if (sb) { + int32_t oldValue = sb->value; + sb->value += ctx->mouseWheel * MOUSE_WHEEL_STEP; + + if (sb->value < sb->min) { + sb->value = sb->min; + } + + if (sb->value > sb->max) { + sb->value = sb->max; + } + + if (sb->value != oldValue) { + int32_t sbScreenX = win->x + sb->x; + int32_t sbScreenY = win->y + sb->y; + dirtyListAdd(&ctx->dirty, sbScreenX, sbScreenY, + sb->orient == ScrollbarVerticalE ? SCROLLBAR_WIDTH : sb->length, + sb->orient == ScrollbarVerticalE ? sb->length : SCROLLBAR_WIDTH); + + if (win->onScroll) { + win->onScroll(win, sb->orient, sb->value); + } + } + } + } } @@ -1549,10 +1582,11 @@ int32_t dvxInit(AppContextT *ctx, int32_t requestedW, int32_t requestedH, int32_ ctx->cursorBg = packColor(&ctx->display, 0, 0, 0); platformMouseInit(ctx->display.width, ctx->display.height); - ctx->mouseX = ctx->display.width / 2; - ctx->mouseY = ctx->display.height / 2; - ctx->prevMouseX = ctx->mouseX; - ctx->prevMouseY = ctx->mouseY; + ctx->hasMouseWheel = platformMouseWheelInit(); + ctx->mouseX = ctx->display.width / 2; + ctx->mouseY = ctx->display.height / 2; + ctx->prevMouseX = ctx->mouseX; + ctx->prevMouseY = ctx->mouseY; ctx->running = true; ctx->lastIconClickId = -1; @@ -3367,6 +3401,7 @@ static void pollMouse(AppContextT *ctx) { ctx->mouseX = mx; ctx->mouseY = my; ctx->mouseButtons = buttons; + ctx->mouseWheel = platformMouseWheelPoll(); } diff --git a/dvx/dvxApp.h b/dvx/dvxApp.h index 4d3cbba..cc0c1eb 100644 --- a/dvx/dvxApp.h +++ b/dvx/dvxApp.h @@ -50,6 +50,8 @@ typedef struct AppContextT { int32_t mouseX; int32_t mouseY; int32_t mouseButtons; + int32_t mouseWheel; // wheel delta this frame (positive=down, negative=up) + bool hasMouseWheel; // true if CuteMouse Wheel API detected int32_t keyModifiers; // current BIOS shift state (KEY_MOD_xxx) // Previous-frame mouse state for edge detection (button press/release // transitions and delta-based cursor movement). diff --git a/dvx/dvxTypes.h b/dvx/dvxTypes.h index fffbd16..5ed7cee 100644 --- a/dvx/dvxTypes.h +++ b/dvx/dvxTypes.h @@ -553,6 +553,9 @@ typedef struct { #define MOUSE_RIGHT 2 #define MOUSE_MIDDLE 4 +// Scrollbar lines to scroll per mouse wheel notch +#define MOUSE_WHEEL_STEP 3 + // ============================================================ // Mouse cursor // ============================================================ diff --git a/dvx/platform/dvxPlatform.h b/dvx/platform/dvxPlatform.h index b23962a..c6369f3 100644 --- a/dvx/platform/dvxPlatform.h +++ b/dvx/platform/dvxPlatform.h @@ -127,6 +127,18 @@ void platformMouseInit(int32_t screenW, int32_t screenH); // to detect press/release edges. void platformMousePoll(int32_t *mx, int32_t *my, int32_t *buttons); +// Detect and activate mouse wheel support. Returns true if the mouse +// driver supports the CuteMouse Wheel API (INT 33h AX=0011h). This +// call also activates wheel reporting — after it returns true, function +// 03h will return wheel delta in BH. Must be called after platformMouseInit. +bool platformMouseWheelInit(void); + +// Read the accumulated wheel delta since the last call. Positive = scroll +// down, negative = scroll up. Returns 0 if no wheel movement or if wheel +// is not supported. The delta is cleared on each read (accumulated by the +// driver between polls). +int32_t platformMouseWheelPoll(void); + // ============================================================ // Input — Keyboard // ============================================================ diff --git a/dvx/platform/dvxPlatformDos.c b/dvx/platform/dvxPlatformDos.c index f184164..ce0c779 100644 --- a/dvx/platform/dvxPlatformDos.c +++ b/dvx/platform/dvxPlatformDos.c @@ -686,6 +686,13 @@ void platformMouseInit(int32_t screenW, int32_t screenH) { // on every mickeyed movement, which is wasteful when we only sample // once per frame anyway. +// Wheel state: detected by platformMouseWheelInit, read by platformMousePoll. +// The wheel delta is extracted from function 03h BH in the same INT call that +// reads position and buttons, avoiding a double call that would clear the +// accumulated counter. +static bool sHasMouseWheel = false; +static int32_t sLastWheelDelta = 0; + void platformMousePoll(int32_t *mx, int32_t *my, int32_t *buttons) { __dpmi_regs r; @@ -695,7 +702,49 @@ void platformMousePoll(int32_t *mx, int32_t *my, int32_t *buttons) { *mx = r.x.cx; *my = r.x.dx; - *buttons = r.x.bx; + *buttons = r.x.bx & 0x07; // BL only: bits 0-2 = left/right/middle + + // BH = signed 8-bit wheel counter (cleared on read by the driver). + // Only meaningful if the wheel API was activated via platformMouseWheelInit. + if (sHasMouseWheel) { + sLastWheelDelta = (int32_t)(int8_t)(r.x.bx >> 8); + } +} + + +// ============================================================ +// platformMouseWheelInit +// ============================================================ +// +// Detects and activates the CuteMouse Wheel API 1.0 (INT 33h AX=0011h). +// The driver returns AX=574Dh ('WM') if supported, with CX bit 0 set if +// a wheel is physically present. Calling this function also switches the +// driver from "wheelkey" mode (faking keypresses) to real wheel reporting +// via function 03h BH. Must be called after platformMouseInit. + +bool platformMouseWheelInit(void) { + __dpmi_regs r; + + memset(&r, 0, sizeof(r)); + r.x.ax = 0x0011; + __dpmi_int(0x33, &r); + + // 0x574D = 'WM' (Wheel Mouse) magic signature + sHasMouseWheel = (r.x.ax == 0x574D) && (r.x.cx & 0x0001); + return sHasMouseWheel; +} + + +// ============================================================ +// platformMouseWheelPoll +// ============================================================ +// +// Returns the wheel delta captured by the last platformMousePoll call. +// Positive = scroll down, negative = scroll up. Returns 0 if no wheel +// movement or if the wheel is not supported. + +int32_t platformMouseWheelPoll(void) { + return sLastWheelDelta; }