[PATCH 01/18] Add Clickpad support

Takashi Iwai tiwai at suse.de
Fri Oct 8 10:22:25 PDT 2010


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

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 <tiwai at suse.de>
---
 src/eventcomm.c    |    6 +++++
 src/synaptics.c    |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/synapticsstr.h |    2 +
 3 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/src/eventcomm.c b/src/eventcomm.c
index 85dfd09..fc5055b 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -269,6 +269,12 @@ event_query_axis_ranges(InputInfoPtr pInfo)
 	}
 
 	xf86Msg(X_PROBED, "%s: buttons:%s\n", pInfo->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_PROBED, "%s: is Clickpad device\n", local->name);
+	}
     }
 }
 
diff --git a/src/synaptics.c b/src/synaptics.c
index 4267c88..6f57d81 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -515,6 +515,18 @@ static void set_default_parameters(InputInfoPtr pInfo)
         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);
@@ -523,6 +535,10 @@ static void set_default_parameters(InputInfoPtr pInfo)
 
     pars->area_top_edge = set_percent_option(opts, "AreaTopEdge", height, priv->miny);
     pars->area_bottom_edge = set_percent_option(opts, "AreaBottomEdge", height, priv->miny);
+    /* in clickpad mode, we don't want to sense the button area as default */
+    if (pars->area_bottom_edge == 0 && priv->is_clickpad)
+	pars->area_bottom_edge = b;
+
     pars->area_left_edge = set_percent_option(opts, "AreaLeftEdge", width, priv->minx);
     pars->area_right_edge = set_percent_option(opts, "AreaRightEdge", width, priv->minx);
 
@@ -1085,6 +1101,44 @@ DeviceInit(DeviceIntPtr dev)
     return Success;
 }
 
+/* clickpad event handling */
+static void
+handle_clickpad(LocalDevicePtr local, struct SynapticsHwState *hw)
+{
+    SynapticsPrivate *priv = (SynapticsPrivate *) (local->private);
+    SynapticsParameters *para = &priv->synpara;
+
+    if (hw->left) { /* clicked? */
+	if (hw->y > para->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
+	     */
+	    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;
+	} else {
+	    /* dragging */
+	    hw->left = priv->prev_hw.left;
+	    hw->right = priv->prev_hw.right;
+	    hw->middle = priv->prev_hw.middle;
+	}
+    }
+    priv->prev_hw = *hw;
+}
 
 /*
  * Convert from absolute X/Y coordinates to a coordinate system where
@@ -2251,6 +2305,10 @@ update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw, in
     SynapticsPrivate *priv = (SynapticsPrivate *) (pInfo->private);
     SynapticsParameters *para = &priv->synpara;
 
+    /* Clickpad handling for button area */
+    if (priv->is_clickpad)
+	handle_clickpad(local, hw);
+
     /* Treat the first two multi buttons as up/down for now. */
     hw->up |= hw->multi[0];
     hw->down |= hw->multi[1];
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 9dc0a19..2e7b9ca 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -235,6 +235,8 @@ typedef struct _SynapticsPrivateRec
     Bool has_pressure;			/* device reports pressure */
     Bool has_width;			/* device reports finger width */
     Bool has_scrollbuttons;		/* device has physical scrollbuttons */
+    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.3.1



More information about the xorg-devel mailing list