[PATCH synaptics v5 16/18] Add soft button areas property

Peter Hutterer peter.hutterer at who-t.net
Mon Mar 12 23:37:43 PDT 2012


From: Chase Douglas <chase.douglas at canonical.com>

Some clickpad devices have button areas painted on them. Set this
property to the area of the right and middle buttons to enable proper
click actions when clicking in the areas.

Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v4:
- deduplicate is_inside_middlebutton_area
- fixes to area checks for left > right || top < bottom
- fixes to area checks for left == right || top == bottom
- removed superfluous check for left == right, was covered already anyway

 include/synaptics-properties.h |    3 +
 man/synaptics.man              |   22 +++++
 src/properties.c               |   24 ++++++
 src/synaptics.c                |  177 ++++++++++++++++++++++++++++++++++++++++
 src/synapticsstr.h             |    1 +
 src/synproto.h                 |    2 +
 tools/synclient.c              |    9 ++
 7 files changed, 238 insertions(+), 0 deletions(-)

diff --git a/include/synaptics-properties.h b/include/synaptics-properties.h
index 140f14b..8c20a0c 100644
--- a/include/synaptics-properties.h
+++ b/include/synaptics-properties.h
@@ -158,6 +158,9 @@
 /* 32 bit, 4 values, left, right, top, bottom */
 #define SYNAPTICS_PROP_AREA "Synaptics Area"
 
+/* 32 bit, 4 values, left, right, top, buttom */
+#define SYNAPTICS_PROP_SOFTBUTTON_AREAS "Synaptics Soft Button Areas"
+
 /* 32 Bit Integer, 2 values, horizontal hysteresis, vertical hysteresis */
 #define SYNAPTICS_PROP_NOISE_CANCELLATION "Synaptics Noise Cancellation"
 
diff --git a/man/synaptics.man b/man/synaptics.man
index 8edc2f0..aaec35f 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -518,6 +518,20 @@ AreaBottomEdge option to any integer value other than zero. If supported by the
 server (version 1.9 and later), the edge may be specified in percent of
 the total height of the touchpad. Property: "Synaptics Area"
 .
+.TP
+.BI "Option \*qSoftButtonAreas\*q \*q" "RBL RBR RBT RBB MBL MBR MBT MBB" \*q
+Enable soft button click area support on ClickPad devices. The first four
+parameters define the area of the right button, and the second four parameters
+define the area of the middle button. The areas are defined by the left, right,
+top, and bottom edges as sequential values of the property. If any edge is set
+to 0, the button is assumed to extend to infinity in the given direction.
+.
+When the user performs a click within the defined soft button areas, the right
+or middle click action is performed.
+.
+The use of soft button areas is disabled by setting all the values for the area
+to 0. Property: "Synaptics Soft Button Areas"
+.
 
 .SH CONFIGURATION DETAILS
 .SS Area handling
@@ -927,6 +941,14 @@ default.
 32 bit, 4 values, left, right, top, bottom. 0 disables an element.
 
 .TP 7
+.BI "Synaptics Soft Button Areas"
+The Right and middle soft button areas are used to support right and middle
+click actions on a ClickPad device. Providing 0 for all values of a given button
+disables the button area.
+
+32 bit, 8 values, RBL, RBR, RBT, RBB, MBL, MBR, MBT, MBB.
+
+.TP 7
 .BI "Synaptics Capabilities"
 This read-only property expresses the physical capability of the touchpad,
 most notably whether the touchpad hardware supports multi-finger tapping and
diff --git a/src/properties.c b/src/properties.c
index 38f21b2..5cd3088 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -92,6 +92,7 @@ Atom prop_gestures              = 0;
 Atom prop_capabilities          = 0;
 Atom prop_resolution            = 0;
 Atom prop_area                  = 0;
+Atom prop_softbutton_areas      = 0;
 Atom prop_noise_cancellation    = 0;
 Atom prop_product_id            = 0;
 Atom prop_device_node           = 0;
