mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 00:00:28 +01:00
tablet: add tablet tool pressure range configuration
Add a configuration option to reduce the available hardware range to a fraction thereof. This is done by copying the absinfo struct for the pressure value and adjusting that copy's minimum/maximum value for scaling into the target normalized range. The 1%/5% tip thresholds are kept but pressure offset detection is disabled if there is a custom pressure range. Unlike the pressure curve which is implemented in the compositor, the pressure min/max range needs to be in libinput, primarily because the tip threshold needs to adjust to any new minimum, allowing for light touches with a pen without triggering tip down even at a higher hardware pressure.
This commit is contained in:
parent
47f0bce7ec
commit
4bc27543e9
8 changed files with 750 additions and 39 deletions
|
|
@ -177,3 +177,17 @@ the non-dominant hand.
|
|||
Note that where a device rotation is higher than 160 but less than 200 degrees,
|
||||
the direction of wheels is also inverted. For all other angles, the wheel
|
||||
direction is left as-is.
|
||||
|
||||
.. _config-tablet-pressure-range:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Tablet tool pressure range
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
The pressure range on a :ref:`Tablet tool <tablet-tools>` can be reduced
|
||||
from the full available hardware range to a subset of that range. The effect
|
||||
of this is that the tablet will not register pressure below the given
|
||||
the given threshold is met, and will reach the maximum logical pressure
|
||||
before the maximum hardware-supported pressure is reached.
|
||||
|
||||
See :ref:`tablet-pressure-range` for more info.
|
||||
|
|
|
|||
|
|
@ -189,6 +189,52 @@ specifically:
|
|||
Pressure offsets are not detected on **LIBINPUT_TABLET_TOOL_TYPE_MOUSE**
|
||||
and **LIBINPUT_TABLET_TOOL_TYPE_LENS** tools.
|
||||
|
||||
|
||||
.. _tablet-pressure-range:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Custom tablet tool pressure ranges
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
On tablets supporting pressure, libinput provides that hardware pressure as
|
||||
a logical range of ``0.0`` up to ``1.0`` for the maximum supported pressure.
|
||||
By default, the hardware range thus maps into the following logical range::
|
||||
|
||||
|
||||
hw minimum hw maximum
|
||||
hw range: |------|-----------------------------------|
|
||||
logical range: |----|-----------------------------------|
|
||||
0.0 | 1.0
|
||||
Tip
|
||||
|
||||
Note that libinput always has some built-in thresholds to filter out erroneous
|
||||
touches with near-zero pressure but otherwise the hardware range maps as-is
|
||||
into the logical range. The :ref:`tip event <tablet-tip>` threshold is defined
|
||||
within this range.
|
||||
|
||||
For some use-cases the full hardware range is not suitable, it may require either
|
||||
too light a pressure for the user to interact or it may require too hard a
|
||||
pressure before the logical maximum is reached. libinput provides
|
||||
the **libinput_tablet_tool_config_pressure_range_set()** function that allows
|
||||
reducing the usable range of the tablet::
|
||||
|
||||
hw minimum hw maximum
|
||||
hw range: |----------|-------------------------------|
|
||||
adjusted range: |------|---------------------|
|
||||
logical range: |----|---------------------|
|
||||
0.0 | 1.0
|
||||
Tip
|
||||
|
||||
A reduced range as shown above will result in
|
||||
|
||||
- all hw pressure below the new minimum to register as logical pressure ``0.0``
|
||||
- all hw pressure above the new maximum to register as logical pressure ``1.0``
|
||||
- the tip event threshold to be relative to the new minimum
|
||||
|
||||
In other words, adjusting the pressure range of a tablet tool is equivalent to
|
||||
reducing the hardware range of said tool. Note that where a custom pressure
|
||||
range is set, detection of :ref:`tablet-pressure-offset` is disabled.
|
||||
|
||||
.. _tablet-serial-numbers:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ normalize_distance(const struct input_absinfo *absinfo)
|
|||
|
||||
static inline double
|
||||
normalize_pressure(const struct input_absinfo *absinfo,
|
||||
int abs_value,
|
||||
struct libinput_tablet_tool *tool)
|
||||
{
|
||||
/**
|
||||
|
|
@ -360,9 +361,10 @@ normalize_pressure(const struct input_absinfo *absinfo,
|
|||
* threshold is 0 pressure.
|
||||
*/
|
||||
struct input_absinfo abs = *absinfo;
|
||||
|
||||
abs.minimum = tool->pressure.threshold.lower;
|
||||
|
||||
return absinfo_normalize(&abs);
|
||||
return absinfo_normalize_value(&abs, abs_value);
|
||||
}
|
||||
|
||||
static inline double
|
||||
|
|
@ -522,15 +524,15 @@ tablet_update_pressure(struct tablet_dispatch *tablet,
|
|||
struct evdev_device *device,
|
||||
struct libinput_tablet_tool *tool)
|
||||
{
|
||||
const struct input_absinfo *absinfo;
|
||||
|
||||
if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_PRESSURE))
|
||||
const struct input_absinfo *abs = libevdev_get_abs_info(device->evdev,
|
||||
ABS_PRESSURE);
|
||||
if (!abs)
|
||||
return;
|
||||
|
||||
if (bit_is_set(tablet->changed_axes,
|
||||
LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) {
|
||||
absinfo = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
|
||||
tablet->axes.pressure = normalize_pressure(absinfo, tool);
|
||||
if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE)) {
|
||||
tablet->axes.pressure = normalize_pressure(&tool->pressure.abs_pressure,
|
||||
abs->value,
|
||||
tool);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1076,26 +1078,94 @@ axis_range_percentage(const struct input_absinfo *a, double percent)
|
|||
return (a->maximum - a->minimum) * percent/100.0 + a->minimum;
|
||||
}
|
||||
|
||||
static bool
|
||||
tablet_get_quirked_pressure_thresholds(struct tablet_dispatch *tablet,
|
||||
int *hi,
|
||||
int *lo)
|
||||
{
|
||||
struct evdev_device *device = tablet->device;
|
||||
struct quirks_context *quirks = evdev_libinput_context(device)->quirks;
|
||||
struct quirks *q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
struct quirk_range r;
|
||||
bool status = false;
|
||||
|
||||
/* Note: the quirk term "range" refers to the hi/lo settings, not the
|
||||
* full available range for the pressure axis */
|
||||
if (q && quirks_get_range(q, QUIRK_ATTR_PRESSURE_RANGE, &r)) {
|
||||
if (r.lower < r.upper) {
|
||||
*hi = r.lower;
|
||||
*lo = r.upper;
|
||||
status = true;
|
||||
} else {
|
||||
evdev_log_info(device, "Invalid pressure range, using defaults\n");
|
||||
}
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_pressure_range_configuration(struct tablet_dispatch *tablet,
|
||||
struct libinput_tablet_tool *tool)
|
||||
{
|
||||
struct evdev_device *device = tablet->device;
|
||||
|
||||
if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_PRESSURE) ||
|
||||
(tool->pressure.range.min == tool->pressure.wanted_range.min &&
|
||||
tool->pressure.range.max == tool->pressure.wanted_range.max))
|
||||
return;
|
||||
|
||||
double min = tool->pressure.wanted_range.min;
|
||||
double max = tool->pressure.wanted_range.max;
|
||||
|
||||
struct input_absinfo abs = *libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
|
||||
|
||||
int minimum = axis_range_percentage(&abs, min * 100.0);
|
||||
int maximum = axis_range_percentage(&abs, max * 100.0);
|
||||
|
||||
abs.minimum = minimum;
|
||||
abs.maximum = maximum;
|
||||
|
||||
/* Only use the quirk pressure range if we don't have a custom range */
|
||||
int hi, lo;
|
||||
if (tool->pressure.wanted_range.min != 0.0 ||
|
||||
tool->pressure.wanted_range.max != 1.0 ||
|
||||
!tablet_get_quirked_pressure_thresholds(tablet, &hi, &lo)) {
|
||||
/* 5 and 1% of the pressure range */
|
||||
hi = axis_range_percentage(&abs, 5);
|
||||
lo = axis_range_percentage(&abs, 1);
|
||||
}
|
||||
|
||||
tool->pressure.abs_pressure = abs;
|
||||
tool->pressure.threshold.upper = hi;
|
||||
tool->pressure.threshold.lower = lo;
|
||||
tool->pressure.range.min = tool->pressure.wanted_range.min;
|
||||
tool->pressure.range.max = tool->pressure.wanted_range.max;
|
||||
|
||||
/* Disable any heuristics */
|
||||
if (tool->pressure.has_configured_range) {
|
||||
tool->pressure.has_offset = true;
|
||||
tool->pressure.heuristic_state = PRESSURE_HEURISTIC_STATE_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
tool_set_pressure_thresholds(struct tablet_dispatch *tablet,
|
||||
struct libinput_tablet_tool *tool)
|
||||
tool_init_pressure_thresholds(struct tablet_dispatch *tablet,
|
||||
struct libinput_tablet_tool *tool)
|
||||
{
|
||||
struct evdev_device *device = tablet->device;
|
||||
const struct input_absinfo *pressure, *distance;
|
||||
struct quirks_context *quirks = NULL;
|
||||
struct quirks *q = NULL;
|
||||
struct quirk_range r;
|
||||
int lo = 0, hi = 1;
|
||||
|
||||
tool->pressure.offset = 0;
|
||||
tool->pressure.has_offset = false;
|
||||
|
||||
pressure = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
|
||||
if (!pressure)
|
||||
goto out;
|
||||
|
||||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
if (!pressure) {
|
||||
tool->pressure.threshold.upper = 1;
|
||||
tool->pressure.threshold.lower = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
distance = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);
|
||||
if (distance) {
|
||||
|
|
@ -1106,24 +1176,40 @@ tool_set_pressure_thresholds(struct tablet_dispatch *tablet,
|
|||
tool->pressure.heuristic_state = PRESSURE_HEURISTIC_STATE_PROXIN1;
|
||||
}
|
||||
|
||||
/* 5 and 1% of the pressure range */
|
||||
hi = axis_range_percentage(pressure, 5);
|
||||
lo = axis_range_percentage(pressure, 1);
|
||||
apply_pressure_range_configuration(tablet, tool);
|
||||
}
|
||||
|
||||
if (q && quirks_get_range(q, QUIRK_ATTR_PRESSURE_RANGE, &r)) {
|
||||
if (r.lower >= r.upper) {
|
||||
evdev_log_info(device,
|
||||
"Invalid pressure range, using defaults\n");
|
||||
} else {
|
||||
hi = r.upper;
|
||||
lo = r.lower;
|
||||
}
|
||||
}
|
||||
out:
|
||||
tool->pressure.threshold.upper = hi;
|
||||
tool->pressure.threshold.lower = lo;
|
||||
static int
|
||||
pressure_range_is_available(struct libinput_tablet_tool *tool)
|
||||
{
|
||||
return bit_is_set(tool->axis_caps, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE);
|
||||
}
|
||||
|
||||
quirks_unref(q);
|
||||
static enum libinput_config_status
|
||||
pressure_range_set(struct libinput_tablet_tool *tool, double min, double max)
|
||||
{
|
||||
if (min < 0.0 || min >= 1.0 || max <= 0.0 || max > 1.0 || max <= min)
|
||||
return LIBINPUT_CONFIG_STATUS_INVALID;
|
||||
|
||||
tool->pressure.wanted_range.min = min;
|
||||
tool->pressure.wanted_range.max = max;
|
||||
tool->pressure.has_configured_range = true;
|
||||
|
||||
return LIBINPUT_CONFIG_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
pressure_range_get(struct libinput_tablet_tool *tool, double *min, double *max)
|
||||
{
|
||||
*min = tool->pressure.wanted_range.min;
|
||||
*max = tool->pressure.wanted_range.max;
|
||||
}
|
||||
|
||||
static void
|
||||
pressure_range_get_default(struct libinput_tablet_tool *tool, double *min, double *max)
|
||||
{
|
||||
*min = 0.0;
|
||||
*max = 1.0;
|
||||
}
|
||||
|
||||
static struct libinput_tablet_tool *
|
||||
|
|
@ -1139,14 +1225,31 @@ tablet_new_tool(struct tablet_dispatch *tablet,
|
|||
.serial = serial,
|
||||
.tool_id = tool_id,
|
||||
.refcount = 1,
|
||||
|
||||
.pressure.range.min = 0.0,
|
||||
.pressure.range.max = 0.0, /* to trigger configuration */
|
||||
.pressure.wanted_range.min = 0.0,
|
||||
.pressure.wanted_range.max = 1.0,
|
||||
|
||||
.config.pressure_range.is_available = pressure_range_is_available,
|
||||
.config.pressure_range.set = pressure_range_set,
|
||||
.config.pressure_range.get = pressure_range_get,
|
||||
.config.pressure_range.get_default = pressure_range_get_default,
|
||||
};
|
||||
|
||||
/* Copy the pressure axis for configuring the range later */
|
||||
struct evdev_device *device = tablet->device;
|
||||
const struct input_absinfo *abs = libevdev_get_abs_info(device->evdev,
|
||||
ABS_PRESSURE);
|
||||
if (abs)
|
||||
tool->pressure.abs_pressure = *abs;
|
||||
|
||||
/* FIXME: known bug - the pressure threshold is only set once on the
|
||||
* first tablet, if a tool is used across multiple tablets with
|
||||
* different pressure ranges this will be wrong. This case is niche
|
||||
* enough that we can fix it if we ever run into it.
|
||||
*/
|
||||
tool_set_pressure_thresholds(tablet, tool);
|
||||
tool_init_pressure_thresholds(tablet, tool);
|
||||
tool_set_bits(tablet, tool);
|
||||
|
||||
return tool;
|
||||
|
|
@ -1272,6 +1375,8 @@ sanitize_pressure_distance(struct tablet_dispatch *tablet,
|
|||
*pressure;
|
||||
|
||||
distance = libevdev_get_abs_info(tablet->device->evdev, ABS_DISTANCE);
|
||||
/* Note: for pressure/distance sanitization we use the real pressure
|
||||
axis, not our configured one */
|
||||
pressure = libevdev_get_abs_info(tablet->device->evdev, ABS_PRESSURE);
|
||||
|
||||
if (!pressure || !distance)
|
||||
|
|
@ -1354,7 +1459,7 @@ update_pressure_offset(struct tablet_dispatch *tablet,
|
|||
const struct input_absinfo *pressure =
|
||||
libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
|
||||
|
||||
if (!pressure ||
|
||||
if (!pressure || tool->pressure.has_configured_range ||
|
||||
!bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))
|
||||
return;
|
||||
|
||||
|
|
@ -1383,7 +1488,7 @@ detect_pressure_offset(struct tablet_dispatch *tablet,
|
|||
const struct input_absinfo *pressure, *distance;
|
||||
int offset;
|
||||
|
||||
if (tool->pressure.has_offset ||
|
||||
if (tool->pressure.has_offset || tool->pressure.has_configured_range ||
|
||||
!bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))
|
||||
return;
|
||||
|
||||
|
|
@ -1999,6 +2104,7 @@ reprocess:
|
|||
tablet_set_status(tablet, TABLET_BUTTONS_RELEASED);
|
||||
if (tablet_has_status(tablet, TABLET_TOOL_IN_CONTACT))
|
||||
tablet_set_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
|
||||
apply_pressure_range_configuration(tablet, tool);
|
||||
} else if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY)) {
|
||||
tablet_mark_all_axes_changed(tablet, tool);
|
||||
update_pressure_offset(tablet, device, tool);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ struct normalized_range_coords {
|
|||
double x, y;
|
||||
};
|
||||
|
||||
/* A [0.0, 1.0] normalized range */
|
||||
struct normalized_range {
|
||||
double min, max;
|
||||
};
|
||||
|
||||
/* A pair of angles in degrees */
|
||||
struct wheel_angle {
|
||||
double x, y;
|
||||
|
|
@ -449,6 +454,13 @@ enum pressure_heuristic_state {
|
|||
PRESSURE_HEURISTIC_STATE_DONE, /** Decision's been made, live with it */
|
||||
};
|
||||
|
||||
struct libinput_tablet_tool_config_pressure_range {
|
||||
int (*is_available)(struct libinput_tablet_tool *tool);
|
||||
enum libinput_config_status (*set)(struct libinput_tablet_tool *tool, double min, double max);
|
||||
void (*get)(struct libinput_tablet_tool *tool, double *min, double *max);
|
||||
void (*get_default)(struct libinput_tablet_tool *tool, double *min, double *max);
|
||||
};
|
||||
|
||||
struct libinput_tablet_tool {
|
||||
struct list link;
|
||||
uint32_t serial;
|
||||
|
|
@ -460,12 +472,22 @@ struct libinput_tablet_tool {
|
|||
void *user_data;
|
||||
|
||||
struct {
|
||||
/* The configured axis we actually work with */
|
||||
struct input_absinfo abs_pressure;
|
||||
struct normalized_range range;
|
||||
struct normalized_range wanted_range;
|
||||
bool has_configured_range;
|
||||
|
||||
struct threshold threshold; /* in device coordinates */
|
||||
int offset; /* in device coordinates */
|
||||
bool has_offset;
|
||||
|
||||
enum pressure_heuristic_state heuristic_state;
|
||||
} pressure;
|
||||
|
||||
struct {
|
||||
struct libinput_tablet_tool_config_pressure_range pressure_range;
|
||||
} config;
|
||||
};
|
||||
|
||||
struct libinput_tablet_pad_mode_group {
|
||||
|
|
|
|||
|
|
@ -4728,6 +4728,75 @@ libinput_device_config_rotation_get_default_angle(struct libinput_device *device
|
|||
return device->config.rotation->get_default_angle(device);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_tablet_tool_config_pressure_range_is_available(struct libinput_tablet_tool *tool)
|
||||
{
|
||||
if (!tool->config.pressure_range.is_available)
|
||||
return 0;
|
||||
|
||||
return tool->config.pressure_range.is_available(tool);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT enum libinput_config_status
|
||||
libinput_tablet_tool_config_pressure_range_set(struct libinput_tablet_tool *tool,
|
||||
double minimum,
|
||||
double maximum)
|
||||
{
|
||||
if (!libinput_tablet_tool_config_pressure_range_is_available(tool))
|
||||
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
|
||||
|
||||
if (minimum < 0.0 || minimum >= 1.0 ||
|
||||
maximum <= 0.0 || maximum > 1.0 ||
|
||||
maximum <= minimum)
|
||||
return LIBINPUT_CONFIG_STATUS_INVALID;
|
||||
|
||||
return tool->config.pressure_range.set(tool, minimum, maximum);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT double
|
||||
libinput_tablet_tool_config_pressure_range_get_minimum(struct libinput_tablet_tool *tool)
|
||||
{
|
||||
double min = 0.0, max = 1.0;
|
||||
|
||||
if (libinput_tablet_tool_config_pressure_range_is_available(tool))
|
||||
tool->config.pressure_range.get(tool, &min, &max);
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT double
|
||||
libinput_tablet_tool_config_pressure_range_get_maximum(struct libinput_tablet_tool *tool)
|
||||
{
|
||||
double min = 0.0, max = 1.0;
|
||||
|
||||
if (libinput_tablet_tool_config_pressure_range_is_available(tool))
|
||||
tool->config.pressure_range.get(tool, &min, &max);
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT double
|
||||
libinput_tablet_tool_config_pressure_range_get_default_minimum(struct libinput_tablet_tool *tool)
|
||||
{
|
||||
double min = 0.0, max = 1.0;
|
||||
|
||||
if (libinput_tablet_tool_config_pressure_range_is_available(tool))
|
||||
tool->config.pressure_range.get_default(tool, &min, &max);
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT double
|
||||
libinput_tablet_tool_config_pressure_range_get_default_maximum(struct libinput_tablet_tool *tool)
|
||||
{
|
||||
double min = 0.0, max = 1.0;
|
||||
|
||||
if (libinput_tablet_tool_config_pressure_range_is_available(tool))
|
||||
tool->config.pressure_range.get_default(tool, &min, &max);
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
#if HAVE_LIBWACOM
|
||||
WacomDeviceDatabase *
|
||||
libinput_libwacom_ref(struct libinput *li)
|
||||
|
|
|
|||
130
src/libinput.h
130
src/libinput.h
|
|
@ -6398,6 +6398,136 @@ libinput_device_config_rotation_get_angle(struct libinput_device *device);
|
|||
unsigned int
|
||||
libinput_device_config_rotation_get_default_angle(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Check if a tablet tool can have a custom pressure range.
|
||||
*
|
||||
* @param tool The libinput tool
|
||||
* @return Non-zero if a device has an adjustible pressure range, zero otherwise.
|
||||
*
|
||||
* @see libinput_tablet_tool_config_pressure_range_set
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_minimum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_maximum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_minimum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_maximum
|
||||
*
|
||||
* @since 1.25
|
||||
*/
|
||||
int
|
||||
libinput_tablet_tool_config_pressure_range_is_available(struct libinput_tablet_tool *tool);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Set the pressure range for this tablet tool. This maps the given logical
|
||||
* pressure range into the available hardware pressure range so that a hardware
|
||||
* pressure of the given minimum value maps into a logical pressure of 0.0 (as
|
||||
* returned by libinput_event_tablet_tool_get_pressure()) and the hardware
|
||||
* pressure of the given maximum value is mapped into the logical pressure
|
||||
* of 1.0 (as returned by . libinput_event_tablet_tool_get_pressure())
|
||||
*
|
||||
* The minimum value must be less than the maximum value, libinput may
|
||||
* libinput may require the values to have a specific distance to each other,
|
||||
* i.e. that (maximium - minimum > N) for an implementation-defined value of N.
|
||||
*
|
||||
* @param tool The libinput tool
|
||||
* @param minimum The minimum pressure value in the range [0.0, 1.0)
|
||||
* @param maximum The maximum pressure value in the range (0.0, 1.0]
|
||||
*
|
||||
* @return A config status code
|
||||
*
|
||||
* @see libinput_tablet_tool_config_pressure_range_is_available
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_minimum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_maximum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_minimum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_maximum
|
||||
*/
|
||||
enum libinput_config_status
|
||||
libinput_tablet_tool_config_pressure_range_set(struct libinput_tablet_tool *tool,
|
||||
double minimum,
|
||||
double maximum);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Get the minimum pressure value for this tablet tool, normalized to the
|
||||
* range [0.0, 1.0] of the available hardware pressure.
|
||||
*
|
||||
* If the tool does not support pressure range configuration, the return value
|
||||
* of this function is always 0.0.
|
||||
*
|
||||
* @param tool The libinput tool
|
||||
* @return The minimum pressure value for this tablet tool
|
||||
*
|
||||
* @see libinput_tablet_tool_config_pressure_range_is_available
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_maximum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_minimum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_maximum
|
||||
*/
|
||||
double
|
||||
libinput_tablet_tool_config_pressure_range_get_minimum(struct libinput_tablet_tool *tool);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Get the maximum pressure value for this tablet tool, normalized to the
|
||||
* range [0.0, 1.0] of the available hardware pressure.
|
||||
*
|
||||
* If the tool does not support pressure range configuration, the return value
|
||||
* of this function is always 1.0.
|
||||
*
|
||||
* @param tool The libinput tool
|
||||
* @return The maximum pressure value for this tablet tool
|
||||
*
|
||||
* @see libinput_tablet_tool_config_pressure_range_is_available
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_minimum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_maximum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_maximum
|
||||
*/
|
||||
double
|
||||
libinput_tablet_tool_config_pressure_range_get_maximum(struct libinput_tablet_tool *tool);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Get the minimum pressure value for this tablet tool, normalized to the
|
||||
* range [0.0, 1.0] of the available hardware pressure.
|
||||
*
|
||||
* If the tool does not support pressure range configuration, the return value
|
||||
* of this function is always 0.0.
|
||||
*
|
||||
* @param tool The libinput tool
|
||||
* @return The minimum pressure value for this tablet tool
|
||||
*
|
||||
* @see libinput_tablet_tool_config_pressure_range_is_available
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_minimum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_maximum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_maximum
|
||||
*/
|
||||
double
|
||||
libinput_tablet_tool_config_pressure_range_get_default_minimum(struct libinput_tablet_tool *tool);
|
||||
|
||||
/**
|
||||
* @ingroup config
|
||||
*
|
||||
* Get the maximum pressure value for this tablet tool, normalized to the
|
||||
* range [0.0, 1.0] of the available hardware pressure.
|
||||
*
|
||||
* If the tool does not support pressure range configuration, the return value
|
||||
* of this function is always 1.0.
|
||||
*
|
||||
* @param tool The libinput tool
|
||||
* @return The maximum pressure value for this tablet tool
|
||||
*
|
||||
* @see libinput_tablet_tool_config_pressure_range_is_available
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_maximum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_maximum
|
||||
* @see libinput_tablet_tool_config_pressure_range_get_default_maximum
|
||||
*/
|
||||
double
|
||||
libinput_tablet_tool_config_pressure_range_get_default_maximum(struct libinput_tablet_tool *tool);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -332,4 +332,13 @@ LIBINPUT_1.23 {
|
|||
libinput_config_accel_destroy;
|
||||
libinput_device_config_accel_apply;
|
||||
libinput_config_accel_set_points;
|
||||
} LIBINPUT_1.21;
|
||||
} LIBINPUT_1.21;
|
||||
|
||||
LIBINPUT_1.26 {
|
||||
libinput_tablet_tool_config_pressure_range_is_available;
|
||||
libinput_tablet_tool_config_pressure_range_set;
|
||||
libinput_tablet_tool_config_pressure_range_get_minimum;
|
||||
libinput_tablet_tool_config_pressure_range_get_maximum;
|
||||
libinput_tablet_tool_config_pressure_range_get_default_minimum;
|
||||
libinput_tablet_tool_config_pressure_range_get_default_maximum;
|
||||
} LIBINPUT_1.23;
|
||||
|
|
|
|||
|
|
@ -4150,6 +4150,317 @@ START_TEST(tablet_pressure_range)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tablet_pressure_config)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *tev;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_DISTANCE, 0 },
|
||||
{ ABS_PRESSURE, 10 },
|
||||
{ -1, -1 },
|
||||
};
|
||||
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_drain_events(li);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_tablet_motion(dev, 70, 70, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
struct libinput_tablet_tool *tool = libinput_event_tablet_tool_get_tool(tev);
|
||||
|
||||
ck_assert(libinput_tablet_tool_config_pressure_range_is_available(tool));
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_minimum(tool), 0.0);
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_maximum(tool), 1.0);
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_default_minimum(tool), 0.0);
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_default_maximum(tool), 1.0);
|
||||
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 0.0, 1.0),
|
||||
LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 0.2, 0.5),
|
||||
LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, -0.1, 1.0),
|
||||
LIBINPUT_CONFIG_STATUS_INVALID);
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 0.0, 0.0),
|
||||
LIBINPUT_CONFIG_STATUS_INVALID);
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 1.0, 1.0),
|
||||
LIBINPUT_CONFIG_STATUS_INVALID);
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 0.0, 1.1),
|
||||
LIBINPUT_CONFIG_STATUS_INVALID);
|
||||
|
||||
/* The last successful one */
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_minimum(tool), 0.2);
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_maximum(tool), 0.5);
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_default_minimum(tool), 0.0);
|
||||
ck_assert_double_eq(libinput_tablet_tool_config_pressure_range_get_default_maximum(tool), 1.0);
|
||||
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tablet_pressure_config_set_minimum)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *tev;
|
||||
struct libinput_tablet_tool *tool;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_DISTANCE, 0 },
|
||||
{ ABS_PRESSURE, 10 },
|
||||
{ -1, -1 },
|
||||
};
|
||||
double p, old_pressure;
|
||||
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_drain_events(li);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_tablet_motion(dev, 70, 70, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
tool = libinput_event_tablet_tool_get_tool(tev);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_gt(p, 0.0);
|
||||
old_pressure = p;
|
||||
|
||||
ck_assert(libinput_tablet_tool_config_pressure_range_is_available(tool));
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 0.4, 1.0),
|
||||
LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* config doesn't take effect until we're out of prox */
|
||||
for (int pos = 71; pos < 80; pos++) {
|
||||
litest_tablet_motion(dev, pos, pos, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_eq(p, old_pressure);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
litest_tablet_proximity_out(dev);
|
||||
litest_timeout_tablet_proxout();
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 10% hw value is below our thresholds, so logical zero */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 10);
|
||||
litest_tablet_proximity_in(dev, 70, 70, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
for (int pos = 71; pos < 80; pos++) {
|
||||
litest_tablet_motion(dev, pos, pos, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_eq(p, 0.00);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
/* 50% hw value mapped into a reduced range of 60% from hw range,
|
||||
plus the 1% minimum offset, so our output pressure is actually ~15% */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 50);
|
||||
litest_tablet_motion(dev, 70, 70, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_TIP);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_gt(p, 0.15);
|
||||
ck_assert_double_le(p, 0.16);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
for (int pos = 71; pos < 80; pos++) {
|
||||
litest_tablet_motion(dev, pos, pos, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_ge(p, 0.15);
|
||||
ck_assert_double_le(p, 0.16);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tablet_pressure_config_set_maximum)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *tev;
|
||||
struct libinput_tablet_tool *tool;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_DISTANCE, 0 },
|
||||
{ ABS_PRESSURE, 10 },
|
||||
{ -1, -1 },
|
||||
};
|
||||
double p, old_pressure;
|
||||
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_drain_events(li);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_tablet_motion(dev, 70, 70, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
tool = libinput_event_tablet_tool_get_tool(tev);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_gt(p, 0.0);
|
||||
old_pressure = p;
|
||||
|
||||
ck_assert(libinput_tablet_tool_config_pressure_range_is_available(tool));
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 0.0, 0.6),
|
||||
LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* config doesn't take effect until we're out of prox */
|
||||
for (int pos = 71; pos < 80; pos++) {
|
||||
litest_tablet_motion(dev, pos, pos, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_eq(p, old_pressure);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
litest_tablet_proximity_out(dev);
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 10);
|
||||
litest_tablet_proximity_in(dev, 70, 70, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* 10% hw value mapped into a reduced range of 60% from hw range,
|
||||
plus the 1% minimum offset so our output pressure is actually ~15% */
|
||||
for (int pos = 71; pos < 80; pos++) {
|
||||
litest_tablet_motion(dev, pos, pos, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_ge(p, 0.15);
|
||||
ck_assert_double_le(p, 0.16);
|
||||
ck_assert_double_gt(p, old_pressure);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
/* 50% hw value mapped into a reduced range of 60% from hw range,
|
||||
plus the 1% minimum offset, so our output pressure is actually ~83% */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 50);
|
||||
|
||||
for (int pos = 71; pos < 80; pos++) {
|
||||
litest_tablet_motion(dev, pos, pos, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_ge(p, 0.82);
|
||||
ck_assert_double_le(p, 0.84);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
for (int hwp = 60; hwp < 100; hwp += 10) {
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, hwp);
|
||||
|
||||
for (int pos = 71; pos < 80; pos++) {
|
||||
litest_tablet_motion(dev, pos, pos, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_eq(p, 1.0);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tablet_pressure_config_set_range)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct libinput_event *event;
|
||||
struct libinput_event_tablet_tool *tev;
|
||||
struct libinput_tablet_tool *tool;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_DISTANCE, 0 },
|
||||
{ ABS_PRESSURE, 10 },
|
||||
{ -1, -1 },
|
||||
};
|
||||
double p, old_pressure;
|
||||
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_drain_events(li);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_tablet_motion(dev, 70, 70, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
tool = libinput_event_tablet_tool_get_tool(tev);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_gt(p, 0.0);
|
||||
old_pressure = p;
|
||||
|
||||
ck_assert(libinput_tablet_tool_config_pressure_range_is_available(tool));
|
||||
ck_assert_int_eq(libinput_tablet_tool_config_pressure_range_set(tool, 0.4, 0.6),
|
||||
LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
libinput_event_destroy(event);
|
||||
|
||||
/* config doesn't take effect until we're out of prox */
|
||||
for (int i = 71; i < 80; i++) {
|
||||
litest_tablet_motion(dev, i, i, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
ck_assert_double_eq(p, old_pressure);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
litest_tablet_proximity_out(dev);
|
||||
litest_timeout_tablet_proxout();
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_tablet_proximity_in(dev, 70, 70, axes);
|
||||
litest_drain_events(li);
|
||||
|
||||
for (double pressure = 0.0, i = 71; pressure <= 100; pressure += 5, i += 0.2) {
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, pressure);
|
||||
litest_tablet_motion(dev, i, i, axes);
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
if (libinput_event_get_type(event) == LIBINPUT_EVENT_TABLET_TOOL_AXIS)
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
else
|
||||
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_TIP);
|
||||
p = libinput_event_tablet_tool_get_pressure(tev);
|
||||
if (pressure <= 40) {
|
||||
ck_assert_double_eq(p, 0.0);
|
||||
} else if (pressure >= 60) {
|
||||
ck_assert_double_eq(p, 1.0);
|
||||
} else {
|
||||
ck_assert_double_ge(p, (pressure - 1 - 40)/20.0);
|
||||
ck_assert_double_le(p, (pressure - 40)/20.0);
|
||||
}
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
pressure_threshold_warning(struct libinput *libinput,
|
||||
enum libinput_log_priority priority,
|
||||
|
|
@ -6335,6 +6646,10 @@ TEST_COLLECTION(tablet)
|
|||
litest_add_for_device(tablet_pressure_offset_increase, LITEST_WACOM_HID4800_PEN);
|
||||
litest_add_for_device(tablet_pressure_offset_exceed_threshold, LITEST_WACOM_HID4800_PEN);
|
||||
|
||||
litest_add(tablet_pressure_config, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add(tablet_pressure_config_set_minimum, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add(tablet_pressure_config_set_maximum, LITEST_TABLET, LITEST_TOTEM);
|
||||
litest_add(tablet_pressure_config_set_range, LITEST_TABLET, LITEST_TOTEM);
|
||||
|
||||
litest_add_for_device(tablet_distance_range, LITEST_WACOM_INTUOS);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue