Ken Thomases : winemac: Add the ability to disable high-resolution scrolling.

Alexandre Julliard julliard at winehq.org
Thu May 15 15:14:28 CDT 2014


Module: wine
Branch: master
Commit: 451915100a61a2e5f3e848d0c6ab7fb477b08d56
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=451915100a61a2e5f3e848d0c6ab7fb477b08d56

Author: Ken Thomases <ken at codeweavers.com>
Date:   Wed May 14 20:15:35 2014 -0500

winemac: Add the ability to disable high-resolution scrolling.

The Mac driver can generate scroll wheel events with values which are not integral
multiples of WHEEL_DELTA.  Apps should handle that by scrolling a corresponding
non-integral multiple of what they'd do for a WHEEL_DELTA-valued scroll or, if
they can't, then at least accumulate scroll distance until its magnitude exceeds
WHEEL_DELTA and do a "chunky" scroll.  However, many apps don't do that properly.
They may scroll way too far/fast or even in the opposite direction.

If the registry setting UsePreciseScrolling is set to "n", the Mac driver will do
that accumulation and chunking itself to work around such broken app behavior.

---

 dlls/winemac.drv/cocoa_app.h    |    3 ++
 dlls/winemac.drv/cocoa_app.m    |   81 ++++++++++++++++++++++++++++++---------
 dlls/winemac.drv/macdrv_cocoa.h |    1 +
 dlls/winemac.drv/macdrv_main.c  |    4 ++
 4 files changed, 70 insertions(+), 19 deletions(-)

diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h
index 0f8926d..fc6c1ec 100644
--- a/dlls/winemac.drv/cocoa_app.h
+++ b/dlls/winemac.drv/cocoa_app.h
@@ -66,6 +66,9 @@ enum {
     double mouseMoveDeltaX, mouseMoveDeltaY;
     NSUInteger unmatchedMouseDowns;
 
+    NSTimeInterval lastScrollTime;
+    double accumScrollX, accumScrollY;
+
     NSMutableDictionary* originalDisplayModes;
     NSMutableDictionary* latentDisplayModes;
     BOOL displaysCapturedForFullscreen;
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m
index e5594d1..d454513 100644
--- a/dlls/winemac.drv/cocoa_app.m
+++ b/dlls/winemac.drv/cocoa_app.m
@@ -1725,7 +1725,7 @@ int macdrv_err_on;
             if (process)
             {
                 macdrv_event* event;
-                CGFloat x, y;
+                double x, y;
                 BOOL continuous = FALSE;
 
                 event = macdrv_create_event(MOUSE_SCROLL, window);
@@ -1768,26 +1768,69 @@ int macdrv_err_on;
                 /* The x,y values so far are in pixels.  Win32 expects to receive some
                    fraction of WHEEL_DELTA == 120.  By my estimation, that's roughly
                    6 times the pixel value. */
-                event->mouse_scroll.x_scroll = 6 * x;
-                event->mouse_scroll.y_scroll = 6 * y;
+                x *= 6;
+                y *= 6;
 
-                if (!continuous)
+                if (use_precise_scrolling)
                 {
-                    /* For non-continuous "clicky" wheels, if there was any motion, make
-                       sure there was at least WHEEL_DELTA motion.  This is so, at slow
-                       speeds where the system's acceleration curve is actually reducing the
-                       scroll distance, the user is sure to get some action out of each click.
-                       For example, this is important for rotating though weapons in a
-                       first-person shooter. */
-                    if (0 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 120)
-                        event->mouse_scroll.x_scroll = 120;
-                    else if (-120 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 0)
-                        event->mouse_scroll.x_scroll = -120;
-
-                    if (0 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 120)
-                        event->mouse_scroll.y_scroll = 120;
-                    else if (-120 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 0)
-                        event->mouse_scroll.y_scroll = -120;
+                    event->mouse_scroll.x_scroll = x;
+                    event->mouse_scroll.y_scroll = y;
+
+                    if (!continuous)
+                    {
+                        /* For non-continuous "clicky" wheels, if there was any motion, make
+                           sure there was at least WHEEL_DELTA motion.  This is so, at slow
+                           speeds where the system's acceleration curve is actually reducing the
+                           scroll distance, the user is sure to get some action out of each click.
+                           For example, this is important for rotating though weapons in a
+                           first-person shooter. */
+                        if (0 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 120)
+                            event->mouse_scroll.x_scroll = 120;
+                        else if (-120 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 0)
+                            event->mouse_scroll.x_scroll = -120;
+
+                        if (0 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 120)
+                            event->mouse_scroll.y_scroll = 120;
+                        else if (-120 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 0)
+                            event->mouse_scroll.y_scroll = -120;
+                    }
+                }
+                else
+                {
+                    /* If it's been a while since the last scroll event or if the scrolling has
+                       reversed direction, reset the accumulated scroll value. */
+                    if ([theEvent timestamp] - lastScrollTime > 1)
+                        accumScrollX = accumScrollY = 0;
+                    else
+                    {
+                        /* The accumulated scroll value is in the opposite direction/sign of the last
+                           scroll.  That's because it's the "debt" resulting from over-scrolling in
+                           that direction.  We accumulate by adding in the scroll amount and then, if
+                           it has the same sign as the scroll value, we subtract any whole or partial
+                           WHEEL_DELTAs, leaving it 0 or the opposite sign.  So, the user switched
+                           scroll direction if the accumulated debt and the new scroll value have the
+                           same sign. */
+                        if ((accumScrollX < 0 && x < 0) || (accumScrollX > 0 && x > 0))
+                            accumScrollX = 0;
+                        if ((accumScrollY < 0 && y < 0) || (accumScrollY > 0 && y > 0))
+                            accumScrollY = 0;
+                    }
+                    lastScrollTime = [theEvent timestamp];
+
+                    accumScrollX += x;
+                    accumScrollY += y;
+
+                    if (accumScrollX > 0 && x > 0)
+                        event->mouse_scroll.x_scroll = 120 * ceil(accumScrollX / 120);
+                    if (accumScrollX < 0 && x < 0)
+                        event->mouse_scroll.x_scroll = 120 * -ceil(-accumScrollX / 120);
+                    if (accumScrollY > 0 && y > 0)
+                        event->mouse_scroll.y_scroll = 120 * ceil(accumScrollY / 120);
+                    if (accumScrollY < 0 && y < 0)
+                        event->mouse_scroll.y_scroll = 120 * -ceil(-accumScrollY / 120);
+
+                    accumScrollX -= event->mouse_scroll.x_scroll;
+                    accumScrollY -= event->mouse_scroll.y_scroll;
                 }
 
                 if (event->mouse_scroll.x_scroll || event->mouse_scroll.y_scroll)
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h
index d3d3ffc..30b6b64 100644
--- a/dlls/winemac.drv/macdrv_cocoa.h
+++ b/dlls/winemac.drv/macdrv_cocoa.h
@@ -148,6 +148,7 @@ extern int left_option_is_alt DECLSPEC_HIDDEN;
 extern int right_option_is_alt DECLSPEC_HIDDEN;
 extern int allow_immovable_windows DECLSPEC_HIDDEN;
 extern int cursor_clipping_locks_windows DECLSPEC_HIDDEN;
+extern int use_precise_scrolling DECLSPEC_HIDDEN;
 
 extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN;
 extern void macdrv_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN;
diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c
index 300b1a7..38352a8 100644
--- a/dlls/winemac.drv/macdrv_main.c
+++ b/dlls/winemac.drv/macdrv_main.c
@@ -56,6 +56,7 @@ BOOL allow_software_rendering = FALSE;
 BOOL disable_window_decorations = FALSE;
 int allow_immovable_windows = TRUE;
 int cursor_clipping_locks_windows = TRUE;
+int use_precise_scrolling = TRUE;
 HMODULE macdrv_module = 0;
 
 
@@ -179,6 +180,9 @@ static void setup_options(void)
     if (!get_config_key(hkey, appkey, "CursorClippingLocksWindows", buffer, sizeof(buffer)))
         cursor_clipping_locks_windows = IS_OPTION_TRUE(buffer[0]);
 
+    if (!get_config_key(hkey, appkey, "UsePreciseScrolling", buffer, sizeof(buffer)))
+        use_precise_scrolling = IS_OPTION_TRUE(buffer[0]);
+
     if (appkey) RegCloseKey(appkey);
     if (hkey) RegCloseKey(hkey);
 }




More information about the wine-cvs mailing list