aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/emuMB.c6
-rw-r--r--src/emuWheel.c20
-rw-r--r--src/evdev.c241
-rw-r--r--src/evdev.h16
5 files changed, 129 insertions, 157 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 2b6c800..4f0937e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,8 @@
# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
# _ladir passes a dummy rpath to libtool so the thing will actually link
# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
-AM_CFLAGS = $(XORG_CFLAGS)
+
+AM_CFLAGS = $(XORG_CFLAGS) $(CWARNFLAGS)
@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
diff --git a/src/emuMB.c b/src/emuMB.c
index 199c0d7..113a708 100644
--- a/src/emuMB.c
+++ b/src/emuMB.c
@@ -309,7 +309,11 @@ void
EvdevMBEmuPreInit(InputInfoPtr pInfo)
{
EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
- pEvdev->emulateMB.enabled = MBEMU_AUTO;
+
+ if (pEvdev->flags & EVDEV_TOUCHSCREEN)
+ pEvdev->emulateMB.enabled = MBEMU_DISABLED;
+ else
+ pEvdev->emulateMB.enabled = MBEMU_AUTO;
if (xf86FindOption(pInfo->options, "Emulate3Buttons"))
{
diff --git a/src/emuWheel.c b/src/emuWheel.c
index e7b2f98..3f0dfd4 100644
--- a/src/emuWheel.c
+++ b/src/emuWheel.c
@@ -100,6 +100,7 @@ EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
WheelAxisPtr pAxis = NULL, pOtherAxis = NULL;
int value = pEv->value;
+ int oldValue;
/* Has wheel emulation been configured to be enabled? */
if (!pEvdev->emulateWheel.enabled)
@@ -118,12 +119,21 @@ EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
}
/* We don't want to intercept real mouse wheel events */
+ if(pEv->type == EV_ABS) {
+ oldValue = pEvdev->vals[pEvdev->axis_map[pEv->code]];
+ pEvdev->vals[pEvdev->axis_map[pEv->code]] = value;
+ value -= oldValue; /* make value into a differential measurement */
+ }
+
switch(pEv->code) {
+
+ /* ABS_X has the same value as REL_X, so this case catches both */
case REL_X:
pAxis = &(pEvdev->emulateWheel.X);
pOtherAxis = &(pEvdev->emulateWheel.Y);
break;
+ /* ABS_Y has the same value as REL_Y, so this case catches both */
case REL_Y:
pAxis = &(pEvdev->emulateWheel.Y);
pOtherAxis = &(pEvdev->emulateWheel.X);
@@ -133,11 +143,11 @@ EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv)
break;
}
- /* If we found REL_X or REL_Y, emulate a mouse wheel.
- Reset the inertia of the other axis when a scroll event was sent
- to avoid the buildup of erroneous scroll events if the user
- doesn't move in a perfectly straight line.
- */
+ /* If we found REL_X, REL_Y, ABS_X or ABS_Y then emulate a mouse
+ wheel. Reset the inertia of the other axis when a scroll event
+ was sent to avoid the buildup of erroneous scroll events if the
+ user doesn't move in a perfectly straight line.
+ */
if (pAxis)
{
if (EvdevWheelEmuInertia(pInfo, pAxis, value))
diff --git a/src/evdev.c b/src/evdev.c
index 13f81b0..7a9da6d 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -32,6 +32,7 @@
#endif
#include <X11/keysym.h>
+#include <X11/extensions/XI.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -80,19 +81,6 @@
#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
-/* evdev flags */
-#define EVDEV_KEYBOARD_EVENTS (1 << 0)
-#define EVDEV_BUTTON_EVENTS (1 << 1)
-#define EVDEV_RELATIVE_EVENTS (1 << 2)
-#define EVDEV_ABSOLUTE_EVENTS (1 << 3)
-#define EVDEV_TOUCHPAD (1 << 4)
-#define EVDEV_INITIALIZED (1 << 5) /* WheelInit etc. called already? */
-#define EVDEV_TOUCHSCREEN (1 << 6)
-#define EVDEV_CALIBRATED (1 << 7) /* run-time calibrated? */
-#define EVDEV_TABLET (1 << 8) /* device looks like a tablet? */
-#define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
-#define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
-
#define MIN_KEYCODE 8
#define GLYPHS_PER_KEY 2
#define AltMask Mod1Mask
@@ -117,6 +105,7 @@ static const char *evdevDefaults[] = {
static int EvdevOn(DeviceIntPtr);
static int EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare);
static void EvdevKbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
+static int EvdevSwitchMode(ClientPtr client, DeviceIntPtr device, int mode);
#ifdef HAVE_PROPERTIES
static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
@@ -125,7 +114,6 @@ static void EvdevInitProperty(DeviceIntPtr dev);
static int EvdevSetProperty(DeviceIntPtr dev, Atom atom,
XIPropertyValuePtr val, BOOL checkonly);
static Atom prop_invert = 0;
-static Atom prop_reopen = 0;
static Atom prop_calibration = 0;
static Atom prop_swap = 0;
static Atom prop_axis_label = 0;
@@ -177,6 +165,38 @@ freeRemap(EvdevPtr ev)
* cannot be used by evdev, leaving us with a space of 2 at the end. */
static EvdevPtr evdev_devices[MAXDEVICES] = {NULL};
+static int EvdevSwitchMode(ClientPtr client, DeviceIntPtr device, int mode)
+{
+ InputInfoPtr pInfo;
+ EvdevPtr pEvdev;
+
+ pInfo = device->public.devicePrivate;
+ pEvdev = pInfo->private;
+
+ if (pEvdev->flags & EVDEV_RELATIVE_EVENTS)
+ {
+ if (mode == Relative)
+ return Success;
+ else
+ return XI_BadMode;
+ }
+
+ switch (mode) {
+ case Absolute:
+ pEvdev->flags &= ~EVDEV_RELATIVE_MODE;
+ break;
+
+ case Relative:
+ pEvdev->flags |= EVDEV_RELATIVE_MODE;
+ break;
+
+ default:
+ return XI_BadMode;
+ }
+
+ return Success;
+}
+
static size_t CountBits(unsigned long *array, size_t nlongs)
{
unsigned int i;
@@ -352,19 +372,6 @@ EvdevQueueKbdEvent(InputInfoPtr pInfo, struct input_event *ev, int value)
)
return;
- if (code > 255)
- {
- if (ev->code <= KEY_MAX && !warned[ev->code])
- {
- xf86Msg(X_WARNING, "%s: unable to handle keycode %d\n",
- pInfo->name, ev->code);
- warned[ev->code] = 1;
- }
-
- /* The X server can't handle keycodes > 255. */
- return;
- }
-
if (pEvdev->num_queue >= EVDEV_MAXQUEUE)
{
xf86Msg(X_NONE, "%s: dropping event due to full queue!\n", pInfo->name);
@@ -418,56 +425,6 @@ EvdevQueueButtonClicks(InputInfoPtr pInfo, int button, int count)
}
}
-/**
- * Coming back from resume may leave us with a file descriptor that can be
- * opened but fails on the first read (ENODEV).
- * In this case, try to open the device until it becomes available or until
- * the predefined count expires.
- */
-static CARD32
-EvdevReopenTimer(OsTimerPtr timer, CARD32 time, pointer arg)
-{
- InputInfoPtr pInfo = (InputInfoPtr)arg;
- EvdevPtr pEvdev = pInfo->private;
-
- do {
- pInfo->fd = open(pEvdev->device, O_RDWR | O_NONBLOCK, 0);
- } while (pInfo->fd < 0 && errno == EINTR);
-
- if (pInfo->fd != -1)
- {
- if (EvdevCacheCompare(pInfo, TRUE) == Success)
- {
- xf86Msg(X_INFO, "%s: Device reopened after %d attempts.\n", pInfo->name,
- pEvdev->reopen_attempts - pEvdev->reopen_left + 1);
- EvdevOn(pInfo->dev);
- } else
- {
- xf86Msg(X_ERROR, "%s: Device has changed - disabling.\n",
- pInfo->name);
- xf86DisableDevice(pInfo->dev, FALSE);
- close(pInfo->fd);
- pInfo->fd = -1;
- pEvdev->min_maj = 0; /* don't hog the device */
- }
- pEvdev->reopen_left = 0;
- return 0;
- }
-
- pEvdev->reopen_left--;
-
- if (!pEvdev->reopen_left)
- {
- xf86Msg(X_ERROR, "%s: Failed to reopen device after %d attempts.\n",
- pInfo->name, pEvdev->reopen_attempts);
- xf86DisableDevice(pInfo->dev, FALSE);
- pEvdev->min_maj = 0; /* don't hog the device */
- return 0;
- }
-
- return 100; /* come back in 100 ms */
-}
-
#define ABS_X_VALUE 0x1
#define ABS_Y_VALUE 0x2
#define ABS_VALUE 0x4
@@ -484,7 +441,7 @@ EvdevProcessValuators(InputInfoPtr pInfo, int v[MAX_VALUATORS], int *num_v,
*num_v = *first_v = 0;
/* convert to relative motion for touchpads */
- if (pEvdev->abs && (pEvdev->flags & EVDEV_TOUCHPAD)) {
+ if (pEvdev->abs && (pEvdev->flags & EVDEV_RELATIVE_MODE)) {
if (pEvdev->tool) { /* meaning, touch is active */
if (pEvdev->old_vals[0] != -1)
pEvdev->delta[REL_X] = pEvdev->vals[0] - pEvdev->old_vals[0];
@@ -610,7 +567,7 @@ EvdevProcessButtonEvent(InputInfoPtr pInfo, struct input_event *ev)
static void
EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
{
- static int value;
+ int value;
EvdevPtr pEvdev = pInfo->private;
/* Get the signed value, earlier kernels had this as unsigned */
@@ -655,7 +612,7 @@ EvdevProcessRelativeMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
static void
EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
{
- static int value;
+ int value;
EvdevPtr pEvdev = pInfo->private;
/* Get the signed value, earlier kernels had this as unsigned */
@@ -668,6 +625,9 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
if (ev->code > ABS_MAX)
return;
+ if (EvdevWheelEmuFilterMotion(pInfo, ev))
+ return;
+
pEvdev->vals[pEvdev->axis_map[ev->code]] = value;
if (ev->code == ABS_X)
pEvdev->abs |= ABS_X_VALUE;
@@ -683,7 +643,7 @@ EvdevProcessAbsoluteMotionEvent(InputInfoPtr pInfo, struct input_event *ev)
static void
EvdevProcessKeyEvent(InputInfoPtr pInfo, struct input_event *ev)
{
- static int value;
+ int value;
EvdevPtr pEvdev = pInfo->private;
/* Get the signed value, earlier kernels had this as unsigned */
@@ -843,7 +803,6 @@ EvdevReadInput(InputInfoPtr pInfo)
{
struct input_event ev[NUM_EVENTS];
int i, len = sizeof(ev);
- EvdevPtr pEvdev = pInfo->private;
while (len == sizeof(ev))
{
@@ -856,11 +815,6 @@ EvdevReadInput(InputInfoPtr pInfo)
xf86RemoveEnabledDevice(pInfo);
close(pInfo->fd);
pInfo->fd = -1;
- if (pEvdev->reopen_timer)
- {
- pEvdev->reopen_left = pEvdev->reopen_attempts;
- pEvdev->reopen_timer = TimerSet(pEvdev->reopen_timer, 0, 100, EvdevReopenTimer, pInfo);
- }
} else if (errno != EAGAIN)
{
/* We use X_NONE here because it doesn't alloc */
@@ -1277,6 +1231,7 @@ EvdevAddAbsClass(DeviceIntPtr device)
EvdevPtr pEvdev;
int num_axes, axis, i = 0;
Atom *atoms;
+ const char *mode;
pInfo = device->public.devicePrivate;
pEvdev = pInfo->private;
@@ -1348,6 +1303,22 @@ EvdevAddAbsClass(DeviceIntPtr device)
TestBit(ABS_TILT_Y, pEvdev->abs_bitmask)))
pInfo->flags |= XI86_POINTER_CAPABLE;
+ if (pEvdev->flags & EVDEV_TOUCHPAD)
+ pEvdev->flags |= EVDEV_RELATIVE_MODE;
+ else
+ pEvdev->flags &= ~EVDEV_RELATIVE_MODE;
+
+ if (xf86FindOption(pInfo->options, "Mode"))
+ {
+ mode = xf86SetStrOption(pInfo->options, "Mode", NULL);
+ if (!strcasecmp("absolute", mode))
+ pEvdev->flags &= ~EVDEV_RELATIVE_MODE;
+ else if (!strcasecmp("relative", mode))
+ pEvdev->flags |= EVDEV_RELATIVE_MODE;
+ else
+ xf86Msg(X_INFO, "%s: unknown mode, use default\n", pInfo->name);
+ }
+
return Success;
}
@@ -1409,6 +1380,9 @@ EvdevAddRelClass(DeviceIntPtr device)
GetMotionHistorySize(), Relative))
return !Success;
+ if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
+ return !Success;
+
for (axis = REL_X; axis <= REL_MAX; axis++)
{
int axnum = pEvdev->axis_map[axis];
@@ -1425,9 +1399,6 @@ EvdevAddRelClass(DeviceIntPtr device)
xfree(atoms);
- if (!InitPtrFeedbackClassDeviceStruct(device, EvdevPtrCtrlProc))
- return !Success;
-
pInfo->flags |= XI86_POINTER_CAPABLE;
return Success;
@@ -1635,9 +1606,6 @@ EvdevInit(DeviceIntPtr device)
/**
* Init all extras (wheel emulation, etc.) and grab the device.
- *
- * Coming from a resume, the grab may fail with ENODEV. In this case, we set a
- * timer to wake up and try to reopen the device later.
*/
static int
EvdevOn(DeviceIntPtr device)
@@ -1649,43 +1617,37 @@ EvdevOn(DeviceIntPtr device)
pInfo = device->public.devicePrivate;
pEvdev = pInfo->private;
- if (pInfo->fd != -1 && pEvdev->grabDevice &&
- (rc = ioctl(pInfo->fd, EVIOCGRAB, (void *)1)))
+ if (pInfo->fd == -1) /* after PreInit fd is still open */
{
- xf86Msg(X_WARNING, "%s: Grab failed (%s)\n", pInfo->name,
- strerror(errno));
+ do {
+ pInfo->fd = open(pEvdev->device, O_RDWR | O_NONBLOCK, 0);
+ } while (pInfo->fd < 0 && errno == EINTR);
- /* ENODEV - device has disappeared after resume */
- if (rc && errno == ENODEV)
- {
- close(pInfo->fd);
- pInfo->fd = -1;
- }
- }
-
- if (pInfo->fd == -1)
- {
- pEvdev->reopen_left = pEvdev->reopen_attempts;
- pEvdev->reopen_timer = TimerSet(pEvdev->reopen_timer, 0, 100, EvdevReopenTimer, pInfo);
- } else
- {
- pEvdev->min_maj = EvdevGetMajorMinor(pInfo);
- if (EvdevIsDuplicate(pInfo))
- {
- xf86Msg(X_WARNING, "%s: Refusing to enable duplicate device.\n",
- pInfo->name);
+ if (pInfo->fd < 0) {
+ xf86Msg(X_ERROR, "Unable to open evdev device \"%s\".\n",
+ pEvdev->device);
return !Success;
}
+ }
- pEvdev->reopen_timer = TimerSet(pEvdev->reopen_timer, 0, 0, NULL, NULL);
+ if (pEvdev->grabDevice && (rc = ioctl(pInfo->fd, EVIOCGRAB, (void *)1)))
+ xf86Msg(X_WARNING, "%s: Grab failed (%s)\n", pInfo->name,
+ strerror(errno));
- xf86FlushInput(pInfo->fd);
- xf86AddEnabledDevice(pInfo);
- EvdevMBEmuOn(pInfo);
- pEvdev->flags |= EVDEV_INITIALIZED;
- device->public.on = TRUE;
+ pEvdev->min_maj = EvdevGetMajorMinor(pInfo);
+ if (EvdevIsDuplicate(pInfo))
+ {
+ xf86Msg(X_WARNING, "%s: Refusing to enable duplicate device.\n",
+ pInfo->name);
+ return !Success;
}
+ xf86FlushInput(pInfo->fd);
+ xf86AddEnabledDevice(pInfo);
+ EvdevMBEmuOn(pInfo);
+ pEvdev->flags |= EVDEV_INITIALIZED;
+ device->public.on = TRUE;
+
return Success;
}
@@ -1722,11 +1684,6 @@ EvdevProc(DeviceIntPtr device, int what)
pEvdev->min_maj = 0;
pEvdev->flags &= ~EVDEV_INITIALIZED;
device->public.on = FALSE;
- if (pEvdev->reopen_timer)
- {
- TimerFree(pEvdev->reopen_timer);
- pEvdev->reopen_timer = NULL;
- }
break;
case DEVICE_CLOSE:
@@ -1892,6 +1849,7 @@ static int
EvdevProbe(InputInfoPtr pInfo)
{
int i, has_rel_axes, has_abs_axes, has_keys, num_buttons, has_scroll;
+ int has_lmr; /* left middle right */
int kernel24 = 0;
int ignore_abs = 0, ignore_rel = 0;
EvdevPtr pEvdev = pInfo->private;
@@ -1934,6 +1892,7 @@ EvdevProbe(InputInfoPtr pInfo)
has_abs_axes = FALSE;
has_keys = FALSE;
has_scroll = FALSE;
+ has_lmr = FALSE;
num_buttons = 0;
/* count all buttons */
@@ -1948,6 +1907,10 @@ EvdevProbe(InputInfoPtr pInfo)
}
}
+ has_lmr = TestBit(BTN_LEFT, pEvdev->key_bitmask) ||
+ TestBit(BTN_MIDDLE, pEvdev->key_bitmask) ||
+ TestBit(BTN_RIGHT, pEvdev->key_bitmask);
+
if (num_buttons)
{
pEvdev->flags |= EVDEV_BUTTON_EVENTS;
@@ -2020,7 +1983,7 @@ EvdevProbe(InputInfoPtr pInfo)
}
} else if (TestBit(ABS_PRESSURE, pEvdev->abs_bitmask) ||
TestBit(BTN_TOUCH, pEvdev->key_bitmask)) {
- if (num_buttons || TestBit(BTN_TOOL_FINGER, pEvdev->key_bitmask)) {
+ if (has_lmr || TestBit(BTN_TOOL_FINGER, pEvdev->key_bitmask)) {
xf86Msg(X_INFO, "%s: Found absolute touchpad.\n", pInfo->name);
pEvdev->flags |= EVDEV_TOUCHPAD;
memset(pEvdev->old_vals, -1, sizeof(int) * pEvdev->num_vals);
@@ -2129,7 +2092,7 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
pInfo->history_size = 0;
pInfo->control_proc = NULL;
pInfo->close_proc = NULL;
- pInfo->switch_mode = NULL;
+ pInfo->switch_mode = EvdevSwitchMode;
pInfo->conversion_proc = NULL;
pInfo->reverse_conversion_proc = NULL;
pInfo->dev = NULL;
@@ -2182,7 +2145,6 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
return NULL;
}
- pEvdev->reopen_attempts = xf86SetIntOption(pInfo->options, "ReopenAttempts", 10);
pEvdev->invert_x = xf86SetBoolOption(pInfo->options, "InvertX", FALSE);
pEvdev->invert_y = xf86SetBoolOption(pInfo->options, "InvertY", FALSE);
pEvdev->swap_axes = xf86SetBoolOption(pInfo->options, "SwapAxes", FALSE);
@@ -2570,18 +2532,6 @@ EvdevInitProperty(DeviceIntPtr dev)
EvdevPtr pEvdev = pInfo->private;
int rc;
BOOL invert[2];
- char reopen;
-
- prop_reopen = MakeAtom(EVDEV_PROP_REOPEN, strlen(EVDEV_PROP_REOPEN),
- TRUE);
-
- reopen = pEvdev->reopen_attempts;
- rc = XIChangeDeviceProperty(dev, prop_reopen, XA_INTEGER, 8,
- PropModeReplace, 1, &reopen, FALSE);
- if (rc != Success)
- return;
-
- XISetDevicePropertyDeletable(dev, prop_reopen, FALSE);
if (pEvdev->flags & (EVDEV_RELATIVE_EVENTS | EVDEV_ABSOLUTE_EVENTS))
{
@@ -2674,13 +2624,6 @@ EvdevSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
pEvdev->invert_x = data[0];
pEvdev->invert_y = data[1];
}
- } else if (atom == prop_reopen)
- {
- if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
- return BadMatch;
-
- if (!checkonly)
- pEvdev->reopen_attempts = *((CARD8*)val->data);
} else if (atom == prop_calibration)
{
if (val->format != 32 || val->type != XA_INTEGER)
diff --git a/src/evdev.h b/src/evdev.h
index af92b21..a404c8f 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -38,7 +38,7 @@
#include <xf86_OSproc.h>
#include <xkbstr.h>
-#ifndef EV_CNT /* linux 2.4 kernels and earlier lack _CNT defines */
+#ifndef EV_CNT /* linux 2.6.23 kernels and earlier lack _CNT defines */
#define EV_CNT (EV_MAX+1)
#endif
#ifndef KEY_CNT
@@ -57,6 +57,20 @@
#define EVDEV_MAXBUTTONS 32
#define EVDEV_MAXQUEUE 32
+/* evdev flags */
+#define EVDEV_KEYBOARD_EVENTS (1 << 0)
+#define EVDEV_BUTTON_EVENTS (1 << 1)
+#define EVDEV_RELATIVE_EVENTS (1 << 2)
+#define EVDEV_ABSOLUTE_EVENTS (1 << 3)
+#define EVDEV_TOUCHPAD (1 << 4)
+#define EVDEV_INITIALIZED (1 << 5) /* WheelInit etc. called already? */
+#define EVDEV_TOUCHSCREEN (1 << 6)
+#define EVDEV_CALIBRATED (1 << 7) /* run-time calibrated? */
+#define EVDEV_TABLET (1 << 8) /* device looks like a tablet? */
+#define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
+#define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
+#define EVDEV_RELATIVE_MODE (1 << 11) /* Force relative events for devices with absolute axes */
+
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3
#define HAVE_PROPERTIES 1
#endif