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

xserver-xorg-input-synaptics: Changes to 'upstream-unstable'



 configure.ac                   |    2 
 include/synaptics-properties.h |    3 
 man/synaptics.man              |   60 ++++++++++---
 src/properties.c               |   65 ++++++++++++++
 src/synaptics.c                |  181 ++++++++++++++++++++++++++++++++++++++++-
 src/synapticsstr.h             |   15 +++
 tools/synclient.c              |    8 +
 7 files changed, 317 insertions(+), 17 deletions(-)

New commits:
commit 8a5533aaa7e6e57bca7674de4cd25b3a18217d44
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Wed Mar 12 09:42:38 2014 +1000

    synaptics 1.7.4
    
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>

diff --git a/configure.ac b/configure.ac
index ea5c002..c41e6da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,7 +23,7 @@
 # Initialize Autoconf
 AC_PREREQ([2.60])
 AC_INIT([xf86-input-synaptics],
-        [1.7.3],
+        [1.7.4],
         [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
         [xf86-input-synaptics])
 AC_CONFIG_SRCDIR([Makefile.am])

commit c189854a688465c820d5ef5767e00b69394a1601
Author: Keith Packard <keithp@keithp.com>
Date:   Sat Feb 22 01:44:37 2014 -0800

    Close device if DeviceOnHook fails
    
    Signed-off-by: Keith Packard <keithp@keithp.com>
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
    (cherry picked from commit 22fe8bdc6668e78853768c62f4d1331114c7eca0)

diff --git a/src/synaptics.c b/src/synaptics.c
index 1c22873..0986e20 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -959,8 +959,10 @@ DeviceOn(DeviceIntPtr dev)
     }
 
     if (priv->proto_ops->DeviceOnHook &&
-        !priv->proto_ops->DeviceOnHook(pInfo, &priv->synpara))
+        !priv->proto_ops->DeviceOnHook(pInfo, &priv->synpara)) {
+        xf86CloseSerial(pInfo->fd);
         return !Success;
+    }
 
     priv->comm.buffer = XisbNew(pInfo->fd, INPUT_BUFFER_SIZE);
     if (!priv->comm.buffer) {

commit 503082bf17dfc4cb3d4b794ea514ac6f413c07f2
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Tue Feb 18 10:14:37 2014 +1000

    man: setting scroll deltas to 0 doesn't work (#75074)
    
    6d47d33 disallows a zero value for horizontal/vertical scroll deltas but the
    man page wasn't updated. We've added separate toggles to enable/disable
    scrolling a few years ago, setting the distance to 0 is not recommended.
    
    X.Org Bug 75074 <http://bugs.freedesktop.org/show_bug.cgi?id=75074>
    
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
    (cherry picked from commit 2ea76fad6545a712713de1a09965158805e83c55)

diff --git a/man/synaptics.man b/man/synaptics.man
index eb04eb2..7da7527 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -585,9 +585,6 @@ effect on scrolling speed.
 Scrolling speed is determined solely from the VertScrollDelta and
 HorizScrollDelta parameters.
 .
-To disable vertical or horizontal scrolling, set VertScrollDelta or
-HorizScrollDelta to zero.
-.
 To invert the direction of vertical or horizontal scrolling, set
 VertScrollDelta or HorizScrollDelta to a negative value.
 .

commit 0b70c76eab57822526585bbd11a1408bd115f26b
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Thu Feb 13 14:55:12 2014 +1000

    Revert "Drop circular pad support"
    
    This reverts commit 3b02e7fd81da4b100fb9ac32378f6d50f54cf0e2.
    
    Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
    
    Conflicts:
    	man/synaptics.man
    	src/synaptics.c
    
    Acked-by: Daniel Stone <daniel@fooishbar.org>
    (cherry picked from commit 4f543ce1d6ae9ca11086a3009d149505590584a8)

diff --git a/include/synaptics-properties.h b/include/synaptics-properties.h
index b717880..19bd2b2 100644
--- a/include/synaptics-properties.h
+++ b/include/synaptics-properties.h
@@ -116,6 +116,9 @@
 #define SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER "Synaptics Circular Scrolling Trigger"
 
 /* 8 bit (BOOL) */
+#define SYNAPTICS_PROP_CIRCULAR_PAD "Synaptics Circular Pad"
+
+/* 8 bit (BOOL) */
 #define SYNAPTICS_PROP_PALM_DETECT "Synaptics Palm Detection"
 
 /* 32 bit, 2 values, width, z */
diff --git a/man/synaptics.man b/man/synaptics.man
index 7652404..eb04eb2 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -351,6 +351,13 @@ l l.
 .TE
 Property: "Synaptics Circular Scrolling Trigger"
 .TP
+.BI "Option \*qCircularPad\*q \*q" boolean \*q
+.
+Instead of being a rectangle, the edge is the ellipse enclosed by the
+Left/Right/Top/BottomEdge parameters.
+.
+For circular touchpads. Property: "Synaptics Circular Pad"
+.TP
 .BI "Option \*qPalmDetect\*q \*q" boolean \*q
 If palm detection should be enabled.
 .
@@ -933,7 +940,6 @@ The following options are no longer part of the driver configuration:
 .TP
 .BI "Option \*qEdgeMotionUseAlways\*q \*q" boolean \*q
 .TP
-.BI "Option \*qCircularPad\*q \*q" boolean \*q
 
 .SH "AUTHORS"
 .LP
diff --git a/src/properties.c b/src/properties.c
index 0041544..886d8c2 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -295,6 +295,9 @@ InitDeviceProperties(InputInfoPtr pInfo)
     prop_circscroll_trigger =
         InitAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER, 8, 1,
                  &para->circular_trigger);
