[PATCH xf86-input-libinput] Add tablet tool area ratio property
Peter Hutterer
peter.hutterer at who-t.net
Tue Nov 1 00:29:56 UTC 2016
By default, the X server maps the tablet axes to the available screen area.
When a tablet is mapped to the screen but has a different aspect ratio than
the screen, input data is skewed. Expose an area ratio property to map the
a subsection of the available tablet area into the desired ratio.
Differences to the wacom driver: there the x/y min/max values must be
specified manually and in device coordinates. For this driver we merely
provide the area ratio (e.g. 4:3) and let the driver work out the rest.
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
include/libinput-properties.h | 3 +
man/libinput.man | 30 ++++++++
src/xf86libinput.c | 154 ++++++++++++++++++++++++++++++++++++++++--
3 files changed, 181 insertions(+), 6 deletions(-)
diff --git a/include/libinput-properties.h b/include/libinput-properties.h
index f76500f..a701316 100644
--- a/include/libinput-properties.h
+++ b/include/libinput-properties.h
@@ -190,4 +190,7 @@
*/
#define LIBINPUT_PROP_TABLET_TOOL_PRESSURECURVE "libinput Tablet Tool Pressurecurve"
+/* Tablet tool area ratio: CARD32, 2 values, w and h */
+#define LIBINPUT_PROP_TABLET_TOOL_AREA_RATIO "libinput Tablet Tool Area Ratio"
+
#endif /* _LIBINPUT_PROPERTIES_H_ */
diff --git a/man/libinput.man b/man/libinput.man
index c1655a7..b75e204 100644
--- a/man/libinput.man
+++ b/man/libinput.man
@@ -161,6 +161,14 @@ points. The respective x/y coordinate must be in the [0.0, 1.0] range. For
more information see section
.B TABLET STYLUS PRESSURE CURVE.
.TP 7
+.BI "Option \*qTabletToolAreaRatio\*q \*q" "w:h" \*q
+Sets the area ratio for a tablet tool. The area always starts at the
+origin (0/0) and expands to the largest available area with the specified
+aspect ratio. Events outside this area are cropped to the area. The special
+value "default" is used for the default mapping (i.e. the device-native
+mapping). For more information see section
+.B TABLET TOOL AREA RATIO.
+.TP 7
.BI "Option \*qTapping\*q \*q" bool \*q
Enables or disables tap-to-click behavior.
.TP 7
@@ -261,6 +269,11 @@ enabled on this device.
.BI "libinput Tablet Tool Pressurecurve"
4 32-bit float values [0.0 to 1.0]. See section
.B TABLET TOOL PRESSURE CURVE
+.TP7
+.BI "libinput Tablet Tool Area Ratio"
+2 32-bit values, corresponding to width and height. Special value 0, 0
+resets to the default ratio. See section
+.B TABLET TOOL AREA RATIO
for more information.
.TP 7
.BI "libinput Tapping Enabled"
@@ -344,6 +357,23 @@ curve (softer) might be "0.0/0.0 0.0/0.05 0.95/1.0 1.0/1.0".
.TP
This feature is provided by this driver, not by libinput.
+.SH TABLET TOOL AREA RATIO
+By default, a tablet tool can access the whole sensor area and the tablet
+area is mapped to the available screen area. For external tablets like
+the Wacom Intuos series, the height:width ratio of the tablet may be
+different to that of the monitor, causing the skew of input data.
+.PP
+To avoid this skew of input data, an area ratio may be set to match the
+ratio of the screen device. For example, a ratio of 4:3 will reduce the
+available area of the tablet to the largest available area with a ratio of
+4:3. Events within this area will scale to the tablet's announced axis
+range, the area ratio is thus transparent to the X server. Any events
+outside this area will send events equal to the maximum value of that axis.
+The area always starts at the device's origin in it's current rotation, i.e.
+it takes left-handed-ness into account.
+.TP
+This feature is provided by this driver, not by libinput.
+
.SH AUTHORS
Peter Hutterer
.SH "SEE ALSO"
diff --git a/src/xf86libinput.c b/src/xf86libinput.c
index 470b1ff..6b0ed20 100644
--- a/src/xf86libinput.c
+++ b/src/xf86libinput.c
@@ -164,6 +164,9 @@ struct xf86libinput {
float rotation_angle;
struct bezier_control_point pressurecurve[4];
+ struct ratio {
+ int x, y;
+ } area;
} options;
struct draglock draglock;
@@ -181,6 +184,10 @@ struct xf86libinput {
int *values;
size_t sz;
} pressurecurve;
+
+ struct scale_factor {
+ double x, y;
+ } area_scale_factor;
};
enum event_handling {
@@ -415,6 +422,29 @@ xf86libinput_set_pressurecurve(struct xf86libinput *driver_data,
driver_data->pressurecurve.sz);
}
+static inline void
+xf86libinput_set_area_ratio(struct xf86libinput *driver_data,
+ const struct ratio *ratio)
+{
+ double f;
+ double w, h;
+
+ if (libinput_device_get_size(driver_data->shared_device->device, &w, &h) != 0)
+ return;
+
+ f = 1.0 * (ratio->x * h)/(ratio->y * w);
+
+ if (f <= 1.0) {
+ driver_data->area_scale_factor.x = 1.0/f;
+ driver_data->area_scale_factor.y = 1.0;
+ } else {
+ driver_data->area_scale_factor.x = 1.0;
+ driver_data->area_scale_factor.y = f;
+ }
+
+ driver_data->options.area = *ratio;
+}
+
static int
LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
BOOL checkonly);
@@ -1636,6 +1666,26 @@ xf86libinput_handle_tablet_button(InputInfoPtr pInfo,
return EVENT_HANDLED;
}
+static void
+xf86libinput_apply_area(InputInfoPtr pInfo, double *x, double *y)
+{
+ struct xf86libinput *driver_data = pInfo->private;
+ const struct scale_factor *f = &driver_data->area_scale_factor;
+ double sx, sy;
+
+ if (driver_data->options.area.x == 0)
+ return;
+
+ /* In left-handed mode, libinput already gives us transformed
+ * coordinates, so we can clip the same way. */
+
+ sx = min(*x * f->x, TABLET_AXIS_MAX);
+ sy = min(*y * f->y, TABLET_AXIS_MAX);
+
+ *x = sx;
+ *y = sy;
+}
+
static enum event_handling
xf86libinput_handle_tablet_axis(InputInfoPtr pInfo,
struct libinput_event_tablet_tool *event)
@@ -1645,16 +1695,18 @@ xf86libinput_handle_tablet_axis(InputInfoPtr pInfo,
ValuatorMask *mask = driver_data->valuators;
struct libinput_tablet_tool *tool;
double value;
+ double x, y;
if (xf86libinput_tool_queue_event(event))
return EVENT_QUEUED;
- value = libinput_event_tablet_tool_get_x_transformed(event,
- TABLET_AXIS_MAX);
- valuator_mask_set_double(mask, 0, value);
- value = libinput_event_tablet_tool_get_y_transformed(event,
- TABLET_AXIS_MAX);
- valuator_mask_set_double(mask, 1, value);
+ x = libinput_event_tablet_tool_get_x_transformed(event,
+ TABLET_AXIS_MAX);
+ y = libinput_event_tablet_tool_get_y_transformed(event,
+ TABLET_AXIS_MAX);
+ xf86libinput_apply_area(pInfo, &x, &y);
+ valuator_mask_set_double(mask, 0, x);
+ valuator_mask_set_double(mask, 1, y);
tool = libinput_event_tablet_tool_get_tool(event);
@@ -2703,6 +2755,35 @@ out:
}
static void
+xf86libinput_parse_tablet_area_option(InputInfoPtr pInfo,
+ struct xf86libinput *driver_data,
+ struct ratio *area_out)
+{
+ char *str;
+ int rc;
+ struct ratio area;
+
+ if ((driver_data->capabilities & CAP_TABLET_TOOL) == 0)
+ return;
+
+ str = xf86SetStrOption(pInfo->options,
+ "TabletToolAreaRatio",
+ NULL);
+ if (!str || strcmp(str, "default") == 0)
+ goto out;
+
+ rc = sscanf(str, "%d:%d", &area.x, &area.y);
+ if (rc != 2 || area.x <= 0 || area.y <= 0) {
+ xf86IDrvMsg(pInfo, X_ERROR, "Invalid tablet tool area ratio: %s\n", str);
+ } else {
+ *area_out = area;
+ }
+
+out:
+ free(str);
+}
+
+static void
xf86libinput_parse_options(InputInfoPtr pInfo,
struct xf86libinput *driver_data,
struct libinput_device *device)
@@ -2739,6 +2820,9 @@ xf86libinput_parse_options(InputInfoPtr pInfo,
xf86libinput_parse_pressurecurve_option(pInfo,
driver_data,
options->pressurecurve);
+ xf86libinput_parse_tablet_area_option(pInfo,
+ driver_data,
+ &options->area);
}
static const char*
@@ -3188,6 +3272,7 @@ static Atom prop_rotation_angle_default;
static Atom prop_draglock;
static Atom prop_horiz_scroll;
static Atom prop_pressurecurve;
+static Atom prop_area_ratio;
/* general properties */
static Atom prop_float;
@@ -3963,6 +4048,41 @@ LibinputSetPropertyPressureCurve(DeviceIntPtr dev,
return Success;
}
+static inline int
+LibinputSetPropertyAreaRatio(DeviceIntPtr dev,
+ Atom atom,
+ XIPropertyValuePtr val,
+ BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ struct xf86libinput *driver_data = pInfo->private;
+ uint32_t *vals;
+ struct ratio area = { 0, 0 };
+
+ if (val->format != 32 || val->size != 2 || val->type != XA_CARDINAL)
+ return BadMatch;
+
+ vals = val->data;
+ area.x = vals[0];
+ area.y = vals[1];
+
+ if (checkonly) {
+ if (area.x < 0 || area.y < 0)
+ return BadValue;
+
+ if ((area.x != 0 && area.y == 0) ||
+ (area.x == 0 && area.y != 0))
+ return BadValue;
+
+ if (!xf86libinput_check_device (dev, atom))
+ return BadMatch;
+ } else {
+ xf86libinput_set_area_ratio(driver_data, &area);
+ }
+
+ return Success;
+}
+
static int
LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
BOOL checkonly)
@@ -4017,6 +4137,8 @@ LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
rc = LibinputSetPropertyRotationAngle(dev, atom, val, checkonly);
else if (atom == prop_pressurecurve)
rc = LibinputSetPropertyPressureCurve(dev, atom, val, checkonly);
+ else if (atom == prop_area_ratio)
+ rc = LibinputSetPropertyAreaRatio(dev, atom, val, checkonly);
else if (atom == prop_device || atom == prop_product_id ||
atom == prop_tap_default ||
atom == prop_tap_drag_default ||
@@ -4870,6 +4992,25 @@ LibinputInitPressureCurveProperty(DeviceIntPtr dev,
}
static void
+LibinputInitTabletAreaRatioProperty(DeviceIntPtr dev,
+ struct xf86libinput *driver_data)
+{
+ const struct ratio *ratio = &driver_data->options.area;
+ uint32_t data[2];
+
+ if ((driver_data->capabilities & CAP_TABLET_TOOL) == 0)
+ return;
+
+ data[0] = ratio->x;
+ data[1] = ratio->y;
+
+ prop_area_ratio = LibinputMakeProperty(dev,
+ LIBINPUT_PROP_TABLET_TOOL_AREA_RATIO,
+ XA_CARDINAL, 32,
+ 2, data);
+}
+
+static void
LibinputInitProperty(DeviceIntPtr dev)
{
InputInfoPtr pInfo = dev->public.devicePrivate;
@@ -4926,4 +5067,5 @@ LibinputInitProperty(DeviceIntPtr dev)
LibinputInitDragLockProperty(dev, driver_data);
LibinputInitHorizScrollProperty(dev, driver_data);
LibinputInitPressureCurveProperty(dev, driver_data);
+ LibinputInitTabletAreaRatioProperty(dev, driver_data);
}
--
2.9.3
More information about the xorg-devel
mailing list