[PATCH] Feature: synaptic three-finger swipe action

Gabriele Mazzotta gabriele.mzt at gmail.com
Sun Aug 17 05:14:36 PDT 2014


> When touchpad can report more then 2 active fingers, we can generate
> action based on swipe gesture. It includes upward, downward, to the
> left and to the right swipes. To all of those gestures can be assigned
> one button event. By default (internal driver default) swipes are
> disabled (assigned button 0). The swipe length (hand displacement)
> required for triggering button event can be set independently for
> horizontal and vertical movement. There is also possibility for
> triggering repeatable events during swipe handling, however it is
> disabled by default.
> 
> The most preferable button assignment is button 8, 9, 10 and 11 for to
> the left, to the right, upward and downward swipes respectively. Such a
> configuration provides browser history navigation (e.g. Firefox) with
> horizontal swipes. Button 10 and 11 are not used, though.
> 
> Added Synaptic driver options:
> * SwipeUpButton, SwipeDownButton, SwipeLeftButton, SwipeRightButton
> * HorizSwipeThreshold, VertSwipeThreshold
> * SingleSwipe
> 
> This changes was developed on Samsung NP530U3C with ETPS/2 Elantech
> Touchpad, which can report up to three-finger touch. Patch is generated
> for driver version 1.7.1 (which is marked as stable in Gentoo linux
> distribution). If it is required I can try to test this patch for
> latest master commit, however as for now I didn't want to break my box
> by switching to the unstable (as marked by Gentoo portage team) driver
> version.

Hi,

I've been using this patch for quite a while, thanks for it.

I noticed that there's partial support to four-finger gestures. Since my 
touchpad can track four fingers (five actually), I decided to complete the code.

