aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChase Douglas <chase.douglas@canonical.com>2012-01-19 14:17:34 -0800
committerPeter Hutterer <peter.hutterer@who-t.net>2012-01-24 12:12:47 +1000
commitbc2f01ab838119a962f5e5eabb36e33d4c084f2c (patch)
tree2c86358d5ccef287aade55d93d1823925e048cb8
parentPrefere relative axis labelling over absolute axis labelling (diff)
downloadxf86-input-evdev-bc2f01ab838119a962f5e5eabb36e33d4c084f2c.tar.gz
xf86-input-evdev-bc2f01ab838119a962f5e5eabb36e33d4c084f2c.tar.bz2
xf86-input-evdev-bc2f01ab838119a962f5e5eabb36e33d4c084f2c.zip
Copy last valuator values into new touch valuator masks
Evdev is a 100% stateful protocol. The following represents three touches. Two touches begin and end at the same time at (500, 500) and (1000, 1000). The third touch begins after the first two end, and is at (500, 500). ABS_MT_SLOT 0 /* Set touch slot */ ABS_MT_TRACKING_ID 0 /* New touch with ID 0 in slot 0 */ ABS_MT_POSITION_X 500 /* Initial X position */ ABS_MT_POSITION_Y 500 /* Initial Y position */ ABS_MT_SLOT 1 /* Set touch slot */ ABS_MT_TRACKING_ID 1 /* New touch with ID 1 in slot 1 */ ABS_MT_POSITION_X 1000 /* Initial X position */ ABS_MT_POSITION_Y 1000 /* Initial Y position */ SYNC /* End of frame */ ABS_MT_SLOT 0 /* Go back to slot 0 */ ABS_MT_TRACKING_ID -1 /* Touch in slot 0 ended */ ABS_MT_SLOT 1 /* Go to slot 1 */ ABS_MT_TRACKING_ID -1 /* Touch in slot 1 ended */ SYNC /* End of frame */ ABS_MT_SLOT 0 /* Go back to slot 0 */ ABS_MT_TRACKING_ID 2 /* New touch in slot 0 with ID 2 */ SYNC /* End of frame */ ABS_MT_TRACKING_ID -1 /* Touch in last slot (0) ended */ SYNC /* End of frame */ Note that touch 2 has the same X and Y position as touch 0. This is implied because no new value was emitted for slot 0. In fact, Linux will not emit an event in the same slot with the same event type and code unless the value has changed. Thus, we can only assume that all the MT valuators have the same values as they were when they were last sent for the given slot. This change adds an array of valuator mask to hold all the last valuator values that came from evdev for each slot. When a new touch begins, all the last values are copied into it. This patch assumes initial axis values of 0 in each slot. Linux and mtdev do not provide a facility to query the current values of axes in each slot yet. This may cause spurious incorrect touch valuator values at the beginning of an X session, but there's nothing we can do about it right now. Signed-off-by: Chase Douglas <chase.douglas@canonical.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/evdev.c113
-rw-r--r--src/evdev.h1
2 files changed, 89 insertions, 25 deletions
diff --git a/src/evdev.c b/src/evdev.c
index 1cdba41..32fe38b 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -746,6 +746,24 @@ EvdevProcessTouch(InputInfoPtr pInfo)
valuator_mask_zero(pEvdev->mt_mask);
}
+static int
+num_slots(EvdevPtr pEvdev)
+{
+ int value = pEvdev->absinfo[ABS_MT_SLOT].maximum -
+ pEvdev->absinfo[ABS_MT_SLOT].minimum + 1;
+
+ /* If we don't know how many slots there are, assume at least 10 */
+ return value > 1 ? value : 10;
+}
+
+static int
+last_mt_vals_slot(EvdevPtr pEvdev)
+{
+ int value = pEvdev->cur_slot - pEvdev->absinfo[ABS_MT_SLOT].minimum;
+
+ return value < num_slots(pEvdev) ? value : -1;
+}
+
static void
EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
{
@@ -757,16 +775,29 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
pEvdev->cur_slot = ev->value;
} else
{
+ int slot_index = last_mt_vals_slot(pEvdev);
+
if (pEvdev->slot_state == SLOTSTATE_EMPTY)
pEvdev->slot_state = SLOTSTATE_UPDATE;
if (ev->code == ABS_MT_TRACKING_ID) {
- if (ev->value >= 0)
- pEvdev->slot_state = SLOTSTATE_OPEN;
- else
- pEvdev->slot_state = SLOTSTATE_CLOSE;
+ if (ev->value >= 0) {
+ pEvdev->slot_state = SLOTSTATE_OPEN;
+
+ if (slot_index >= 0)
+ valuator_mask_copy(pEvdev->mt_mask,
+ pEvdev->last_mt_vals[slot_index]);
+ else
+ xf86IDrvMsg(pInfo, X_WARNING,
+ "Attempted to copy values from out-of-range "
+ "slot, touch events may be incorrect.\n");
+ } else
+ pEvdev->slot_state = SLOTSTATE_CLOSE;
} else {
map = pEvdev->axis_map[ev->code];
valuator_mask_set(pEvdev->mt_mask, map, ev->value);
+ if (slot_index >= 0)
+ valuator_mask_set(pEvdev->last_mt_vals[slot_index], map,
+ ev->value);
}
}
}
@@ -1027,6 +1058,28 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
#undef ABS_Y_VALUE
#undef ABS_VALUE
+static void
+EvdevFreeMasks(EvdevPtr pEvdev)
+{
+ int i;
+
+ valuator_mask_free(&pEvdev->vals);
+ valuator_mask_free(&pEvdev->old_vals);
+ valuator_mask_free(&pEvdev->prox);
+#ifdef MULTITOUCH
+ valuator_mask_free(&pEvdev->mt_mask);
+ if (pEvdev->last_mt_vals)
+ {
+ for (i = 0; i < num_slots(pEvdev); i++)
+ valuator_mask_free(&pEvdev->last_mt_vals[i]);
+ free(pEvdev->last_mt_vals);
+ pEvdev->last_mt_vals = NULL;
+ }
+ for (i = 0; i < EVDEV_MAXQUEUE; i++)
+ valuator_mask_free(&pEvdev->queue[i].touchMask);
+#endif
+}
+
/* just a magic number to reduce the number of reads */
#define NUM_EVENTS 16
@@ -1258,6 +1311,24 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
goto out;
}
+ pEvdev->last_mt_vals = calloc(num_slots(pEvdev), sizeof(ValuatorMask *));
+ if (!pEvdev->last_mt_vals) {
+ xf86IDrvMsg(pInfo, X_ERROR,
+ "%s: failed to allocate MT last values mask array.\n",
+ device->name);
+ goto out;
+ }
+
+ for (i = 0; i < num_slots(pEvdev); i++) {
+ pEvdev->last_mt_vals[i] = valuator_mask_new(num_mt_axes_total);
+ if (!pEvdev->last_mt_vals[i]) {
+ xf86IDrvMsg(pInfo, X_ERROR,
+ "%s: failed to allocate MT last values mask.\n",
+ device->name);
+ goto out;
+ }
+ }
+
for (i = 0; i < EVDEV_MAXQUEUE; i++) {
pEvdev->queue[i].touchMask =
valuator_mask_new(num_mt_axes_total);
@@ -1321,6 +1392,17 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
device->name);
goto out;
}
+
+ for (i = 0; i < num_slots(pEvdev); i++) {
+ for (axis = ABS_MT_TOUCH_MAJOR; axis < ABS_MAX; axis++) {
+ if (pEvdev->axis_map[axis] >= 0) {
+ /* XXX: read initial values from mtdev when it adds support
+ * for doing so. */
+ valuator_mask_set(pEvdev->last_mt_vals[i],
+ pEvdev->axis_map[axis], 0);
+ }
+ }
+ }
}
#endif
@@ -1426,14 +1508,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
return Success;
out:
- valuator_mask_free(&pEvdev->vals);
- valuator_mask_free(&pEvdev->old_vals);
- valuator_mask_free(&pEvdev->prox);
-#ifdef MULTITOUCH
- valuator_mask_free(&pEvdev->mt_mask);
- for (i = 0; i < EVDEV_MAXQUEUE; i++)
- valuator_mask_free(&pEvdev->queue[i].touchMask);
-#endif
+ EvdevFreeMasks(pEvdev);
return !Success;
}
@@ -1767,9 +1842,6 @@ EvdevProc(DeviceIntPtr device, int what)
{
InputInfoPtr pInfo;
EvdevPtr pEvdev;
-#ifdef MULTITOUCH
- int i;
-#endif
pInfo = device->public.devicePrivate;
pEvdev = pInfo->private;
@@ -1806,16 +1878,7 @@ EvdevProc(DeviceIntPtr device, int what)
close(pInfo->fd);
pInfo->fd = -1;
}
- valuator_mask_free(&pEvdev->vals);
- valuator_mask_free(&pEvdev->old_vals);
- valuator_mask_free(&pEvdev->prox);
-#ifdef MULTITOUCH
- valuator_mask_free(&pEvdev->mt_mask);
- for (i = 0; i < EVDEV_MAXQUEUE; i++)
- valuator_mask_free(&pEvdev->queue[i].touchMask);
- if (pEvdev->mtdev)
- mtdev_close(pEvdev->mtdev);
-#endif
+ EvdevFreeMasks(pEvdev);
EvdevRemoveDevice(pInfo);
pEvdev->min_maj = 0;
break;
diff --git a/src/evdev.h b/src/evdev.h
index 1713b89..309b215 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -158,6 +158,7 @@ typedef struct {
ValuatorMask *old_vals; /* old values for calculating relative motion */
ValuatorMask *prox; /* last values set while not in proximity */
ValuatorMask *mt_mask;
+ ValuatorMask **last_mt_vals;
int cur_slot;
enum SlotState slot_state;
#ifdef MULTITOUCH