From ddfc3a79ca4834af30eb2a8bbd5124b0a23fd038 Mon Sep 17 00:00:00 2001 From: Eric Piel Date: Sun, 24 May 2009 13:43:13 +0200 Subject: [PATCH] xinput: add inversion and axis mapping input properties Inversion and axis mapping properties of a pointer device allow to change the default direct mapping between the physical valuators and the deplacement of the pointer. The main goal is to have the devices follow the same rotation/reflection as the display. The evdev has already similar properties, but with this patch all the pointer devices benefits of them. --- Xi/xiproperty.c | 2 + dix/devices.c | 61 ++++++++++++++++++++++++++++++++++++++++ dix/getevents.c | 32 +++++++++++++++++++++ hw/xfree86/common/xf86Xinput.c | 1 + include/inputstr.h | 4 ++ include/xserver-properties.h | 8 +++++ 6 files changed, 108 insertions(+), 0 deletions(-) diff --git a/Xi/xiproperty.c b/Xi/xiproperty.c index b04ee94..b463441 100644 --- a/Xi/xiproperty.c +++ b/Xi/xiproperty.c @@ -50,6 +50,8 @@ static struct dev_properties char *name; } dev_properties[] = { {0, XI_PROP_ENABLED}, + {0, XI_PROP_INVERT_AXES}, + {0, XI_PROP_MAP_AXES}, {0, XATOM_FLOAT} }; diff --git a/dix/devices.c b/dix/devices.c index 0858f20..7f9ce15 100644 --- a/dix/devices.c +++ b/dix/devices.c @@ -107,6 +107,7 @@ static int DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, BOOL checkonly) { + int i; if (property == XIGetKnownProperty(XI_PROP_ENABLED)) { if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1) @@ -125,6 +126,43 @@ DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, DisableDevice(dev); } } + else if (property == XIGetKnownProperty(XI_PROP_INVERT_AXES)) + { + if (prop->format != 8 || prop->type != XA_INTEGER || + dev->valuator == NULL || prop->size != dev->valuator->numAxes) + return BadValue; + + if (!checkonly) + { + BOOL *invert = (BOOL*)prop->data; + for (i = 0; i < prop->size; i++) + { + dev->invert[i] = !!invert[i]; + } + } + } + else if (property == XIGetKnownProperty(XI_PROP_MAP_AXES)) + { + if (prop->format != 8 || prop->type != XA_INTEGER || + dev->valuator == NULL || prop->size != dev->valuator->numAxes) + return BadValue; + + CARD8 *axis_map = (CARD8*)prop->data; + /* Can only map to an existing axis (but we don't mind several axis mapped to the same one */ + for (i = 0; i < prop->size; i++) + { + if (axis_map[i] >= prop->size) + return BadValue; + } + + if (!checkonly) + { + for (i = 0; i < prop->size; i++) + { + dev->axis_map[i] = axis_map[i]; + } + } + } return Success; } @@ -190,6 +228,7 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) DeviceIntPtr dev, *prev; /* not a typo */ DeviceIntPtr devtmp; int devid; + int i; char devind[MAXDEVICES]; BOOL enabled; @@ -236,11 +275,19 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) *prev = dev; dev->next = NULL; + /* Input properties */ enabled = FALSE; XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), XA_INTEGER, 8, PropModeReplace, 1, &enabled, FALSE); XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE); + + for (i = 0; i < MAX_VALUATORS; i++) + { + dev->invert[i] = FALSE; + dev->axis_map[i] = i; + } + XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL); return dev; @@ -335,6 +382,20 @@ EnableDevice(DeviceIntPtr dev) XA_INTEGER, 8, PropModeReplace, 1, &enabled, TRUE); + /* Properties only for pointer devices */ + if ((dev->valuator != NULL) && (dev->valuator->numAxes > 0)) + { + int ret = XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_INVERT_AXES), + XA_INTEGER, 8, PropModeReplace, dev->valuator->numAxes, + dev->invert, FALSE); + XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_INVERT_AXES), FALSE); + + ret = XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_MAP_AXES), + XA_INTEGER, 8, PropModeReplace, dev->valuator->numAxes, + dev->axis_map, FALSE); + XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_MAP_AXES), FALSE); + } + ev.type = DevicePresenceNotify; ev.time = currentTime.milliseconds; ev.devchange = DeviceEnabled; diff --git a/dix/getevents.c b/dix/getevents.c index 9747b35..0c8e465 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -735,6 +735,33 @@ countValuatorEvents(int num_valuators) } /** + * Invert and remap the axes of a device according to its input properties + */ +static void +invertAndMapValuators(DeviceIntPtr pDev, int num_valuators, int *valuators) +{ + int i; + int tmp[num_valuators]; + + /* invert the valuators */ + for (i = 0; i < num_valuators; i++) + { + if (pDev->invert[i]) + valuators[i] = -valuators[i]; + } + + /* remap */ + for (i = 0; i < num_valuators; i++) + { + tmp[i] = valuators[pDev->axis_map[i]]; + } + for (i = 0; i < num_valuators; i++) + { + valuators[i] = tmp[i]; + } +} + +/** * Convenience wrapper around GetKeyboardValuatorEvents, that takes no * valuators. */ @@ -850,6 +877,7 @@ GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type, events++; if (num_valuators) { kbp->deviceid |= MORE_EVENTS; + invertAndMapValuators(pDev, num_valuators, valuators); clipValuators(pDev, first_valuator, num_valuators, valuators); events = getValuatorEvents(events, pDev, first_valuator, num_valuators, valuators); @@ -933,6 +961,7 @@ FreeEventList(EventListPtr list, int num_events) xfree(list); } + /** * Generate a series of xEvents (filled into the EventList) representing * pointer motion, or button presses. Xi and XKB-aware. @@ -976,6 +1005,8 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, events = updateFromMaster(events, pDev, &num_events); + invertAndMapValuators(pDev, num_valuators, valuators); + if (flags & POINTER_ABSOLUTE) { if (flags & POINTER_SCREEN) /* valuators are in screen coords */ @@ -1089,6 +1120,7 @@ GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type, if (num_valuators) { kbp->deviceid |= MORE_EVENTS; events++; + invertAndMapValuators(pDev, num_valuators, valuators); clipValuators(pDev, first_valuator, num_valuators, valuators); events = getValuatorEvents(events, pDev, first_valuator, num_valuators, valuators); diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c index 1f41234..691ad46 100644 --- a/hw/xfree86/common/xf86Xinput.c +++ b/hw/xfree86/common/xf86Xinput.c @@ -750,6 +750,7 @@ xf86PostMotionEventP(DeviceIntPtr device, flags = POINTER_RELATIVE | POINTER_ACCELERATE; #if XFreeXDGA + // XXX might need some special tricks in case of axis swapping /* The evdev driver may not always send all axes across. */ if (num_valuators >= 1 && first_valuator <= 1) { if (miPointerGetScreen(device)) { diff --git a/include/inputstr.h b/include/inputstr.h index a6f823c..3fc05db 100644 --- a/include/inputstr.h +++ b/include/inputstr.h @@ -475,6 +475,10 @@ typedef struct _DeviceIntRec { int numValuators; } last; + /* Axis inversion and mapping */ + BOOL invert[MAX_VALUATORS]; + CARD8 axis_map[MAX_VALUATORS]; + /* Input device property handling. */ struct { XIPropertyPtr properties; diff --git a/include/xserver-properties.h b/include/xserver-properties.h index f8aeab6..7bf4047 100644 --- a/include/xserver-properties.h +++ b/include/xserver-properties.h @@ -33,4 +33,12 @@ /* BOOL. 0 - device disabled, 1 - device enabled */ #define XI_PROP_ENABLED "Device Enabled" +/* Axis inversion */ +/* BOOL, list as long as there are axes in the device, 1 inverts axis */ +#define XI_PROP_INVERT_AXES "Axis Inversion" + +/* Axis mapping */ +/* CARD8, list as long as there are axes in the device, 0 1 2... is the default */ +#define XI_PROP_MAP_AXES "Axis Mapping" + #endif -- 1.6.2.4