summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChase Douglas <chase.douglas@canonical.com>2010-11-08 11:08:01 -0500
committerPeter Hutterer <peter.hutterer@who-t.net>2011-11-11 15:50:06 +1000
commite18abd0049421a98e61c15c2d56cfe2821cf4739 (patch)
tree0ebde526d8b251044e3ecc06f3b6354056ad912c
parent683a55e504f4fc2d1c847c54986439a0c61b2f20 (diff)
Add experimental XI 2.1 multitouch support
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 <chase.douglas@canonical.com> Amendments: XI_TouchMotion -> XI_TouchUpdate, rename mtMask to mt_mask Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--configure.ac11
-rw-r--r--src/evdev.c217
-rw-r--r--src/evdev.h25
3 files changed, 237 insertions, 16 deletions
diff --git a/configure.ac b/configure.ac
index aca3a41..8acc862 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,6 +48,17 @@ XORG_DEFAULT_OPTIONS
PKG_CHECK_MODULES(XORG, [xorg-server >= 1.10] xproto inputproto)
PKG_CHECK_MODULES(UDEV, udev)
+# Whether to include support for experimental XI 2.2 multitouch
+AC_ARG_ENABLE(multitouch,
+ AC_HELP_STRING([--enable-multitouch],
+ [Enable experimental XI 2.2 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 5e65e35..16f7339 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -85,6 +85,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",
@@ -352,7 +360,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;
}
}
@@ -365,7 +373,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;
}
}
@@ -377,11 +385,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.
@@ -675,6 +699,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->mt_mask)
+ return;
+
+ if (pEvdev->close_slot) {
+ EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mt_mask,
+ XI_TouchEnd);
+ pEvdev->close_slot = 0;
+ } else {
+ EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mt_mask,
+ pEvdev->open_slot ? XI_TouchBegin :
+ XI_TouchUpdate);
+ pEvdev->open_slot = 0;
+ }
+
+ valuator_mask_zero(pEvdev->mt_mask);
+}
+
+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->mt_mask, map, ev->value);
+ }
+}
+#else
+#define EvdevProcessTouch(pInfo)
+#define EvdevProcessTouchEvent(pInfo, ev)
+#endif /* MULTITOUCH */
+
/**
* Take the absolute motion input event and process it accordingly.
*/
@@ -698,9 +769,13 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
if (EvdevWheelEmuFilterMotion(pInfo, ev))
return;
- map = pEvdev->axis_map[ev->code];
- valuator_mask_set(pEvdev->vals, 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->vals, map, value);
+ pEvdev->abs_queued = 1;
+ }
}
/**
@@ -796,6 +871,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)
@@ -818,26 +896,33 @@ 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 (Evdev3BEmuFilterEvent(pInfo,
- pEvdev->queue[i].key,
+ pEvdev->queue[i].detail.key,
pEvdev->queue[i].val))
break;
if (pEvdev->abs_queued && pEvdev->in_proximity) {
- xf86PostButtonEventP(pInfo->dev, Absolute, pEvdev->queue[i].key,
+ xf86PostButtonEventP(pInfo->dev, Absolute, pEvdev->queue[i].detail.key,
pEvdev->queue[i].val, first_v, num_v,
v + first_v);
} else
- xf86PostButtonEvent(pInfo->dev, Relative, pEvdev->queue[i].key,
+ xf86PostButtonEvent(pInfo->dev, Relative, 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
}
}
}
@@ -856,6 +941,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);
@@ -1014,6 +1100,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
InputInfoPtr pInfo;
EvdevPtr pEvdev;
int num_axes, axis, i = 0;
+ int num_mt_axes = 0;
Atom *atoms;
pInfo = device->public.devicePrivate;
@@ -1026,11 +1113,36 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
if (num_axes < 1)
goto out;
+#ifdef MULTITOUCH
+ for (axis = ABS_MT_SLOT; axis < ABS_MAX; axis++)
+ {
+ if (EvdevBitIsSet(pEvdev->abs_bitmask, axis))
+ {
+ if(axis != ABS_MT_SLOT && axis != ABS_MT_TRACKING_ID)
+ num_mt_axes++;
+ num_axes--;
+ }
+ }
+#endif
+
if (num_axes > MAX_VALUATORS) {
xf86IDrvMsg(pInfo, X_WARNING, "found %d axes, limiting to %d.\n", num_axes, MAX_VALUATORS);
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
+
+ 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->vals = valuator_mask_new(num_axes);
@@ -1040,17 +1152,39 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
goto out;
}
}
- atoms = malloc(pEvdev->num_vals * sizeof(Atom));
+#ifdef MULTITOUCH
+ if (num_mt_axes > 0) {
+ pEvdev->mt_mask = valuator_mask_new(num_mt_axes);
+ if (!pEvdev->mt_mask) {
+ 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 (!EvdevBitIsSet(pEvdev->abs_bitmask, axis))
+ if (!EvdevBitIsSet(pEvdev->abs_bitmask, axis) ||
+ 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, atoms,
GetMotionHistorySize(), Absolute)) {
@@ -1058,7 +1192,26 @@ EvdevAddAbsValuatorClass(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;
@@ -1079,6 +1232,25 @@ EvdevAddAbsValuatorClass(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++)
@@ -1129,6 +1301,11 @@ 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
return !Success;
}
@@ -1462,6 +1639,9 @@ EvdevProc(DeviceIntPtr device, int what)
{
InputInfoPtr pInfo;
EvdevPtr pEvdev;
+#ifdef MULTITOUCH
+ int i;
+#endif
pInfo = device->public.devicePrivate;
pEvdev = pInfo->private;
@@ -1501,6 +1681,11 @@ EvdevProc(DeviceIntPtr device, int what)
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
EvdevRemoveDevice(pInfo);
pEvdev->min_maj = 0;
break;
@@ -1959,6 +2144,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 b2e2f42..6e3b850 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -109,9 +109,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 {
@@ -126,6 +137,12 @@ typedef struct {
ValuatorMask *vals; /* new values coming in */
ValuatorMask *old_vals; /* old values for calculating relative motion */
ValuatorMask *prox; /* last values set while not in proximity */
+#ifdef MULTITOUCH
+ ValuatorMask *mt_mask;
+ int cur_slot;
+ BOOL close_slot;
+ BOOL open_slot;
+#endif
int flags;
int in_proximity; /* device in proximity */
@@ -216,6 +233,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,