[RFC XI 2.1 - xf86-input-evdev 2/3] Add experimental XI 2.1 multitouch support
Chase Douglas
chase.douglas at canonical.com
Fri Nov 12 14:35:12 PST 2010
From: Chase Douglas <chase.douglas at ubuntu.com>
This multitouch addition only supports slotted MT evdev protocol
devices. Support must be enabled at configure time using
--enable-multitouch. It is built on the masked valuator support in
XInput ABI 12, so do not attempt to build it for an earlier ABI.
Signed-off-by: Chase Douglas <chase.douglas at canonical.com>
---
configure.ac | 11 ++++
src/evdev.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
src/evdev.h | 5 ++
3 files changed, 167 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index 07cd64e..cc9e721 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 4984019..8b13e9f 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",
@@ -743,6 +751,60 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
}
}
+#ifdef MULTITOUCH
+static void
+EvdevProcessTouch(InputInfoPtr pInfo)
+{
+ EvdevPtr pEvdev = pInfo->private;
+ int map = pEvdev->axis_map[ABS_MT_TRACKING_ID] - pEvdev->num_vals;
+
+ if (pEvdev->cur_slot < 0 || !pEvdev->mtMask)
+ return;
+
+ if (valuator_mask_isset(pEvdev->mtMask, map) &&
+ valuator_mask_get(pEvdev->mtMask, map) < 0) {
+ valuator_mask_set(pEvdev->mtMask, map,
+ pEvdev->mt_slot_map[pEvdev->cur_slot]);
+ xf86PostTouchEvent(pInfo->dev, pEvdev->mtMask, 1);
+ pEvdev->mt_slot_map[pEvdev->cur_slot] = -1;
+ } else {
+ if (pEvdev->mt_slot_map[pEvdev->cur_slot] < 0)
+ if (!valuator_mask_isset(pEvdev->mtMask, map))
+ xf86Msg(X_WARNING, "%s: New touch without tracking ID.\n",
+ pInfo->dev->name);
+ else {
+ int tracking_id = valuator_mask_get(pEvdev->mtMask, map);
+ pEvdev->mt_slot_map[pEvdev->cur_slot] = tracking_id;
+ }
+ else if (!valuator_mask_isset(pEvdev->mtMask, map))
+ valuator_mask_set(pEvdev->mtMask, map,
+ pEvdev->mt_slot_map[pEvdev->cur_slot]);
+
+ xf86PostTouchEvent(pInfo->dev, pEvdev->mtMask, 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 {
+ 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.
*/
@@ -766,11 +828,16 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
if (EvdevWheelEmuFilterMotion(pInfo, ev))
return;
- map = pEvdev->axis_map[ev->code];
#ifdef HAVE_MASKED_VALUATORS
- 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;
+ }
#else
+ map = pEvdev->axis_map[ev->code];
pEvdev->vals[map] = value;
if (ev->code == ABS_X)
pEvdev->abs_queued |= ABS_X_VALUE;
@@ -936,6 +1003,7 @@ EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev)
#ifdef HAVE_MASKED_VALUATORS
EvdevProcessValuators(pInfo);
+ EvdevProcessTouch(pInfo);
#else
EvdevProcessValuators(pInfo, v, &num_v, &first_v);
#endif
@@ -1416,7 +1484,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;
@@ -1425,7 +1493,13 @@ EvdevAddAbsClass(DeviceIntPtr device)
if (!TestBit(EV_ABS, pEvdev->bitmask))
return !Success;
+#ifdef HAVE_MASKED_VALUATORS
+ num_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MT_SLOT);
+ num_mt_axes = CountBits((uint8_t *)pEvdev->abs_bitmask, ABS_MAX) - num_axes;
+#else
num_axes = EvdevCountBits(pEvdev->abs_bitmask, NLONGS(ABS_MAX));
+ num_mt_axes = 0;
+#endif
if (num_axes < 1)
return !Success;
@@ -1434,6 +1508,13 @@ EvdevAddAbsClass(DeviceIntPtr device)
num_axes = MAX_VALUATORS;
}
+#ifdef MULTITOUCH
+ 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
+
pEvdev->num_vals = num_axes;
#ifdef HAVE_MASKED_VALUATORS
if (num_axes > 0) {
@@ -1444,21 +1525,28 @@ EvdevAddAbsClass(DeviceIntPtr device)
if (!pEvdev->oldMask)
goto out;
}
+#ifdef MULTITOUCH
+ if (num_mt_axes > 0) {
+ pEvdev->mtMask = valuator_mask_new(num_mt_axes);
+ if (!pEvdev->mtMask)
+ goto out;
+ }
+#endif
#else
memset(pEvdev->vals, 0, num_axes * sizeof(int));
memset(pEvdev->old_vals, -1, num_axes * sizeof(int));
#endif
- atoms = malloc(pEvdev->num_vals * sizeof(Atom));
+ atoms = malloc((pEvdev->num_vals + num_mt_axes) * sizeof(Atom));
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)
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
@@ -1470,7 +1558,29 @@ EvdevAddAbsClass(DeviceIntPtr device)
GetMotionHistorySize(), Absolute))
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;
+
+ pEvdev->mt_slot_map = malloc(num_touches * sizeof(int));
+ if (!pEvdev->mt_slot_map)
+ goto out;
+
+ for (i = 0; i < num_touches; i++)
+ pEvdev->mt_slot_map[i] = -1;
+
+ if (!InitTouchClassDeviceStruct(device, num_touches, mode, num_mt_axes))
+ goto out;
+ }
+#endif
+
+ for (axis = ABS_X; axis < ABS_MT_SLOT; axis++) {
int axnum = pEvdev->axis_map[axis];
int resolution = 10000;
@@ -1500,6 +1610,25 @@ EvdevAddAbsClass(DeviceIntPtr device)
#endif
}
+#ifdef MULTITOUCH
+ for (axis = ABS_MT_SLOT; 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++)
@@ -1539,6 +1668,12 @@ EvdevAddAbsClass(DeviceIntPtr device)
out:
#ifdef HAVE_MASKED_VALUATORS
+#ifdef MULTITOUCH
+ free(pEvdev->mtMask);
+ pEvdev->mtMask = NULL;
+ free(pEvdev->mt_slot_map);
+ pEvdev->mt_slot_map = NULL;
+#endif
free(pEvdev->mask);
pEvdev->mask = NULL;
free(pEvdev->oldMask);
@@ -1923,6 +2058,10 @@ EvdevProc(DeviceIntPtr device, int what)
free(pEvdev->mask);
free(pEvdev->oldMask);
free(pEvdev->proxMask);
+#ifdef MULTITOUCH
+ free(pEvdev->mt_slot_map);
+ free(pEvdev->mtMask);
+#endif
EvdevRemoveDevice(pInfo);
pEvdev->min_maj = 0;
break;
@@ -2439,6 +2578,10 @@ EvdevPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
if (!EvdevOpenDevice(pInfo))
goto error;
+#ifdef MULTITOUCH
+ pEvdev->cur_slot = -1;
+#endif
+
/*
* We initialize pEvdev->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 bd5cb16..63c75a3 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -129,6 +129,11 @@ typedef struct {
ValuatorMask *mask;
ValuatorMask *oldMask;
ValuatorMask *proxMask;
+#ifdef MULTITOUCH
+ ValuatorMask *mtMask;
+ int *mt_slot_map;
+ int cur_slot;
+#endif
#else
int vals[MAX_VALUATORS];
int old_vals[MAX_VALUATORS]; /* Translate absolute inputs to relative */
--
1.7.1
More information about the xorg-devel
mailing list