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

Peter Hutterer peter.hutterer at who-t.net
Thu Feb 23 17:24:58 PST 2012


On Thu, Feb 23, 2012 at 01:02:23PM -0800, Chase Douglas wrote:
> 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>

this needs synclient integration too, possible as follow-up. Likewise for
any other option added.

> ---
>  include/synaptics-properties.h |    3 +
>  man/synaptics.man              |   22 +++++
>  src/properties.c               |   30 ++++++
>  src/synaptics.c                |  193 ++++++++++++++++++++++++++++++++++++++++
>  src/synapticsstr.h             |    8 ++
>  src/synproto.h                 |    2 +
>  6 files changed, 258 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..f50b249 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 edge is assumed to extend to infinity in the given direction.

that is rather confusing wording. If RBR is 0, it extends to infinity? More
that the button area does so. It also conflicts with the wording below
according to this, if all values are 0 they should extend to infinity.

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

this should be up there too.

> +
> +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..3828229 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_right_left_edge;
> +    values[1] = para->softbutton_right_right_edge;
> +    values[2] = para->softbutton_right_top_edge;
> +    values[3] = para->softbutton_right_bottom_edge;
> +    values[4] = para->softbutton_middle_left_edge;
> +    values[5] = para->softbutton_middle_right_edge;
> +    values[6] = para->softbutton_middle_top_edge;
> +    values[7] = para->softbutton_middle_bottom_edge;
> +    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,25 @@ 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)
> +    {
> +        INT32 *areas;
> +
> +        if (prop->size != 8 || prop->format != 32 || prop->type != XA_INTEGER)
> +            return BadMatch;
> +
> +        areas = (INT32*)prop->data;
> +        if (!SynapticsIsSoftButtonAreasValid(areas))
> +            return BadValue;
> +
> +        para->softbutton_right_left_edge    = areas[0];
> +        para->softbutton_right_right_edge   = areas[1];
> +        para->softbutton_right_top_edge     = areas[2];
> +        para->softbutton_right_bottom_edge  = areas[3];
> +        para->softbutton_middle_left_edge   = areas[4];
> +        para->softbutton_middle_right_edge  = areas[5];
> +        para->softbutton_middle_top_edge    = areas[6];
> +        para->softbutton_middle_bottom_edge = areas[7];
>      } 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 05ea6b9..26ac5ef 100644
> --- a/src/synaptics.c
> +++ b/src/synaptics.c
> @@ -410,6 +410,127 @@ 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_MAX;

shouldn't this be INT_MIN?

> +        int right_right = values[1] ? values[1] : INT_MAX;
> +        int right_top = values[2] ? values[2] : -INT_MAX;
> +        int right_bottom = values[3] ? values[3] : INT_MAX;
> +        int middle_left = values[4] ? values[4] : -INT_MAX;
> +        int middle_right = values[5] ? values[5] : INT_MAX;
> +        int middle_top = values[6] ? values[6] : -INT_MAX;
> +        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;
> +
> +    pars->softbutton_right_left_edge = values[0];
> +    pars->softbutton_right_right_edge = values[1];
> +    pars->softbutton_right_top_edge = values[2];
> +    pars->softbutton_right_bottom_edge = values[3];
> +    pars->softbutton_middle_left_edge = values[4];
> +    pars->softbutton_middle_right_edge = values[5];
> +    pars->softbutton_middle_top_edge = values[6];
> +    pars->softbutton_middle_bottom_edge = values[7];
> +
> +    return;
> +
> +fail:
> +    xf86IDrvMsg(pInfo, X_WARNING, "invalid SoftButtonAreas value '%s'\n",
> +                option_string);

X_ERROR, and it should state what it does here (i.e. "ignoring area")

> +}
> +                                      
> +
>  static void set_default_parameters(InputInfoPtr pInfo)
>  {
>      SynapticsPrivate *priv = pInfo->private; /* read-only */
> @@ -602,6 +723,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
> @@ -1355,6 +1478,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_right_left_edge == 0 &&
> +        para->softbutton_right_right_edge == 0 &&
> +        para->softbutton_right_top_edge == 0 &&
> +        para->softbutton_right_bottom_edge == 0)
> +        return FALSE;
> +
> +    if (para->softbutton_right_left_edge &&
> +        x < para->softbutton_right_left_edge)
> +	inside_area = FALSE;
> +    else if (para->softbutton_right_right_edge &&
> +             x > para->softbutton_right_right_edge)
> +	inside_area = FALSE;
> +    else if (para->softbutton_right_top_edge &&
> +             y < para->softbutton_right_top_edge)
> +	inside_area = FALSE;
> +    else if (para->softbutton_right_bottom_edge &&
> +             y > para->softbutton_right_bottom_edge)
> +	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_middle_left_edge == 0 &&
> +        para->softbutton_middle_right_edge == 0 &&
> +        para->softbutton_middle_top_edge == 0 &&
> +        para->softbutton_middle_bottom_edge == 0)
> +        return FALSE;
> +
> +    if (para->softbutton_middle_left_edge &&
> +        x < para->softbutton_middle_left_edge)
> +	inside_area = FALSE;
> +    else if (para->softbutton_middle_right_edge &&
> +             x > para->softbutton_middle_right_edge)
> +	inside_area = FALSE;
> +    else if (para->softbutton_middle_top_edge &&
> +             y < para->softbutton_middle_top_edge)
> +	inside_area = FALSE;
> +    else if (para->softbutton_middle_bottom_edge &&
> +             y > para->softbutton_middle_bottom_edge)
> +	inside_area = FALSE;
> +
> +    return inside_area;
> +}
> +
>  static CARD32
>  timerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
>  {
> @@ -2498,6 +2675,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(!para->clickpad && hw->left && hw->numFingers >= 1){
>          handle_clickfinger(para, hw);
> diff --git a/src/synapticsstr.h b/src/synapticsstr.h
> index 944fd6b..baee4d9 100644
> --- a/src/synapticsstr.h
> +++ b/src/synapticsstr.h
> @@ -180,6 +180,14 @@ 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_right_left_edge;
> +    int softbutton_right_right_edge;
> +    int softbutton_right_top_edge;
> +    int softbutton_right_bottom_edge;
> +    int softbutton_middle_left_edge;
> +    int softbutton_middle_right_edge;
> +    int softbutton_middle_top_edge;
> +    int softbutton_middle_bottom_edge;       /* soft button area coordinates absolute */

yikes. can we use an array please?

Cheers,
  Peter

>      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_ */
> -- 
> 1.7.9
> 


More information about the xorg-devel mailing list