+    prop_circpad =
+        InitAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_PAD, 8, 1,
+                 &para->circular_pad);
     prop_palm =
         InitAtom(pInfo->dev, SYNAPTICS_PROP_PALM_DETECT, 8, 1,
                  &para->palm_detect);
@@ -666,6 +669,12 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
         para->circular_trigger = trigger;
 
     }
+    else if (property == prop_circpad) {
+        if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
+            return BadMatch;
+
+        para->circular_pad = *(BOOL *) prop->data;
+    }
     else if (property == prop_palm) {
         if (prop->size != 1 || prop->format != 8 || prop->type != XA_INTEGER)
             return BadMatch;
diff --git a/src/synaptics.c b/src/synaptics.c
index 493986d..1c22873 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -701,6 +701,7 @@ set_default_parameters(InputInfoPtr pInfo)
     pars->circular_scrolling =
         xf86SetBoolOption(opts, "CircularScrolling", FALSE);
     pars->circular_trigger = xf86SetIntOption(opts, "CircScrollTrigger", 0);
+    pars->circular_pad = xf86SetBoolOption(opts, "CircularPad", FALSE);
     pars->palm_detect = xf86SetBoolOption(opts, "PalmDetect", FALSE);
     pars->palm_min_width = xf86SetIntOption(opts, "PalmMinWidth", palmMinWidth);
     pars->palm_min_z = xf86SetIntOption(opts, "PalmMinZ", palmMinZ);
@@ -1328,6 +1329,32 @@ DeviceInit(DeviceIntPtr dev)
     return !Success;
 }
 
+/*
+ * Convert from absolute X/Y coordinates to a coordinate system where
+ * -1 corresponds to the left/upper edge and +1 corresponds to the
+ * right/lower edge.
+ */
+static void
+relative_coords(SynapticsPrivate * priv, int x, int y,
+                double *relX, double *relY)
+{
+    int minX = priv->synpara.left_edge;
+    int maxX = priv->synpara.right_edge;
+    int minY = priv->synpara.top_edge;
+    int maxY = priv->synpara.bottom_edge;
+    double xCenter = (minX + maxX) / 2.0;
+    double yCenter = (minY + maxY) / 2.0;
+
+    if ((maxX - xCenter > 0) && (maxY - yCenter > 0)) {
+        *relX = (x - xCenter) / (maxX - xCenter);
+        *relY = (y - yCenter) / (maxY - yCenter);
+    }
+    else {
+        *relX = 0;
+        *relY = 0;
+    }
+}
+
 /* return angle of point relative to center */
 static double
 angle(SynapticsPrivate * priv, int x, int y)
@@ -1352,10 +1379,38 @@ diffa(double a1, double a2)
 }
 
 static enum EdgeType
+circular_edge_detection(SynapticsPrivate * priv, int x, int y)
+{
+    enum EdgeType edge = 0;
+    double relX, relY, relR;
+
+    relative_coords(priv, x, y, &relX, &relY);
+    relR = SQR(relX) + SQR(relY);
+
+    if (relR > 1) {
+        /* we are outside the ellipse enclosed by the edge parameters */
+        if (relX > M_SQRT1_2)
+            edge |= RIGHT_EDGE;
+        else if (relX < -M_SQRT1_2)
+            edge |= LEFT_EDGE;
+
+        if (relY < -M_SQRT1_2)
+            edge |= TOP_EDGE;
+        else if (relY > M_SQRT1_2)
+            edge |= BOTTOM_EDGE;
+    }
+
+    return edge;
+}
+
+static enum EdgeType
 edge_detection(SynapticsPrivate * priv, int x, int y)
 {
     enum EdgeType edge = NO_EDGE;
 
+    if (priv->synpara.circular_pad)
+        return circular_edge_detection(priv, x, y);
+
     if (x > priv->synpara.right_edge)
         edge |= RIGHT_EDGE;
     else if (x < priv->synpara.left_edge)
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 3f66b14..54bc154 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -190,6 +190,7 @@ typedef struct _SynapticsParameters {
     Bool circular_scrolling;    /* Enable circular scrolling */
     double scroll_dist_circ;    /* Scrolling angle radians */
     int circular_trigger;       /* Trigger area for circular scrolling */
+    Bool circular_pad;          /* Edge has an oval or circular shape */
     Bool palm_detect;           /* Enable Palm Detection */
     int palm_min_width;         /* Palm detection width */
     int palm_min_z;             /* Palm detection depth */
diff --git a/tools/synclient.c b/tools/synclient.c
index f999311..ac31a66 100644
--- a/tools/synclient.c
+++ b/tools/synclient.c
@@ -121,6 +121,7 @@ static struct Parameter params[] = {
     {"CircularScrolling",     PT_BOOL,   0, 1,     SYNAPTICS_PROP_CIRCULAR_SCROLLING,	8,	0},
     {"CircScrollDelta",       PT_DOUBLE, .01, 3,   SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST,	0 /* float */,	0},
     {"CircScrollTrigger",     PT_INT,    0, 8,     SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER,	8,	0},
+    {"CircularPad",           PT_BOOL,   0, 1,     SYNAPTICS_PROP_CIRCULAR_PAD,	8,	0},
     {"PalmDetect",            PT_BOOL,   0, 1,     SYNAPTICS_PROP_PALM_DETECT,	8,	0},
     {"PalmMinWidth",          PT_INT,    0, 15,    SYNAPTICS_PROP_PALM_DIMENSIONS,	32,	0},
     {"PalmMinZ",              PT_INT,    0, 255,   SYNAPTICS_PROP_PALM_DIMENSIONS,	32,	1},

commit 1bd4ca3b5af6e5ee98c7d7f153fd4ee643c29e1a
Author: Peter Hutterer <peter.hutterer@who-t.net>
Date:   Fri Jan 17 08:24:35 2014 +1000

    Revert "Purge scrollbuttons (repeat)"
    
    This reverts commit 0903d99ada1755f11a2a5cbf89a345de896e18ec.
    
    Scroll buttons are still present in some modern devices, e.g. the Fujitsu
    Lifebook E782 and others in the series.
    
    Conflicts:
    	include/synaptics.h
    	man/synaptics.man
    	src/synaptics.c
    
    (cherry picked from commit e0069c154440305ece6def92a9813a9f8004b2fb)

diff --git a/man/synaptics.man b/man/synaptics.man
index 079a5f8..7652404 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -198,6 +198,41 @@ Default: 0.5 percent of the diagonal or (in case of evdev) the appropriate
 The minimum vertical HW distance required to generate motion events. See
 \fBHorizHysteresis\fR.
 .TP
+.BI "Option \*qUpDownScrolling\*q \*q" boolean \*q
+If on, the up/down buttons generate button 4/5 events.
+.
+If off, the up button generates a double click and the down button
+generates a button 2 event. This option is only available for touchpads with
+physical scroll buttons.
+Property: "Synaptics Button Scrolling"
+.TP
+.BI "Option \*qLeftRightScrolling\*q \*q" boolean \*q
+If on, the left/right buttons generate button 6/7 events.
+.
+If off, the left/right buttons both generate button 2 events.
+This option is only available for touchpads with physical scroll buttons.
+Property: "Synaptics Button Scrolling"
+.TP
+.BI "Option \*qUpDownScrollRepeat\*q \*q" boolean \*q
+If on, and the up/down buttons are used for scrolling
+(\fBUpDownScrolling\fR), these buttons will send auto-repeating 4/5 events,
+with the delay between repeats determined by \fBScrollButtonRepeat\fR.
+This option is only available for touchpads with physical scroll buttons.
+Property: "Synaptics Button Scrolling Repeat"
+.TP
+.BI "Option \*qLeftRightScrollRepeat\*q \*q" boolean \*q
+If on, and the left/right buttons are used for scrolling
+(\fBLeftRightScrolling\fR), these buttons will send auto-repeating 6/7 events,
+with the delay between repeats determined by \fBScrollButtonRepeat\fR.
+This option is only available for touchpads with physical scroll buttons.
+Property: "Synaptics Button Scrolling Repeat"
+.TP
+.BI "Option \*qScrollButtonRepeat\*q \*q" integer \*q
+The number of milliseconds between repeats of button events 4-7 from the
+up/down/left/right scroll buttons.
+This option is only available for touchpads with physical scroll buttons.
+Property: "Synaptics Button Scrolling Time"
+.TP
 .BI "Option \*qEmulateMidButtonTime\*q \*q" integer \*q
 Maximum time (in milliseconds) for middle button emulation. Property:
 "Synaptics Middle Button Timeout"
@@ -733,6 +768,10 @@ FLOAT, 4 values, min, max, accel, <deprecated>
 8 bit (BOOL), 2 values, updown, leftright.
 
 .TP 7
+.BI "Synaptics Button Scrolling Repeat"
+8 bit (BOOL), 2 values, updown, leftright.
+
+.TP 7
 .BI "Synaptics Button Scrolling Time"
 32 bit.
 
@@ -894,16 +933,6 @@ The following options are no longer part of the driver configuration:
 .TP
 .BI "Option \*qEdgeMotionUseAlways\*q \*q" boolean \*q
 .TP
-.BI "Option \*qUpDownScrolling\*q \*q" boolean \*q
-.TP
-.BI "Option \*qLeftRightScrolling\*q \*q" boolean \*q
-.TP
-.BI "Option \*qUpDownScrollRepeat\*q \*q" boolean \*q
-.TP
-.BI "Option \*qLeftRightScrollRepeat\*q \*q" boolean \*q
-.TP
-.BI "Option \*qScrollButtonRepeat\*q \*q" integer \*q
-.TP
 .BI "Option \*qCircularPad\*q \*q" boolean \*q
 
 .SH "AUTHORS"
diff --git a/src/properties.c b/src/properties.c
index 797f1da..0041544 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -68,6 +68,9 @@ Atom prop_speed = 0;
 Atom prop_edgemotion_pressure = 0;
 Atom prop_edgemotion_speed = 0;
 Atom prop_edgemotion_always = 0;
+Atom prop_buttonscroll = 0;
+Atom prop_buttonscroll_repeat = 0;
+Atom prop_buttonscroll_time = 0;
 Atom prop_off = 0;
 Atom prop_lockdrags = 0;
 Atom prop_lockdrags_time = 0;
@@ -247,6 +250,22 @@ InitDeviceProperties(InputInfoPtr pInfo)
     fvalues[3] = 0;
     prop_speed = InitFloatAtom(pInfo->dev, SYNAPTICS_PROP_SPEED, 4, fvalues);
 
+    if (priv->has_scrollbuttons) {
+        values[0] = para->updown_button_scrolling;
+        values[1] = para->leftright_button_scrolling;
+        prop_buttonscroll =
+            InitAtom(pInfo->dev, SYNAPTICS_PROP_BUTTONSCROLLING, 8, 2, values);
+
+        values[0] = para->updown_button_repeat;
+        values[1] = para->leftright_button_repeat;
+        prop_buttonscroll_repeat =
+            InitAtom(pInfo->dev, SYNAPTICS_PROP_BUTTONSCROLLING_REPEAT, 8, 2,
+                     values);
+        prop_buttonscroll_time =
+            InitAtom(pInfo->dev, SYNAPTICS_PROP_BUTTONSCROLLING_TIME, 32, 1,
+                     &para->scroll_button_repeat);
+    }
+
     prop_off =
         InitAtom(pInfo->dev, SYNAPTICS_PROP_OFF, 8, 1, &para->touchpad_off);
     prop_lockdrags =
@@ -518,6 +537,43 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
         para->max_speed = speed[1];
         para->accl = speed[2];
     }
+    else if (property == prop_buttonscroll) {
+        BOOL *scroll;
+
+        if (!priv->has_scrollbuttons)
+            return BadMatch;
+
+        if (prop->size != 2 || prop->format != 8 || prop->type != XA_INTEGER)
+            return BadMatch;
+
+        scroll = (BOOL *) prop->data;
+        para->updown_button_scrolling = scroll[0];
+        para->leftright_button_scrolling = scroll[1];
+
+    }
+    else if (property == prop_buttonscroll_repeat) {
+        BOOL *repeat;
+
+        if (!priv->has_scrollbuttons)
+            return BadMatch;
+
+        if (prop->size != 2 || prop->format != 8 || prop->type != XA_INTEGER)
+            return BadMatch;
+
+        repeat = (BOOL *) prop->data;
+        para->updown_button_repeat = repeat[0];
+        para->leftright_button_repeat = repeat[1];
+    }
+    else if (property == prop_buttonscroll_time) {
+        if (!priv->has_scrollbuttons)
+            return BadMatch;
+
+        if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+            return BadMatch;
+
+        para->scroll_button_repeat = *(INT32 *) prop->data;
+
+    }
     else if (property == prop_off) {
         CARD8 off;
 
diff --git a/src/synaptics.c b/src/synaptics.c
index e391a98..493986d 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -669,6 +669,20 @@ set_default_parameters(InputInfoPtr pInfo)
     pars->scroll_twofinger_horiz =
         xf86SetBoolOption(opts, "HorizTwoFingerScroll", horizTwoFingerScroll);
     pars->touchpad_off = xf86SetIntOption(opts, "TouchpadOff", TOUCHPAD_ON);
+
+    if (priv->has_scrollbuttons) {
+        pars->updown_button_scrolling =
+            xf86SetBoolOption(opts, "UpDownScrolling", TRUE);
+        pars->leftright_button_scrolling =
+            xf86SetBoolOption(opts, "LeftRightScrolling", TRUE);
+        pars->updown_button_repeat =
+            xf86SetBoolOption(opts, "UpDownScrollRepeat", TRUE);
+        pars->leftright_button_repeat =
+            xf86SetBoolOption(opts, "LeftRightScrollRepeat", TRUE);
+    }
+    pars->scroll_button_repeat =
+        xf86SetIntOption(opts, "ScrollButtonRepeat", 100);
+
     pars->locked_drags = xf86SetBoolOption(opts, "LockedDrags", FALSE);
     pars->locked_drag_time = xf86SetIntOption(opts, "LockedDragTimeout", 5000);
     pars->tap_action[RT_TAP] = xf86SetIntOption(opts, "RTCornerButton", 0);
@@ -818,6 +832,8 @@ SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
     xf86ErrorFVerb(6, "port opened successfully\n");
 
     /* initialize variables */
+    priv->repeatButtons = 0;
+    priv->nextRepeat = 0;
     priv->count_packet_finger = 0;
     priv->tap_state = TS_START;
     priv->tap_button = 0;
@@ -995,6 +1011,7 @@ SynapticsReset(SynapticsPrivate * priv)
     priv->circ_scroll_on = FALSE;
     priv->circ_scroll_vert = FALSE;
     priv->mid_emu_state = MBE_OFF;
+    priv->nextRepeat = 0;
     priv->lastButtons = 0;
     priv->prev_z = 0;
     priv->prevFingers = 0;
@@ -2555,6 +2572,46 @@ handle_clickfinger(SynapticsPrivate * priv, struct SynapticsHwState *hw)
     }
 }
 
+/* Adjust the hardware state according to the extra buttons (if the touchpad
+ * has any and not many touchpads do these days). These buttons are up/down
+ * tilt buttons and/or left/right buttons that then map into a specific
+ * function (or scrolling into).
+ */
+static Bool
+adjust_state_from_scrollbuttons(const InputInfoPtr pInfo,
+                                struct SynapticsHwState *hw)
+{
+    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+    SynapticsParameters *para = &priv->synpara;
+    Bool double_click = FALSE;
+
+    if (!para->updown_button_scrolling) {
+        if (hw->down) {         /* map down button to middle button */
+            hw->middle = TRUE;
+        }
+
+        if (hw->up) {           /* up button generates double click */
+            if (!priv->prev_up)
+                double_click = TRUE;
+        }
+        priv->prev_up = hw->up;
+
+        /* reset up/down button events */
+        hw->up = hw->down = FALSE;
+    }
+
+    /* Left/right button scrolling, or middle clicks */
+    if (!para->leftright_button_scrolling) {
+        if (hw->multi[2] || hw->multi[3])
+            hw->middle = TRUE;
+
+        /* reset left/right button events */
+        hw->multi[2] = hw->multi[3] = FALSE;
+    }
+
+    return double_click;
+}
+
 static void
 update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw,
                        struct SynapticsHwState *old, CARD32 now, int *delay)