@@ -300,6 +301,16 @@ InitDeviceProperties(InputInfoPtr pInfo)
     values[3] = para->area_bottom_edge;
     prop_area = InitAtom(pInfo->dev, SYNAPTICS_PROP_AREA, 32, 4, values);
 
+    values[0] = para->softbutton_areas[0][0];
+    values[1] = para->softbutton_areas[0][1];
+    values[2] = para->softbutton_areas[0][2];
+    values[3] = para->softbutton_areas[0][3];
+    values[4] = para->softbutton_areas[1][0];
+    values[5] = para->softbutton_areas[1][1];
+    values[6] = para->softbutton_areas[1][2];
+    values[7] = para->softbutton_areas[1][3];
+    prop_softbutton_areas = InitAtom(pInfo->dev, SYNAPTICS_PROP_SOFTBUTTON_AREAS, 32, 8, values);
+
     values[0] = para->hyst_x;
     values[1] = para->hyst_y;
     prop_noise_cancellation = InitAtom(pInfo->dev,
@@ -711,6 +722,19 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
         para->area_right_edge  = area[1];
         para->area_top_edge    = area[2];
         para->area_bottom_edge = area[3];
+    } else if (property == prop_softbutton_areas)
+    {
+        int *areas;
+
+        if (prop->size != 8 || prop->format != 32 || prop->type != XA_INTEGER)
+            return BadMatch;
+
+        areas = (int*)prop->data;
+        if (!SynapticsIsSoftButtonAreasValid(areas))
+            return BadValue;
+
+        memcpy(para->softbutton_areas[0], areas, 4 * sizeof(int));
+        memcpy(para->softbutton_areas[1], areas + 4, 4 * sizeof(int));
     } else if (property == prop_noise_cancellation) {
         INT32 *hyst;
         if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
diff --git a/src/synaptics.c b/src/synaptics.c
index 2770bd8..1164918 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -429,6 +429,126 @@ static int set_percent_option(pointer options, const char* optname,
     return result;
 }
 
+Bool SynapticsIsSoftButtonAreasValid(int *values)
+{
+    Bool right_disabled = FALSE;
+    Bool middle_disabled = FALSE;
+
+    /* Check right button area */
+    if ((((values[0] != 0) && (values[1] != 0)) && (values[0] > values[1])) ||
+        (((values[2] != 0) && (values[3] != 0)) && (values[2] > values[3])))
+        return FALSE;
+
+    /* Check middle button area */
+    if ((((values[4] != 0) && (values[5] != 0)) && (values[4] > values[5])) ||
+        (((values[6] != 0) && (values[7] != 0)) && (values[6] > values[7])))
+        return FALSE;
+
+    if (values[0] == 0 && values[1] == 0 && values[2] == 0 && values[3] == 0)
+        right_disabled = TRUE;
+
+    if (values[4] == 0 && values[5] == 0 && values[6] == 0 && values[7] == 0)
+        middle_disabled = TRUE;
+
+    if (!right_disabled &&
+            ((values[0] && values[0] == values[1]) ||
+             (values[2] && values[2] == values[3])))
+        return FALSE;
+
+    if (!middle_disabled &&
+        ((values[4] && values[4] == values[5]) ||
+         (values[6] && values[6] == values[7])))
+        return FALSE;
+
+    /* Check for overlapping button areas */
+    if (!right_disabled && !middle_disabled)
+    {
+        int right_left = values[0] ? values[0] : INT_MIN;
+        int right_right = values[1] ? values[1] : INT_MAX;
+        int right_top = values[2] ? values[2] : INT_MIN;
+        int right_bottom = values[3] ? values[3] : INT_MAX;
+        int middle_left = values[4] ? values[4] : INT_MIN;
+        int middle_right = values[5] ? values[5] : INT_MAX;
+        int middle_top = values[6] ? values[6] : INT_MIN;
+        int middle_bottom = values[7] ? values[7] : INT_MAX;
+
+        /* If areas overlap in the Y axis */
+        if ((right_bottom <= middle_bottom && right_bottom >= middle_top) ||
+            (right_top <= middle_bottom && right_top >= middle_top))
+        {
+            /* Check for overlapping left edges */
+            if ((right_left < middle_left && right_right >= middle_left) ||
+                (middle_left < right_left && middle_right >= right_left))
+                return FALSE;
+
+            /* Check for overlapping right edges */
+            if ((right_right > middle_right && right_left <= middle_right) ||
+                (middle_right > right_right && middle_left <= right_right))
+                return FALSE;
+        }
+
+        /* If areas overlap in the X axis */
+        if ((right_left >= middle_left && right_left <= middle_right) ||
+            (right_right >= middle_left && right_right <= middle_right))
+        {
+            /* Check for overlapping top edges */
+            if ((right_top < middle_top && right_bottom >= middle_top) ||
+                (middle_top < right_top && middle_bottom >= right_top))
+                return FALSE;
+
+            /* Check for overlapping bottom edges */
+            if ((right_bottom > middle_bottom && right_top <= middle_bottom) ||
+                (middle_bottom > right_bottom && middle_top <= right_bottom))
+                return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+static void set_softbutton_areas_option(InputInfoPtr pInfo)
+{
+    SynapticsPrivate *priv = pInfo->private;
+    SynapticsParameters *pars = &priv->synpara;
+    int values[8];
+    char *option_string;
+    char *next_num;
+    char *end_str;
+    int i;
+
+    option_string = xf86CheckStrOption(pInfo->options, "SoftButtonAreas", NULL);
+    if (!option_string)
+        return;
+
+    next_num = option_string;
+
+    for (i = 0; i < 8 && *next_num != '\0'; i++)
+    {
+        long int value = strtol(next_num, &end_str, 0);
+        if (value > INT_MAX || value < -INT_MAX)
+            goto fail;
+
+        values[i] = value;
+
+        if (next_num != end_str)
+            next_num = end_str;
+        else
+            goto fail;
+    }
+
+    if (i < 8 || *next_num != '\0' || !SynapticsIsSoftButtonAreasValid(values))
+        goto fail;
+
+    memcpy(pars->softbutton_areas[0], values, 4 * sizeof(int));
+    memcpy(pars->softbutton_areas[1], values + 4, 4 * sizeof(int));
+
+    return;
+
+fail:
+    xf86IDrvMsg(pInfo, X_ERROR, "invalid SoftButtonAreas value '%s', keeping defaults\n",
+                option_string);
+}
+
 static void set_default_parameters(InputInfoPtr pInfo)
 {
     SynapticsPrivate *priv = pInfo->private; /* read-only */
@@ -623,6 +743,8 @@ static void set_default_parameters(InputInfoPtr pInfo)
 	pars->bottom_edge = tmp;
 	xf86IDrvMsg(pInfo, X_WARNING, "TopEdge is bigger than BottomEdge. Fixing.\n");
     }
+
+    set_softbutton_areas_option(pInfo);
 }
 
 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 14
@@ -1381,6 +1503,45 @@ is_inside_active_area(SynapticsPrivate *priv, int x, int y)
     return inside_area;
 }
 
+static Bool
+is_inside_button_area(SynapticsParameters *para, int which, int x, int y)
+{
+    Bool inside_area = TRUE;
+
+    if (para->softbutton_areas[which][0] == 0 &&
+        para->softbutton_areas[which][1] == 0 &&
+        para->softbutton_areas[which][2] == 0 &&
+        para->softbutton_areas[which][3] == 0)
+        return FALSE;
+
+    if (para->softbutton_areas[which][0] &&
+        x < para->softbutton_areas[which][0])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[which][1] &&
+             x > para->softbutton_areas[which][1])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[which][2] &&
+             y < para->softbutton_areas[which][2])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[which][3] &&
+             y > para->softbutton_areas[which][3])
+	inside_area = FALSE;
+
+    return inside_area;
+}
+
+static Bool
+is_inside_rightbutton_area(SynapticsParameters *para, int x, int y)
+{
+    return is_inside_button_area(para, 0, x, y);
+}
+
+static Bool
+is_inside_middlebutton_area(SynapticsParameters *para, int x, int y)
+{
+    return is_inside_button_area(para, 1, x, y);
+}
+
 static CARD32
 timerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
 {
@@ -2589,6 +2750,22 @@ update_hw_button_state(const InputInfoPtr pInfo, struct SynapticsHwState *hw,
     /* 3rd button emulation */
     hw->middle |= HandleMidButtonEmulation(priv, hw, now, delay);
 
+    /* If this is a clickpad and the user clicks in a soft button area, press
+     * the soft button instead. */
+    if (para->clickpad && hw->left && !hw->right && !hw->middle)
+    {
+        if (is_inside_rightbutton_area(para, hw->x, hw->y))
+        {
+            hw->left = 0;
+            hw->right = 1;
+        }
+        else if (is_inside_middlebutton_area(para, hw->x, hw->y))
+        {
+            hw->left = 0;
+            hw->middle = 1;
+        }
+    }
+
     /* Fingers emulate other buttons. ClickFinger can only be
        triggered on transition, when left is pressed
      */
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 84c8a97..fcefc46 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -181,6 +181,7 @@ typedef struct _SynapticsParameters
     unsigned int resolution_horiz;          /* horizontal resolution of touchpad in units/mm */
     unsigned int resolution_vert;           /* vertical resolution of touchpad in units/mm */
     int area_left_edge, area_right_edge, area_top_edge, area_bottom_edge; /* area coordinates absolute */
+    int softbutton_areas[2][4];             /* soft button area coordinates, 0 => right, 1 => middle button */
     int hyst_x, hyst_y;                     /* x and y width of hysteresis box */
 } SynapticsParameters;
 
diff --git a/src/synproto.h b/src/synproto.h
index 41284b3..95ebc92 100644
--- a/src/synproto.h
+++ b/src/synproto.h
@@ -120,4 +120,6 @@ extern void SynapticsCopyHwState(struct SynapticsHwState *dst,
                                  const struct SynapticsHwState *src);
 extern void SynapticsResetTouchHwState(struct SynapticsHwState *hw);
 
+extern Bool SynapticsIsSoftButtonAreasValid(int *values);
+
 #endif /* _SYNPROTO_H_ */
diff --git a/tools/synclient.c b/tools/synclient.c
index 6e77ee8..942312a 100644
--- a/tools/synclient.c
+++ b/tools/synclient.c
@@ -38,6 +38,7 @@
 #include <string.h>
 #include <stddef.h>
 #include <math.h>
+#include <limits.h>
 
 #include <X11/Xdefs.h>
 #include <X11/Xatom.h>
@@ -145,6 +146,14 @@ static struct Parameter params[] = {
     {"HorizHysteresis",       PT_INT,    0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	0},
     {"VertHysteresis",        PT_INT,    0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	1},
     {"ClickPad",              PT_BOOL,   0, 1,     SYNAPTICS_PROP_CLICKPAD,	8,	0},
+    {"RightButtonAreaLeft",   PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	0},
+    {"RightButtonAreaRight",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	1},
+    {"RightButtonAreaTop",    PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	2},
+    {"RightButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	3},
+    {"MiddleButtonAreaLeft",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	4},
+    {"MiddleButtonAreaRight", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	5},
+    {"MiddleButtonAreaTop",   PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	6},
+    {"MiddleButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	7},
     { NULL, 0, 0, 0, 0 }
 };
 
-- 
1.7.7.6



More information about the xorg-devel mailing list