[PATCH xf86-input-synaptics v4 08/10] Add soft button areas property

Chase Douglas chase.douglas at canonical.com
Fri Mar 2 12:42:34 PST 2012


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>
---
 include/synaptics-properties.h |    3 +
 man/synaptics.man              |   22 +++++
 src/properties.c               |   24 +++++
 src/synaptics.c                |  186 ++++++++++++++++++++++++++++++++++++++++
 src/synapticsstr.h             |    1 +
 src/synproto.h                 |    2 +
 tools/synclient.c              |    9 ++
 7 files changed, 247 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 11b4156..355b6af 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,
@@ -725,6 +736,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 22a063c..202ae9b 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -410,6 +410,120 @@ 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;
+
+    /* 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 identical right and left edges */
+            if (right_left == middle_left || right_right == middle_right)
+                return FALSE;
+
+            /* 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 */
@@ -610,6 +724,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
@@ -1363,6 +1479,60 @@ is_inside_active_area(SynapticsPrivate *priv, int x, int y)
     return inside_area;
 }
 
+static Bool
+is_inside_rightbutton_area(SynapticsParameters *para, int x, int y)
+{
+    Bool inside_area = TRUE;
+
+    if (para->softbutton_areas[0][0] == 0 &&
+        para->softbutton_areas[0][1] == 0 &&
+        para->softbutton_areas[0][2] == 0 &&
+        para->softbutton_areas[0][3] == 0)
+        return FALSE;
+
+    if (para->softbutton_areas[0][0] &&
+        x < para->softbutton_areas[0][0])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[0][1] &&
+             x > para->softbutton_areas[0][1])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[0][2] &&
+             y < para->softbutton_areas[0][2])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[0][3] &&
+             y > para->softbutton_areas[0][3])
+	inside_area = FALSE;
+
+    return inside_area;
+}
+
+static Bool
+is_inside_middlebutton_area(SynapticsParameters *para, int x, int y)
+{
+    Bool inside_area = TRUE;
+
+    if (para->softbutton_areas[1][0] == 0 &&
+        para->softbutton_areas[1][1] == 0 &&
+        para->softbutton_areas[1][2] == 0 &&
+        para->softbutton_areas[1][3] == 0)
+        return FALSE;
+
+    if (para->softbutton_areas[1][0] &&
+        x < para->softbutton_areas[1][0])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[1][1] &&
+             x > para->softbutton_areas[1][1])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[1][2] &&
+             y < para->softbutton_areas[1][2])
+	inside_area = FALSE;
+    else if (para->softbutton_areas[1][3] &&
+             y > para->softbutton_areas[1][3])
+	inside_area = FALSE;
+
+    return inside_area;
+}
+
 static CARD32
 timerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
 {
@@ -2506,6 +2676,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 */
     if(hw->left && hw->numFingers >= 1){
         handle_clickfinger(para, hw);
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 944fd6b..5270af6 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -180,6 +180,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 29e8f3b..3b9f803 100644
--- a/src/synproto.h
+++ b/src/synproto.h
@@ -117,4 +117,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 7da0661..fc95209 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>
@@ -143,6 +144,14 @@ static struct Parameter params[] = {
     {"AreaTopEdge",           PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	2},
     {"AreaBottomEdge",        PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	3},
     {"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.9



More information about the xorg-devel mailing list