[PATCH v2 28/28] Input: Add smooth-scrolling support to GetPointerEvents

Daniel Stone daniel at fooishbar.org
Thu Jun 9 10:17:36 PDT 2011


For scroll wheel support, we used to send buttons 4/5 and 6/7 for
horizontal/vertical positive/negative scroll events.  For touchpads, we
really want more fine-grained scroll values.  GetPointerEvents now
accepts both old-school scroll button presses, and new-style scroll axis
events, while emitting both types of events to support both old and new
clients.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
 dix/devices.c      |    8 ++++
 dix/getevents.c    |  108 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 include/inputstr.h |    2 +
 3 files changed, 114 insertions(+), 4 deletions(-)

v2: Cache horiz/vert scroll axes in DeviceIntRec, rather than scanning for
    them on every GPE.  Changed an ungodly series of if branches testing
    for legacy button events to a much cleaner switch.  More incisive comments.
    Removed duplicate XI2.h include.

    Outstanding gotchas: We don't send x/y with the button events, and the
    scroll delta currently accumulates until it hits a magnitude of 1.0.
    Probably need to clean up the button -> axis -> button conversion
    further.

diff --git a/dix/devices.c b/dix/devices.c
index 0ccf252..3801913 100644
--- a/dix/devices.c
+++ b/dix/devices.c
@@ -1261,6 +1261,8 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
 {
     int i;
     ValuatorClassPtr valc;
+    Atom h_scroll_label = XIGetKnownProperty(AXIS_LABEL_PROP_REL_HSCROLL);
+    Atom v_scroll_label = XIGetKnownProperty(AXIS_LABEL_PROP_REL_VSCROLL);
 
     if (!dev)
         return FALSE;
@@ -1281,6 +1283,8 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
     valc->motion = NULL;
     valc->first_motion = 0;
     valc->last_motion = 0;
+    valc->h_scroll_axis = -1;
+    valc->v_scroll_axis = -1;
 
     valc->numMotionEvents = numMotionEvents;
     valc->motionHintWindow = NullWindow;
@@ -1295,6 +1299,10 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels,
     for (i=0; i<numAxes; i++) {
         InitValuatorAxisStruct(dev, i, labels[i], NO_AXIS_LIMITS, NO_AXIS_LIMITS,
                                0, 0, 0, mode);
+        if (labels[i] == h_scroll_label)
+            valc->h_scroll_axis = i;
+        else if (labels[i] == v_scroll_label)
+            valc->v_scroll_axis = i;
 	valc->axisVal[i]=0;
     }
 
diff --git a/dix/getevents.c b/dix/getevents.c
index 03c7938..8788ac6 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -2,6 +2,7 @@
  * Copyright © 2006 Nokia Corporation
  * Copyright © 2006-2007 Daniel Stone
  * Copyright © 2008 Red Hat, Inc.
+ * Copyright © 2011 The Chromium Authors
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -65,6 +66,7 @@
 #include "exevents.h"
 #include "extnsionst.h"
 #include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
+#include "xserver-properties.h"
 
 /* Number of motion history events to store. */
 #define MOTION_HISTORY_SIZE 256
@@ -622,8 +624,10 @@ GetMaximumEventsNum(void) {
     /* One raw event
      * One device event
      * One possible device changed event
+     * Lots of possible separate button scroll events (horiz + vert)
+     * Lots of possible separate raw button scroll events (horiz + vert)
      */
-    return 3;
+    return 51;
 }
 
 
@@ -1208,7 +1212,10 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
                  int buttons, int flags, const ValuatorMask *mask_in)
 {
     CARD32 ms = GetTimeInMillis();
-    int num_events = 0;
+    int num_events = 0, nev_tmp;
+    int h_scroll_axis = pDev->valuator->h_scroll_axis;
+    int v_scroll_axis = pDev->valuator->v_scroll_axis;
+    ValuatorMask mask;
 
     /* refuse events from disabled devices */
     if (!pDev->enabled)
@@ -1219,8 +1226,101 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 
     events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT,
                               &num_events);
