From bda0c7478e26f0dabf74373b78bcadd45b2f466b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 23 Oct 2025 13:31:55 +1000 Subject: [PATCH] tablet: when configuring a user-defined pressure range, zero the offset When a user configures a pressure range, the tool would get locked into the current offset even if that offset was still pending. For example, a sequence of - tool in-prox with pressure 50% - libinput_tablet_tool_config_pressure_range_set(tool, 0.0, 0.9) - tool out-of-prox, tool-in-prox - libinput applies the tool config, tool now has a configured range, has_offset = true - tool out-of-prox, tool-in-prox - update_pressure_range() sees has_offset = true, scales the last offset (50%) to the actual offset. Fix this by resetting the detected offset to zero when we shortcut the heuristics. A user-defined pressure range should include the tool's pressure offset anyway, the user knows this much better than our heuristics. Closes: 1177 Part-of: --- src/evdev-tablet.c | 6 ++-- test/test-tablet.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 12a8d508..4e2bb3d0 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -2192,13 +2192,13 @@ update_pressure_range(struct tablet_dispatch *tablet, threshold->threshold.upper = hi; threshold->threshold.lower = lo; - if (threshold->has_offset) - set_pressure_offset(threshold, threshold->offset); - /* Disable any heuristics */ if (tool->pressure.has_configured_range) { threshold->has_offset = true; threshold->heuristic_state = PRESSURE_HEURISTIC_STATE_DONE; + threshold->offset = pressure_offset_from_double(0.0); + } else if (threshold->has_offset) { + set_pressure_offset(threshold, threshold->offset); } } diff --git a/test/test-tablet.c b/test/test-tablet.c index a68002f6..0df752fc 100644 --- a/test/test-tablet.c +++ b/test/test-tablet.c @@ -4970,6 +4970,86 @@ START_TEST(tablet_pressure_config_set_range) } END_TEST +START_TEST(tablet_pressure_config_resets_offset) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct axis_replacement axes[] = { + { ABS_DISTANCE, 70 }, + { ABS_PRESSURE, 70 }, /* high pressure offset */ + { -1, -1 }, + }; + + if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_PRESSURE)) + return LITEST_NOT_APPLICABLE; + + litest_tablet_proximity_in(dev, 5, 100, axes); + litest_drain_events(li); + litest_dispatch(li); + + litest_tablet_motion(dev, 70, 70, axes); + litest_dispatch(li); + + { + _destroy_(libinput_event) *event = libinput_get_event(li); + auto tev = + litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS); + auto tool = libinput_event_tablet_tool_get_tool(tev); + + litest_assert( + libinput_tablet_tool_config_pressure_range_is_available(tool)); + litest_assert_enum_eq( + libinput_tablet_tool_config_pressure_range_set(tool, + 0.01, + 0.99), + LIBINPUT_CONFIG_STATUS_SUCCESS); + } + + litest_tablet_proximity_out(dev); + litest_timeout_tablet_proxout(li); + litest_drain_events(li); + + /* Config should be applied on prox in */ + litest_axis_set_value(axes, ABS_PRESSURE, 71); + litest_tablet_proximity_in(dev, 72, 72, axes); + litest_drain_events(li); + litest_tablet_proximity_out(dev); + litest_timeout_tablet_proxout(li); + litest_drain_events(li); + + /* Two prox in/out cycles to get past the heuristics on devices without + * ABS_DISTANCE + */ + litest_axis_set_value(axes, ABS_PRESSURE, 72); + litest_tablet_proximity_in(dev, 75, 75, axes); + litest_drain_events(li); + litest_tablet_proximity_out(dev); + litest_timeout_tablet_proxout(li); + litest_drain_events(li); + + for (double pressure = 10.0, i = 71; pressure <= 25; pressure += 5, i += 0.2) { + litest_log_group("Prox in/out with pressure %.f", pressure) { + litest_axis_set_value(axes, ABS_PRESSURE, pressure); + litest_tablet_proximity_in(dev, i, i, axes); + litest_dispatch(li); + + _destroy_(libinput_event) *event = libinput_get_event(li); + auto tev = litest_is_tablet_event( + event, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + double p = libinput_event_tablet_tool_get_pressure(tev); + /* checking if >5% is good enough here, it'd be zero if the + * 70% threshold were locked in */ + litest_assert_double_gt(p, 0.05); + + litest_tablet_proximity_out(dev); + litest_timeout_tablet_proxout(li); + litest_drain_events(li); + } + } +} +END_TEST + static void pressure_threshold_warning(struct libinput *libinput, enum libinput_log_priority priority, @@ -7629,6 +7709,7 @@ TEST_COLLECTION(tablet) 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(tablet_pressure_config_resets_offset, LITEST_TABLET, LITEST_TOTEM); litest_add_for_device(tablet_distance_range, LITEST_WACOM_INTUOS5_PEN);