@@ -2634,6 +2691,66 @@ post_scroll_events(const InputInfoPtr pInfo)
         xf86PostMotionEventM(pInfo->dev, FALSE, priv->scroll_events_mask);
 }
 
+static inline int
+repeat_scrollbuttons(const InputInfoPtr pInfo,
+                     const struct SynapticsHwState *hw,
+                     int buttons, CARD32 now, int delay)
+{
+    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+    SynapticsParameters *para = &priv->synpara;
+    int repeat_delay, timeleft;
+    int rep_buttons = 0;
+
+    if (para->updown_button_repeat)
+        rep_buttons |= (1 << (4 - 1)) | (1 << (5 - 1));
+    if (para->leftright_button_repeat)
+        rep_buttons |= (1 << (6 - 1)) | (1 << (7 - 1));
+
+    /* Handle auto repeat buttons */
+    repeat_delay = clamp(para->scroll_button_repeat, SBR_MIN, SBR_MAX);
+    if (((hw->up || hw->down) && para->updown_button_repeat &&
+         para->updown_button_scrolling) ||
+        ((hw->multi[2] || hw->multi[3]) && para->leftright_button_repeat &&
+         para->leftright_button_scrolling)) {
+        priv->repeatButtons = buttons & rep_buttons;
+        if (!priv->nextRepeat) {
+            priv->nextRepeat = now + repeat_delay * 2;
+        }
+    }
+    else {
+        priv->repeatButtons = 0;
+        priv->nextRepeat = 0;
+    }
+
+    if (priv->repeatButtons) {
+        timeleft = TIME_DIFF(priv->nextRepeat, now);
+        if (timeleft > 0)
+            delay = MIN(delay, timeleft);
+        if (timeleft <= 0) {
+            int change, id;
+
+            change = priv->repeatButtons;
+            while (change) {
+                id = ffs(change);
+                change &= ~(1 << (id - 1));
+                if (id == 4)
+                    priv->scroll.delta_y -= para->scroll_dist_vert;
+                else if (id == 5)
+                    priv->scroll.delta_y += para->scroll_dist_vert;
+                else if (id == 6)
+                    priv->scroll.delta_x -= para->scroll_dist_horiz;
+                else if (id == 7)
+                    priv->scroll.delta_x += para->scroll_dist_horiz;
+            }
+
+            priv->nextRepeat = now + repeat_delay;
+            delay = MIN(delay, repeat_delay);
+        }
+    }
+
+    return delay;
+}
+
 /* Update the open slots and number of active touches */
 static void
 UpdateTouchState(InputInfoPtr pInfo, struct SynapticsHwState *hw)
