[PATCH] [synaptic] swipe actions based on the tree-fingers touch

Arkadiusz Bokowy (Arkq) arkadiusz.bokowy at gmail.com
Sun Nov 30 09:30:22 PST 2014


[PATCH] [synaptic] Swipe action based on the tree-fingers touch

When touchpad can report more then 2 active fingers, we can generate action
based on swipe gesture. For now it includes swipes to the left and to the
right. One button click event can be assigned to those actions, which by
default (internal driver default) is button 0 - swipes are disabled.

The most preferable button assignment is button 8 and 9 for to the left and
to the right swipes respectively. Such a configuration provides browser
history navigation (e.g. Firefox) with horizontal swipes.

Added Synaptic driver options:
* SwipeLeftButton
* SwipeRightButton
* SwipeThreshold

Signed-off-by: Arkadiusz Bokowy <arkadiusz.bokowy at gmail.com>
---
 include/synaptics-properties.h |  7 +++++
 man/synaptics.man              | 11 +++++++
 src/properties.c               | 29 +++++++++++++++++
 src/synaptics.c                | 71 ++++++++++++++++++++++++++++++++++++++++--
 src/synapticsstr.h             | 15 +++++++++
 tools/synclient.c              |  3 ++
 6 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/include/synaptics-properties.h b/include/synaptics-properties.h
index 32ab2e1..86b40ef 100644
--- a/include/synaptics-properties.h
+++ b/include/synaptics-properties.h
@@ -104,6 +104,13 @@
  * element. order: Finger 1, 2, 3 */
 #define SYNAPTICS_PROP_CLICK_ACTION "Synaptics Click Action"
 
+/* 8 bit, up to MAX_SWIPE values (see synaptics.h), 0 disables an
+ * element. order: Left, Right */
+#define SYNAPTICS_PROP_SWIPE_ACTION "Synaptics Swipe Action"
+
+/* 32 bit */
+#define SYNAPTICS_PROP_SWIPE_THRESHOLD "Synaptics Swipe Threshold"
+
 /* 8 bit (BOOL) */
 #define SYNAPTICS_PROP_CIRCULAR_SCROLLING "Synaptics Circular Scrolling"
 
diff --git a/man/synaptics.man b/man/synaptics.man
index 76756be..a3f695e 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -363,6 +363,17 @@ Left/Right/Top/BottomEdge parameters.
 .
 For circular touchpads. Property: "Synaptics Circular Pad"
 .TP
+.BI "Option \*qSwipeLeftButton\*q \*q" integer \*q
+Which mouse button is reported on a tree-finger swipe to the left. Property:
+"Synaptics Swipe Action"
+.TP
+.BI "Option \*qSwipeRightButton\*q \*q" integer \*q
+Which mouse button is reported on a tree-finger swipe to the right. Property:
+"Synaptics Swipe Action"
+.TP
+.BI "Option \*qSwipeThreshold\*q \*q" integer \*q
+Threshold for triggering swipe event. Property: "Synaptics Swipe Threshold"
+.TP
 .BI "Option \*qPalmDetect\*q \*q" boolean \*q
 If palm detection should be enabled.
 .
diff --git a/src/properties.c b/src/properties.c
index c776e6c..3405946 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -80,6 +80,8 @@ Atom prop_circscroll = 0;
 Atom prop_circscroll_dist = 0;
 Atom prop_circscroll_trigger = 0;
 Atom prop_circpad = 0;
+Atom prop_swipeaction = 0;
+Atom prop_swipethreshold = 0;
 Atom prop_palm = 0;
 Atom prop_palm_dim = 0;
 Atom prop_coastspeed = 0;
@@ -317,6 +319,14 @@ InitDeviceProperties(InputInfoPtr pInfo)
     prop_circpad =
         InitAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_PAD, 8, 1,
                  &para->circular_pad);
+
+    memcpy(values, para->swipe_action, MAX_SWIPE * sizeof(int));
+    prop_swipeaction =
+        InitAtom(pInfo->dev, SYNAPTICS_PROP_SWIPE_ACTION, 8, MAX_SWIPE, values);
+    prop_swipethreshold =
+        InitAtom(pInfo->dev, SYNAPTICS_PROP_SWIPE_THRESHOLD, 32, 1,
+                 &para->swipe_threshold);
+
     prop_palm =
         InitAtom(pInfo->dev, SYNAPTICS_PROP_PALM_DETECT, 8, 1,
                  &para->palm_detect);
@@ -694,6 +704,25 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
 
         para->circular_pad = *(BOOL *) prop->data;
     }
