From: Chase Douglas <[email protected]> This multitouch addition only supports slotted MT evdev protocol devices. Support must be enabled at configure time using --enable-multitouch.
Signed-off-by: Chase Douglas <[email protected]> --- v5: Fixed merge conflicts. Updated to new xf86PostTouchEvent API, including explicitly tracking touchpoint creation and destruction, rather than relying on the server to do it for us. Removed mt_slot_map, as we no longer need to hand the server monotonic touch IDs: it does that for us. configure.ac | 11 +++ src/evdev.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/evdev.h | 25 ++++++- 3 files changed, 233 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 887021c..02ab67a 100644 --- a/configure.ac +++ b/configure.ac @@ -47,6 +47,17 @@ XORG_DEFAULT_OPTIONS # Obtain compiler/linker options from server and required extensions PKG_CHECK_MODULES(XORG, xorg-server xproto inputproto) +# Whether to include support for experimental XI 2.1 multitouch +AC_ARG_ENABLE(multitouch, + AC_HELP_STRING([--enable-multitouch], + [Enable experimental XI 2.1 multitouch support [[default: disabled]]]), + [MULTITOUCH=$enableval], + [MULTITOUCH=no]) + +if test "x$MULTITOUCH" = xyes; then + AC_DEFINE(MULTITOUCH, 1, [Enable experimental multitouch code]) +fi + # Define a configure option for an alternate input module directory AC_ARG_WITH(xorg-module-dir, AC_HELP_STRING([--with-xorg-module-dir=DIR], diff --git a/src/evdev.c b/src/evdev.c index 393f443..32d9109 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -87,6 +87,14 @@ #define MODEFLAG 8 #define COMPOSEFLAG 16 +#ifndef ABS_MT_SLOT +#define ABS_MT_SLOT 0x2f +#endif + +#ifndef ABS_MT_TRACKING_ID +#define ABS_MT_TRACKING_ID 0x39 +#endif + static char *evdevDefaults[] = { "XkbRules", "evdev", "XkbModel", "evdev", @@ -317,7 +325,7 @@ EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value) if ((pQueue = EvdevNextInQueue(pInfo))) { pQueue->type = EV_QUEUE_KEY; - pQueue->key = code; + pQueue->detail.key = code; pQueue->val = value; } } @@ -330,7 +338,7 @@ EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value) if ((pQueue = EvdevNextInQueue(pInfo))) { pQueue->type = EV_QUEUE_BTN; - pQueue->key = button; + pQueue->detail.key = button; pQueue->val = value; } } @@ -342,11 +350,27 @@ EvdevQueueProximityEvent(InputInfoPtr pInfo, int value) if ((pQueue = EvdevNextInQueue(pInfo))) { pQueue->type = EV_QUEUE_PROXIMITY; - pQueue->key = 0; + pQueue->detail.key = 0; pQueue->val = value; } } +#ifdef MULTITOUCH +void +EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch, ValuatorMask *mask, + uint16_t evtype) +{ + EventQueuePtr pQueue; + if ((pQueue = EvdevNextInQueue(pInfo))) + { + pQueue->type = EV_QUEUE_TOUCH; + pQueue->detail.touch = touch; + valuator_mask_copy(pQueue->touchMask, mask); + pQueue->val = evtype; + } +} +#endif + /** * Post button event right here, right now. * Interface for MB emulation since these need to post immediately. @@ -615,6 +639,53 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev) } } +#ifdef MULTITOUCH +static void +EvdevProcessTouch(InputInfoPtr pInfo) +{ + EvdevPtr pEvdev = pInfo->private; + + if (pEvdev->cur_slot < 0 || !pEvdev->mtMask) + return; + + if (pEvdev->close_slot) { + EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mtMask, + XI_TouchEnd); + pEvdev->close_slot = 0; + } else { + EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mtMask, + pEvdev->open_slot ? XI_TouchBegin : + XI_TouchMotion); + pEvdev->open_slot = 0; + } + + valuator_mask_zero(pEvdev->mtMask); +} + +static void +EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev) +{ + EvdevPtr pEvdev = pInfo->private; + int map; + + if (ev->code == ABS_MT_SLOT) { + EvdevProcessTouch(pInfo); + pEvdev->cur_slot = ev->value; + } else if (ev->code == ABS_MT_TRACKING_ID) { + if (ev->value >= 0) + pEvdev->open_slot = 1; + else + pEvdev->close_slot = 1; + } else { + map = pEvdev->axis_map[ev->code] - pEvdev->num_vals; + valuator_mask_set(pEvdev->mtMask, map, ev->value); + } +} +#else +#define EvdevProcessTouch(pInfo) +#define EvdevProcessTouchEvent(pInfo, ev) +#endif /* MULTITOUCH */ + /** * Take the absolute motion input event and process it accordingly. */ @@ -638,9 +709,13 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev) if (EvdevWheelEmuFilterMotion(pInfo, ev)) return; - map = pEvdev->axis_map[ev->code]; - valuator_mask_set(pEvdev->mask, map, value); - pEvdev->abs_queued = 1; + if (ev->code >= ABS_MT_SLOT) + EvdevProcessTouchEvent(pInfo, ev); + else { + map = pEvdev->axis_map[ev->code]; + valuator_mask_set(pEvdev->mask, map, value); + pEvdev->abs_queued = 1; + } } /** @@ -736,6 +811,9 @@ EvdevPostProximityEvents(InputInfoPtr pInfo, int which, int num_v, int first_v, switch (pEvdev->queue[i].type) { case EV_QUEUE_KEY: case EV_QUEUE_BTN: +#ifdef MULTITOUCH + case EV_QUEUE_TOUCH: +#endif break; case EV_QUEUE_PROXIMITY: if (pEvdev->queue[i].val == which) @@ -758,23 +836,30 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int num_v, int first_v, for (i = 0; i < pEvdev->num_queue; i++) { switch (pEvdev->queue[i].type) { case EV_QUEUE_KEY: - xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].key, + xf86PostKeyboardEvent(pInfo->dev, pEvdev->queue[i].detail.key, pEvdev->queue[i].val); break; case EV_QUEUE_BTN: #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11 if (pEvdev->abs_queued && pEvdev->in_proximity) { - xf86PostButtonEventP(pInfo->dev, 1, pEvdev->queue[i].key, + xf86PostButtonEventP(pInfo->dev, 1, pEvdev->queue[i].detail.key, pEvdev->queue[i].val, first_v, num_v, v + first_v); } else #endif - xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].key, + xf86PostButtonEvent(pInfo->dev, 0, pEvdev->queue[i].detail.key, pEvdev->queue[i].val, 0, 0); break; case EV_QUEUE_PROXIMITY: break; +#ifdef MULTITOUCH + case EV_QUEUE_TOUCH: + xf86PostTouchEvent(pInfo->dev, pEvdev->queue[i].detail.touch, + pEvdev->queue[i].val, 0, + pEvdev->queue[i].touchMask); + break; +#endif } } } @@ -793,6 +878,7 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev) EvdevProcessProximityState(pInfo); EvdevProcessValuators(pInfo); + EvdevProcessTouch(pInfo); EvdevPostProximityEvents(pInfo, TRUE, num_v, first_v, v); EvdevPostRelativeMotionEvents(pInfo, num_v, first_v, v); @@ -801,7 +887,6 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev) EvdevPostProximityEvents(pInfo, FALSE, num_v, first_v, v); memset(pEvdev->delta, 0, sizeof(pEvdev->delta)); - memset(pEvdev->queue, 0, sizeof(pEvdev->queue)); if (pEvdev->mask) valuator_mask_zero(pEvdev->mask); pEvdev->num_queue = 0; @@ -1268,7 +1353,7 @@ EvdevAddAbsClass(DeviceIntPtr device) { InputInfoPtr pInfo; EvdevPtr pEvdev; - int num_axes, axis, i = 0; + int num_axes, num_mt_axes, axis, i = 0; Atom *atoms; pInfo = device->public.devicePrivate; @@ -1277,15 +1362,32 @@ EvdevAddAbsClass(DeviceIntPtr device) if (!TestBit(EV_ABS, pEvdev->bitmask)) return !Success; - num_axes = EvdevCountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX)); - if (num_axes < 1) - return !Success; + num_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MT_SLOT); + num_mt_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MAX) - num_axes; if (num_axes > MAX_VALUATORS) { xf86Msg(X_WARNING, "%s: found %d axes, limiting to %d.\n", device->name, num_axes, MAX_VALUATORS); num_axes = MAX_VALUATORS; } +#ifdef MULTITOUCH + if (TestBit(ABS_MT_SLOT, pEvdev->abs_bitmask)) + num_mt_axes--; + if (TestBit(ABS_MT_TRACKING_ID, pEvdev->abs_bitmask)) + num_mt_axes--; + + if (num_mt_axes > MAX_VALUATORS) { + xf86Msg(X_WARNING, "%s: found %d MT axes, limiting to %d.\n", device->name, num_axes, MAX_VALUATORS); + num_mt_axes = MAX_VALUATORS; + } +#endif + + if (num_axes < 1 && num_mt_axes < 1) { + xf86Msg(X_WARNING, "%s: no absolute or touch axes found.\n", + device->name); + return !Success; + } + pEvdev->num_vals = num_axes; if (num_axes > 0) { pEvdev->mask = valuator_mask_new(num_axes); @@ -1301,17 +1403,39 @@ EvdevAddAbsClass(DeviceIntPtr device) goto out; } } - atoms = malloc(pEvdev->num_vals * sizeof(Atom)); +#ifdef MULTITOUCH + if (num_mt_axes > 0) { + pEvdev->mtMask = valuator_mask_new(num_mt_axes); + if (!pEvdev->mtMask) { + xf86Msg(X_ERROR, "%s: failed to allocate MT valuator mask.\n", + device->name); + goto out; + } + for (i = 0; i < EVDEV_MAXQUEUE; i++) { + pEvdev->queue[i].touchMask = + valuator_mask_new(num_mt_axes); + if (!pEvdev->queue[i].touchMask) { + xf86Msg(X_ERROR, "%s: failed to allocate MT valuator masks for " + "evdev event queue.\n", device->name); + goto out; + } + } + } +#endif + atoms = malloc((pEvdev->num_vals + num_mt_axes) * sizeof(Atom)); + + i = 0; for (axis = ABS_X; i < MAX_VALUATORS && axis <= ABS_MAX; axis++) { pEvdev->axis_map[axis] = -1; - if (!TestBit(axis, pEvdev->abs_bitmask)) + if (!TestBit(axis, pEvdev->abs_bitmask) || axis == ABS_MT_SLOT || + axis == ABS_MT_TRACKING_ID) continue; pEvdev->axis_map[axis] = i; i++; } - EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms); + EvdevInitAxesLabels(pEvdev, pEvdev->num_vals + num_mt_axes, atoms); if (!InitValuatorClassDeviceStruct(device, num_axes, #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7 @@ -1326,7 +1450,26 @@ EvdevAddAbsClass(DeviceIntPtr device) goto out; } - for (axis = ABS_X; axis <= ABS_MAX; axis++) { +#ifdef MULTITOUCH + if (num_mt_axes > 0) + { + int num_touches = 10; + int mode = pEvdev->flags & EVDEV_TOUCHPAD ? + XIDependentTouch : XIDirectTouch; + + if (pEvdev->absinfo[ABS_MT_SLOT].maximum > 0) + num_touches = pEvdev->absinfo[ABS_MT_SLOT].maximum; + + if (!InitTouchClassDeviceStruct(device, num_touches, mode, + num_mt_axes)) { + xf86Msg(X_ERROR, "%s: failed to initialize touch class device.\n", + device->name); + goto out; + } + } +#endif + + for (axis = ABS_X; axis < ABS_MT_SLOT; axis++) { int axnum = pEvdev->axis_map[axis]; int resolution = 10000; @@ -1353,6 +1496,25 @@ EvdevAddAbsClass(DeviceIntPtr device) xf86InitValuatorDefaults(device, axnum); } +#ifdef MULTITOUCH + for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) { + int axnum = pEvdev->axis_map[axis] - pEvdev->num_vals; + int resolution = 10000; + + if (axnum < 0) + continue; + + if (pEvdev->absinfo[axis].resolution) + resolution = pEvdev->absinfo[axis].resolution * 1000; + + xf86InitTouchValuatorAxisStruct(device, axnum, + atoms[axnum + pEvdev->num_vals], + pEvdev->absinfo[axis].minimum, + pEvdev->absinfo[axis].maximum, + pEvdev->absinfo[axis].resolution); + } +#endif + free(atoms); for (i = 0; i < ArrayLength(proximity_bits); i++) @@ -1400,6 +1562,13 @@ EvdevAddAbsClass(DeviceIntPtr device) return Success; out: +#ifdef MULTITOUCH + free(pEvdev->mtMask); + pEvdev->mtMask = NULL; + for (i = 0; i < EVDEV_MAXQUEUE; i++) + free(pEvdev->queue[i].touchMask); + pEvdev->queue[i].touchMask = NULL; +#endif free(pEvdev->mask); pEvdev->mask = NULL; free(pEvdev->oldMask); @@ -1749,6 +1918,9 @@ EvdevProc(DeviceIntPtr device, int what) { InputInfoPtr pInfo; EvdevPtr pEvdev; +#ifdef MULTITOUCH + int i; +#endif pInfo = device->public.devicePrivate; pEvdev = pInfo->private; @@ -1785,6 +1957,11 @@ EvdevProc(DeviceIntPtr device, int what) free(pEvdev->mask); free(pEvdev->oldMask); free(pEvdev->proxMask); +#ifdef MULTITOUCH + free(pEvdev->mtMask); + for (i = 0; i < EVDEV_MAXQUEUE; i++) + free(pEvdev->queue[i].touchMask); +#endif EvdevRemoveDevice(pInfo); pEvdev->min_maj = 0; break; @@ -2250,6 +2427,10 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) if (rc != Success) goto error; +#ifdef MULTITOUCH + pEvdev->cur_slot = -1; +#endif + /* * We initialize pEvdev->in_proximity to 1 so that device that doesn't use * proximity will still report events. diff --git a/src/evdev.h b/src/evdev.h index 6af145f..62619dd 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -110,9 +110,20 @@ typedef struct { EV_QUEUE_KEY, /* xf86PostKeyboardEvent() */ EV_QUEUE_BTN, /* xf86PostButtonEvent() */ EV_QUEUE_PROXIMITY, /* xf86PostProximityEvent() */ +#ifdef MULTITOUCH + EV_QUEUE_TOUCH, /*xf86PostTouchEvent() */ +#endif } type; - int key; /* May be either a key code or button number. */ - int val; /* State of the key/button; pressed or released. */ + union { + int key; /* May be either a key code or button number. */ +#ifdef MULTITOUCH + unsigned int touch; /* Touch ID */ +#endif + } detail; + int val; /* State of the key/button/touch; pressed or released. */ +#ifdef MULTITOUCH + ValuatorMask *touchMask; +#endif } EventQueueRec, *EventQueuePtr; typedef struct { @@ -124,6 +135,12 @@ typedef struct { ValuatorMask *mask; ValuatorMask *oldMask; ValuatorMask *proxMask; +#ifdef MULTITOUCH + ValuatorMask *mtMask; + int cur_slot; + BOOL close_slot; + BOOL open_slot; +#endif int flags; int in_proximity; /* device in proximity */ @@ -202,6 +219,10 @@ typedef struct { void EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value); void EvdevQueueButtonEvent(InputInfoPtr pInfo, int button, int value); void EvdevQueueProximityEvent(InputInfoPtr pInfo, int value); +#ifdef MULTITOUCH +void EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch, + ValuatorMask *mask, uint16_t type); +#endif void EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value); void EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count); void EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int num_v, int first_v, -- 1.7.2.3 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
