diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2024-06-07 11:08:50 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2024-06-10 09:27:57 +0000 |
commit | 72c8eb25f80fa286d945bc5ab086ba1978446687 (patch) | |
tree | 40baebe8443c8cce13d694cc22174b47209ce063 | |
parent | 74335c6fd697a60976d52786598a7dd4ba17405a (diff) |
Implement tablet tool pressure range support
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | include/libinput-properties.h | 9 | ||||
-rw-r--r-- | man/libinput.man | 8 | ||||
-rw-r--r-- | meson.build | 4 | ||||
-rw-r--r-- | src/xf86libinput.c | 165 |
5 files changed, 197 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index b9ac4b4..a2e6e15 100644 --- a/configure.ac +++ b/configure.ac @@ -88,6 +88,17 @@ AC_LINK_IFELSE( [libinput_have_custom_accel=yes]], [AC_MSG_RESULT([no]) [libinput_have_custom_accel=no]]) +AC_MSG_CHECKING([if libinput_tablet_tool_config_pressure_range_set is available]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[#include <libinput.h>]], + [[libinput_tablet_tool_config_pressure_range_set(0)]])], + [AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_LIBINPUT_PRESURE_RANGE, [1], + [libinput_tablet_tool_config_pressure_range_set() is available]) + [libinput_have_pressure_range=yes]], + [AC_MSG_RESULT([no]) + [libinput_have_pressure_range=no]]) + LIBS=$OLD_LIBS CFLAGS=$OLD_CFLAGS diff --git a/include/libinput-properties.h b/include/libinput-properties.h index d5b5197..505259f 100644 --- a/include/libinput-properties.h +++ b/include/libinput-properties.h @@ -222,6 +222,15 @@ */ #define LIBINPUT_PROP_TABLET_TOOL_PRESSURECURVE "libinput Tablet Tool Pressurecurve" +/* Tablet tool pressure range: float, 2 values, 32 bit + * Value range is [0.0, 1.0] for min and max physical pressure to map to the logical range + * Default value: 0.0 1.0 + */ +#define LIBINPUT_PROP_TABLET_TOOL_PRESSURE_RANGE "libinput Tablet Tool Pressure Range" + +/* Tablet tool pressure range: float, 2 values, 32 bit, read-only */ +#define LIBINPUT_PROP_TABLET_TOOL_PRESSURE_RANGE_DEFAULT "libinput Tablet Tool Pressure Range Default" + /* Tablet tool area ratio: CARD32, 2 values, w and h */ #define LIBINPUT_PROP_TABLET_TOOL_AREA_RATIO "libinput Tablet Tool Area Ratio" diff --git a/man/libinput.man b/man/libinput.man index f907766..46a8ef2 100644 --- a/man/libinput.man +++ b/man/libinput.man @@ -210,6 +210,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 \*qTabletToolPressureRange\*q \*q" "min max" \*q +Set the pressure range for a tablet stylus to the given subset of the physical +range. The min/max values must be in the [0.0, 1.0] range. For +example a min of 0.3 means the tablet will send 0 pressure for anything equal +or below 30% of the physical pressure range and a max of 0.7 means +the tablet sends its maximum pressure value for any pressure equal or higher to +70% of the physical pressure range. +.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 diff --git a/meson.build b/meson.build index 4c2a821..101ee89 100644 --- a/meson.build +++ b/meson.build @@ -57,6 +57,10 @@ if cc.has_function('libinput_config_accel_create', dependencies: dep_libinput) config_h.set('HAVE_LIBINPUT_CUSTOM_ACCEL', 1) endif +if cc.has_function('libinput_tablet_tool_config_pressure_range_set', + dependencies: dep_libinput) + config_h.set('HAVE_LIBINPUT_PRESSURE_RANGE', 1) +endif dir_headers = get_option('sdkdir') if dir_headers == '' diff --git a/src/xf86libinput.c b/src/xf86libinput.c index 91af896..26e8959 100644 --- a/src/xf86libinput.c +++ b/src/xf86libinput.c @@ -192,6 +192,9 @@ struct xf86libinput { float rotation_angle; struct bezier_control_point pressurecurve[4]; + struct range { + float min, max; + } pressure_range; struct ratio { int x, y; } area; @@ -455,6 +458,25 @@ xf86libinput_set_pressurecurve(struct xf86libinput *driver_data, driver_data->pressurecurve.sz); } +static inline bool +xf86libinput_set_pressure_range(struct xf86libinput *driver_data, + const struct range *range) +{ +#if HAVE_LIBINPUT_PRESSURE_RANGE + struct libinput_tablet_tool *tool = driver_data->tablet_tool; + + if (!tool) + return FALSE; + + return libinput_tablet_tool_config_pressure_range_is_available(tool) && + libinput_tablet_tool_config_pressure_range_set(tool, + range->min, + range->max) == LIBINPUT_CONFIG_STATUS_SUCCESS; +#else + return FALSE; +#endif +} + static inline void xf86libinput_set_area_ratio(struct xf86libinput *driver_data, const struct ratio *ratio) @@ -879,6 +901,27 @@ LibinputApplyConfigRotation(DeviceIntPtr dev, driver_data->options.rotation_angle); } +static void +LibinputApplyConfigPressureRange(DeviceIntPtr dev, + struct xf86libinput *driver_data, + struct libinput_device *device) +{ +#if HAVE_LIBINPUT_PRESSURE_RANGE + InputInfoPtr pInfo = dev->public.devicePrivate; + struct libinput_tablet_tool *tool = driver_data->tablet_tool; + struct range *range = &driver_data->options.pressure_range; + + if (!subdevice_has_capabilities(dev, CAP_TABLET_TOOL)) + return; + + if (tool && libinput_tablet_tool_config_pressure_range_is_available(tool) && + libinput_tablet_tool_config_pressure_range_set(tool, range->min, range->max) != LIBINPUT_CONFIG_STATUS_SUCCESS) + xf86IDrvMsg(pInfo, X_ERROR, + "Failed to set PressureRange to %.2f..%.2f\n", + range->min, range->max); +#endif +} + static inline void LibinputApplyConfig(DeviceIntPtr dev) { @@ -897,6 +940,7 @@ LibinputApplyConfig(DeviceIntPtr dev) LibinputApplyConfigMiddleEmulation(dev, driver_data, device); LibinputApplyConfigDisableWhileTyping(dev, driver_data, device); LibinputApplyConfigRotation(dev, driver_data, device); + LibinputApplyConfigPressureRange(dev, driver_data, device); } static int @@ -3539,6 +3583,46 @@ out: xf86libinput_set_pressurecurve(driver_data, controls); } +static void +xf86libinput_parse_pressure_range_option(InputInfoPtr pInfo, + struct xf86libinput *driver_data, + struct range *range) +{ +#if HAVE_LIBINPUT_PRESSURE_RANGE + struct libinput_tablet_tool *tool = driver_data->tablet_tool; + float min, max; + char *str; + int rc; + + range->min = 0.0; + range->max = 1.0; + + if ((driver_data->capabilities & CAP_TABLET_TOOL) == 0) + return; + + if (!tool || !libinput_tablet_tool_config_pressure_range_is_available(tool)) + return; + + str = xf86SetStrOption(pInfo->options, + "TabletToolPressureRange", + NULL); + if (!str) + return; + + rc = sscanf(str, "%f %f", &min, &max); + if (rc != 2) + goto out; + + if (min < 0.0 || max > 1.0 || min >= max) + goto out; + + range->min = min; + range->max = max; +out: + free(str); +#endif +} + static inline bool want_area_handling(struct xf86libinput *driver_data) { @@ -3629,6 +3713,7 @@ xf86libinput_parse_options(InputInfoPtr pInfo, xf86libinput_parse_pressurecurve_option(pInfo, driver_data, options->pressurecurve); + xf86libinput_parse_pressure_range_option(pInfo, driver_data, &options->pressure_range); xf86libinput_parse_tablet_area_option(pInfo, driver_data, &options->area); @@ -4103,6 +4188,8 @@ static Atom prop_mode_groups_rings; static Atom prop_mode_groups_strips; static Atom prop_rotation_angle; static Atom prop_rotation_angle_default; +static Atom prop_pressure_range; +static Atom prop_pressure_range_default; /* driver properties */ static Atom prop_draglock; @@ -5111,6 +5198,42 @@ LibinputSetPropertyPressureCurve(DeviceIntPtr dev, } static inline int +LibinputSetPropertyPressureRange(DeviceIntPtr dev, + Atom atom, + XIPropertyValuePtr val, + BOOL checkonly) +{ + InputInfoPtr pInfo = dev->public.devicePrivate; + struct xf86libinput *driver_data = pInfo->private; + float *vals; + struct range range = { 0.0, 1.0 }; + + if (val->format != 32 || val->size != 2 || val->type != prop_float) + return BadMatch; + + vals = val->data; + range.min = vals[0]; + range.max = vals[1]; + + if (checkonly) { + if (range.min < 0.0 || range.max > 1.0 || range.min >= range.max) + return BadValue; + + /* Disallow reducing the range to less than 20% of the range, mostly + * to avoid footguns */ + if (range.max - range.min < 0.2) + return BadValue; + + if (!xf86libinput_check_device(dev, atom)) + return BadMatch; + } else { + driver_data->options.pressure_range = range; + } + + return Success; +} + +static inline int LibinputSetPropertyAreaRatio(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, @@ -5261,6 +5384,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_pressure_range) + rc = LibinputSetPropertyPressureRange(dev, atom, val, checkonly); else if (atom == prop_area_ratio) rc = LibinputSetPropertyAreaRatio(dev, atom, val, checkonly); else if (atom == prop_hires_scroll) @@ -5279,6 +5404,7 @@ LibinputSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, atom == prop_mode_groups_strips || atom == prop_natural_scroll_default || atom == prop_product_id || + atom == prop_pressure_range_default || atom == prop_rotation_angle_default || atom == prop_scroll_button_default || atom == prop_scroll_buttonlock_default || @@ -6264,6 +6390,44 @@ LibinputInitPressureCurveProperty(DeviceIntPtr dev, } static void +LibinputInitPressureRangeProperty(DeviceIntPtr dev, + struct xf86libinput *driver_data) +{ +#if HAVE_LIBINPUT_PRESSURE_RANGE + struct libinput_tablet_tool *tool = driver_data->tablet_tool; + const struct range *range = &driver_data->options.pressure_range; + float data[2] = { + range->min, + range->max, + }; + + if ((driver_data->capabilities & CAP_TABLET_TOOL) == 0) + return; + + + if (!tool || !libinput_tablet_tool_config_pressure_range_is_available(tool)) + return; + + prop_pressure_range = LibinputMakeProperty(dev, + LIBINPUT_PROP_TABLET_TOOL_PRESSURE_RANGE, + prop_float, 32, + 2, &data); + if (!prop_pressure_range) + return; + + data[0] = libinput_tablet_tool_config_pressure_range_get_default_minimum(tool); + data[1] = libinput_tablet_tool_config_pressure_range_get_default_maximum(tool); + prop_pressure_range_default = LibinputMakeProperty(dev, + LIBINPUT_PROP_TABLET_TOOL_PRESSURE_RANGE_DEFAULT, + prop_float, 32, + 2, &data); + + if (!prop_pressure_range_default) + return; +#endif +} + +static void LibinputInitTabletAreaRatioProperty(DeviceIntPtr dev, struct xf86libinput *driver_data) { @@ -6386,6 +6550,7 @@ LibinputInitProperty(DeviceIntPtr dev) LibinputInitHorizScrollProperty(dev, driver_data); LibinputInitScrollPixelDistanceProperty(dev, driver_data, device); LibinputInitPressureCurveProperty(dev, driver_data); + LibinputInitPressureRangeProperty(dev, driver_data); LibinputInitTabletAreaRatioProperty(dev, driver_data); LibinputInitTabletSerialProperty(dev, driver_data); LibinputInitHighResolutionScrollProperty(dev, driver_data, device); |