This is a squashed commit with all the changes I made (it depends on
http://lists.x.org/archives/xorg-devel/2014-August/043571.html)

---
 src/eventcomm.c    |  8 +++++-
 src/properties.c   |  8 +++---
 src/synaptics.c    | 72 ++++++++++++++++++++++++++++++++++--------------------
 src/synapticsstr.h |  4 +--
 src/synproto.h     |  1 +
 tools/synclient.c  | 12 ++++++---
 6 files changed, 69 insertions(+), 36 deletions(-)

diff --git a/src/eventcomm.c b/src/eventcomm.c
index de17841..35a8b91 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -647,6 +647,8 @@ count_fingers(InputInfoPtr pInfo, const struct CommData *comm)
         fingers = 2;
     else if (comm->threeFingers)
         fingers = 3;
+    else if (comm->fourFingers)
+        fingers = 4;
 
     if (priv->has_touch && proto_data->num_touches > fingers)
         fingers = proto_data->num_touches;
@@ -678,7 +680,8 @@ EventReadHwState(InputInfoPtr pInfo,
     /* Reset cumulative values if buttons were not previously pressed and no
      * two-finger scrolling is ongoing, or no finger was previously present. */
     if (((!hw->left && !hw->right && !hw->middle) &&
-        !(priv->vert_scroll_twofinger_on || priv->vert_scroll_twofinger_on)) ||
+        !(priv->vert_scroll_twofinger_on || priv->horiz_scroll_twofinger_on ||
+        priv->swipe.threefinger_on || priv->swipe.fourfinger_on)) ||
         hw->z < para->finger_low) {
         hw->cumulative_dx = hw->x;
         hw->cumulative_dy = hw->y;
@@ -747,6 +750,9 @@ EventReadHwState(InputInfoPtr pInfo,
             case BTN_TOOL_TRIPLETAP:
                 comm->threeFingers = v;
                 break;
+            case BTN_TOOL_QUADTAP:
+                comm->fourFingers = v;
+                break;
             case BTN_TOUCH:
                 if (!priv->has_pressure)
                     hw->z = v ? para->finger_high + 1 : 0;
diff --git a/src/properties.c b/src/properties.c
index cb89e7b..ac2d8f0 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -320,9 +320,9 @@ InitDeviceProperties(InputInfoPtr pInfo)
         InitAtom(pInfo->dev, SYNAPTICS_PROP_CIRCULAR_PAD, 8, 1,
                  &para->circular_pad);
 
-    memcpy(values, para->swipe_action, MAX_SWIPE * sizeof(int));
+    memcpy(values, para->swipe_action, 2 * MAX_SWIPE * sizeof(int));
     prop_swipeaction =
-        InitAtom(pInfo->dev, SYNAPTICS_PROP_SWIPE_ACTION, 8, MAX_SWIPE, values);
+        InitAtom(pInfo->dev, SYNAPTICS_PROP_SWIPE_ACTION, 8, 2 * MAX_SWIPE, values);
     values[0] = para->swipe_threshold_x;
     values[1] = para->swipe_threshold_y;
     prop_swipethreshold =
@@ -719,7 +719,9 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
         action = (CARD8 *) prop->data;
 
         for (i = 0; i < MAX_SWIPE; i++)
-            para->swipe_action[i] = action[i];
+            para->swipe_action[0][i] = action[i];
+        for (i = 0; i < MAX_SWIPE; i++)
+            para->swipe_action[1][i] = action[MAX_SWIPE + i];
     }
     else if (property == prop_swipethreshold) {
         INT32 *swipe_thresholds;
diff --git a/src/synaptics.c b/src/synaptics.c
index a84536b..0cf1a07 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -741,14 +741,22 @@ 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[UP_SWIPE] =
-        xf86SetIntOption(opts, "SwipeUpButton", 0);
-    pars->swipe_action[DOWN_SWIPE] =
-        xf86SetIntOption(opts, "SwipeDownButton", 0);
-    pars->swipe_action[LEFT_SWIPE] =
-        xf86SetIntOption(opts, "SwipeLeftButton", 0);
-    pars->swipe_action[RIGHT_SWIPE] =
-        xf86SetIntOption(opts, "SwipeRightButton", 0);
+    pars->swipe_action[0][UP_SWIPE] =
+        xf86SetIntOption(opts, "SwipeThreeUpButton", 0);
+    pars->swipe_action[0][DOWN_SWIPE] =
+        xf86SetIntOption(opts, "SwipeThreeDownButton", 0);
+    pars->swipe_action[0][LEFT_SWIPE] =
+        xf86SetIntOption(opts, "SwipeThreeLeftButton", 0);
+    pars->swipe_action[0][RIGHT_SWIPE] =
+        xf86SetIntOption(opts, "SwipeThreeRightButton", 0);
+    pars->swipe_action[1][UP_SWIPE] =
+        xf86SetIntOption(opts, "SwipeFourUpButton", 0);
+    pars->swipe_action[1][DOWN_SWIPE] =
+        xf86SetIntOption(opts, "SwipeFourDownButton", 0);
+    pars->swipe_action[1][LEFT_SWIPE] =
+        xf86SetIntOption(opts, "SwipeFourLeftButton", 0);
+    pars->swipe_action[1][RIGHT_SWIPE] =
+        xf86SetIntOption(opts, "SwipeFourRightButton", 0);
     pars->swipe_threshold_x =
         xf86SetIntOption(opts, "HorizSwipeThreshold", horizSwipeThreshold);
     pars->swipe_threshold_y =
@@ -1976,16 +1984,15 @@ HandleTapProcessing(SynapticsPrivate * priv, struct SynapticsHwState *hw,
 
     touch = finger >= FS_TOUCHED && priv->finger_state == FS_UNTOUCHED;
     release = finger == FS_UNTOUCHED && priv->finger_state >= FS_TOUCHED;
-    /* TODO: better way to determine how many fingers was actually used
-     * for gesture - there could be up to 5 fingers (or 6 ?) */
     move = (finger >= FS_TOUCHED &&
             (priv->tap_max_fingers <=
-             (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))));
+             (priv->swipe.fourfinger_on ? 4 :
+              (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)))));
     press = (hw->left || hw->right || hw->middle);
 
     if (touch) {
@@ -2658,7 +2665,8 @@ HandleSwipe(SynapticsPrivate *priv, struct SynapticsHwState *hw, Bool finger)
         return;
     }
 