@@ -2830,6 +2947,8 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
 
     /* these two just update hw->left, right, etc. */
     update_hw_button_state(pInfo, hw, priv->old_hw_state, now, &delay);
+    if (priv->has_scrollbuttons)
+        double_click = adjust_state_from_scrollbuttons(pInfo, hw);
 
     /* now we know that these _coordinates_ aren't in the area.
        invalid are: x, y, z, numFingers, fingerWidth
@@ -2921,6 +3040,9 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
                             0, 0);
     }
 
+    if (priv->has_scrollbuttons)
+        delay = repeat_scrollbuttons(pInfo, hw, buttons, now, delay);
+
     /* Process scroll events only if coordinates are
      * in the Synaptics Area
      */
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 3d6f756..3f66b14 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -55,6 +55,10 @@
 #define SYNAPTICS_MAX_TOUCHES	10
 #define SYN_MAX_BUTTONS 12      /* Max number of mouse buttons */
 
+/* Minimum and maximum values for scroll_button_repeat */
+#define SBR_MIN 10
+#define SBR_MAX 1000
+
 enum OffState {
     TOUCHPAD_ON = 0,
     TOUCHPAD_OFF = 1,
@@ -168,6 +172,12 @@ typedef struct _SynapticsParameters {
     Bool scroll_twofinger_horiz;        /* Enable/disable horizontal two-finger scrolling */
     double min_speed, max_speed, accl;  /* movement parameters */
 
+    Bool updown_button_scrolling;       /* Up/Down-Button scrolling or middle/double-click */
+    Bool leftright_button_scrolling;    /* Left/right-button scrolling, or two lots of middle button */
+    Bool updown_button_repeat;  /* If up/down button being used to scroll, auto-repeat? */
+    Bool leftright_button_repeat;       /* If left/right button being used to scroll, auto-repeat? */
+    int scroll_button_repeat;   /* time, in milliseconds, between scroll events being
+                                 * sent when holding down scroll buttons */
     int touchpad_off;           /* Switches the touchpad off
                                  * 0 : Not off
                                  * 1 : Off
@@ -209,7 +219,7 @@ struct _SynapticsPrivateRec {
 
     const char *device;         /* device node */
     CARD32 timer_time;          /* when timer last fired */
-    OsTimerPtr timer;           /* for tap processing, etc */
+    OsTimerPtr timer;           /* for up/down-button repeat, tap processing, etc */
 
     struct CommData comm;
 
@@ -254,6 +264,8 @@ struct _SynapticsPrivateRec {
                                    False: Generate horizontal events */
     double frac_x, frac_y;      /* absolute -> relative fraction */
     enum MidButtonEmulation mid_emu_state;      /* emulated 3rd button */
+    int repeatButtons;          /* buttons for repeat */
+    int nextRepeat;             /* Time when to trigger next auto repeat event */
     int lastButtons;            /* last state of the buttons */
     int prev_z;                 /* previous z value, for palm detection */
     int prevFingers;            /* previous numFingers, for transition detection */
diff --git a/tools/synclient.c b/tools/synclient.c
index bd7cb61..f999311 100644
--- a/tools/synclient.c
+++ b/tools/synclient.c
@@ -50,6 +50,8 @@
 #endif
 
 #define SYN_MAX_BUTTONS 12
+#define SBR_MIN 10
+#define SBR_MAX 1000
 
 union flong {                   /* Xlibs 64-bit property handling madness */
     long l;
@@ -98,6 +100,11 @@ static struct Parameter params[] = {
     {"MinSpeed",              PT_DOUBLE, 0, 255.0,   SYNAPTICS_PROP_SPEED,	0, /*float */	0},
     {"MaxSpeed",              PT_DOUBLE, 0, 255.0,   SYNAPTICS_PROP_SPEED,	0, /*float */	1},
     {"AccelFactor",           PT_DOUBLE, 0, 1.0,   SYNAPTICS_PROP_SPEED,	0, /*float */	2},
+    {"UpDownScrolling",       PT_BOOL,   0, 1,     SYNAPTICS_PROP_BUTTONSCROLLING,  8,	0},
+    {"LeftRightScrolling",    PT_BOOL,   0, 1,     SYNAPTICS_PROP_BUTTONSCROLLING,  8,	1},
+    {"UpDownScrollRepeat",    PT_BOOL,   0, 1,     SYNAPTICS_PROP_BUTTONSCROLLING_REPEAT,   8,	0},
+    {"LeftRightScrollRepeat", PT_BOOL,   0, 1,     SYNAPTICS_PROP_BUTTONSCROLLING_REPEAT,   8,	1},
+    {"ScrollButtonRepeat",    PT_INT,    SBR_MIN , SBR_MAX, SYNAPTICS_PROP_BUTTONSCROLLING_TIME, 32,	0},
     {"TouchpadOff",           PT_INT,    0, 2,     SYNAPTICS_PROP_OFF,		8,	0},
     {"LockedDrags",           PT_BOOL,   0, 1,     SYNAPTICS_PROP_LOCKED_DRAGS,	8,	0},
     {"LockedDragTimeout",     PT_INT,    0, 30000, SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT,	32,	0},


Reply to: