Fix mouse state packing bit-field overlap

The old packing was:
  X << 32 | Y << 16 | buttons
where X and Y were full 32-bit values. Y's upper 16 bits (bits 32-47)
overlapped with X (bits 32-63), and buttons (bits 0-31) overlapped with
Y (bits 16-47). This corrupted X whenever Y >= 65536, and corrupted Y
whenever buttons had any bits set above bit 15.

The Lean unpacking side already assumed a non-overlapping layout:
  X = bits 63:32, Y = bits 31:16 (masked to 16), buttons = bits 15:0

Now the C side explicitly masks Y and buttons to 16 bits before packing,
matching the Lean expectations. This means Y is limited to [-32768,
32767] which is adequate for screen coordinates and typical relative
mode deltas.

Also fix the SDLIO error type in sdl_set_relative_mouse_mode (same
lean_mk_io_user_error issue fixed in the earlier commit).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Greg Shuflin
2026-03-23 13:17:24 -07:00
co-authored by Claude Opus 4.6
parent e3dcc8da14
commit 3ec33e9a27
+8 -4
View File
@@ -652,15 +652,19 @@ lean_obj_res sdl_get_mouse_state(lean_obj_arg w) {
mouse_cache.last_frame_tick = current_tick;
}
uint64_t packed = ((uint64_t)(uint32_t)(int32_t)mouse_cache.x << 32) |
((uint64_t)(uint32_t)(int32_t)mouse_cache.y << 16) |
(uint64_t)mouse_cache.buttons;
// Pack into 64 bits: X[63:32] | Y[31:16] | buttons[15:0]
// X gets full 32 bits; Y and buttons are truncated to 16 bits each.
int32_t ix = (int32_t)mouse_cache.x;
int32_t iy = (int32_t)mouse_cache.y;
uint64_t packed = ((uint64_t)(uint32_t)ix << 32) |
((uint64_t)((uint32_t)iy & 0xFFFF) << 16) |
((uint64_t)(mouse_cache.buttons & 0xFFFF));
return lean_io_result_mk_ok(lean_box_uint64(packed));
}
lean_obj_res sdl_set_relative_mouse_mode(b_lean_obj_arg g_window, bool enabled, lean_obj_arg w) {
SDL_Window* window = (SDL_Window*)lean_get_external_data(g_window);
if (window == NULL) return lean_io_result_mk_error(lean_mk_io_user_error(lean_mk_string("C: Window is NULL")));
if (window == NULL) return lean_io_result_mk_error(lean_mk_string("C: Window is NULL"));
int32_t result = SDL_SetWindowRelativeMouseMode(window, enabled);
mouse_cache.relative_mode = enabled;
mouse_cache.last_frame_tick = 0; // Force refresh