[gtk/wip.win32.fixes: 9/9] GdkWin32: Rework scroll input handling




commit 114c07368e267291166e0768f2557323ffe24761
Author: Luca Bacci <luca bacci982 gmail com>
Date:   Tue Apr 12 11:00:03 2022 +0200

    GdkWin32: Rework scroll input handling
    
    Accumulate fractional deltas and generate discrete scroll events
    only when a full detent is reached.
    
    Also rework the code style and comments.
    
    References:
    
      [1] Why are mouse wheel messages delivered to the focus window
          instead of the window under the mouse?
          https://devblogs.microsoft.com/oldnewthing/20160420-00/?p=93325
    
      [2] Scrollbars Part 6 – The wheel
          https://devblogs.microsoft.com/oldnewthing/20030807-00/?p=42963

 gdk/win32/gdkevents-win32.c | 178 ++++++++++++++++++++++++++------------------
 1 file changed, 107 insertions(+), 71 deletions(-)
---
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index a5306a42cd..d0669f9074 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1760,9 +1760,6 @@ gdk_event_translate (MSG *msg,
 
   int i;
 
-  double delta_x, delta_y;
-  GdkScrollDirection direction;
-
   display = gdk_display_get_default ();
   win32_display = GDK_WIN32_DISPLAY (display);
 
@@ -2659,65 +2656,70 @@ gdk_event_translate (MSG *msg,
 
     case WM_MOUSEWHEEL:
     case WM_MOUSEHWHEEL:
+    {
+      static GdkSurface *last_scroll_surface = NULL;
+      static gint16 accumulated_x = 0;
+      static gint16 accumulated_y = 0;
+
+      gint16 scroll_x = 0;
+      gint16 scroll_y = 0;
+
+      char classname[64];
+
       GDK_NOTE (EVENTS, g_print (" %d", (short) HIWORD (msg->wParam)));
 
-      /* WM_MOUSEWHEEL is delivered to the focus window. Work around
-       * that. Also, the position is in screen coordinates, not client
-       * coordinates as with the button messages. I love the
-       * consistency of Windows.
-       */
+      /* On versions of Windows before Windows 10, the WM_MOUSEWHEEL
+       * is delivered to the window that has keyboard focus, not the
+       * window under the pointer. Work around that.
+       * Also, the position is in screen coordinates, not client
+       * coordinates as with the button messages. */
       point.x = GET_X_LPARAM (msg->lParam);
       point.y = GET_Y_LPARAM (msg->lParam);
 
-      if ((hwnd = WindowFromPoint (point)) == NULL)
-       break;
+      hwnd = WindowFromPoint (point);
+      if (!hwnd)
+        break;
 
-      {
-       char classname[64];
-
-       /* The synapitics trackpad drivers have this irritating
-          feature where it pops up a window right under the pointer
-          when you scroll. We backtrack and to the toplevel and
-          find the innermost child instead. */
-       if (GetClassNameA (hwnd, classname, sizeof(classname)) &&
-           strcmp (classname, SYNAPSIS_ICON_WINDOW_CLASS) == 0)
-         {
-           HWND hwndc;
-
-           /* Find our toplevel window */
-           hwnd = GetAncestor (msg->hwnd, GA_ROOT);
-
-           /* Walk back up to the outermost child at the desired point */
-           do {
-             ScreenToClient (hwnd, &point);
-             hwndc = ChildWindowFromPoint (hwnd, point);
-             ClientToScreen (hwnd, &point);
-           } while (hwndc != hwnd && (hwnd = hwndc, 1));
-         }
-      }
+      /* The synapitics trackpad drivers have this irritating
+         feature where it pops up a window right under the pointer
+         when you scroll. We backtrack and to the toplevel and
+         find the innermost child instead. */
+      if (GetClassNameA (hwnd, classname, sizeof(classname)) &&
+          strcmp (classname, SYNAPSIS_ICON_WINDOW_CLASS) == 0)
+        {
+          HWND hwndc;
 
-      msg->hwnd = hwnd;
-      if ((new_window = gdk_win32_handle_table_lookup (msg->hwnd)) == NULL)
-       break;
+          /* Find our toplevel window */
+          hwnd = GetAncestor (msg->hwnd, GA_ROOT);
 
-      if (new_window != window)
-       {
-         g_set_object (&window, new_window);
-       }
+          /* Walk back up to the outermost child at the desired point */
+          do {
+            ScreenToClient (hwnd, &point);
+            hwndc = ChildWindowFromPoint (hwnd, point);
+            ClientToScreen (hwnd, &point);
+          } while (hwndc != hwnd && (hwnd = hwndc, 1));
+        }
 
-      impl = GDK_WIN32_SURFACE (window);
-      ScreenToClient (msg->hwnd, &point);
+      msg->hwnd = hwnd;
 
-      delta_x = delta_y = 0.0;
+      g_set_object (&window, gdk_win32_handle_table_lookup (hwnd));
+      if (!window)
+        break;
+
+      if (window != last_scroll_surface)
+        {
+          accumulated_y = 0;
+          accumulated_x = 0;
+          last_scroll_surface = window;
+        }
 
       if (msg->message == WM_MOUSEWHEEL)
-        delta_y = (double) GET_WHEEL_DELTA_WPARAM (msg->wParam) / (double) WHEEL_DELTA;
+        scroll_y = GET_WHEEL_DELTA_WPARAM (msg->wParam);
       else if (msg->message == WM_MOUSEHWHEEL)
-        delta_x = (double) GET_WHEEL_DELTA_WPARAM (msg->wParam) / (double) WHEEL_DELTA;
-      /* Positive delta scrolls up, not down,
-         see API documentation for WM_MOUSEWHEEL message.
-       */
-      delta_y *= -1.0;
+        scroll_x = GET_WHEEL_DELTA_WPARAM (msg->wParam);
+
+      accumulated_y += scroll_y;
+      accumulated_x += scroll_x;
 
       _gdk_device_virtual_set_active (_gdk_device_manager->core_pointer,
                                       _gdk_device_manager->system_pointer);
@@ -2727,34 +2729,68 @@ gdk_event_translate (MSG *msg,
                                     NULL,
                                     _gdk_win32_get_next_tick (msg->time),
                                     build_pointer_event_state (msg),
-                                    delta_x,
-                                    delta_y,
+                                    (double) scroll_x / (double) WHEEL_DELTA,
+                                    (double) -scroll_y / (double) WHEEL_DELTA,
                                     FALSE,
                                     GDK_SCROLL_UNIT_WHEEL);
 
-      /* Append the discrete version too */
-      direction = 0;
-      if (msg->message == WM_MOUSEWHEEL)
-       direction = (((short) HIWORD (msg->wParam)) > 0)
-                     ? GDK_SCROLL_UP
-                      : GDK_SCROLL_DOWN;
-      else if (msg->message == WM_MOUSEHWHEEL)
-       direction = (((short) HIWORD (msg->wParam)) > 0)
-                      ? GDK_SCROLL_RIGHT
-                      : GDK_SCROLL_LEFT;
-
-      event = gdk_scroll_event_new_discrete (window,
-                                             device_manager_win32->core_pointer,
-                                             NULL,
-                                             _gdk_win32_get_next_tick (msg->time),
-                                             build_pointer_event_state (msg),
-                                             direction,
-                                             TRUE);
-
       _gdk_win32_append_event (event);
 
+      while (accumulated_y / WHEEL_DELTA)
+        {
+          GdkScrollDirection direction;
+
+          if (accumulated_y > 0)
+            {
+              direction = GDK_SCROLL_UP;
+              accumulated_y -= WHEEL_DELTA;
+            }
+          else
+            {
+              direction = GDK_SCROLL_DOWN;
+              accumulated_y += WHEEL_DELTA;
+            }
+
+          event = gdk_scroll_event_new_discrete (window,
+                                                 device_manager_win32->core_pointer,
+                                                 NULL,
+                                                 _gdk_win32_get_next_tick (msg->time),
+                                                 build_pointer_event_state (msg),
+                                                 direction,
+                                                 TRUE);
+
+          _gdk_win32_append_event (event);
+        }
+
+      while (accumulated_x / WHEEL_DELTA)
+        {
+          GdkScrollDirection direction;
+
+          if (accumulated_x > 0)
+            {
+              direction = GDK_SCROLL_LEFT;
+              accumulated_x -= WHEEL_DELTA;
+            }
+          else
+            {
+              direction = GDK_SCROLL_RIGHT;
+              accumulated_x += WHEEL_DELTA;
+            }
+
+          event = gdk_scroll_event_new_discrete (window,
+                                                 device_manager_win32->core_pointer,
+                                                 NULL,
+                                                 _gdk_win32_get_next_tick (msg->time),
+                                                 build_pointer_event_state (msg),
+                                                 direction,
+                                                 TRUE);
+
+          _gdk_win32_append_event (event);
+        }
+
       return_val = TRUE;
-      break;
+    }
+    break;
 
      case WM_MOUSEACTIVATE:
        {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]