diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 71e66430..cd208a8f 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -326,10 +326,47 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet, double deltas[LIBINPUT_TABLET_TOOL_AXIS_MAX + 1] = {0}; double deltas_discrete[LIBINPUT_TABLET_TOOL_AXIS_MAX + 1] = {0}; double oldval; + struct device_coords point, old_point; + const struct input_absinfo *absinfo; - for (a = LIBINPUT_TABLET_TOOL_AXIS_X; a <= LIBINPUT_TABLET_TOOL_AXIS_MAX; a++) { - const struct input_absinfo *absinfo; + /* x/y are special for left-handed and calibration */ + a = LIBINPUT_TABLET_TOOL_AXIS_X; + old_point.x = tablet->axes[a]; + if (bit_is_set(tablet->changed_axes, a)) { + absinfo = libevdev_get_abs_info(device->evdev, + axis_to_evcode(a)); + axis_update_needed = true; + if (device->left_handed.enabled) + tablet->axes[a] = invert_axis(absinfo); + else + tablet->axes[a] = absinfo->value; + } + point.x = tablet->axes[a]; + + a = LIBINPUT_TABLET_TOOL_AXIS_Y; + old_point.y = tablet->axes[a]; + if (bit_is_set(tablet->changed_axes, a)) { + absinfo = libevdev_get_abs_info(device->evdev, + axis_to_evcode(a)); + axis_update_needed = true; + + if (device->left_handed.enabled) + tablet->axes[a] = invert_axis(absinfo); + else + tablet->axes[a] = absinfo->value; + } + point.y = tablet->axes[a]; + + evdev_transform_absolute(device, &point); + evdev_transform_absolute(device, &old_point); + + axes[LIBINPUT_TABLET_TOOL_AXIS_X] = point.x; + axes[LIBINPUT_TABLET_TOOL_AXIS_Y] = point.y; + deltas[LIBINPUT_TABLET_TOOL_AXIS_X] = point.x - old_point.x; + deltas[LIBINPUT_TABLET_TOOL_AXIS_Y] = point.y - old_point.y; + + for (a = LIBINPUT_TABLET_TOOL_AXIS_DISTANCE; a <= LIBINPUT_TABLET_TOOL_AXIS_MAX; a++) { if (!bit_is_set(tablet->changed_axes, a)) { axes[a] = tablet->axes[a]; continue; @@ -1088,6 +1125,14 @@ static struct evdev_dispatch_interface tablet_interface = { tablet_check_initial_proximity, }; +static void +tablet_init_calibration(struct tablet_dispatch *tablet, + struct evdev_device *device) +{ + if (libevdev_has_property(device->evdev, INPUT_PROP_DIRECT)) + evdev_init_calibration(device, &tablet->base); +} + static int tablet_init(struct tablet_dispatch *tablet, struct evdev_device *device) @@ -1100,6 +1145,8 @@ tablet_init(struct tablet_dispatch *tablet, tablet->current_tool_type = LIBINPUT_TOOL_NONE; list_init(&tablet->tool_list); + tablet_init_calibration(tablet, device); + for (axis = LIBINPUT_TABLET_TOOL_AXIS_X; axis <= LIBINPUT_TABLET_TOOL_AXIS_MAX; axis++) { diff --git a/src/evdev.c b/src/evdev.c index 5a733409..993c5d8a 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1178,7 +1178,7 @@ evdev_init_button_scroll(struct evdev_device *device, return 0; } -static void +void evdev_init_calibration(struct evdev_device *device, struct evdev_dispatch *dispatch) { diff --git a/src/evdev.h b/src/evdev.h index d7b372f6..75a2cb6a 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -290,6 +290,10 @@ void evdev_transform_absolute(struct evdev_device *device, struct device_coords *point); +void +evdev_init_calibration(struct evdev_device *device, + struct evdev_dispatch *dispatch); + int evdev_device_init_pointer_acceleration(struct evdev_device *device, struct motion_filter *filter); diff --git a/test/pointer.c b/test/pointer.c index 5c33d50f..d043fa8a 100644 --- a/test/pointer.c +++ b/test/pointer.c @@ -1600,7 +1600,7 @@ litest_setup_tests(void) litest_add("pointer:scroll", pointer_scroll_natural_enable_config, LITEST_WHEEL, LITEST_TABLET); litest_add("pointer:scroll", pointer_scroll_natural_wheel, LITEST_WHEEL, LITEST_TABLET); - litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE|LITEST_PROTOCOL_A); + litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE|LITEST_PROTOCOL_A|LITEST_TABLET); /* tests touchpads too */ litest_add("pointer:left-handed", pointer_left_handed_defaults, LITEST_BUTTON, LITEST_ANY); diff --git a/test/tablet.c b/test/tablet.c index 125ab4bf..18f08b23 100644 --- a/test/tablet.c +++ b/test/tablet.c @@ -2364,6 +2364,172 @@ START_TEST(tablet_pressure_distance_exclusive) } END_TEST +START_TEST(tablet_calibration_has_matrix) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *d = dev->libinput_device; + enum libinput_config_status status; + int rc; + float calibration[6] = {1, 0, 0, 0, 1, 0}; + int has_calibration; + + has_calibration = libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT); + + rc = libinput_device_config_calibration_has_matrix(d); + ck_assert_int_eq(rc, has_calibration); + rc = libinput_device_config_calibration_get_matrix(d, calibration); + ck_assert_int_eq(rc, 0); + rc = libinput_device_config_calibration_get_default_matrix(d, + calibration); + ck_assert_int_eq(rc, 0); + + status = libinput_device_config_calibration_set_matrix(d, + calibration); + if (has_calibration) + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + else + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED); +} +END_TEST + +START_TEST(tablet_calibration_set_matrix_delta) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_device *d = dev->libinput_device; + enum libinput_config_status status; + float calibration[6] = {0.5, 0, 0, 0, 0.5, 0}; + struct libinput_event *event; + struct libinput_event_tablet_tool *tablet_event; + struct axis_replacement axes[] = { + { ABS_DISTANCE, 10 }, + { -1, -1 } + }; + int has_calibration; + double dx, dy, mdx, mdy; + + has_calibration = libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT); + if (!has_calibration) + return; + + litest_tablet_proximity_in(dev, 100, 100, axes); + litest_drain_events(li); + + litest_tablet_motion(dev, 80, 80, axes); + libinput_dispatch(li); + + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_AXIS); + + dx = libinput_event_tablet_tool_get_axis_delta(tablet_event, + LIBINPUT_TABLET_TOOL_AXIS_X); + dy = libinput_event_tablet_tool_get_axis_delta(tablet_event, + LIBINPUT_TABLET_TOOL_AXIS_Y); + libinput_event_destroy(event); + litest_tablet_proximity_out(dev); + litest_drain_events(li); + + status = libinput_device_config_calibration_set_matrix(d, + calibration); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_tablet_proximity_in(dev, 100, 100, axes); + litest_drain_events(li); + + litest_tablet_motion(dev, 80, 80, axes); + libinput_dispatch(li); + + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_AXIS); + + mdx = libinput_event_tablet_tool_get_axis_delta(tablet_event, + LIBINPUT_TABLET_TOOL_AXIS_X); + mdy = libinput_event_tablet_tool_get_axis_delta(tablet_event, + LIBINPUT_TABLET_TOOL_AXIS_Y); + libinput_event_destroy(event); + litest_drain_events(li); + + ck_assert_double_gt(dx, mdx * 2 - 1); + ck_assert_double_lt(dx, mdx * 2 + 1); + ck_assert_double_gt(dy, mdy * 2 - 1); + ck_assert_double_lt(dy, mdy * 2 + 1); +} +END_TEST + +START_TEST(tablet_calibration_set_matrix) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_device *d = dev->libinput_device; + enum libinput_config_status status; + float calibration[6] = {0.5, 0, 0, 0, 1, 0}; + struct libinput_event *event; + struct libinput_event_tablet_tool *tablet_event; + struct axis_replacement axes[] = { + { ABS_DISTANCE, 10 }, + { -1, -1 } + }; + int has_calibration; + double x, y; + + has_calibration = libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT); + if (!has_calibration) + return; + + litest_drain_events(li); + + status = libinput_device_config_calibration_set_matrix(d, + calibration); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_tablet_proximity_in(dev, 100, 100, axes); + libinput_dispatch(li); + + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + x = libinput_event_tablet_tool_get_x_transformed(tablet_event, 100); + y = libinput_event_tablet_tool_get_y_transformed(tablet_event, 100); + libinput_event_destroy(event); + + ck_assert_double_gt(x, 49.0); + ck_assert_double_lt(x, 51.0); + ck_assert_double_gt(y, 99.0); + ck_assert_double_lt(y, 100.0); + + litest_tablet_proximity_out(dev); + libinput_dispatch(li); + litest_tablet_proximity_in(dev, 50, 50, axes); + litest_tablet_proximity_out(dev); + litest_drain_events(li); + + calibration[0] = 1; + calibration[4] = 0.5; + status = libinput_device_config_calibration_set_matrix(d, + calibration); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_tablet_proximity_in(dev, 100, 100, axes); + libinput_dispatch(li); + + event = libinput_get_event(li); + tablet_event = litest_is_tablet_event(event, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + x = libinput_event_tablet_tool_get_x_transformed(tablet_event, 100); + y = libinput_event_tablet_tool_get_y_transformed(tablet_event, 100); + libinput_event_destroy(event); + + ck_assert_double_gt(x, 99.0); + ck_assert_double_lt(x, 100.0); + ck_assert_double_gt(y, 49.0); + ck_assert_double_lt(y, 51.0); + + litest_tablet_proximity_out(dev); +} +END_TEST + void litest_setup_tests(void) { @@ -2408,4 +2574,8 @@ litest_setup_tests(void) litest_add("tablet:time", tablet_time_usec, LITEST_TABLET, LITEST_ANY); litest_add("tablet:pressure", tablet_pressure_distance_exclusive, LITEST_TABLET | LITEST_DISTANCE, LITEST_ANY); + + litest_add("tablet:calibration", tablet_calibration_has_matrix, LITEST_TABLET, LITEST_ANY); + litest_add("tablet:calibration", tablet_calibration_set_matrix, LITEST_TABLET, LITEST_ANY); + litest_add("tablet:calibration", tablet_calibration_set_matrix_delta, LITEST_TABLET, LITEST_ANY); }