Mouse wheel support added.

This commit is contained in:
Scott Duensing 2026-03-18 16:31:28 -05:00
parent 937be903af
commit 5cf6db01e1
5 changed files with 106 additions and 5 deletions

View file

@ -1096,6 +1096,39 @@ static void dispatchEvents(AppContextT *ctx) {
win->onMouse(win, relX, relY, buttons); 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); ctx->cursorBg = packColor(&ctx->display, 0, 0, 0);
platformMouseInit(ctx->display.width, ctx->display.height); platformMouseInit(ctx->display.width, ctx->display.height);
ctx->mouseX = ctx->display.width / 2; ctx->hasMouseWheel = platformMouseWheelInit();
ctx->mouseY = ctx->display.height / 2; ctx->mouseX = ctx->display.width / 2;
ctx->prevMouseX = ctx->mouseX; ctx->mouseY = ctx->display.height / 2;
ctx->prevMouseY = ctx->mouseY; ctx->prevMouseX = ctx->mouseX;
ctx->prevMouseY = ctx->mouseY;
ctx->running = true; ctx->running = true;
ctx->lastIconClickId = -1; ctx->lastIconClickId = -1;
@ -3367,6 +3401,7 @@ static void pollMouse(AppContextT *ctx) {
ctx->mouseX = mx; ctx->mouseX = mx;
ctx->mouseY = my; ctx->mouseY = my;
ctx->mouseButtons = buttons; ctx->mouseButtons = buttons;
ctx->mouseWheel = platformMouseWheelPoll();
} }

View file

@ -50,6 +50,8 @@ typedef struct AppContextT {
int32_t mouseX; int32_t mouseX;
int32_t mouseY; int32_t mouseY;
int32_t mouseButtons; 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) int32_t keyModifiers; // current BIOS shift state (KEY_MOD_xxx)
// Previous-frame mouse state for edge detection (button press/release // Previous-frame mouse state for edge detection (button press/release
// transitions and delta-based cursor movement). // transitions and delta-based cursor movement).

View file

@ -553,6 +553,9 @@ typedef struct {
#define MOUSE_RIGHT 2 #define MOUSE_RIGHT 2
#define MOUSE_MIDDLE 4 #define MOUSE_MIDDLE 4
// Scrollbar lines to scroll per mouse wheel notch
#define MOUSE_WHEEL_STEP 3
// ============================================================ // ============================================================
// Mouse cursor // Mouse cursor
// ============================================================ // ============================================================

View file

@ -127,6 +127,18 @@ void platformMouseInit(int32_t screenW, int32_t screenH);
// to detect press/release edges. // to detect press/release edges.
void platformMousePoll(int32_t *mx, int32_t *my, int32_t *buttons); 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 // Input — Keyboard
// ============================================================ // ============================================================

View file

@ -686,6 +686,13 @@ void platformMouseInit(int32_t screenW, int32_t screenH) {
// on every mickeyed movement, which is wasteful when we only sample // on every mickeyed movement, which is wasteful when we only sample
// once per frame anyway. // 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) { void platformMousePoll(int32_t *mx, int32_t *my, int32_t *buttons) {
__dpmi_regs r; __dpmi_regs r;
@ -695,7 +702,49 @@ void platformMousePoll(int32_t *mx, int32_t *my, int32_t *buttons) {
*mx = r.x.cx; *mx = r.x.cx;
*my = r.x.dx; *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;
} }