mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 01:10:25 +01:00
tablet: apply pressure offset handling for non-distance tablets
Previously we only applied pressure offset handling for tablets that supported ABS_DISTANCE. Detecting a pressure offset when the tool doesn't actually touch the surface is easy after all. But tablets without distance handling may also have a pressure offset, so let's try to detect this. This is obviously harder since the pen will always touch the tablet's surface whenever it is in proximity and thus will always have *some* pressure applied to it. The process here is to merely observe the minimum pressure value during the first two strokes of the pen. On the third prox in, that minimum pressure value is taken as the offset. If the pressure drops below the offset, the offset is adjusted downwards [1] so over time we'll get closer to the pen's real offset. [1] this is already done for distance tablets too Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
ecf02deb17
commit
a244b9e32b
3 changed files with 107 additions and 11 deletions
|
|
@ -1085,7 +1085,7 @@ tool_set_pressure_thresholds(struct tablet_dispatch *tablet,
|
|||
struct libinput_tablet_tool *tool)
|
||||
{
|
||||
struct evdev_device *device = tablet->device;
|
||||
const struct input_absinfo *pressure;
|
||||
const struct input_absinfo *pressure, *distance;
|
||||
struct quirks_context *quirks = NULL;
|
||||
struct quirks *q = NULL;
|
||||
struct quirk_range r;
|
||||
|
|
@ -1101,7 +1101,14 @@ tool_set_pressure_thresholds(struct tablet_dispatch *tablet,
|
|||
quirks = evdev_libinput_context(device)->quirks;
|
||||
q = quirks_fetch_for_device(quirks, device->udev_device);
|
||||
|
||||
tool->pressure.offset = pressure->minimum;
|
||||
distance = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);
|
||||
if (distance) {
|
||||
tool->pressure.offset = pressure->minimum;
|
||||
tool->pressure.heuristic_state = PRESSURE_HEURISTIC_STATE_DONE;
|
||||
} else {
|
||||
tool->pressure.offset = pressure->maximum;
|
||||
tool->pressure.heuristic_state = PRESSURE_HEURISTIC_STATE_PROXIN1;
|
||||
}
|
||||
|
||||
/* 5 and 1% of the pressure range */
|
||||
hi = axis_range_percentage(pressure, 5);
|
||||
|
|
@ -1337,18 +1344,24 @@ update_pressure_offset(struct tablet_dispatch *tablet,
|
|||
libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
|
||||
|
||||
if (!pressure ||
|
||||
!bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE) ||
|
||||
!tool->pressure.has_offset)
|
||||
!bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_PRESSURE))
|
||||
return;
|
||||
|
||||
/* If we have an event that falls below the current offset, adjust
|
||||
* the offset downwards. A fast contact can start with a
|
||||
* higher-than-needed pressure offset and then we'd be tied into a
|
||||
* high pressure offset for the rest of the session.
|
||||
*
|
||||
* If we are still pending the offset decision, only update the observed
|
||||
* offset value, don't actually set it to have an offset.
|
||||
*/
|
||||
int offset = pressure->value;
|
||||
if (offset < tool->pressure.offset)
|
||||
set_pressure_offset(tool, offset);
|
||||
if (tool->pressure.has_offset) {
|
||||
if (offset < tool->pressure.offset)
|
||||
set_pressure_offset(tool, offset);
|
||||
} else if (tool->pressure.heuristic_state != PRESSURE_HEURISTIC_STATE_DONE) {
|
||||
tool->pressure.offset = min(offset, tool->pressure.offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1366,16 +1379,43 @@ detect_pressure_offset(struct tablet_dispatch *tablet,
|
|||
pressure = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
|
||||
distance = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);
|
||||
|
||||
if (!pressure || !distance)
|
||||
if (!pressure)
|
||||
return;
|
||||
|
||||
offset = pressure->value;
|
||||
if (offset <= pressure->minimum)
|
||||
return;
|
||||
|
||||
/* If we're closer than 50% of the distance axis, skip pressure
|
||||
* offset detection, too likely to be wrong */
|
||||
if (distance->value < axis_range_percentage(distance, 50))
|
||||
if (distance) {
|
||||
/* If we're closer than 50% of the distance axis, skip pressure
|
||||
* offset detection, too likely to be wrong */
|
||||
if (distance->value < axis_range_percentage(distance, 50))
|
||||
return;
|
||||
} else {
|
||||
/* A device without distance will always have some pressure on
|
||||
* contact. Offset detection is delayed for a few proximity ins
|
||||
* in the hope we'll find the minimum value until then. That
|
||||
* offset is updated during motion events so by the time the
|
||||
* deciding prox-in arrives we should know the minimum offset.
|
||||
*/
|
||||
if (offset > pressure->minimum)
|
||||
tool->pressure.offset = min(offset, tool->pressure.offset);
|
||||
|
||||
switch (tool->pressure.heuristic_state) {
|
||||
case PRESSURE_HEURISTIC_STATE_PROXIN1:
|
||||
case PRESSURE_HEURISTIC_STATE_PROXIN2:
|
||||
tool->pressure.heuristic_state++;
|
||||
return;
|
||||
case PRESSURE_HEURISTIC_STATE_DECIDE:
|
||||
tool->pressure.heuristic_state++;
|
||||
offset = tool->pressure.offset;
|
||||
break;
|
||||
case PRESSURE_HEURISTIC_STATE_DONE:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset <= pressure->minimum)
|
||||
return;
|
||||
|
||||
if (offset > axis_range_percentage(pressure, 20)) {
|
||||
|
|
|
|||
|
|
@ -442,6 +442,13 @@ struct tablet_axes {
|
|||
struct phys_ellipsis size;
|
||||
};
|
||||
|
||||
enum pressure_heuristic_state {
|
||||
PRESSURE_HEURISTIC_STATE_PROXIN1, /** First proximity in event */
|
||||
PRESSURE_HEURISTIC_STATE_PROXIN2, /** Second proximity in event */
|
||||
PRESSURE_HEURISTIC_STATE_DECIDE, /** Decide on offset now */
|
||||
PRESSURE_HEURISTIC_STATE_DONE, /** Decision's been made, live with it */
|
||||
};
|
||||
|
||||
struct libinput_tablet_tool {
|
||||
struct list link;
|
||||
uint32_t serial;
|
||||
|
|
@ -456,6 +463,8 @@ struct libinput_tablet_tool {
|
|||
struct threshold threshold; /* in device coordinates */
|
||||
int offset; /* in device coordinates */
|
||||
bool has_offset;
|
||||
|
||||
enum pressure_heuristic_state heuristic_state;
|
||||
} pressure;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3829,6 +3829,22 @@ START_TEST(tablet_pressure_offset_set)
|
|||
{ -1, -1 },
|
||||
};
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_DISTANCE)) {
|
||||
/* First two prox ins won't do anything, coming with 10% should give
|
||||
* us ~10% pressure */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
libinput_dispatch(li);
|
||||
|
||||
assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, 0.20);
|
||||
assert_pressure(li, LIBINPUT_EVENT_TABLET_TOOL_TIP, 0.20);
|
||||
litest_tablet_proximity_out(dev);
|
||||
litest_drain_events(li);
|
||||
}
|
||||
}
|
||||
|
||||
/* This activates the pressure offset */
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_drain_events(li);
|
||||
|
|
@ -3900,6 +3916,13 @@ START_TEST(tablet_pressure_offset_decrease)
|
|||
litest_tablet_proximity_out(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* offset 15 on prox in - this one is so we trigger on the next prox
|
||||
* in for the no-distance tablets */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 15);
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_tablet_proximity_out(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* a reduced pressure value must reduce the offset */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 10);
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
|
|
@ -3959,7 +3982,13 @@ START_TEST(tablet_pressure_offset_increase)
|
|||
litest_tablet_proximity_out(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* offset 30 on second prox in - must not change the offset */
|
||||
/* offset 25 on second prox in - must not change the offset */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 25);
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_tablet_proximity_out(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* offset 30 on third prox in - must not change the offset */
|
||||
litest_axis_set_value(axes, ABS_PRESSURE, 30);
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_drain_events(li);
|
||||
|
|
@ -4092,6 +4121,15 @@ START_TEST(tablet_pressure_offset_exceed_threshold)
|
|||
int warning_triggered = 0;
|
||||
struct litest_user_data *user_data = libinput_get_user_data(li);
|
||||
|
||||
/* Tablet without distance: offset takes effect on third prox-in */
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_DISTANCE)) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
litest_tablet_proximity_in(dev, 5, 100, axes);
|
||||
litest_tablet_proximity_out(dev);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
}
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
user_data->private = &warning_triggered;
|
||||
|
|
@ -6150,6 +6188,7 @@ TEST_COLLECTION(tablet)
|
|||
litest_add(tablet_calibration_set_matrix_delta, LITEST_TABLET, LITEST_TOTEM|LITEST_PRECALIBRATED);
|
||||
|
||||
litest_add(tablet_pressure_min_max, LITEST_TABLET, LITEST_ANY);
|
||||
/* Tests for pressure offset with distance */
|
||||
litest_add_for_device(tablet_pressure_range, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device(tablet_pressure_offset_set, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device(tablet_pressure_offset_decrease, LITEST_WACOM_INTUOS);
|
||||
|
|
@ -6157,6 +6196,14 @@ TEST_COLLECTION(tablet)
|
|||
litest_add_for_device(tablet_pressure_offset_exceed_threshold, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device(tablet_pressure_offset_none_for_zero_distance, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device(tablet_pressure_offset_none_for_small_distance, LITEST_WACOM_INTUOS);
|
||||
/* Tests for pressure offset without distance */
|
||||
litest_add_for_device(tablet_pressure_range, LITEST_WACOM_HID4800_PEN);
|
||||
litest_add_for_device(tablet_pressure_offset_set, LITEST_WACOM_HID4800_PEN);
|
||||
litest_add_for_device(tablet_pressure_offset_decrease, LITEST_WACOM_HID4800_PEN);
|
||||
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_for_device(tablet_distance_range, LITEST_WACOM_INTUOS);
|
||||
|
||||
litest_add(relative_no_profile, LITEST_TABLET, LITEST_ANY);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue