From 683a55e504f4fc2d1c847c54986439a0c61b2f20 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 25 Oct 2011 09:59:50 +1000 Subject: Use a new "Virtual Device" boolean property to mark virtual devices Use udev to check for the device's sysfs path, if it contains LNXSYSTM it's a kernel-emulated device. This property can then be used to determine if there are any real devices connected, allowing the desktop environment to e.g. turn off the touchpad whenever there's a mouse attached. Signed-off-by: Peter Hutterer --- configure.ac | 1 + src/evdev.c | 53 +++++++++++++++++++++++++++++++++++++++++++++- src/udev.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/udev.c diff --git a/configure.ac b/configure.ac index 1494a19..aca3a41 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,7 @@ XORG_DEFAULT_OPTIONS # Obtain compiler/linker options from server and required extensions PKG_CHECK_MODULES(XORG, [xorg-server >= 1.10] xproto inputproto) +PKG_CHECK_MODULES(UDEV, udev) # Define a configure option for an alternate input module directory AC_ARG_WITH(xorg-module-dir, diff --git a/src/evdev.c b/src/evdev.c index 428d3c1..5e65e35 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -56,6 +57,10 @@ #define XI_PROP_PRODUCT_ID "Device Product ID" #endif +#ifndef XI_PROP_VIRTUAL_DEVICE +#define XI_PROP_VIRTUAL_DEVICE "Virtual Device" +#endif + /* removed from server, purge when dropping support for server 1.10 */ #define XI86_SEND_DRAG_EVENTS 0x08 @@ -119,6 +124,7 @@ static Atom prop_swap; static Atom prop_axis_label; static Atom prop_btn_label; static Atom prop_device; +static Atom prop_virtual; /* All devices the evdev driver has allocated and knows about. * MAXDEVICES is safe as null-terminated array, as two devices (VCP and VCK) @@ -277,6 +283,39 @@ SetXkbOption(InputInfoPtr pInfo, char *name, char **option) } } +static BOOL +EvdevDeviceIsVirtual(const char* devicenode) +{ + struct udev *udev = NULL; + struct udev_device *device = NULL; + struct stat st; + int rc = FALSE; + const char *devpath; + + udev = udev_new(); + if (!udev) + goto out; + + stat(devicenode, &st); + device = udev_device_new_from_devnum(udev, 'c', st.st_rdev); + + if (!device) + goto out; + + + devpath = udev_device_get_devpath(device); + if (!devpath) + goto out; + + if (strstr(devpath, "LNXSYSTM")) + rc = TRUE; + +out: + udev_device_unref(device); + udev_unref(udev); + return rc; +} + #ifndef HAVE_SMOOTH_SCROLLING static int wheel_up_button = 4; static int wheel_down_button = 5; @@ -2317,6 +2356,17 @@ EvdevInitProperty(DeviceIntPtr dev) if (rc != Success) return; + if (EvdevDeviceIsVirtual(pEvdev->device)) + { + BOOL virtual = 1; + prop_virtual = MakeAtom(XI_PROP_VIRTUAL_DEVICE, + strlen(XI_PROP_VIRTUAL_DEVICE), TRUE); + rc = XIChangeDeviceProperty(dev, prop_virtual, XA_INTEGER, 8, + PropModeReplace, 1, &virtual, FALSE); + XISetDevicePropertyDeletable(dev, prop_virtual, FALSE); + } + + XISetDevicePropertyDeletable(dev, prop_device, FALSE); if (pEvdev->flags & (EVDEV_RELATIVE_EVENTS | EVDEV_ABSOLUTE_EVENTS)) @@ -2426,7 +2476,8 @@ EvdevSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, if (!checkonly) pEvdev->swap_axes = *((BOOL*)val->data); } else if (atom == prop_axis_label || atom == prop_btn_label || - atom == prop_product_id || atom == prop_device) + atom == prop_product_id || atom == prop_device || + atom == prop_virtual) return BadAccess; /* Read-only properties */ return Success; diff --git a/src/udev.c b/src/udev.c new file mode 100644 index 0000000..9570d8f --- /dev/null +++ b/src/udev.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2011 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Red Hat + * not be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. Red + * Hat makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Peter Hutterer (peter.hutterer@redhat.com) + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "evdev.h" + +#include +#include +#include + +Bool +udev_device_is_virtual(const char* devicenode) +{ + struct udev *udev = NULL; + struct udev_device *device = NULL; + struct stat st; + int rc = FALSE; + const char *devpath; + + udev = udev_new(); + if (!udev) + goto out; + + stat(devicenode, &st); + device = udev_device_new_from_devnum(udev, 'c', st.st_rdev); + + if (!device) + goto out; + + + devpath = udev_device_get_devpath(device); + if (!devpath) + goto out; + + if (strstr(devpath, "LNXSYSTM")) + rc = TRUE; + +out: + udev_device_unref(device); + udev_unref(udev); + return rc; +} -- cgit v1.2.3 From e18abd0049421a98e61c15c2d56cfe2821cf4739 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Mon, 8 Nov 2010 11:08:01 -0500 Subject: 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 Amendments: XI_TouchMotion -> XI_TouchUpdate, rename mtMask to mt_mask Signed-off-by: Peter Hutterer --- configure.ac | 11 +++ src/evdev.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/evdev.h | 25 ++++++- 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, -- cgit v1.2.3 From c9a2b4e9ce9b15e57241184df78c72ec8f6a4705 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Mon, 8 Nov 2010 14:35:02 -0500 Subject: Use MTDev for multitouch devices MTDev translates all multitouch devices to the slotted evdev protocol. This provides a clean and uniform interface and reduces message handling inside the input module and X. Signed-off-by: Chase Douglas --- configure.ac | 3 +++ src/Makefile.am | 1 + src/evdev.c | 39 ++++++++++++++++++++++++++++++++++++--- src/evdev.h | 5 +++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 8acc862..cfff2d4 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,9 @@ AC_ARG_ENABLE(multitouch, if test "x$MULTITOUCH" = xyes; then AC_DEFINE(MULTITOUCH, 1, [Enable experimental multitouch code]) + + # Obtain compiler/linker options for mtdev + PKG_CHECK_MODULES(MTDEV, mtdev) fi # Define a configure option for an alternate input module directory diff --git a/src/Makefile.am b/src/Makefile.am index b3a5671..cca1b0c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,7 @@ AM_CPPFLAGS =-I$(top_srcdir)/include @DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la @DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version +@DRIVER_NAME@_drv_la_LIBADD = $(MTDEV_LIBS) @DRIVER_NAME@_drv_ladir = @inputdir@ @DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \ diff --git a/src/evdev.c b/src/evdev.c index 16f7339..48bfaea 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -998,7 +998,17 @@ EvdevReadInput(InputInfoPtr pInfo) while (len == sizeof(ev)) { - len = read(pInfo->fd, &ev, sizeof(ev)); +#ifdef MULTITOUCH + EvdevPtr pEvdev = pInfo->private; + + if (pEvdev->mtdev) + len = mtdev_get(pEvdev->mtdev, pInfo->fd, ev, NUM_EVENTS) * + sizeof(struct input_event); + else + len = read(pInfo->fd, &ev, sizeof(ev)); +#else + len = read(pInfo->fd, &ev, sizeof(ev)); +#endif if (len <= 0) { if (errno == ENODEV) /* May happen after resume */ @@ -1199,8 +1209,8 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) 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 (pEvdev->mtdev->caps.slot.maximum > 0) + num_touches = pEvdev->mtdev->caps.slot.maximum; if (!InitTouchClassDeviceStruct(device, num_touches, mode, num_mt_axes)) { @@ -1685,6 +1695,8 @@ EvdevProc(DeviceIntPtr device, int what) 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 EvdevRemoveDevice(pInfo); pEvdev->min_maj = 0; @@ -2084,6 +2096,16 @@ EvdevOpenDevice(InputInfoPtr pInfo) pEvdev->device = device; xf86IDrvMsg(pInfo, X_CONFIG, "Device: \"%s\"\n", device); + +#ifdef MULTITOUCH + pEvdev->mtdev = malloc(sizeof(struct mtdev)); + if (!pEvdev->mtdev) + { + xf86Msg(X_ERROR, "%s: Couldn't allocate mtdev structure\n", + pInfo->name); + return BadAlloc; + } +#endif } if (pInfo->fd < 0) @@ -2098,6 +2120,17 @@ EvdevOpenDevice(InputInfoPtr pInfo) } } +#ifdef MULTITOUCH + if (mtdev_open(pEvdev->mtdev, pInfo->fd) == 0) + pEvdev->cur_slot = pEvdev->mtdev->caps.slot.value; + else { + free(pEvdev->mtdev); + pEvdev->mtdev = NULL; + xf86Msg(X_ERROR, "%s: Couldn't open mtdev device\n", pInfo->name); + return FALSE; + } +#endif + /* Check major/minor of device node to avoid adding duplicate devices. */ pEvdev->min_maj = EvdevGetMajorMinor(pInfo); if (EvdevIsDuplicate(pInfo)) diff --git a/src/evdev.h b/src/evdev.h index 6e3b850..c588b5d 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -39,6 +39,10 @@ #include #include +#ifdef MULTITOUCH +#include +#endif + #ifndef EV_CNT /* linux 2.6.23 kernels and earlier lack _CNT defines */ #define EV_CNT (EV_MAX+1) #endif @@ -142,6 +146,7 @@ typedef struct { int cur_slot; BOOL close_slot; BOOL open_slot; + struct mtdev *mtdev; #endif int flags; -- cgit v1.2.3 From 907b7cad3fd892ca3349cd18e9ccdc5659027b40 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Thu, 2 Dec 2010 18:01:41 -0500 Subject: Ensure touchpad events are always processed with MT Without this change, an MT touchpad in relative mode could end a touch while not resetting the oldMask used to calculate relative values. This fix allows a Magic Trackpad to behave as a relative mode device again. Signed-off-by: Chase Douglas --- src/evdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index 48bfaea..d32427c 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -774,8 +774,9 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev) else { map = pEvdev->axis_map[ev->code]; valuator_mask_set(pEvdev->vals, map, value); - pEvdev->abs_queued = 1; } + + pEvdev->abs_queued = 1; } /** -- cgit v1.2.3 From c1b89bda12c1897120bace941625cfa27e547458 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 25 Oct 2011 14:52:26 +1000 Subject: Remove duplicate line Signed-off-by: Peter Hutterer --- src/evdev.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index d32427c..9e3cc4e 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1006,10 +1006,9 @@ EvdevReadInput(InputInfoPtr pInfo) len = mtdev_get(pEvdev->mtdev, pInfo->fd, ev, NUM_EVENTS) * sizeof(struct input_event); else - len = read(pInfo->fd, &ev, sizeof(ev)); -#else - len = read(pInfo->fd, &ev, sizeof(ev)); #endif + len = read(pInfo->fd, &ev, sizeof(ev)); + if (len <= 0) { if (errno == ENODEV) /* May happen after resume */ -- cgit v1.2.3 From 91d90a79593369ba1079d06a75f09ceaa9143768 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 25 Oct 2011 14:55:47 +1000 Subject: Use mtdev API to allocate/free mtdev structs Signed-off-by: Peter Hutterer --- src/evdev.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 9e3cc4e..ce7cb7f 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -2096,16 +2096,6 @@ EvdevOpenDevice(InputInfoPtr pInfo) pEvdev->device = device; xf86IDrvMsg(pInfo, X_CONFIG, "Device: \"%s\"\n", device); - -#ifdef MULTITOUCH - pEvdev->mtdev = malloc(sizeof(struct mtdev)); - if (!pEvdev->mtdev) - { - xf86Msg(X_ERROR, "%s: Couldn't allocate mtdev structure\n", - pInfo->name); - return BadAlloc; - } -#endif } if (pInfo->fd < 0) @@ -2121,11 +2111,10 @@ EvdevOpenDevice(InputInfoPtr pInfo) } #ifdef MULTITOUCH - if (mtdev_open(pEvdev->mtdev, pInfo->fd) == 0) + pEvdev->mtdev = mtdev_new_open(pInfo->fd); + if (pEvdev->mtdev) pEvdev->cur_slot = pEvdev->mtdev->caps.slot.value; else { - free(pEvdev->mtdev); - pEvdev->mtdev = NULL; xf86Msg(X_ERROR, "%s: Couldn't open mtdev device\n", pInfo->name); return FALSE; } @@ -2137,6 +2126,10 @@ EvdevOpenDevice(InputInfoPtr pInfo) { xf86IDrvMsg(pInfo, X_WARNING, "device file is duplicate. Ignoring.\n"); close(pInfo->fd); +#ifdef MULTITOUCH + mtdev_close_delete(pEvdev->mtdev); + pEvdev->mtdev = NULL; +#endif return BadMatch; } -- cgit v1.2.3 From fabee66bcc7260ec50c3091be3f9b503eea65e61 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 25 Oct 2011 15:06:38 +1000 Subject: 0 is the value for "unknown/unlimited" number of touches Signed-off-by: Peter Hutterer --- src/evdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index ce7cb7f..8108969 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1205,7 +1205,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) #ifdef MULTITOUCH if (num_mt_axes > 0) { - int num_touches = 10; + int num_touches = 0; int mode = pEvdev->flags & EVDEV_TOUCHPAD ? XIDependentTouch : XIDirectTouch; -- cgit v1.2.3 From fc4f98153c2608389d87e37316036a31fb1021e7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 26 Oct 2011 09:59:34 +1000 Subject: MT axes are counted separately, make sure they're initialized too. Signed-off-by: Peter Hutterer --- src/evdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index 8108969..366de37 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1196,7 +1196,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) EvdevInitAxesLabels(pEvdev, pEvdev->num_vals + num_mt_axes, atoms); - if (!InitValuatorClassDeviceStruct(device, num_axes, atoms, + if (!InitValuatorClassDeviceStruct(device, num_axes + num_mt_axes, atoms, GetMotionHistorySize(), Absolute)) { xf86IDrvMsg(pInfo, X_ERROR, "failed to initialize valuator class device.\n"); goto out; -- cgit v1.2.3 From 6127923fe0d50cb9b9ac4ae0a3876ba6f180137c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 26 Oct 2011 10:51:16 +1000 Subject: When resetting the queue, don't reset the touchMask Otherwise we segfault after the first SYN event Signed-off-by: Peter Hutterer --- src/evdev.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index 366de37..4291343 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -935,6 +935,7 @@ static void EvdevPostQueuedEvents(InputInfoPtr pInfo, int num_v, int first_v, static void EvdevProcessSyncEvent(InputInfoPtr pInfo, struct input_event *ev) { + int i; int num_v = 0, first_v = 0; int v[MAX_VALUATORS] = {}; EvdevPtr pEvdev = pInfo->private; @@ -951,7 +952,15 @@ 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)); + for (i = 0; i < ArrayLength(pEvdev->queue); i++) + { + EventQueuePtr queue = &pEvdev->queue[i]; + queue->detail.key = 0; + queue->type = 0; + queue->val = 0; + /* don't reset the touchMask */ + } + if (pEvdev->vals) valuator_mask_zero(pEvdev->vals); pEvdev->num_queue = 0; -- cgit v1.2.3 From 239e972be1f2c6a984dd6c5aecce710d0b866257 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 26 Oct 2011 11:14:04 +1000 Subject: Simplify a condition, only the event type differs here Signed-off-by: Peter Hutterer --- src/evdev.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 4291343..97da9c8 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -704,20 +704,23 @@ static void EvdevProcessTouch(InputInfoPtr pInfo) { EvdevPtr pEvdev = pInfo->private; + int type; 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; - } + if (pEvdev->close_slot) + type = XI_TouchEnd; + else if (pEvdev->open_slot) + type = XI_TouchBegin; + else + type = XI_TouchUpdate; + + + EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mt_mask, type); + + pEvdev->close_slot = 0; + pEvdev->open_slot = 0; valuator_mask_zero(pEvdev->mt_mask); } -- cgit v1.2.3 From 9411749f76c31a8054ded62a6fb767c8135b4d4e Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 26 Oct 2011 13:09:30 +1000 Subject: Replace open_slot/close_slot with a SlotState enum Signed-off-by: Peter Hutterer --- src/evdev.c | 11 +++++------ src/evdev.h | 9 +++++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 97da9c8..b55a0aa 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -709,9 +709,9 @@ EvdevProcessTouch(InputInfoPtr pInfo) if (pEvdev->cur_slot < 0 || !pEvdev->mt_mask) return; - if (pEvdev->close_slot) + if (pEvdev->slot_state == SLOTSTATE_CLOSE) type = XI_TouchEnd; - else if (pEvdev->open_slot) + else if (pEvdev->slot_state == SLOTSTATE_OPEN) type = XI_TouchBegin; else type = XI_TouchUpdate; @@ -719,8 +719,7 @@ EvdevProcessTouch(InputInfoPtr pInfo) EvdevQueueTouchEvent(pInfo, pEvdev->cur_slot, pEvdev->mt_mask, type); - pEvdev->close_slot = 0; - pEvdev->open_slot = 0; + pEvdev->slot_state = SLOTSTATE_EMPTY; valuator_mask_zero(pEvdev->mt_mask); } @@ -736,9 +735,9 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev) pEvdev->cur_slot = ev->value; } else if (ev->code == ABS_MT_TRACKING_ID) { if (ev->value >= 0) - pEvdev->open_slot = 1; + pEvdev->slot_state = SLOTSTATE_OPEN; else - pEvdev->close_slot = 1; + pEvdev->slot_state = SLOTSTATE_CLOSE; } else { map = pEvdev->axis_map[ev->code] - pEvdev->num_vals; valuator_mask_set(pEvdev->mt_mask, map, ev->value); diff --git a/src/evdev.h b/src/evdev.h index c588b5d..165aea4 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -100,6 +100,12 @@ enum fkeymode { FKEYMODE_MMKEYS, /* function keys send multimedia keys */ }; +enum SlotState { + SLOTSTATE_OPEN = 8, + SLOTSTATE_CLOSE, + SLOTSTATE_EMPTY, +}; + /* axis specific data for wheel emulation */ typedef struct { int up_button; @@ -144,8 +150,7 @@ typedef struct { #ifdef MULTITOUCH ValuatorMask *mt_mask; int cur_slot; - BOOL close_slot; - BOOL open_slot; + enum SlotState slot_state; struct mtdev *mtdev; #endif -- cgit v1.2.3 From 2ce305129ca94394096f4d697d51eb120de2940b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 26 Oct 2011 13:21:18 +1000 Subject: Skip event posting for empty slots. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ABS_MT_SLOT comes before any other events. The following order of events is common for protocol B devices (and mtdev): ... EV_SYN ABS_MT_SLOT → posting here means we miss on the position information ABS_MT_POSITION_X ABS_MT_POSITION_Y ABS_MT_SLOT ABS_MT_POSITION_X ABS_MT_POSITION_Y EV_SYN Store the stot state as SLOT_EMPTY after posting an event (i.e. EV_SYN and ABS_MT_SLOT) and then don't post until the next slot/syn event. Signed-off-by: Peter Hutterer --- src/evdev.c | 17 +++++++++++++---- src/evdev.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index b55a0aa..13b1e10 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -709,6 +709,10 @@ EvdevProcessTouch(InputInfoPtr pInfo) if (pEvdev->cur_slot < 0 || !pEvdev->mt_mask) return; + /* 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; else if (pEvdev->slot_state == SLOTSTATE_OPEN) @@ -733,14 +737,19 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev) if (ev->code == ABS_MT_SLOT) { EvdevProcessTouch(pInfo); pEvdev->cur_slot = ev->value; - } else if (ev->code == ABS_MT_TRACKING_ID) { + } else + { + 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; - } else { - map = pEvdev->axis_map[ev->code] - pEvdev->num_vals; - valuator_mask_set(pEvdev->mt_mask, map, ev->value); + } else { + map = pEvdev->axis_map[ev->code] - pEvdev->num_vals; + valuator_mask_set(pEvdev->mt_mask, map, ev->value); + } } } #else diff --git a/src/evdev.h b/src/evdev.h index 165aea4..27e404c 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -103,6 +103,7 @@ enum fkeymode { enum SlotState { SLOTSTATE_OPEN = 8, SLOTSTATE_CLOSE, + SLOTSTATE_UPDATE, SLOTSTATE_EMPTY, }; -- cgit v1.2.3 From 5e9b027807cc205dc9c4efbb8360ac4b20317682 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 31 Oct 2011 08:58:18 +1000 Subject: Replace 0/1 button values with enums BUTTON_PRESS is much harder to confuse with a button number than a simple 1. Signed-off-by: Peter Hutterer --- src/emuMB.c | 3 ++- src/emuThird.c | 19 ++++++++++--------- src/evdev.c | 5 +++-- src/evdev.h | 7 ++++++- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/emuMB.c b/src/emuMB.c index b7a57b8..eb01495 100644 --- a/src/emuMB.c +++ b/src/emuMB.c @@ -191,7 +191,8 @@ EvdevMBEmuTimer(InputInfoPtr pInfo) pEvdev->emulateMB.pending = FALSE; if ((id = stateTab[pEvdev->emulateMB.state][4][0]) != 0) { - EvdevPostButtonEvent(pInfo, abs(id), (id >= 0)); + EvdevPostButtonEvent(pInfo, abs(id), + (id >= 0) ? BUTTON_PRESS : BUTTON_RELEASE); pEvdev->emulateMB.state = stateTab[pEvdev->emulateMB.state][4][2]; } else { diff --git a/src/emuThird.c b/src/emuThird.c index d89fd9e..7461767 100644 --- a/src/emuThird.c +++ b/src/emuThird.c @@ -58,7 +58,7 @@ enum EmulationState { }; static void -Evdev3BEmuPostButtonEvent(InputInfoPtr pInfo, int button, int press) +Evdev3BEmuPostButtonEvent(InputInfoPtr pInfo, int button, enum ButtonAction act) { EvdevPtr pEvdev = pInfo->private; struct emulate3B *emu3B = &pEvdev->emulate3B; @@ -72,7 +72,8 @@ Evdev3BEmuPostButtonEvent(InputInfoPtr pInfo, int button, int press) if (emu3B->flags & EVDEV_ABSOLUTE_EVENTS) absolute = Absolute; - xf86PostButtonEventP(pInfo->dev, absolute, button, press, 0, + xf86PostButtonEventP(pInfo->dev, absolute, button, + (act == BUTTON_PRESS) ? 1 : 0, 0, (absolute ? 2 : 0), emu3B->startpos); } @@ -92,7 +93,7 @@ Evdev3BEmuTimer(OsTimerPtr timer, CARD32 time, pointer arg) sigstate = xf86BlockSIGIO (); emu3B->state = EM3B_EMULATING; - Evdev3BEmuPostButtonEvent(pInfo, emu3B->button, 1); + Evdev3BEmuPostButtonEvent(pInfo, emu3B->button, BUTTON_PRESS); xf86UnblockSIGIO (sigstate); return 0; } @@ -145,14 +146,14 @@ Evdev3BEmuFilterEvent(InputInfoPtr pInfo, int button, BOOL press) switch (emu3B->state) { case EM3B_PENDING: - Evdev3BEmuPostButtonEvent(pInfo, 1, 1); + Evdev3BEmuPostButtonEvent(pInfo, 1, BUTTON_PRESS); Evdev3BCancel(pInfo); break; case EM3B_EMULATING: /* We're emulating and now the user pressed a different * button. Just release the emulating one, tell the user to * not do that and get on with life */ - Evdev3BEmuPostButtonEvent(pInfo, emu3B->button, 0); + Evdev3BEmuPostButtonEvent(pInfo, emu3B->button, BUTTON_RELEASE); Evdev3BCancel(pInfo); break; default: @@ -171,11 +172,11 @@ Evdev3BEmuFilterEvent(InputInfoPtr pInfo, int button, BOOL press) switch(emu3B->state) { case EM3B_PENDING: - Evdev3BEmuPostButtonEvent(pInfo, 1, 1); + Evdev3BEmuPostButtonEvent(pInfo, 1, BUTTON_PRESS); Evdev3BCancel(pInfo); break; case EM3B_EMULATING: - Evdev3BEmuPostButtonEvent(pInfo, emu3B->button, 0); + Evdev3BEmuPostButtonEvent(pInfo, emu3B->button, BUTTON_RELEASE); Evdev3BCancel(pInfo); ret = TRUE; break; @@ -237,7 +238,7 @@ Evdev3BEmuProcessAbsMotion(InputInfoPtr pInfo, ValuatorMask *vals) if (cancel) { - Evdev3BEmuPostButtonEvent(pInfo, 1, 1); + Evdev3BEmuPostButtonEvent(pInfo, 1, BUTTON_PRESS); Evdev3BCancel(pInfo); } } @@ -262,7 +263,7 @@ Evdev3BEmuProcessRelMotion(InputInfoPtr pInfo, int dx, int dy) if (abs(emu3B->delta[0]) > emu3B->threshold || abs(emu3B->delta[1]) > emu3B->threshold) { - Evdev3BEmuPostButtonEvent(pInfo, 1, 1); + Evdev3BEmuPostButtonEvent(pInfo, 1, BUTTON_PRESS); Evdev3BCancel(pInfo); } } diff --git a/src/evdev.c b/src/evdev.c index 13b1e10..4bb55f5 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -411,9 +411,10 @@ EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch, ValuatorMask *mask, * Interface for MB emulation since these need to post immediately. */ void -EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value) +EvdevPostButtonEvent(InputInfoPtr pInfo, int button, enum ButtonAction act) { - xf86PostButtonEvent(pInfo->dev, Relative, button, value, 0, 0); + xf86PostButtonEvent(pInfo->dev, Relative, button, + (act == BUTTON_PRESS) ? 1 : 0, 0, 0); } void diff --git a/src/evdev.h b/src/evdev.h index 27e404c..5fd99ff 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -107,6 +107,11 @@ enum SlotState { SLOTSTATE_EMPTY, }; +enum ButtonAction { + BUTTON_RELEASE = 0, + BUTTON_PRESS = 1 +}; + /* axis specific data for wheel emulation */ typedef struct { int up_button; @@ -248,7 +253,7 @@ void EvdevQueueProximityEvent(InputInfoPtr pInfo, int value); void EvdevQueueTouchEvent(InputInfoPtr pInfo, unsigned int touch, ValuatorMask *mask, uint16_t type); #endif -void EvdevPostButtonEvent(InputInfoPtr pInfo, int button, int value); +void EvdevPostButtonEvent(InputInfoPtr pInfo, int button, enum ButtonAction act); void EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count); void EvdevPostRelativeMotionEvents(InputInfoPtr pInfo, int num_v, int first_v, int v[MAX_VALUATORS]); -- cgit v1.2.3 From 3175a2a96d448a0b2584a58ab3d05fbebb11fab1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 2 Nov 2011 09:53:34 +1000 Subject: Print to the log if we find multitouch axes. No real effect on the code, but it helps to have that line in the log when searching for driver issues. Signed-off-by: Peter Hutterer --- src/evdev.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index 4bb55f5..f88074b 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1866,6 +1866,7 @@ EvdevProbe(InputInfoPtr pInfo) { int i, has_rel_axes, has_abs_axes, has_keys, num_buttons, has_scroll; int has_lmr; /* left middle right */ + int has_mt; /* multitouch */ int ignore_abs = 0, ignore_rel = 0; EvdevPtr pEvdev = pInfo->private; int rc = 1; @@ -1899,6 +1900,7 @@ EvdevProbe(InputInfoPtr pInfo) has_keys = FALSE; has_scroll = FALSE; has_lmr = FALSE; + has_mt = FALSE; num_buttons = 0; /* count all buttons */ @@ -1966,6 +1968,15 @@ EvdevProbe(InputInfoPtr pInfo) } } +#ifdef MULTITOUCH + for (i = ABS_MT_SLOT; i < ABS_MAX; i++) { + if (EvdevBitIsSet(pEvdev->abs_bitmask, i)) { + has_mt = TRUE; + break; + } + } +#endif + if (ignore_abs && has_abs_axes) { xf86IDrvMsg(pInfo, X_INFO, "Absolute axes present but ignored.\n"); @@ -1974,6 +1985,9 @@ EvdevProbe(InputInfoPtr pInfo) xf86IDrvMsg(pInfo, X_PROBED, "Found absolute axes\n"); pEvdev->flags |= EVDEV_ABSOLUTE_EVENTS; + if (has_mt) + xf86IDrvMsg(pInfo, X_PROBED, "Found absolute multitouch axes\n"); + if ((EvdevBitIsSet(pEvdev->abs_bitmask, ABS_X) && EvdevBitIsSet(pEvdev->abs_bitmask, ABS_Y))) { xf86IDrvMsg(pInfo, X_PROBED, "Found x and y absolute axes\n"); -- cgit v1.2.3 From fac1a41c75a7c4bfabff34dc8ed1dff2587c6011 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Fri, 11 Nov 2011 15:57:26 +1000 Subject: Add the required defines to compile against the inputproto Signed-off-by: Peter Hutterer --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index cfff2d4..381883b 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,8 @@ AC_ARG_ENABLE(multitouch, if test "x$MULTITOUCH" = xyes; then AC_DEFINE(MULTITOUCH, 1, [Enable experimental multitouch code]) + AC_DEFINE(XINPUT2_1_USE_UNSTABLE_PROTOCOL, 1, [Enable XI 2.1 protocol]) + AC_DEFINE(XINPUT2_2_USE_UNSTABLE_PROTOCOL, 1, [Enable XI 2.2 protocol]) # Obtain compiler/linker options for mtdev PKG_CHECK_MODULES(MTDEV, mtdev) -- cgit v1.2.3 From cf93a21df1dd66118d3a1f5a0769d48f317de749 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Tue, 29 Nov 2011 18:02:58 -0800 Subject: Don't send pointer events for multitouch touchscreen devices Pointer events will be emulated by the server. Signed-off-by: Chase Douglas --- src/evdev.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index f88074b..760f3ce 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -781,14 +781,14 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev) if (EvdevWheelEmuFilterMotion(pInfo, ev)) return; - if (ev->code >= ABS_MT_SLOT) + if (ev->code >= ABS_MT_SLOT) { EvdevProcessTouchEvent(pInfo, ev); - else { + pEvdev->abs_queued = 1; + } else if (!pEvdev->mt_mask) { map = pEvdev->axis_map[ev->code]; valuator_mask_set(pEvdev->vals, map, value); + pEvdev->abs_queued = 1; } - - pEvdev->abs_queued = 1; } /** @@ -823,7 +823,8 @@ EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev) * BTN_TOUCH as the proximity notifier */ if (!pEvdev->use_proximity) pEvdev->in_proximity = value ? ev->code : 0; - if (!(pEvdev->flags & (EVDEV_TOUCHSCREEN | EVDEV_TABLET))) + if (!(pEvdev->flags & (EVDEV_TOUCHSCREEN | EVDEV_TABLET)) || + pEvdev->mt_mask) break; /* Treat BTN_TOUCH from devices that only have BTN_TOUCH as * BTN_LEFT. */ -- cgit v1.2.3 From fed454192ddc4ad94226040c657deb6abea3df88 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 15 Dec 2011 08:55:32 +1000 Subject: Use xf86InitValuatorAxisStruct, the touch-specific version was dropped Signed-off-by: Peter Hutterer --- src/evdev.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 760f3ce..8adfefd 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1275,11 +1275,12 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) 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); + xf86InitValuatorAxisStruct(device, axnum, + atoms[axnum + pEvdev->num_vals], + pEvdev->absinfo[axis].minimum, + pEvdev->absinfo[axis].maximum, + resolution, 0, resolution, + Absolute); } #endif -- cgit v1.2.3 From f3c628acc4f7399325756590cdc72e769341243c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 20 Dec 2011 10:56:22 +1000 Subject: Map ABS_MT_POSITION_X/Y into ABS_X/Y MT axes are the same as traditional axes, so one into the other so we get x/y coordinates regardless wich axes it comes from. Signed-off-by: Peter Hutterer --- src/evdev.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index 8adfefd..9a5608b 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -748,7 +748,12 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev) else pEvdev->slot_state = SLOTSTATE_CLOSE; } else { - map = pEvdev->axis_map[ev->code] - pEvdev->num_vals; + if (ev->code == ABS_MT_POSITION_X) + map = pEvdev->axis_map[ABS_X]; + else if (ev->code == ABS_MT_POSITION_Y) + map = pEvdev->axis_map[ABS_Y]; + else + map = pEvdev->axis_map[ev->code] - pEvdev->num_vals; valuator_mask_set(pEvdev->mt_mask, map, ev->value); } } -- cgit v1.2.3 From a1c3f8efbbff7f93e216ccdb32bd176a8ba33b09 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 20 Dec 2011 13:32:06 +1000 Subject: Drop now-unnecessary XI 2.1 and XI 2.2 error suppression defines Gone since inputproto 2.1.99.3 Signed-off-by: Peter Hutterer --- configure.ac | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index 381883b..cfff2d4 100644 --- a/configure.ac +++ b/configure.ac @@ -57,8 +57,6 @@ AC_ARG_ENABLE(multitouch, if test "x$MULTITOUCH" = xyes; then AC_DEFINE(MULTITOUCH, 1, [Enable experimental multitouch code]) - AC_DEFINE(XINPUT2_1_USE_UNSTABLE_PROTOCOL, 1, [Enable XI 2.1 protocol]) - AC_DEFINE(XINPUT2_2_USE_UNSTABLE_PROTOCOL, 1, [Enable XI 2.2 protocol]) # Obtain compiler/linker options for mtdev PKG_CHECK_MODULES(MTDEV, mtdev) -- cgit v1.2.3 From 191660189a01b9c96bb4c0fa1a2e5008ae666238 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 20 Dec 2011 14:14:16 +1000 Subject: Add is_blacklisted_axis() helper The kernel exports a bunch of information as axis that shouldn't be an axis and we don't treat it as axis in the server. Add this helper instead of checking for the axis codes manually. No function change. Signed-off-by: Peter Hutterer --- src/evdev.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 9a5608b..00c9935 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1131,6 +1131,23 @@ EvdevAddKeyClass(DeviceIntPtr device) return Success; } +/** + * return TRUE if the axis is not one we should count as true axis + */ +static int +is_blacklisted_axis(int axis) +{ + switch(axis) + { + case ABS_MT_SLOT: + case ABS_MT_TRACKING_ID: + return TRUE; + default: + return FALSE; + } +} + + static int EvdevAddAbsValuatorClass(DeviceIntPtr device) { @@ -1155,7 +1172,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) { if (EvdevBitIsSet(pEvdev->abs_bitmask, axis)) { - if(axis != ABS_MT_SLOT && axis != ABS_MT_TRACKING_ID) + if (!is_blacklisted_axis(axis)) num_mt_axes++; num_axes--; } @@ -1215,7 +1232,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) for (axis = ABS_X; i < MAX_VALUATORS && axis <= ABS_MAX; axis++) { pEvdev->axis_map[axis] = -1; if (!EvdevBitIsSet(pEvdev->abs_bitmask, axis) || - axis == ABS_MT_SLOT || axis == ABS_MT_TRACKING_ID) + is_blacklisted_axis(axis)) continue; pEvdev->axis_map[axis] = i; i++; -- cgit v1.2.3 From e99ab2314f712df8dd705b16008755f8b3095707 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 20 Dec 2011 15:08:06 +1000 Subject: Don't count legacy and MT axes twice The kernel exports both ABS_X and ABS_MT_POSITION_X (and a couple others) for a multi-touch capable device. For such devices, only count the axis once since we submit ABS_MT_POSITION_X through ABS_X. Signed-off-by: Peter Hutterer --- src/evdev.c | 107 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 27 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 00c9935..aef1d6e 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -748,12 +748,7 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev) else pEvdev->slot_state = SLOTSTATE_CLOSE; } else { - if (ev->code == ABS_MT_POSITION_X) - map = pEvdev->axis_map[ABS_X]; - else if (ev->code == ABS_MT_POSITION_Y) - map = pEvdev->axis_map[ABS_Y]; - else - map = pEvdev->axis_map[ev->code] - pEvdev->num_vals; + map = pEvdev->axis_map[ev->code]; valuator_mask_set(pEvdev->mt_mask, map, ev->value); } } @@ -1131,6 +1126,24 @@ EvdevAddKeyClass(DeviceIntPtr device) return Success; } +/* MT axes are counted twice - once as ABS_X (which the kernel keeps for + * backwards compatibility), once as ABS_MT_POSITION_X. So we need to keep a + * mapping of those axes to make sure we only count them once + */ +struct mt_axis_mappings { + int mt_code; + int code; + Bool needs_mapping; /* TRUE if both code and mt_code are present */ + int mapping; /* Logical mapping of 'code' axis */ +}; + +static struct mt_axis_mappings mt_axis_mappings[] = { + {ABS_MT_POSITION_X, ABS_X}, + {ABS_MT_POSITION_Y, ABS_Y}, + {ABS_MT_PRESSURE, ABS_PRESSURE}, + {ABS_MT_DISTANCE, ABS_DISTANCE}, +}; + /** * return TRUE if the axis is not one we should count as true axis */ @@ -1154,7 +1167,9 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) InputInfoPtr pInfo; EvdevPtr pEvdev; int num_axes, axis, i = 0; - int num_mt_axes = 0; + int num_mt_axes = 0, /* number of MT-only axes */ + num_mt_axes_total = 0; /* total number of MT axes, including + double-counted ones, excluding blacklisted */ Atom *atoms; pInfo = device->public.devicePrivate; @@ -1172,26 +1187,35 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) { if (EvdevBitIsSet(pEvdev->abs_bitmask, axis)) { + int j; + Bool skip = FALSE; + + for (j = 0; j < ArrayLength(mt_axis_mappings); j++) + { + if (mt_axis_mappings[j].mt_code == axis && + BitIsOn(pEvdev->abs_bitmask, mt_axis_mappings[j].code)) + { + mt_axis_mappings[j].needs_mapping = TRUE; + skip = TRUE; + } + } + if (!is_blacklisted_axis(axis)) - num_mt_axes++; + { + num_mt_axes_total++; + if (!skip) + num_mt_axes++; + } num_axes--; } } #endif - - if (num_axes > MAX_VALUATORS) { + if (num_axes + num_mt_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) { + if (num_axes < 1 && num_mt_axes_total < 1) { xf86Msg(X_WARNING, "%s: no absolute or touch axes found.\n", device->name); return !Success; @@ -1207,8 +1231,8 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) } } #ifdef MULTITOUCH - if (num_mt_axes > 0) { - pEvdev->mt_mask = valuator_mask_new(num_mt_axes); + if (num_mt_axes_total > 0) { + pEvdev->mt_mask = valuator_mask_new(num_mt_axes_total); if (!pEvdev->mt_mask) { xf86Msg(X_ERROR, "%s: failed to allocate MT valuator mask.\n", device->name); @@ -1217,7 +1241,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) for (i = 0; i < EVDEV_MAXQUEUE; i++) { pEvdev->queue[i].touchMask = - valuator_mask_new(num_mt_axes); + valuator_mask_new(num_mt_axes_total); if (!pEvdev->queue[i].touchMask) { xf86Msg(X_ERROR, "%s: failed to allocate MT valuator masks for " "evdev event queue.\n", device->name); @@ -1230,12 +1254,27 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) i = 0; for (axis = ABS_X; i < MAX_VALUATORS && axis <= ABS_MAX; axis++) { + int j; + int mapping; pEvdev->axis_map[axis] = -1; if (!EvdevBitIsSet(pEvdev->abs_bitmask, axis) || is_blacklisted_axis(axis)) continue; - pEvdev->axis_map[axis] = i; - i++; + + mapping = i; + + for (j = 0; j < ArrayLength(mt_axis_mappings); j++) + { + if (mt_axis_mappings[j].code == axis) + mt_axis_mappings[j].mapping = mapping; + else if (mt_axis_mappings[j].mt_code == axis && + mt_axis_mappings[j].needs_mapping) + mapping = mt_axis_mappings[j].mapping; + } + + pEvdev->axis_map[axis] = mapping; + if (mapping == i) + i++; } EvdevInitAxesLabels(pEvdev, pEvdev->num_vals + num_mt_axes, atoms); @@ -1247,7 +1286,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) } #ifdef MULTITOUCH - if (num_mt_axes > 0) + if (num_mt_axes_total > 0) { int num_touches = 0; int mode = pEvdev->flags & EVDEV_TOUCHPAD ? @@ -1257,7 +1296,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) num_touches = pEvdev->mtdev->caps.slot.maximum; if (!InitTouchClassDeviceStruct(device, num_touches, mode, - num_mt_axes)) { + num_mt_axes_total)) { xf86Msg(X_ERROR, "%s: failed to initialize touch class device.\n", device->name); goto out; @@ -1288,17 +1327,31 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device) #ifdef MULTITOUCH for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) { - int axnum = pEvdev->axis_map[axis] - pEvdev->num_vals; + int axnum = pEvdev->axis_map[axis]; int resolution = 10000; + int j; + BOOL skip = FALSE; if (axnum < 0) continue; + for (j = 0; j < ArrayLength(mt_axis_mappings); j++) + if (mt_axis_mappings[j].mt_code == axis && + mt_axis_mappings[j].needs_mapping) + { + skip = TRUE; + break; + } + + /* MT axis is mapped, don't set up twice */ + if (skip) + continue; + if (pEvdev->absinfo[axis].resolution) resolution = pEvdev->absinfo[axis].resolution * 1000; xf86InitValuatorAxisStruct(device, axnum, - atoms[axnum + pEvdev->num_vals], + atoms[axnum], pEvdev->absinfo[axis].minimum, pEvdev->absinfo[axis].maximum, resolution, 0, resolution, -- cgit v1.2.3