summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Tissoires <tissoire@cena.fr>2010-03-18 20:01:14 +0100
committerBenjamin Tissoires <tissoire@cena.fr>2010-03-18 20:13:46 +0100
commit71322a6079f4d7e08a215bcc09c27e158f56bcd0 (patch)
tree97a4dcf69121c4fcacb41208c54e81a0dcdef7b2
parente53d32e016d43592fb660a2a885c0f938890107b (diff)
Support for N-Trig devices that don't send Tracking IDmultitouch-subdevs
In case of devices that don't send the tracking ID, the driver has to track the different touches to keep their tracking ID. This is needed as the device may not send the touches is the same order each time. Signed-off-by: Benjamin Tissoires <tissoire@cena.fr> Signed-off-by: Carlos Garnacho <carlosg@gnome.org>
-rw-r--r--src/evdev.c121
-rw-r--r--src/evdev.h1
2 files changed, 112 insertions, 10 deletions
diff --git a/src/evdev.c b/src/evdev.c
index cc03976..30f28d6 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -723,6 +723,51 @@ EvdevCopyFromTouchData(InputInfoPtr pInfo, EvdevTouchDataPtr pTouchData, int id)
pEvdev->vals[pEvdev->axis_map[ABS_MT_TRACKING_ID]] = id;
}
+static EvdevSubdevInfoPtr
+EvdevFindClosestSubdevInfo(InputInfoPtr pInfo, int x, int y, int *distance, int *id)
+{
+ EvdevPtr pEvdev = pInfo->private, pEvdevSubdev;
+ EvdevSubdevInfoPtr subdev = NULL, pSubdevInfo;
+ int old_x, old_y, dx, dy, i;
+ int dist, min_distance = MAXINT;
+
+ for (i = 0; i < pEvdev->num_multitouch; ++i) {
+ pSubdevInfo = &pEvdev->subdev_info[i];
+
+ /* Skip non-existent or previously unused subdevs */
+ if (!pSubdevInfo || pSubdevInfo->id <= 0)
+ continue;
+
+ pEvdevSubdev = pSubdevInfo->pInfo->private;
+
+ old_x = pEvdevSubdev->vals[pEvdev->axis_map[ABS_MT_POSITION_X]];
+ old_y = pEvdevSubdev->vals[pEvdev->axis_map[ABS_MT_POSITION_Y]];
+
+ dx = (x - old_x) > 0 ? x - old_x : old_x - x;
+
+ dy = (y - old_y) > 0 ? y - old_y : old_y - y;
+
+ dist = dx + dy;
+
+ /* Return subdev only if it's the closest
+ * to the current event and if it wasn't
+ * previously assigned to a closer event
+ */
+ if (dist < min_distance) {
+ min_distance = dist;
+
+ if (dist < pSubdevInfo->distance) {
+ subdev = pSubdevInfo;
+ *id = i + 1; /* 0 means no id */
+ }
+ }
+ }
+
+ *distance = min_distance;
+
+ return subdev;
+}
+
/**
* Post the release of mt-events that were not send before.
*/
@@ -733,21 +778,76 @@ EvdevPostMTMotionEvents(InputInfoPtr pInfo, struct input_event *ev)
EvdevSubdevInfoPtr pSubdevInfo;
EvdevSubdevInfoPtr subdev_map[MAX_VALUATORS_MT] = { 0 };
EvdevTouchDataPtr pTouchData;
- int i;
+ int x, y, distance, id;
+ int i, j;
- for (i = 0; i < pEvdev->num_mt_events; ++i) {
- pTouchData = &pEvdev->mt_events[i];
- pSubdevInfo = EvdevFindMatchingIdSubdevInfo(pInfo, pTouchData->id);
+ if (pEvdev->has_tracking_id) {
+ for (i = 0; i < pEvdev->num_mt_events; ++i) {
+ pTouchData = &pEvdev->mt_events[i];
+ pSubdevInfo = EvdevFindMatchingIdSubdevInfo(pInfo, pTouchData->id);
+
+ if (!pSubdevInfo) {
+ /* There was no previous subdev for this tracking ID */
+ pSubdevInfo = EvdevFindUnallocatedSubdev(pInfo);
+
+ if (pSubdevInfo)
+ pSubdevInfo->id = pTouchData->id;
+ }
+
+ subdev_map[i] = pSubdevInfo;
+ }
+ } else {
+ /* First, map the MT events to the subdevices,
+ * the order of the MT events is not guaranteed.
+ */
+ for (i = 0; i < pEvdev->num_mt_events; ++i) {
+ pTouchData = &pEvdev->mt_events[i];
+
+ x = pTouchData->vals[pEvdev->axis_map[ABS_MT_POSITION_X]];
+ y = pTouchData->vals[pEvdev->axis_map[ABS_MT_POSITION_Y]];
- if (!pSubdevInfo) {
- /* There was no previous subdev for this tracking ID */
- pSubdevInfo = EvdevFindUnallocatedSubdev(pInfo);
+ pSubdevInfo = EvdevFindClosestSubdevInfo(pInfo, x, y, &distance, &id);
- if (pSubdevInfo)
- pSubdevInfo->id = pTouchData->id;
+ /* No closest, unassigned subdevice
+ * was found for this MT event
+ */
+ if (!pSubdevInfo) {
+ subdev_map[i] = NULL;
+ continue;
+ }
+
+ /* This is purely heuristic. Given event granularity and finger size,
+ * if the subdev has been assigned before to a MT event that's farther
+ * than the current one, it is quite likely that it's the current event
+ * which truly corresponds to it, and the other event actually was a new
+ * touch. So we settle things in order to take a new subdev to handle
+ * the initially misassigned MT event.
+ */
+ if (pSubdevInfo->distance > distance) {
+ for (j = 0; j < i; ++j) {
+ if (subdev_map[j] == pSubdevInfo)
+ subdev_map[j] = NULL;
+ }
+ }
+
+ subdev_map[i] = pSubdevInfo;
+ pSubdevInfo->distance = distance;
+ pSubdevInfo->id = id;
}
- subdev_map[i] = pSubdevInfo;
+ /* Go through MT events which don't have a subdev
+ * assigned yet, take a new subdevice to handle these
+ */
+ for (i = 0; i < pEvdev->num_mt_events; ++i) {
+ if (subdev_map[i])
+ continue;
+
+ subdev_map[i] = EvdevFindUnallocatedSubdev(pInfo);
+
+ /*if (!subdev_map[i]) {
+ xf86Msg(X_WARNING, "No free subdev for MT event. %s:%d\n", __FILE__, __LINE__);
+ }*/
+ }
}
/* Now, actually process the MT events,
@@ -763,6 +863,7 @@ EvdevPostMTMotionEvents(InputInfoPtr pInfo, struct input_event *ev)
EvdevCopyFromTouchData(pSubdevInfo->pInfo, pTouchData, pSubdevInfo->id);
EvdevSendSyncEvent(pSubdevInfo->pInfo);
pSubdevInfo->used = TRUE;
+ pSubdevInfo->distance = MAXINT;
}
/* Now reset things in order to
diff --git a/src/evdev.h b/src/evdev.h
index a345e6e..78135c4 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -136,6 +136,7 @@ typedef struct {
typedef struct _EvdevSubdevInfo{
BOOL used;
InputInfoPtr pInfo;
+ int distance; /* X/Y Distance during MT event generation */
int id;
} EvdevSubdevInfoRec, *EvdevSubdevInfoPtr;