-    if (priv->swipe.threefinger_on || priv->swipe.fourfinger_on) {
+    if ((priv->swipe.threefinger_on && hw->numFingers == 3) || 
+        (priv->swipe.fourfinger_on && hw->numFingers == 4)) {
         /* 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;
@@ -2978,37 +2986,48 @@ static void
 post_swipe_events(const InputInfoPtr pInfo) {
     SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
     SynapticsParameters *para = &priv->synpara;
+    int i = 0;
 
     /* there is no need to go any further if those conditions are not met */
     if (!(priv->swipe.threefinger_on || priv->swipe.fourfinger_on) ||
          (priv->swipe.posted && para->single_swipe))
       return;
 
+    if (priv->swipe.fourfinger_on)
+      i = 1;
+
     /* swipes are intrinsically related - one big if stack */
-    if (para->swipe_action[UP_SWIPE] &&
+    if (para->swipe_action[i][UP_SWIPE] &&
         priv->swipe.delta_y < -para->swipe_threshold_y) {
-        post_button_click(pInfo, para->swipe_action[UP_SWIPE]);
+        post_button_click(pInfo, para->swipe_action[i][UP_SWIPE]);
         priv->swipe.posted = TRUE;
         priv->swipe.delta_y = 0;
     }
-    else if (para->swipe_action[DOWN_SWIPE] &&
+    else if (para->swipe_action[i][DOWN_SWIPE] &&
         priv->swipe.delta_y > para->swipe_threshold_y) {
-        post_button_click(pInfo, para->swipe_action[DOWN_SWIPE]);
+        post_button_click(pInfo, para->swipe_action[i][DOWN_SWIPE]);
         priv->swipe.posted = TRUE;
         priv->swipe.delta_y = 0;
     }
-    else if (para->swipe_action[LEFT_SWIPE] &&
+    else if (para->swipe_action[i][LEFT_SWIPE] &&
         priv->swipe.delta_x < -para->swipe_threshold_x) {
-        post_button_click(pInfo, para->swipe_action[LEFT_SWIPE]);
+        post_button_click(pInfo, para->swipe_action[i][LEFT_SWIPE]);
         priv->swipe.posted = TRUE;
         priv->swipe.delta_x = 0;
     }
-    else if (para->swipe_action[RIGHT_SWIPE] &&
+    else if (para->swipe_action[i][RIGHT_SWIPE] &&
         priv->swipe.delta_x > para->swipe_threshold_x) {
-        post_button_click(pInfo, para->swipe_action[RIGHT_SWIPE]);
+        post_button_click(pInfo, para->swipe_action[i][RIGHT_SWIPE]);
         priv->swipe.posted = TRUE;
         priv->swipe.delta_x = 0;
     }
+    /* In case no button is defined for a specific gesture. */
+    else if (abs(priv->swipe.delta_x) > para->swipe_threshold_x) {
+        priv->swipe.delta_x = 0;
+    }
+    else if (abs(priv->swipe.delta_y) > para->swipe_threshold_y) {
+        priv->swipe.delta_y = 0;
+    }      
 }
 
 /* Update the open slots and number of active touches */
@@ -3191,7 +3210,8 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw, CARD32 now,
      * is ongoing, use cumulative relative touch movements for motion */
     if (para->clickpad &&
         ((priv->lastButtons & 7) ||
-        (priv->vert_scroll_twofinger_on || priv->horiz_scroll_twofinger_on)) &&
+        (priv->vert_scroll_twofinger_on || priv->horiz_scroll_twofinger_on ||
+        priv->swipe.threefinger_on || priv->swipe.fourfinger_on)) &&
         priv->last_button_area != TOP_BUTTON_AREA) {
         hw->x = hw->cumulative_dx;
         hw->y = hw->cumulative_dy;
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 553226c..c63e261 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -214,7 +214,7 @@ 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_action[2][MAX_SWIPE];     /* Button to report on swipe action */
     int swipe_threshold_x;      /* Threshold for horizontal swipe event */
     int swipe_threshold_y;      /* Threshold for vertical swipe event */
     Bool single_swipe;          /* Allow only one action per swipe */
@@ -280,7 +280,7 @@ struct _SynapticsPrivateRec {
         double delta_y;         /* accumulated vert swipe delta */
         Bool posted;            /* indicate that event was posted */
         Bool threefinger_on;    /* swipe event with three fingers */
-        Bool fourfinger_on;     /* XXX: ?? swipe event with four fingers */
+        Bool fourfinger_on;     /* swipe event with four fingers */
     } swipe;
     int count_packet_finger;    /* packet counter with finger on the touchpad */
     int button_delay_millis;    /* button delay for 3rd button emulation */
diff --git a/src/synproto.h b/src/synproto.h
index c52838c..7e9f8bd 100644
--- a/src/synproto.h
+++ b/src/synproto.h
@@ -93,6 +93,7 @@ struct CommData {
     Bool oneFinger;
     Bool twoFingers;
     Bool threeFingers;
+    Bool fourFingers;
 };
 
 struct _SynapticsParameters;
diff --git a/tools/synclient.c b/tools/synclient.c
index 94dad62..ef61259 100644
--- a/tools/synclient.c
+++ b/tools/synclient.c
@@ -122,10 +122,14 @@ 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},
-    {"SwipeUpButton",         PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 0},
-    {"SwipeDownButton",       PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 1},
-    {"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},
+    {"SwipeThreeUpButton",    PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 0},
+    {"SwipeThreeDownButton",  PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 1},
+    {"SwipeThreeLeftButton",  PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 2},
+    {"SwipeThreeRightButton", PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 3},
+    {"SwipeFourUpButton",     PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 4},
+    {"SwipeFourDownButton",   PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 5},
+    {"SwipeFourLeftButton",   PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 6},
+    {"SwipeFourRightButton",  PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_SWIPE_ACTION,	8, 7},
     {"HorizSwipeThreshold",   PT_INT,    0, 10000, SYNAPTICS_PROP_SWIPE_THRESHOLD, 32, 0},
     {"VertSwipeThreshold",    PT_INT,    0, 10000, SYNAPTICS_PROP_SWIPE_THRESHOLD, 32, 1},
     {"SingleSwipe",           PT_BOOL,   0, 1,     SYNAPTICS_PROP_SINGLE_SWIPE,	8, 0},
-- 
2.1.0


More information about the xorg-devel mailing list