-    num_events += fill_pointer_events(events, pDev, type, buttons, ms, flags,
-                                      mask_in);
+
+    valuator_mask_copy(&mask, mask_in);
+
+    /* Turn a scroll button press into a smooth-scrolling event if necessary. */
+    if (type == ButtonPress)
+    {
+        double val, adj;
+        int axis;
+
+        switch (buttons) {
+        case 4:
+            adj = 1.0;
+            axis = v_scroll_axis;
+            break;
+        case 5:
+            adj = -1.0;
+            axis = v_scroll_axis;
+            break;
+        case 6:
+            adj = 1.0;
+            axis = h_scroll_axis;
+            break;
+        case 7:
+            adj = -1.0;
+            axis = h_scroll_axis;
+            break;
+        default:
+            adj = 0.0;
+            axis = -1;
+            break;
+        }
+
+        if (adj != 0.0 && axis != -1)
+        {
+            val = valuator_mask_get_double(&mask, axis) + adj;
+            valuator_mask_set_double(&mask, axis, val);
+            type = MotionNotify;
+            buttons = 0;
+        }
+    }
+
+    /* First fill out the original event set, with smooth-scrolling axes. */
+    nev_tmp = fill_pointer_events(events, pDev, type, buttons, ms, flags,
+                                  &mask);
+    events += nev_tmp;
+    num_events += nev_tmp;
+
+    /* Now turn the smooth-scrolling axes back into emulated button presses
+     * for legacy clients. */
+    while ((v_scroll_axis != -1 &&
+            fabs(pDev->last.valuators[v_scroll_axis]) >= 1.0) ||
+           (h_scroll_axis != -1 &&
+            fabs(pDev->last.valuators[h_scroll_axis]) >= 1.0))
+    {
+        int b = 0;
+
+        /* fill_pointer_events() generates four events: one normal and one raw
+         * event each for the emulated button press and release both. */
+        if (num_events + 4 >= GetMaximumEventsNum())
+            break;
+
+        if (v_scroll_axis != -1 && pDev->last.valuators[v_scroll_axis] <= -1.0)
+        {
+            pDev->last.valuators[v_scroll_axis] += 1.0;
+            b = 4;
+        }
+        else if (v_scroll_axis != -1 &&
+                 pDev->last.valuators[v_scroll_axis] >= 1.0)
+        {
+            pDev->last.valuators[v_scroll_axis] -= 1.0;
+            b = 5;
+        }
+        else if (h_scroll_axis != -1 &&
+                 pDev->last.valuators[h_scroll_axis] <= -1.0)
+        {
+            pDev->last.valuators[h_scroll_axis] += 1.0;
+            b = 6;
+        }
+        else if (h_scroll_axis != -1 &&
+                 pDev->last.valuators[h_scroll_axis] >= 1.0)
+        {
+            pDev->last.valuators[h_scroll_axis] -= 1.0;
+            b = 7;
+        }
+
+        nev_tmp = fill_pointer_events(events, pDev, ButtonPress, b, ms,
+                                      POINTER_EMULATED, NULL);
+        events += nev_tmp;
+        num_events += nev_tmp;
+        nev_tmp = fill_pointer_events(events, pDev, ButtonRelease, b, ms,
+                                      POINTER_EMULATED, NULL);
+        events += nev_tmp;
+        num_events += nev_tmp;
+    }
+
     return num_events;
 }
 
diff --git a/include/inputstr.h b/include/inputstr.h
index 11d69e7..d905fff 100644
--- a/include/inputstr.h
+++ b/include/inputstr.h
@@ -283,6 +283,8 @@ typedef struct _ValuatorClassRec {
     unsigned short	  numAxes;
     double		  *axisVal; /* always absolute, but device-coord system */
     ValuatorAccelerationRec	accelScheme;
+    int                   h_scroll_axis; /* horiz smooth-scrolling axis */
+    int                   v_scroll_axis; /* vert smooth-scrolling axis */
 } ValuatorClassRec;
 
 typedef struct _ButtonClassRec {
-- 
1.7.5.3



More information about the xorg-devel mailing list