mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-31 14:40:08 +01:00
tablet: fix tilt handling for even-ranged tablets
The tablet tilt range may be set as [-N, M] in which case we assume that a value of zero is vertical (and thus should result in a libinput tilt value of zero). Unfortunately some tablets report an even total value range, e.g. [-64, 63] so zero is not actually the mathematical center of the axis. Fix this by bumping the axis maximum so zero becomes the logical center. All devices we've seen so far have [-A, (A-1)] as range so bumping it by one makes it symmetric.
This commit is contained in:
parent
72eca2db56
commit
0322403ea4
2 changed files with 135 additions and 1 deletions
|
|
@ -368,7 +368,7 @@ normalize_pressure(const struct input_absinfo *absinfo,
|
|||
static inline double
|
||||
adjust_tilt(const struct input_absinfo *absinfo)
|
||||
{
|
||||
double value = (absinfo->value - absinfo->minimum) / absinfo_range(absinfo);
|
||||
double value = absinfo_normalize(absinfo);
|
||||
const int WACOM_MAX_DEGREES = 64;
|
||||
|
||||
/* If resolution is nonzero, it's in units/radian. But require
|
||||
|
|
@ -2562,6 +2562,57 @@ tablet_reject_device(struct evdev_device *device)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
tablet_fix_tilt(struct tablet_dispatch *tablet,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
struct libevdev *evdev = device->evdev;
|
||||
|
||||
if (libevdev_has_event_code(evdev, EV_ABS, ABS_TILT_X) !=
|
||||
libevdev_has_event_code(evdev, EV_ABS, ABS_TILT_Y)) {
|
||||
libevdev_disable_event_code(evdev, EV_ABS, ABS_TILT_X);
|
||||
libevdev_disable_event_code(evdev, EV_ABS, ABS_TILT_Y);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!libevdev_has_event_code(evdev, EV_ABS, ABS_TILT_X))
|
||||
return;
|
||||
|
||||
/* Wacom has three types of devices:
|
||||
* - symmetrical: [-90, 90], like the ISDv4 524c
|
||||
* - asymmetrical: [-64, 63], like the Cintiq l3HDT
|
||||
* - zero-based: [0, 127], like the Cintiq 12WX
|
||||
*
|
||||
* Note how the latter two cases have an even range and thus do
|
||||
* not have a logical center value. But this is tilt and at
|
||||
* least in the asymmetrical case we assume that hardware zero
|
||||
* means vertical. So we cheat and adjust the range depending
|
||||
* on whether it's odd, then use the center value.
|
||||
*
|
||||
* Since it's always the max that's one too low let's go with that and
|
||||
* fix it if we run into a device where that isn't the case.
|
||||
*/
|
||||
for (unsigned int axis = ABS_TILT_X; axis <= ABS_TILT_Y; axis++) {
|
||||
struct input_absinfo abs = *libevdev_get_abs_info(evdev, axis);
|
||||
|
||||
/* Don't touch axes reporting radians */
|
||||
if (abs.resolution != 0)
|
||||
continue;
|
||||
|
||||
if ((int)absinfo_range(&abs) % 2 == 1)
|
||||
continue;
|
||||
|
||||
abs.maximum += 1;
|
||||
libevdev_set_abs_info(evdev, axis, &abs);
|
||||
|
||||
evdev_log_debug(device,
|
||||
"Adjusting %s range to [%d, %d]\n",
|
||||
libevdev_event_code_get_name(EV_ABS, axis),
|
||||
abs.minimum,
|
||||
abs.maximum);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
tablet_init(struct tablet_dispatch *tablet,
|
||||
struct evdev_device *device)
|
||||
|
|
@ -2592,6 +2643,7 @@ tablet_init(struct tablet_dispatch *tablet,
|
|||
libevdev_disable_event_code(evdev, EV_KEY, BTN_TOOL_LENS);
|
||||
}
|
||||
|
||||
tablet_fix_tilt(tablet, device);
|
||||
tablet_init_calibration(tablet, device);
|
||||
tablet_init_proximity_threshold(tablet, device);
|
||||
rc = tablet_init_accel(tablet, device);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@
|
|||
#include "litest.h"
|
||||
#include "util-input-event.h"
|
||||
|
||||
enum {
|
||||
TILT_MINIMUM,
|
||||
TILT_CENTER,
|
||||
TILT_MAXIMUM,
|
||||
};
|
||||
|
||||
static inline unsigned int
|
||||
pick_stylus_or_btn0(struct litest_device *dev)
|
||||
{
|
||||
|
|
@ -4487,6 +4493,80 @@ START_TEST(tilt_y)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tilt_fixed_points)
|
||||
{
|
||||
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, 10 },
|
||||
{ ABS_PRESSURE, 0 },
|
||||
{ -1, -1 }
|
||||
};
|
||||
int testcase = _i; /* ranged test */
|
||||
int axis_value;
|
||||
double expected;
|
||||
|
||||
/* On devices with a range of [-N, M], make sure we calculate the hw zero position
|
||||
* as zero and that the respective min/max resolve to our (hardcoded) min/max degree
|
||||
* values
|
||||
*/
|
||||
const struct input_absinfo *abs = libevdev_get_abs_info(dev->evdev, ABS_TILT_X);
|
||||
if (abs->minimum >= 0)
|
||||
return;
|
||||
|
||||
/* If the tablet reports physical resolutions we don't need to test them */
|
||||
if (abs->resolution != 0)
|
||||
return;
|
||||
|
||||
/* see tablet_fix_tilt() */
|
||||
bool is_adjusted = (int)absinfo_range(abs) % 2 == 0;
|
||||
|
||||
switch (testcase) {
|
||||
case TILT_MINIMUM:
|
||||
axis_value = abs->minimum;
|
||||
expected = -64.0;
|
||||
break;
|
||||
case TILT_CENTER:
|
||||
axis_value = 0;
|
||||
expected = 0.0;
|
||||
break;
|
||||
case TILT_MAXIMUM:
|
||||
axis_value = abs->maximum;
|
||||
expected = 64.0;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_push_event_frame(dev);
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
litest_event(dev, EV_ABS, ABS_TILT_X, axis_value);
|
||||
litest_event(dev, EV_ABS, ABS_TILT_Y, axis_value);
|
||||
litest_pop_event_frame(dev);
|
||||
|
||||
libinput_dispatch(li);
|
||||
event = libinput_get_event(li);
|
||||
tev = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
|
||||
double tx = libinput_event_tablet_tool_get_tilt_x(tev);
|
||||
double ty = libinput_event_tablet_tool_get_tilt_y(tev);
|
||||
ck_assert_double_eq(tx, expected);
|
||||
if (is_adjusted) {
|
||||
ck_assert_double_ge(ty, expected - 1);
|
||||
ck_assert_double_lt(ty, expected);
|
||||
} else {
|
||||
ck_assert_double_eq(ty, expected);
|
||||
}
|
||||
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(relative_no_profile)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -6152,6 +6232,7 @@ TEST_COLLECTION(tablet)
|
|||
struct range with_timeout = { 0, 2 };
|
||||
struct range xyaxes = { ABS_X, ABS_Y + 1 };
|
||||
struct range lh_transitions = {0, 16}; /* 2 bits for in, 2 bits for out */
|
||||
struct range tilt_cases = {TILT_MINIMUM, TILT_MAXIMUM + 1};
|
||||
|
||||
litest_add(tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
litest_add(tool_user_data, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
|
||||
|
|
@ -6213,6 +6294,7 @@ TEST_COLLECTION(tablet)
|
|||
litest_add(tilt_not_available, LITEST_TABLET, LITEST_TILT);
|
||||
litest_add(tilt_x, LITEST_TABLET|LITEST_TILT, LITEST_ANY);
|
||||
litest_add(tilt_y, LITEST_TABLET|LITEST_TILT, LITEST_ANY);
|
||||
litest_add_ranged(tilt_fixed_points, LITEST_TABLET|LITEST_TILT, LITEST_ANY, &tilt_cases);
|
||||
litest_add_for_device(left_handed, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device(left_handed_tilt, LITEST_WACOM_INTUOS);
|
||||
litest_add_for_device(left_handed_mouse_rotation, LITEST_WACOM_INTUOS);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue