summaryrefslogtreecommitdiff
path: root/src/eventcomm.c
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2012-02-07 02:51:08 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2012-02-07 02:51:08 +1000
commite4ee51e771a6da247362549044a076462791022b (patch)
treebdb8a66e115c2cf2dfca2d41eb5ed92b911f8cb7 /src/eventcomm.c
parentda0d20d0fd5cce3707b54146e54e2df0c697e1b4 (diff)
parent6b808dc766a0d1e64e19e4d5fad5f8a1a4e0d62d (diff)
Merge branch 'fixes' of git://people.freedesktop.org/~cndougla/xf86-input-synaptics
Diffstat (limited to 'src/eventcomm.c')
-rw-r--r--src/eventcomm.c107
1 files changed, 99 insertions, 8 deletions
diff --git a/src/eventcomm.c b/src/eventcomm.c
index be0f4ee..ce26934 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -78,6 +78,8 @@ struct eventcomm_proto_data
} slot_state;
ValuatorMask *mt_mask;
ValuatorMask **last_mt_vals;
+ unsigned int num_touches;
+ int *open_slots;
#endif
};
@@ -106,9 +108,12 @@ UninitializeTouch(InputInfoPtr pInfo)
SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
struct eventcomm_proto_data *proto_data = (struct eventcomm_proto_data*)priv->proto_data;
- if (!proto_data->mtdev)
+ if (!priv->has_touch)
return;
+ free(proto_data->open_slots);
+ proto_data->open_slots = NULL;
+
valuator_mask_free(&proto_data->mt_mask);
if (proto_data->last_mt_vals)
{
@@ -131,6 +136,9 @@ InitializeTouch(InputInfoPtr pInfo)
struct eventcomm_proto_data *proto_data = (struct eventcomm_proto_data*)priv->proto_data;
int i;
+ if (!priv->has_touch)
+ return;
+
proto_data->mtdev = mtdev_new_open(pInfo->fd);
if (!proto_data->mtdev)
{
@@ -183,6 +191,8 @@ InitializeTouch(InputInfoPtr pInfo)
for (j = 0; j < priv->num_mt_axes; j++)
valuator_mask_set(proto_data->last_mt_vals[i], 4 + j, 0);
}
+
+ proto_data->open_slots = malloc(num_slots(proto_data) * sizeof(int));
}
#endif
@@ -511,13 +521,82 @@ SynapticsReadEvent(InputInfoPtr pInfo, struct input_event *ev)
return rc;
}
+#ifdef HAVE_MTDEV
+static void
+EventBeginTouches(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ struct eventcomm_proto_data *proto_data = priv->proto_data;
+ int first_slot;
+
+ proto_data->num_touches++;
+ proto_data->open_slots[proto_data->num_touches - 1] = proto_data->cur_slot;
+
+ /* Don't start a touch if it's the only one. */
+ if (proto_data->num_touches < 2)
+ return;
+
+ xf86PostTouchEvent(pInfo->dev, proto_data->cur_slot, XI_TouchBegin, 0,
+ proto_data->mt_mask);
+
+ /* If this is the third or more touch, we've already begun the first touch.
+ */
+ if (proto_data->num_touches > 2)
+ return;
+
+ /* If this is the second touch, begin the first touch at this time. */
+ first_slot = proto_data->open_slots[0];
+ xf86PostTouchEvent(pInfo->dev, first_slot, XI_TouchBegin, 0,
+ proto_data->last_mt_vals[first_slot]);
+}
+
+static void
+EventEndTouches(InputInfoPtr pInfo)
+{
+ SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
+ struct eventcomm_proto_data *proto_data = priv->proto_data;
+ int first_slot;
+ int i;
+ Bool found;
+
+ found = FALSE;
+ for (i = 0; i < proto_data->num_touches - 1; i++)
+ {
+ if (proto_data->open_slots[i] == proto_data->cur_slot)
+ found = TRUE;
+
+ if (found)
+ proto_data->open_slots[i] = proto_data->open_slots[i + 1];
+ }
+
+ proto_data->num_touches--;
+
+ /* If this was the only touch left on the device, don't send a touch end
+ * event because we are inhibiting its touch sequence. */
+ if (proto_data->num_touches == 0)
+ return;
+
+ xf86PostTouchEvent(pInfo->dev, proto_data->cur_slot, XI_TouchEnd, 0,
+ proto_data->mt_mask);
+
+ /* If there is at least two other touches on the device, we don't need to
+ * end any more touches. */
+ if (proto_data->num_touches >= 2)
+ return;
+
+ /* We've gone down to one touch, so we must end the touch as well. */
+ first_slot = proto_data->open_slots[0];
+ xf86PostTouchEvent(pInfo->dev, first_slot, XI_TouchEnd, 0,
+ proto_data->last_mt_vals[first_slot]);
+}
+#endif
+
static void
EventProcessTouch(InputInfoPtr pInfo)
{
#ifdef HAVE_MTDEV
SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
struct eventcomm_proto_data *proto_data = priv->proto_data;
- int type;
if (proto_data->cur_slot < 0 || !priv->has_touch)
return;
@@ -529,19 +608,18 @@ EventProcessTouch(InputInfoPtr pInfo)
switch (proto_data->slot_state)
{
case SLOTSTATE_CLOSE:
- type = XI_TouchEnd;
+ EventEndTouches(pInfo);
break;
case SLOTSTATE_OPEN:
- type = XI_TouchBegin;
+ EventBeginTouches(pInfo);
break;
default:
- type = XI_TouchUpdate;
+ if (proto_data->num_touches >= 2)
+ xf86PostTouchEvent(pInfo->dev, proto_data->cur_slot,
+ XI_TouchUpdate, 0, proto_data->mt_mask);
break;
}
- xf86PostTouchEvent(pInfo->dev, proto_data->cur_slot, type, 0,
- proto_data->mt_mask);
-
proto_data->slot_state = SLOTSTATE_EMPTY;
valuator_mask_zero(proto_data->mt_mask);
#endif
@@ -555,6 +633,9 @@ EventProcessTouchEvent(InputInfoPtr pInfo, struct CommData *comm,
SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
struct eventcomm_proto_data *proto_data = priv->proto_data;
+ if (!priv->has_touch)
+ return;
+
if (ev->code == ABS_MT_SLOT)
{
EventProcessTouch(pInfo);
@@ -731,10 +812,20 @@ event_query_touch(InputInfoPtr pInfo)
struct eventcomm_proto_data *proto_data = priv->proto_data;
struct mtdev *mtdev;
int i;
+ int rc;
+ uint8_t prop;
priv->num_touches = 0;
priv->num_mt_axes = 0;
+ SYSCALL(rc = ioctl(pInfo->fd, EVIOCGPROP(sizeof(prop)), &prop));
+ if (rc >= 0 && BitIsOn(&prop, INPUT_PROP_SEMI_MT))
+ {
+ xf86IDrvMsg(pInfo, X_INFO,
+ "ignoring touch events for semi-multitouch device\n");
+ return;
+ }
+
mtdev = mtdev_new_open(pInfo->fd);
if (!mtdev)
{