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 <[email protected]> --- 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 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel
