From 6e5994eca8183f40c37d100666397a3e53a8b061 Mon Sep 17 00:00:00 2001 From: Adam Scott Date: Tue, 13 May 2025 13:09:59 -0400 Subject: [PATCH] [Web] Fix Web MouseWheel scrolling --- platform/web/display_server_web.cpp | 37 +++++++++++++++++---- platform/web/display_server_web.h | 4 +-- platform/web/godot_js.h | 2 +- platform/web/js/libs/library_godot_input.js | 2 +- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index 06e8c71dff2..6e9acae9113 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -634,18 +634,18 @@ Point2i DisplayServerWeb::mouse_get_position() const { } // Wheel -int DisplayServerWeb::mouse_wheel_callback(double p_delta_x, double p_delta_y) { +int DisplayServerWeb::mouse_wheel_callback(int p_delta_mode, double p_delta_x, double p_delta_y) { #ifdef PROXY_TO_PTHREAD_ENABLED if (!Thread::is_main_thread()) { - callable_mp_static(DisplayServerWeb::_mouse_wheel_callback).call_deferred(p_delta_x, p_delta_y); + callable_mp_static(DisplayServerWeb::_mouse_wheel_callback).call_deferred(p_delta_mode, p_delta_x, p_delta_y); return true; } #endif - return _mouse_wheel_callback(p_delta_x, p_delta_y); + return _mouse_wheel_callback(p_delta_mode, p_delta_x, p_delta_y); } -int DisplayServerWeb::_mouse_wheel_callback(double p_delta_x, double p_delta_y) { +int DisplayServerWeb::_mouse_wheel_callback(int p_delta_mode, double p_delta_x, double p_delta_y) { if (!godot_js_display_canvas_is_focused() && !godot_js_is_ime_focused()) { if (get_singleton()->cursor_inside_canvas) { godot_js_display_canvas_focus(); @@ -665,21 +665,44 @@ int DisplayServerWeb::_mouse_wheel_callback(double p_delta_x, double p_delta_y) ev->set_ctrl_pressed(input->is_key_pressed(Key::CTRL)); ev->set_meta_pressed(input->is_key_pressed(Key::META)); + enum DeltaMode { + DELTA_MODE_PIXEL = 0, + DELTA_MODE_LINE = 1, + DELTA_MODE_PAGE = 2, + }; + const float MOUSE_WHEEL_PIXEL_FACTOR = 0.03f; + const float MOUSE_WHEEL_LINE_FACTOR = 0.3f; + const float MOUSE_WHEEL_PAGE_FACTOR = 1.0f; + float mouse_wheel_factor; + + switch (p_delta_mode) { + case DELTA_MODE_PIXEL: { + mouse_wheel_factor = MOUSE_WHEEL_PIXEL_FACTOR; + } break; + case DELTA_MODE_LINE: { + mouse_wheel_factor = MOUSE_WHEEL_LINE_FACTOR; + } break; + case DELTA_MODE_PAGE: { + mouse_wheel_factor = MOUSE_WHEEL_PAGE_FACTOR; + } break; + } + if (p_delta_y < 0) { ev->set_button_index(MouseButton::WHEEL_UP); + ev->set_factor(-p_delta_y * mouse_wheel_factor); } else if (p_delta_y > 0) { ev->set_button_index(MouseButton::WHEEL_DOWN); + ev->set_factor(p_delta_y * mouse_wheel_factor); } else if (p_delta_x > 0) { ev->set_button_index(MouseButton::WHEEL_LEFT); + ev->set_factor(p_delta_x * mouse_wheel_factor); } else if (p_delta_x < 0) { ev->set_button_index(MouseButton::WHEEL_RIGHT); + ev->set_factor(-p_delta_x * mouse_wheel_factor); } else { return false; } - // Different browsers give wildly different delta values, and we can't - // interpret deltaMode, so use default value for wheel events' factor. - MouseButtonMask button_flag = mouse_button_to_mask(ev->get_button_index()); BitField button_mask = input->get_mouse_button_mask(); button_mask.set_flag(button_flag); diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h index 759f14f1eb0..ed0342a79b7 100644 --- a/platform/web/display_server_web.h +++ b/platform/web/display_server_web.h @@ -122,8 +122,8 @@ private: static int _mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers); WASM_EXPORT static void mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers, double p_pressure); static void _mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers, double p_pressure); - WASM_EXPORT static int mouse_wheel_callback(double p_delta_x, double p_delta_y); - static int _mouse_wheel_callback(double p_delta_x, double p_delta_y); + WASM_EXPORT static int mouse_wheel_callback(int p_delta_mode, double p_delta_x, double p_delta_y); + static int _mouse_wheel_callback(int p_delta_mode, double p_delta_x, double p_delta_y); WASM_EXPORT static void touch_callback(int p_type, int p_count); static void _touch_callback(int p_type, int p_count); WASM_EXPORT static void key_callback(int p_pressed, int p_repeat, int p_modifiers); diff --git a/platform/web/godot_js.h b/platform/web/godot_js.h index 4e282181d0d..91e2576b66f 100644 --- a/platform/web/godot_js.h +++ b/platform/web/godot_js.h @@ -61,7 +61,7 @@ extern int godot_js_pwa_update(); // Input extern void godot_js_input_mouse_button_cb(int (*p_callback)(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers)); extern void godot_js_input_mouse_move_cb(void (*p_callback)(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers, double p_pressure)); -extern void godot_js_input_mouse_wheel_cb(int (*p_callback)(double p_delta_x, double p_delta_y)); +extern void godot_js_input_mouse_wheel_cb(int (*p_callback)(int p_delta_mode, double p_delta_x, double p_delta_y)); extern void godot_js_input_touch_cb(void (*p_callback)(int p_type, int p_count), uint32_t *r_identifiers, double *r_coords); extern void godot_js_input_key_cb(void (*p_callback)(int p_type, int p_repeat, int p_modifiers), char r_code[32], char r_key[32]); extern void godot_js_input_vibrate_handheld(int p_duration_ms); diff --git a/platform/web/js/libs/library_godot_input.js b/platform/web/js/libs/library_godot_input.js index 2ba60916ac0..90ef7a4883c 100644 --- a/platform/web/js/libs/library_godot_input.js +++ b/platform/web/js/libs/library_godot_input.js @@ -526,7 +526,7 @@ const GodotInput = { godot_js_input_mouse_wheel_cb: function (callback) { const func = GodotRuntime.get_func(callback); function wheel_cb(evt) { - if (func(evt['deltaX'] || 0, evt['deltaY'] || 0)) { + if (func(evt.deltaMode, evt.deltaX ?? 0, evt.deltaY ?? 0)) { evt.preventDefault(); } }