Browse Source

Backends: GLFW: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)

Namely, GLFW JS emulation seems to quantize values to a min of -1/+1 which breaks modern OSX/Windows emulating smoothness with stepping wheels (slow steps are sending sub-1.0 values)
+ Massage changelog.
ocornut 2 years ago
parent
commit
d0b1aaa076
2 changed files with 46 additions and 19 deletions
  1. 33 2
      backends/imgui_impl_glfw.cpp
  2. 13 17
      docs/CHANGELOG.txt

+ 33 - 2
backends/imgui_impl_glfw.cpp

@@ -16,7 +16,7 @@
 
 // CHANGELOG
 // (minor and older changes stripped away, please see git history for details)
-//  2023-02-02: Inputs: Scaling X value on Emscripten (bug?). (#4019, #6096)
+//  2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)
 //  2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty.
 //  2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
 //  2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
@@ -76,6 +76,11 @@
 #include <GLFW/glfw3native.h>   // for glfwGetWin32Window
 #endif
 
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#include <emscripten/html5.h>
+#endif
+
 // We gather version tests as define in order to easily see which features are version-dependent.
 #define GLFW_VERSION_COMBINED           (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
 #ifdef GLFW_RESIZE_NESW_CURSOR          // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
@@ -285,7 +290,8 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
         bd->PrevUserCallbackScroll(window, xoffset, yoffset);
 
 #ifdef __EMSCRIPTEN__
-    xoffset /= 100.0;
+    // Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback().
+    return;
 #endif
 
     ImGuiIO& io = ImGui::GetIO();
@@ -406,6 +412,24 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
 	// Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
 }
 
+#ifdef __EMSCRIPTEN__
+static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void*)
+{
+    // Mimic Emscripten_HandleWheel() in SDL.
+    // Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096
+    float multiplier = 0.0f;
+    if (ev->deltaMode == DOM_DELTA_PIXEL)       { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step.
+    else if (ev->deltaMode == DOM_DELTA_LINE)   { multiplier = 1.0f / 3.0f; }   // 3 lines make up a step.
+    else if (ev->deltaMode == DOM_DELTA_PAGE)   { multiplier = 80.0f; }         // A page makes up 80 steps.
+    float wheel_x = ev->deltaX * -multiplier;
+    float wheel_y = ev->deltaY * -multiplier;
+    ImGuiIO& io = ImGui::GetIO();
+    io.AddMouseWheelEvent(wheel_x, wheel_y);
+    //IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y);
+    return EM_TRUE;
+}
+#endif
+
 void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
 {
     ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
@@ -503,6 +527,13 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
     if (install_callbacks)
         ImGui_ImplGlfw_InstallCallbacks(window);
 
+    // Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096)
+    // We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves.
+    // FIXME: May break chaining in case user registered their own Emscripten callback?
+#ifdef __EMSCRIPTEN__
+    emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, false, ImGui_ImplEmscripten_WheelCallback);
+#endif
+
     bd->ClientApi = client_api;
     return true;
 }

+ 13 - 17
docs/CHANGELOG.txt

@@ -35,36 +35,26 @@ HOW TO UPDATE?
  VERSION 1.89.3 (In Progress)
 -----------------------------------------------------------------------
 