+    else if (property == prop_swipeaction) {
+        int i;
+        CARD8 *action;
+
+        if (prop->size > MAX_SWIPE || prop->format != 8 ||
+            prop->type != XA_INTEGER)
+            return BadMatch;
+
+        action = (CARD8 *) prop->data;
+
+        for (i = 0; i < MAX_SWIPE; i++)
+            para->swipe_action[i] = action[i];
+    }
+    else if (property == prop_swipethreshold) {
+        if (prop->size != 1 || prop->format != 32 || prop->type != XA_INTEGER)
+            return BadMatch;
+
+        para->swipe_threshold = *(INT32 *) 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 9807439..fc91ff9 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -573,6 +573,7 @@ set_default_parameters(InputInfoPtr pInfo)
     Bool vertTwoFingerScroll, horizTwoFingerScroll;
     int horizResolution = 1;
     int vertResolution = 1;
+    int swipeThreshold;
     int width, height, diag, range;
     int horizHyst, vertHyst;
     int middle_button_timeout;
@@ -641,6 +642,9 @@ set_default_parameters(InputInfoPtr pInfo)
     vertTwoFingerScroll = priv->has_double ? TRUE : FALSE;
     horizTwoFingerScroll = FALSE;
 
+    /* Calculate the minimal required swipe distance */
+    swipeThreshold = width * 0.15;
+
     /* Use resolution reported by hardware if available */
     if ((priv->resx > 0) && (priv->resy > 0)) {
         horizResolution = priv->resx;
@@ -734,6 +738,12 @@ set_default_parameters(InputInfoPtr pInfo)
         xf86SetBoolOption(opts, "CircularScrolling", FALSE);
     pars->circular_trigger = xf86SetIntOption(opts, "CircScrollTrigger", 0);
     pars->circular_pad = xf86SetBoolOption(opts, "CircularPad", FALSE);
+    pars->swipe_action[LEFT_SWIPE] =
+        xf86SetIntOption(opts, "SwipeLeftButton", 0);
+    pars->swipe_action[RIGHT_SWIPE] =
+        xf86SetIntOption(opts, "SwipeRightButton", 0);
+    pars->swipe_threshold =
+        xf86SetIntOption(opts, "SwipeThreshold", swipeThreshold);
     pars->palm_detect = xf86SetBoolOption(opts, "PalmDetect", FALSE);
     pars->palm_min_width = xf86SetIntOption(opts, "PalmMinWidth", palmMinWidth);
     pars->palm_min_z = xf86SetIntOption(opts, "PalmMinZ", palmMinZ);
@@ -1994,8 +2004,9 @@ HandleTapProcessing(SynapticsPrivate * priv, struct SynapticsHwState *hw,
     release = finger == FS_UNTOUCHED && priv->finger_state >= FS_TOUCHED;
     move = (finger >= FS_TOUCHED &&
             (priv->tap_max_fingers <=
-             ((priv->horiz_scroll_twofinger_on ||
-               priv->vert_scroll_twofinger_on) ? 2 : 1)) &&
+             (priv->swipe.threefinger_on ? 3 :
+              ((priv->horiz_scroll_twofinger_on ||
+                priv->vert_scroll_twofinger_on) ? 2 : 1))) &&
             (priv->prevFingers == hw->numFingers &&
              ((abs(hw->x - priv->touch_on.x) >= para->tap_move) ||
               (abs(hw->y - priv->touch_on.y) >= para->tap_move))));
@@ -2674,6 +2685,33 @@ HandleScrolling(SynapticsPrivate * priv, struct SynapticsHwState *hw,
     return delay;
 }
 
+static void
+HandleSwipe(SynapticsPrivate *priv, struct SynapticsHwState *hw, Bool finger)
+{
+    SynapticsParameters *para = &priv->synpara;
+
+    /* not enough fingers touched, clear swipe tracking */
+    if (!finger || hw->numFingers < 3) {
+        priv->swipe.threefinger_on = FALSE;
+        priv->swipe.posted = FALSE;
+        return;
+    }
+
+    if (priv->swipe.threefinger_on) {
+        /* swipe was activated, accumulate delta */
+        priv->swipe.delta_x += hw->x - priv->swipe.last_x;
+        priv->swipe.delta_y += hw->y - priv->swipe.last_y;
+    }
+    else {
+        priv->swipe.threefinger_on = hw->numFingers == 3;
+        priv->swipe.delta_x = 0;
+        priv->swipe.delta_y = 0;
+    }
+
+    priv->swipe.last_x = hw->x;
+    priv->swipe.last_y = hw->y;
+}
+
 /**
  * Check if any 2+ fingers are close enough together to assume this is a
  * ClickFinger action.
@@ -2974,6 +3012,29 @@ repeat_scrollbuttons(const InputInfoPtr pInfo,
     return delay;
 }
 
+static void
+post_swipe_events(const InputInfoPtr pInfo) {
+    SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
+    SynapticsParameters *para = &priv->synpara;
+
+    /* there is no need to go any further if those conditions are not met */
+    if (!priv->swipe.threefinger_on || priv->swipe.posted)
+      return;
+
+    if (para->swipe_action[LEFT_SWIPE] &&
+        priv->swipe.delta_x < -para->swipe_threshold) {
+        post_button_click(pInfo, para->swipe_action[LEFT_SWIPE]);
+        priv->swipe.posted = TRUE;
+        priv->swipe.delta_x = 0;
+    }
+    else if (para->swipe_action[RIGHT_SWIPE] &&
+        priv->swipe.delta_x > para->swipe_threshold) {
+        post_button_click(pInfo, para->swipe_action[RIGHT_SWIPE]);
+        priv->swipe.posted = TRUE;
+        priv->swipe.delta_x = 0;
+    }
+}
+
 /* Update the open slots and number of active touches */
 static void
 UpdateTouchState(InputInfoPtr pInfo, struct SynapticsHwState *hw)
@@ -3222,6 +3283,8 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
         if (timeleft > 0)
             delay = MIN(delay, timeleft);
 
+        HandleSwipe(priv, hw, (finger >= FS_TOUCHED));
+
         /*
          * Compensate for unequal x/y resolution. This needs to be done after
          * calculations that require unadjusted coordinates, for example edge
@@ -3292,6 +3355,10 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
         priv->scroll.last_millis = hw->millis;
     }
 
+    /* Process swipe events only in the active area */
+    if (inside_active_area)
+        post_swipe_events(pInfo);
+
     if (double_click) {
         post_button_click(pInfo, 1);
         post_button_click(pInfo, 1);
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 75f52d5..b1c74c1 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -83,6 +83,11 @@ enum ClickFingerEvent {
     MAX_CLICK
 };
 
+enum SwipeEvent {
+    LEFT_SWIPE = 0,             /* Swipe to the left, three fingers */
+    RIGHT_SWIPE,                /* Swipe to the right, three fingers */
+    MAX_SWIPE
+};
 
 typedef struct _SynapticsMoveHist {
     int x, y;
@@ -206,6 +211,8 @@ typedef struct _SynapticsParameters {
     int locked_drag_time;       /* timeout for locked drags */
     int tap_action[MAX_TAP];    /* Button to report on tap events */
     int click_action[MAX_CLICK];        /* Button to report on click with fingers */
+    int swipe_action[MAX_SWIPE];        /* Button to report on swipe action */
+    int swipe_threshold;        /* Threshold for swipe event */
     Bool circular_scrolling;    /* Enable circular scrolling */
     double scroll_dist_circ;    /* Scrolling angle radians */
     int circular_trigger;       /* Trigger area for circular scrolling */
@@ -263,6 +270,14 @@ struct _SynapticsPrivateRec {
         double coast_delta_y;   /* Accumulated vertical coast delta */
         int packets_this_scroll;        /* Events received for this scroll */
     } scroll;
+    struct {
+        int last_x;             /* last x-swipe position */
+        int last_y;             /* last y-swipe position */
+        double delta_x;         /* accumulated horiz swipe delta */
+        double delta_y;         /* accumulated vert swipe delta */
+        Bool posted;            /* indicate that event was posted */
+        Bool threefinger_on;    /* swipe event with three fingers */
+    } swipe;
     int count_packet_finger;    /* packet counter with finger on the touchpad */
     int button_delay_millis;    /* button delay for 3rd button emulation */
     Bool prev_up;               /* Previous up button value, for double click emulation */
diff --git a/tools/synclient.c b/tools/synclient.c
index ac31a66..7470793 100644
--- a/tools/synclient.c
+++ b/tools/synclient.c
@@ -122,6 +122,9 @@ static struct Parameter params[] = {
     {"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},
+    {"SwipeLeftButton",       PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 2},
+    {"SwipeRightButton",      PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 3},
+    {"SwipeThreshold",        PT_INT,    0, 10000, SYNAPTICS_PROP_SWIPE_THRESHOLD, 32, 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},
-- 
2.0.4


More information about the xorg-devel mailing list