dix: add 3x3 transformation matrix xinput property for multi-head handling
For absolute input devices (E.G. touchscreens) in multi-head setups, we need a way to bind the device to an randr output. This adds the infrastructure to the server to allow us to do so. positionSprite() scales input coordinates to the dimensions of the shared (total) screen frame buffer, so to restrict motion to an output we need to scale/rotate/translate device coordinates to a subset of the frame buffer before passing them on to positionSprite. This is done here using a 3x3 transformation matrix, which is applied to the device coordinates using homogeneous coordinates, E.G.: [ c0 c1 c2 ] [ x ] [ c3 c4 c5 ] * [ y ] [ c6 c7 c8 ] [ 1 ] Notice: As input devices have varying input ranges, the coordinates are first scaled to the [0..1] range for generality, and afterwards scaled back up. E.G. for a dual head setup (using same resolution) next to each other, you would want to scale the X coordinates of the touchscreen connected to the both heads by 50%, and translate (offset) the coordinates of the rightmost head by 50%, or in matrix form: left: right: [ 0.5 0 0 ] [ 0.5 0 0.5 ] [ 0 1 0 ] [ 0 1 0 ] [ 0 0 1 ] [ 0 0 0 ] Which can be done using xinput: xinput set-prop <left> --type=float "Coordinate Transformation Matrix" \ 0.5 0 0 0 1 0 0 0 1 xinput set-prop <right> --type=float "Coordinate Transformation Matrix" \ 0.5 0 0.5 0 1 0 0 0 1 Likewise more complication setups involving more heads, rotation or different resolution can be handled. Signed-off-by: Peter Korsgaard <peter.korsgaard@barco.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
e4582d9e5c
commit
6cccf0131c
|
@ -177,7 +177,9 @@ static struct dev_properties
|
||||||
{0, BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP},
|
{0, BTN_LABEL_PROP_BTN_TOOL_TRIPLETAP},
|
||||||
|
|
||||||
{0, BTN_LABEL_PROP_BTN_GEAR_DOWN},
|
{0, BTN_LABEL_PROP_BTN_GEAR_DOWN},
|
||||||
{0, BTN_LABEL_PROP_BTN_GEAR_UP}
|
{0, BTN_LABEL_PROP_BTN_GEAR_UP},
|
||||||
|
|
||||||
|
{0, XI_PROP_TRANSFORM}
|
||||||
};
|
};
|
||||||
|
|
||||||
static long XIPropHandlerID = 1;
|
static long XIPropHandlerID = 1;
|
||||||
|
|
|
@ -77,6 +77,8 @@ SOFTWARE.
|
||||||
#include <X11/extensions/XI.h>
|
#include <X11/extensions/XI.h>
|
||||||
#include <X11/extensions/XI2.h>
|
#include <X11/extensions/XI2.h>
|
||||||
#include <X11/extensions/XIproto.h>
|
#include <X11/extensions/XIproto.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <pixman.h>
|
||||||
#include "exglobals.h"
|
#include "exglobals.h"
|
||||||
#include "exevents.h"
|
#include "exevents.h"
|
||||||
#include "xiquerydevice.h" /* for SizeDeviceClasses */
|
#include "xiquerydevice.h" /* for SizeDeviceClasses */
|
||||||
|
@ -91,6 +93,48 @@ SOFTWARE.
|
||||||
|
|
||||||
static void RecalculateMasterButtons(DeviceIntPtr slave);
|
static void RecalculateMasterButtons(DeviceIntPtr slave);
|
||||||
|
|
||||||
|
static void
|
||||||
|
DeviceSetTransform(DeviceIntPtr dev, float *transform)
|
||||||
|
{
|
||||||
|
struct pixman_f_transform scale;
|
||||||
|
double sx, sy;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculate combined transformation matrix:
|
||||||
|
*
|
||||||
|
* M = InvScale * Transform * Scale
|
||||||
|
*
|
||||||
|
* So we can later transform points using M * p
|
||||||
|
*
|
||||||
|
* Where:
|
||||||
|
* Scale scales coordinates into 0..1 range
|
||||||
|
* Transform is the user supplied (affine) transform
|
||||||
|
* InvScale scales coordinates back up into their native range
|
||||||
|
*/
|
||||||
|
sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value;
|
||||||
|
sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value;
|
||||||
|
|
||||||
|
/* invscale */
|
||||||
|
pixman_f_transform_init_scale(&scale, sx, sy);
|
||||||
|
scale.m[0][2] = dev->valuator->axes[0].min_value;
|
||||||
|
scale.m[1][2] = dev->valuator->axes[1].min_value;
|
||||||
|
|
||||||
|
/* transform */
|
||||||
|
for (y=0; y<3; y++)
|
||||||
|
for (x=0; x<3; x++)
|
||||||
|
dev->transform.m[y][x] = *transform++;
|
||||||
|
|
||||||
|
pixman_f_transform_multiply(&dev->transform, &scale, &dev->transform);
|
||||||
|
|
||||||
|
/* scale */
|
||||||
|
pixman_f_transform_init_scale(&scale, 1.0 / sx, 1.0 / sy);
|
||||||
|
scale.m[0][2] = -dev->valuator->axes[0].min_value / sx;
|
||||||
|
scale.m[1][2] = -dev->valuator->axes[1].min_value / sy;
|
||||||
|
|
||||||
|
pixman_f_transform_multiply(&dev->transform, &dev->transform, &scale);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DIX property handler.
|
* DIX property handler.
|
||||||
*/
|
*/
|
||||||
|
@ -115,6 +159,21 @@ DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
|
||||||
else if (!(*((CARD8*)prop->data)) && dev->enabled)
|
else if (!(*((CARD8*)prop->data)) && dev->enabled)
|
||||||
DisableDevice(dev, TRUE);
|
DisableDevice(dev, TRUE);
|
||||||
}
|
}
|
||||||
|
} else if (property == XIGetKnownProperty(XI_PROP_TRANSFORM))
|
||||||
|
{
|
||||||
|
float *f = (float*)prop->data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (prop->format != 32 || prop->size != 9 ||
|
||||||
|
prop->type != XIGetKnownProperty(XATOM_FLOAT))
|
||||||
|
return BadValue;
|
||||||
|
|
||||||
|
for (i=0; i<9; i++)
|
||||||
|
if (!isfinite(f[i]))
|
||||||
|
return BadValue;
|
||||||
|
|
||||||
|
if (!checkonly)
|
||||||
|
DeviceSetTransform(dev, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
|
@ -183,6 +242,7 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
|
||||||
int devid;
|
int devid;
|
||||||
char devind[MAXDEVICES];
|
char devind[MAXDEVICES];
|
||||||
BOOL enabled;
|
BOOL enabled;
|
||||||
|
float transform[9];
|
||||||
|
|
||||||
/* Find next available id, 0 and 1 are reserved */
|
/* Find next available id, 0 and 1 are reserved */
|
||||||
memset(devind, 0, sizeof(char)*MAXDEVICES);
|
memset(devind, 0, sizeof(char)*MAXDEVICES);
|
||||||
|
@ -234,6 +294,17 @@ AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart)
|
||||||
XA_INTEGER, 8, PropModeReplace, 1, &enabled,
|
XA_INTEGER, 8, PropModeReplace, 1, &enabled,
|
||||||
FALSE);
|
FALSE);
|
||||||
XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE);
|
XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE);
|
||||||
|
|
||||||
|
/* unity matrix */
|
||||||
|
memset(transform, 0, sizeof(transform));
|
||||||
|
transform[0] = transform[4] = transform[8] = 1.0f;
|
||||||
|
|
||||||
|
XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
|
||||||
|
XIGetKnownProperty(XATOM_FLOAT), 32,
|
||||||
|
PropModeReplace, 9, transform, FALSE);
|
||||||
|
XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
|
||||||
|
FALSE);
|
||||||
|
|
||||||
XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL);
|
XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL);
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/Xproto.h>
|
#include <X11/Xproto.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
@ -56,6 +57,7 @@
|
||||||
|
|
||||||
#include <X11/extensions/XI.h>
|
#include <X11/extensions/XI.h>
|
||||||
#include <X11/extensions/XIproto.h>
|
#include <X11/extensions/XIproto.h>
|
||||||
|
#include <pixman.h>
|
||||||
#include "exglobals.h"
|
#include "exglobals.h"
|
||||||
#include "exevents.h"
|
#include "exevents.h"
|
||||||
#include "exglobals.h"
|
#include "exglobals.h"
|
||||||
|
@ -997,6 +999,22 @@ FreeEventList(EventListPtr list, int num_events)
|
||||||
free(list);
|
free(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
transformAbsolute(DeviceIntPtr dev, int v[MAX_VALUATORS])
|
||||||
|
{
|
||||||
|
struct pixman_f_vector p;
|
||||||
|
|
||||||
|
/* p' = M * p in homogeneous coordinates */
|
||||||
|
p.v[0] = v[0];
|
||||||
|
p.v[1] = v[1];
|
||||||
|
p.v[2] = 1.0;
|
||||||
|
|
||||||
|
pixman_f_transform_point(&dev->transform, &p);
|
||||||
|
|
||||||
|
v[0] = lround(p.v[0]);
|
||||||
|
v[1] = lround(p.v[1]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a series of xEvents (filled into the EventList) representing
|
* Generate a series of xEvents (filled into the EventList) representing
|
||||||
* pointer motion, or button presses. Xi and XKB-aware.
|
* pointer motion, or button presses. Xi and XKB-aware.
|
||||||
|
@ -1068,6 +1086,7 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
|
||||||
scr->height);
|
scr->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transformAbsolute(pDev, valuators);
|
||||||
moveAbsolute(pDev, &x, &y, first_valuator, num_valuators, valuators);
|
moveAbsolute(pDev, &x, &y, first_valuator, num_valuators, valuators);
|
||||||
} else {
|
} else {
|
||||||
if (flags & POINTER_ACCELERATE) {
|
if (flags & POINTER_ACCELERATE) {
|
||||||
|
|
|
@ -49,6 +49,7 @@ SOFTWARE.
|
||||||
#ifndef INPUTSTRUCT_H
|
#ifndef INPUTSTRUCT_H
|
||||||
#define INPUTSTRUCT_H
|
#define INPUTSTRUCT_H
|
||||||
|
|
||||||
|
#include <pixman.h>
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "dixstruct.h"
|
#include "dixstruct.h"
|
||||||
|
@ -550,6 +551,9 @@ typedef struct _DeviceIntRec {
|
||||||
XIPropertyPtr properties;
|
XIPropertyPtr properties;
|
||||||
XIPropertyHandlerPtr handlers; /* NULL-terminated */
|
XIPropertyHandlerPtr handlers; /* NULL-terminated */
|
||||||
} properties;
|
} properties;
|
||||||
|
|
||||||
|
/* coordinate transformation matrix for absolute input devices */
|
||||||
|
struct pixman_f_transform transform;
|
||||||
} DeviceIntRec;
|
} DeviceIntRec;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -35,6 +35,13 @@
|
||||||
/* BOOL. If present, device is a virtual XTEST device */
|
/* BOOL. If present, device is a virtual XTEST device */
|
||||||
#define XI_PROP_XTEST_DEVICE "XTEST Device"
|
#define XI_PROP_XTEST_DEVICE "XTEST Device"
|
||||||
|
|
||||||
|
/* Coordinate transformation matrix for absolute input devices
|
||||||
|
* FLOAT, 9 values in row-major order, coordinates in 0..1 range:
|
||||||
|
* [c0 c1 c2] [x]
|
||||||
|
* [c3 c4 c5] * [y]
|
||||||
|
* [c6 c7 c8] [1] */
|
||||||
|
#define XI_PROP_TRANSFORM "Coordinate Transformation Matrix"
|
||||||
|
|
||||||
/* Pointer acceleration properties */
|
/* Pointer acceleration properties */
|
||||||
/* INTEGER of any format */
|
/* INTEGER of any format */
|
||||||
#define ACCEL_PROP_PROFILE_NUMBER "Device Accel Profile"
|
#define ACCEL_PROP_PROFILE_NUMBER "Device Accel Profile"
|
||||||
|
|
Loading…
Reference in New Issue