-Breaking changes:
+All changes:
 
 - Inputs, Scrolling: Made horizontal scroll wheel and horizontal scroll direction consistent
   accross backends/os. (#4019, #6096, #1463) [@PathogenDavid, @ocornut, @rokups]
   - Clarified that 'wheel_y > 0.0f' scrolls Up, 'wheel_y > 0.0f' scrolls Down.
-  - Clarified that 'wheel_x > 0.0f' scrolls Left, 'wheel_x > 0.0f' scrolls Right.
-  - Backends: Win32: flipping WM_MOUSEHWHEEL value to match other backends and
-    offer consistent horizontal scrolling direction. (#4019)
-  - Backends: SDL: flipping SDL_MOUSEWHEEL 'wheel.x' value to match other backends and
-    offer consistent horizontal scrolling direction. (#4019)
+    Clarified that 'wheel_x > 0.0f' scrolls Left, 'wheel_x > 0.0f' scrolls Right.
+  - Backends: Fixed horizontal scroll direction for Win32 and SDL backends. (#4019)
   - Shift+WheelY support on non-OSX machines was already correct. (#2424, #1463)
     (whereaas on OSX machines Shift+WheelY turns into WheelX at the OS level).
-  - If you use a custom-backend, you should verify that:
-    - Wheel up (*) emit wheel_y > 0.0f values and scrolls up.
-    - Wheel down (*) emit wheel_y < 0.0f values and scrolls down.
-    - Wheel left (*) or mod+wheel up emit wheel_x > 0.0f values and scroll Left.
-    - Wheel right (*) or mod+wheel down emits wheel_x < 0.0f values and scroll Right.
-    - (*) both axises flipped on OSX for mouse and touchpad when 'Natural Scrolling' is on.
-    - (*) both axises flipped On Windows for touchpad only when 'Settings->Touchpad->Down motion scrolls up' is set.
+  - If you use a custom-backend, you should verify horizontal wheel direction.
+    - Axises are flipped by OSX for mouse & touchpad when 'Natural Scrolling' is on.
+    - Axises are flipped by Windows for touchpad when 'Settings->Touchpad->Down motion scrolls up' is on.
     - You can use 'Demo->Tools->Debug Log->IO" to visualize values submitted to Dear ImGui.
   - Known issues remaining with Emscripten:
-    - The magnitude of wheeling values on Emscripten setups is still not great. (#6096)
+    - The magnitude of wheeling values on Emscripten was improved but isn't perfect. (#6096)
     - When running the Emscripten app on a Mac with a mouse, SHIFT+WheelY doesn't turn into WheelX.
       This is because we don't know that we are running on Mac and apply our own Shift+swapping
       on top of OSX' own swapping, so wheel axises are swapped twice. Emscripten apps may need
       to find a way to detect this and set io.ConfigMacOSXBehaviors manually (if you know a way
       let us know!), or offer the "OSX-style behavior" option to their user.
-
-All changes:
-
 - Window: Avoid rendering shapes for hidden resize grips.
 - Tables: Raised max Columns count from 64 to 512. (#6094, #5305, #4876, #3572)
   The previous limit was due to using 64-bit integers but we moved to bits-array
@@ -89,11 +79,17 @@ All changes:
   can exacerbate that. (#6114, #3644)
 - Backends: OSX: Fixed scroll/wheel scaling for devices emitting events with
   hasPreciseScrollingDeltas==false (e.g. non-Apple mices).
+- Backends: Win32: flipping WM_MOUSEHWHEEL value to match other backends and
+  offer consistent horizontal scrolling direction. (#4019)
+- Backends: SDL: flipping SDL_MOUSEWHEEL 'wheel.x' value to match other backends and
+  offer consistent horizontal scrolling direction. (#4019)
 - Backends: SDL: Removed SDL_MOUSEWHEEL value clamping. (#4019, #6096, #6081)
 - Backends: SDL: Added support for SDL 2.0.18+ preciseX/preciseY mouse wheel data
   for smooth scrolling as reported by SDL. (#4019, #6096)
 - Backends: SDL: Avoid calling SDL_SetCursor() when cursor has not changed, as the function
   is surprisingly costly on Mac with latest SDL (may be fixed in next SDL version). (#6113)
+- Backends: GLFW: Registering custom low-level mouse wheel handler to get more accurate
+  scrolling impulses on Emscripten. (#4019, #6096) [@ocornut, @wolfpld, @tolopolarity]
 - Backends: WebGPU: Fix building for latest WebGPU specs (remove implicit layout generation).
   (#6117, #4116, #3632) [@tonygrue, @bfierz]
 - Examples: refactord all examples to use a "MainLoopStep()" function. This is in order