The previous implementation considers that a new slot means a TouchBegin, and the deletion of the slot a TouchEnd. However, this is not compliant with the mt evdev specification as the touch state is given by ABS_MT_DISTANCE == 0. Before Win 8 specification, no known multitouch devices present in proximity events (like the hovering of Wacom stylus). But since this specification exists, there may be devices exposing ABS_MT_DISTANCE.
The modification here consists in storing the current touch state of each slot, to be able to detect if we need to forward Begin/End/Update event by just setting the touch property to true or false. The benefit of it is that we can now easily add proximity support and several touch begin/end within the same slot. Signed-off-by: Benjamin Tissoires <[email protected]> --- src/evdev.c | 47 +++++++++++++++++++++++++++++++---------------- src/evdev.h | 8 +++++++- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 8d7853b..256037c 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -736,21 +736,33 @@ EvdevProcessTouch(InputInfoPtr pInfo) EvdevPtr pEvdev = pInfo->private; int type; int slot_index = last_mt_vals_slot(pEvdev); + EvdevMTState *mt_state; if (slot_index < 0 || !pEvdev->mt_mask) return; + mt_state = &pEvdev->mt_state[slot_index]; + /* If the ABS_MT_SLOT is the first event we get after EV_SYN, skip this */ if (pEvdev->slot_state == SLOTSTATE_EMPTY) return; if (pEvdev->slot_state == SLOTSTATE_CLOSE) - type = XI_TouchEnd; + mt_state->touch = FALSE; else if (pEvdev->slot_state == SLOTSTATE_OPEN) - type = XI_TouchBegin; - else - type = XI_TouchUpdate; + mt_state->touch = TRUE; + type = XI_TouchUpdate; + + if (mt_state->touch != mt_state->touch_state) { + /* We are getting in/out of touch */ + if (mt_state->touch) + type = XI_TouchBegin; + else + type = XI_TouchEnd; + + mt_state->touch_state = mt_state->touch; + } EvdevQueueTouchEvent(pInfo, slot_index, pEvdev->mt_mask, type); @@ -794,6 +806,7 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev) { EvdevPtr pEvdev = pInfo->private; int map; + EvdevMTState *mt_state; if (!EvdevIsMTDevice(pEvdev)) return; @@ -813,19 +826,21 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev) return; } + mt_state = &pEvdev->mt_state[slot_index]; + 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; valuator_mask_copy(pEvdev->mt_mask, - pEvdev->last_mt_vals[slot_index]); + mt_state->last_vals); } else pEvdev->slot_state = SLOTSTATE_CLOSE; } else { map = pEvdev->axis_map[ev->code]; valuator_mask_set(pEvdev->mt_mask, map, ev->value); - valuator_mask_set(pEvdev->last_mt_vals[slot_index], map, ev->value); + valuator_mask_set(mt_state->last_vals, map, ev->value); } } } @@ -1098,12 +1113,12 @@ EvdevFreeMasks(EvdevPtr pEvdev) valuator_mask_free(&pEvdev->prox); #ifdef MULTITOUCH valuator_mask_free(&pEvdev->mt_mask); - if (pEvdev->last_mt_vals) + if (pEvdev->mt_state) { 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; + valuator_mask_free(&pEvdev->mt_state[i].last_vals); + free(pEvdev->mt_state); + pEvdev->mt_state = NULL; } for (i = 0; i < EVDEV_MAXQUEUE; i++) valuator_mask_free(&pEvdev->queue[i].touchMask); @@ -1333,17 +1348,17 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) goto out; } - pEvdev->last_mt_vals = calloc(num_slots(pEvdev), sizeof(ValuatorMask *)); - if (!pEvdev->last_mt_vals) { + pEvdev->mt_state = calloc(num_slots(pEvdev), sizeof(EvdevMTState)); + if (!pEvdev->mt_state) { xf86IDrvMsg(pInfo, X_ERROR, - "%s: failed to allocate MT last values mask array.\n", + "%s: failed to allocate MT state.\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]) { + pEvdev->mt_state[i].last_vals = valuator_mask_new(num_mt_axes_total); + if (!pEvdev->mt_state[i].last_vals) { xf86IDrvMsg(pInfo, X_ERROR, "%s: failed to allocate MT last values mask.\n", device->name); @@ -1439,7 +1454,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) strerror(errno)); } for (i = 0; i < num_touches; i++) - valuator_mask_set(pEvdev->last_mt_vals[i], + valuator_mask_set(pEvdev->mt_state[i].last_vals, pEvdev->axis_map[axis], mt_request_data[i]); } diff --git a/src/evdev.h b/src/evdev.h index 2901886..6195c79 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -150,6 +150,12 @@ typedef struct { } EventQueueRec, *EventQueuePtr; typedef struct { + ValuatorMask *last_vals; + int touch; /* per-slot incoming touch state */ + int touch_state; /* per-slot current touch state */ +} EvdevMTState; + +typedef struct { unsigned short id_vendor; unsigned short id_product; @@ -163,11 +169,11 @@ 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 struct mtdev *mtdev; + EvdevMTState *mt_state; #endif int flags; -- 1.8.0.2 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
