This patch adds the support for Synaptics Clickpad devices.
It requires the change in Linux kernel synaptics input driver, found in
        https://patchwork.kernel.org/patch/92435/
The kernel patch is already included in linux-input GIT tree, which
will hit Linus tree sooner or later.

When the kernel driver sets only the left-button bit evbit and no
multi-finger is possible, Clickpad mode is activated.  In this mode,
the bottom touch area is used as button emulations.  Clicking at the
bottom-left, bottom-center and bottom-right zone corresponds to a left,
center and right click.

Signed-off-by: Takashi Iwai <[email protected]>
---

v2->v3: Fix the mis-detection of Clickpad device with double-tap feature
        (e.g. MacBook)
        Fix one forgotten spacing issue Peter suggested

 src/eventcomm.c    |    6 ++++
 src/synaptics.c    |   72 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/synapticsstr.h |    2 +
 3 files changed, 79 insertions(+), 1 deletions(-)

diff --git a/src/eventcomm.c b/src/eventcomm.c
index d00d810..6b44778 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -252,6 +252,12 @@ event_query_axis_ranges(LocalDevicePtr local)
        if ((priv->has_triple = (TEST_BIT(BTN_TOOL_TRIPLETAP, keybits) != 0)))
           strcat(buf, " triple");
        xf86Msg(X_INFO, "%s: buttons:%s\n", local->name, buf);
+
+       /* clickpad device reports only the single left button mask */
+       if (priv->has_left && !priv->has_right && !priv->has_middle && 
!priv->has_double) {
+           priv->is_clickpad = TRUE;
+           xf86Msg(X_INFO, "%s: is Clickpad device\n", local->name);
+       }
     }
 }
 
diff --git a/src/synaptics.c b/src/synaptics.c
index 091dbe1..554f7a3 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -457,6 +457,18 @@ static void set_default_parameters(LocalDevicePtr local)
         vertResolution = priv->resy;
     }
 
+    /* Clickpad mode -- bottom area is used as buttons */
+    if (priv->is_clickpad) {
+       int button_bottom;
+       /* Clickpad devices usually the button area at the bottom, and
+        * its size seems ca. 20% of the touchpad height no matter how
+        * large the pad is.
+        */
+       button_bottom = priv->maxy - (abs(priv->maxy - priv->miny) * 20) / 100;
+       if (button_bottom < b && button_bottom >= t)
+           b = button_bottom;
+    }
+
     /* set the parameters */
     pars->left_edge = xf86SetIntOption(opts, "LeftEdge", l);
     pars->right_edge = xf86SetIntOption(opts, "RightEdge", r);
@@ -2052,6 +2064,59 @@ HandleClickWithFingers(SynapticsParameters *para, struct 
SynapticsHwState *hw)
     }
 }
 
+/* clickpad event handling */
+static void
+HandleClickpad(LocalDevicePtr local, struct SynapticsHwState *hw, edge_type 
edge)
+{
+    SynapticsPrivate *priv = (SynapticsPrivate *) (local->private);
+    SynapticsParameters *para = &priv->synpara;
+
+    if (edge & BOTTOM_EDGE) {
+       /* button area */
+       int width = priv->maxx - priv->minx;
+       int left_button_x, right_button_x;
+
+       /* left and right clickpad button ranges;
+        * the gap between them is interpreted as a middle-button click
+        */
+       left_button_x = width * 2 / 5 + priv->minx;
+       right_button_x = width * 3 / 5 + priv->minx;
+
+       /* clickpad reports only one button, and we need
+        * to fake left/right buttons depending on the touch position
+        */
+       if (hw->left) { /* clicked? */
+           hw->left = 0;
+           if (hw->x < left_button_x)
+               hw->left = 1;
+           else if (hw->x > right_button_x)
+               hw->right = 1;
+           else
+               hw->middle = 1;
+       }
+
+       /* Don't move pointer position in the button area during clicked,
+        * except for horiz/vert scrolling is enabled.
+        *
+        * The synaptics driver tends to be pretty sensitive.  This hack
+        * is to avoid that the pointer moves slightly and misses the
+        * poistion you aimed to click.
+        *
+        * Also, when the pointer movement is reported, the dragging
+        * (with a sort of multi-touching) doesn't work well, too.
+        */
+       if (hw->left || !(para->scroll_edge_horiz ||
+                         ((edge & RIGHT_EDGE) && para->scroll_edge_vert)))
+           hw->z = 0; /* don't move pointer */
+
+    } else if (hw->left) {
+       /* dragging */
+       hw->left = priv->prev_hw.left;
+       hw->right = priv->prev_hw.right;
+       hw->middle = priv->prev_hw.middle;
+    }
+    priv->prev_hw = *hw;
+}
 
 /*
  * React on changes in the hardware state. This function is called every time
@@ -2102,6 +2167,12 @@ HandleState(LocalDevicePtr local, struct 
SynapticsHwState *hw)
     if (para->touchpad_off == 1)
        return delay;
 
+    edge = edge_detection(priv, hw->x, hw->y);
+
+    /* Clickpad handling for button area */
+    if (priv->is_clickpad)
+       HandleClickpad(local, hw, edge);
+
     /* Treat the first two multi buttons as up/down for now. */
     hw->up |= hw->multi[0];
     hw->down |= hw->multi[1];
@@ -2152,7 +2223,6 @@ HandleState(LocalDevicePtr local, struct SynapticsHwState 
*hw)
        hw->multi[2] = hw->multi[3] = FALSE;
     }
 
-    edge = edge_detection(priv, hw->x, hw->y);
     inside_active_area = is_inside_active_area(priv, hw->x, hw->y);
 
     finger = SynapticsDetectFinger(priv, hw);
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index bd19c79..05e43d3 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -232,6 +232,8 @@ typedef struct _SynapticsPrivateRec
     Bool has_double;                   /* double click detected for this 
device */
     Bool has_triple;                   /* triple click detected for this 
device */
     Bool has_pressure;                 /* device reports pressure */
+    Bool is_clickpad;                  /* is Clickpad device (one-button) */
+    struct SynapticsHwState prev_hw;   /* previous h/w state (for clickpad) */
 
     enum TouchpadModel model;          /* The detected model */
 } SynapticsPrivate;
-- 
1.7.0.4

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to