diff options
author | Benjamin Tissoires <tissoire@cena.fr> | 2010-03-18 20:01:14 +0100 |
---|---|---|
committer | Benjamin Tissoires <tissoire@cena.fr> | 2010-03-18 20:13:46 +0100 |
commit | 71322a6079f4d7e08a215bcc09c27e158f56bcd0 (patch) | |
tree | 97a4dcf69121c4fcacb41208c54e81a0dcdef7b2 | |
parent | e53d32e016d43592fb660a2a885c0f938890107b (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.c | 121 | ||||
-rw-r--r-- | src/evdev.h | 1 |
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; |