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;
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);
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
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)) {
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;
struct threshold threshold; /* in device coordinates */
int offset; /* in device coordinates */
bool has_offset;
+
+ enum pressure_heuristic_state heuristic_state;
} pressure;
};
{ -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);
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);
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);
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;
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);
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);