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

Peter Hutterer peter.hutterer at who-t.net
Wed Jun 22 20:35:59 PDT 2011


On Thu, Jun 09, 2011 at 06:17:36PM +0100, Daniel Stone wrote:
> 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;
>  }

every time I see 95 lines being added to one function something in me diese
a little.
you don't seem to be accessing anything but v_scroll_axis and h_scroll_axis
from the local stack anyway, why not make the while loop a:
    int emulate_scroll_button_events(events, device, hscroll, vscroll)

Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net> for the lot though
(well, the unreviewed ones)

Cheers,
  Peter

>  
> 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