diff --git a/doc/tablet-support.dox b/doc/tablet-support.dox index cc5d4091..ff4e4607 100644 --- a/doc/tablet-support.dox +++ b/doc/tablet-support.dox @@ -83,15 +83,19 @@ additionally provide tilt information along the x and y axis. @image html tablet-axes.svg "Illustration of the distance, pressure and tilt axes" -The granularity and precision of these axes varies between tablet devices -and cannot usually be mapped into a physical unit. -libinput normalizes distance and pressure into the [0, 1] range and the tilt -axes into the [-1, 1] range with 0 as the neutral point. +The granularity and precision of the distance and pressure axes varies +between tablet devices and cannot usually be mapped into a physical unit. +libinput normalizes distance and pressure into the [0, 1] range. While the normalization range is identical for these axes, a caller should not interpret identical values as identical across axes, i.e. a value v1 on the distance axis has no relation to the same value v1 on the pressure axis. +The tilt axes provide the angle in degrees between a vertical line out of +the tablet and the top of the stylus. The angle is measured along the x and +y axis, respectively, a positive tilt angle thus means that the stylus' top +is tilted towards the logical right and/or bottom of the tablet. + @section tablet-fake-proximity Handling of proximity events libinput's @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY events notify a caller diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index e684055b..9fd98403 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -225,13 +225,22 @@ normalize_pressure(const struct input_absinfo *absinfo, } static inline double -normalize_tilt(const struct input_absinfo *absinfo) +adjust_tilt(const struct input_absinfo *absinfo) { double range = absinfo->maximum - absinfo->minimum; double value = (absinfo->value - absinfo->minimum) / range; + const int WACOM_MAX_DEGREES = 64; /* Map to the (-1, 1) range */ - return (value * 2) - 1; + value = (value * 2) - 1; + + /* Wacom supports physical [-64, 64] degrees, so map to that by + * default. If other tablets have a different physical range or + * nonzero physical offsets, they need extra treatment + * here. + */ + + return value * WACOM_MAX_DEGREES; } static inline int32_t @@ -398,17 +407,17 @@ tablet_handle_slider(struct tablet_dispatch *tablet, return tablet->axes.slider; } -static inline struct normalized_range_coords +static inline struct tilt_degrees tablet_handle_tilt(struct tablet_dispatch *tablet, struct evdev_device *device) { - struct normalized_range_coords tilt; + struct tilt_degrees tilt; const struct input_absinfo *absinfo; if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_X)) { absinfo = libevdev_get_abs_info(device->evdev, ABS_TILT_X); - tablet->axes.tilt.x = normalize_tilt(absinfo); + tablet->axes.tilt.x = adjust_tilt(absinfo); if (device->left_handed.enabled) tablet->axes.tilt.x *= -1; } @@ -417,7 +426,7 @@ tablet_handle_tilt(struct tablet_dispatch *tablet, if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_Y)) { absinfo = libevdev_get_abs_info(device->evdev, ABS_TILT_Y); - tablet->axes.tilt.y = normalize_tilt(absinfo); + tablet->axes.tilt.y = adjust_tilt(absinfo); if (device->left_handed.enabled) tablet->axes.tilt.y *= -1; } diff --git a/src/libinput-private.h b/src/libinput-private.h index bc7000d7..8d2492aa 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -63,6 +63,11 @@ struct normalized_range_coords { double x, y; }; +/* A pair of angles in degrees */ +struct tilt_degrees { + double x, y; +}; + /* A threshold with an upper and lower limit */ struct threshold { int upper; @@ -74,7 +79,7 @@ struct tablet_axes { struct normalized_coords delta; double distance; double pressure; - struct normalized_range_coords tilt; + struct tilt_degrees tilt; double rotation; double slider; double wheel; diff --git a/src/libinput.h b/src/libinput.h index d808c162..b14c2811 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1648,12 +1648,16 @@ libinput_event_tablet_tool_get_distance(struct libinput_event_tablet_tool *event * @ingroup event_tablet * * Returns the current tilt along the X axis of the tablet's current logical - * orientation, normalized to the range [-1, 1]. + * orientation, in degrees off the tablet's z axis. That is, if the tool is + * perfectly orthogonal to the tablet, the tilt angle is 0. When the top + * tilts towards the logical top/left of the tablet, the x/y tilt angles are + * negative, if the top tilts towards the logical bottom/right of the + * tablet, the x/y tilt angles are positive. * * If this axis does not exist on the current tool, this function returns 0. * * @param event The libinput tablet tool event - * @return The current value of the the axis + * @return The current value of the the axis in degrees */ double libinput_event_tablet_tool_get_tilt_x(struct libinput_event_tablet_tool *event); @@ -1662,12 +1666,16 @@ libinput_event_tablet_tool_get_tilt_x(struct libinput_event_tablet_tool *event); * @ingroup event_tablet * * Returns the current tilt along the Y axis of the tablet's current logical - * orientation, normalized to the range [-1, 1]. + * orientation, in degrees off the tablet's z axis. That is, if the tool is + * perfectly orthogonal to the tablet, the tilt angle is 0. When the top + * tilts towards the logical top/left of the tablet, the x/y tilt angles are + * negative, if the top tilts towards the logical bottom/right of the + * tablet, the x/y tilt angles are positive. * * If this axis does not exist on the current tool, this function returns 0. * * @param event The libinput tablet tool event - * @return The current value of the the axis + * @return The current value of the the axis in degrees */ double libinput_event_tablet_tool_get_tilt_y(struct libinput_event_tablet_tool *event); diff --git a/test/tablet.c b/test/tablet.c index 8936d577..bd4172dd 100644 --- a/test/tablet.c +++ b/test/tablet.c @@ -3081,7 +3081,7 @@ START_TEST(tilt_x) struct axis_replacement axes[] = { { ABS_DISTANCE, 10 }, { ABS_PRESSURE, 0 }, - { ABS_TILT_X, 90 }, + { ABS_TILT_X, 10 }, { ABS_TILT_Y, 0 }, { -1, -1 } }; @@ -3097,19 +3097,18 @@ START_TEST(tilt_x) tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); - /* 90% of the actual axis but mapped into a [-1, 1] range, so we - * expect a pos. value of 80. Rounding errors in the scaling though, - * we'll get something between 0.79 and 0.80 */ + /* 90% of the actual axis but mapped into a [-64, 64] tilt range, so + * we expect 51 degrees ± rounding errors */ tx = libinput_event_tablet_tool_get_tilt_x(tev); - ck_assert_double_gt(tx, 0.79); - ck_assert_double_le(tx, 0.80); + ck_assert_double_le(tx, -50); + ck_assert_double_ge(tx, -52); ty = libinput_event_tablet_tool_get_tilt_y(tev); - ck_assert_double_eq(ty, -1); + ck_assert_double_eq(ty, -64); libinput_event_destroy(event); - expected_tx = -1.0; + expected_tx = -64.0; litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 1); @@ -3123,19 +3122,20 @@ START_TEST(tilt_x) LIBINPUT_EVENT_TABLET_TOOL_AXIS); tx = libinput_event_tablet_tool_get_tilt_x(tev); - ck_assert_double_gt(tx, expected_tx - 0.1); - ck_assert_double_lt(tx, expected_tx + 0.1); + ck_assert_double_ge(tx, expected_tx - 2); + ck_assert_double_le(tx, expected_tx + 2); ty = libinput_event_tablet_tool_get_tilt_y(tev); - ck_assert_double_eq(ty, -1); + ck_assert_double_eq(ty, -64); libinput_event_destroy(event); - expected_tx += 0.1; + expected_tx = tx + 6.04; } /* the last event must reach the max */ - ck_assert_double_eq(tx, 1.0); + ck_assert_double_ge(tx, 63.0); + ck_assert_double_le(tx, 64.0); } END_TEST @@ -3149,7 +3149,7 @@ START_TEST(tilt_y) { ABS_DISTANCE, 10 }, { ABS_PRESSURE, 0 }, { ABS_TILT_X, 0 }, - { ABS_TILT_Y, 90 }, + { ABS_TILT_Y, 10 }, { -1, -1 } }; double tx, ty; @@ -3164,19 +3164,18 @@ START_TEST(tilt_y) tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); - /* 90% of the actual axis but mapped into a [-1, 1] range, so we - * expect a pos. value of 80. Rounding errors in the scaling though, - * we'll get something between 0.79 and 0.80 */ + /* 90% of the actual axis but mapped into a [-64, 64] tilt range, so + * we expect 50 degrees ± rounding errors */ ty = libinput_event_tablet_tool_get_tilt_y(tev); - ck_assert_double_gt(ty, 0.79); - ck_assert_double_le(ty, 0.80); + ck_assert_double_le(ty, -50); + ck_assert_double_ge(ty, -52); tx = libinput_event_tablet_tool_get_tilt_x(tev); - ck_assert_double_eq(tx, -1); + ck_assert_double_eq(tx, -64); libinput_event_destroy(event); - expected_ty = -1.0; + expected_ty = -64; litest_axis_set_value(axes, ABS_DISTANCE, 0); litest_axis_set_value(axes, ABS_PRESSURE, 1); @@ -3190,19 +3189,20 @@ START_TEST(tilt_y) LIBINPUT_EVENT_TABLET_TOOL_AXIS); ty = libinput_event_tablet_tool_get_tilt_y(tev); - ck_assert_double_gt(ty, expected_ty - 0.1); - ck_assert_double_lt(ty, expected_ty + 0.1); + ck_assert_double_ge(ty, expected_ty - 2); + ck_assert_double_le(ty, expected_ty + 2); tx = libinput_event_tablet_tool_get_tilt_x(tev); - ck_assert_double_eq(tx, -1); + ck_assert_double_eq(tx, -64); libinput_event_destroy(event); - expected_ty += 0.1; + expected_ty = ty + 6; } /* the last event must reach the max */ - ck_assert_double_eq(ty, 1.0); + ck_assert_double_ge(ty, 63.0); + ck_assert_double_le(tx, 64.0); } END_TEST