}
}
+static inline int
+axis_range_percentage(const struct input_absinfo *a, double percent)
+{
+ return (a->maximum - a->minimum) * percent/100.0 + a->minimum;
+}
+
+static void
+tablet_change_area(struct evdev_device *device)
+{
+ struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
+
+ if (memcmp(&tablet->area.rect, &tablet->area.want_rect, sizeof(tablet->area.rect)) == 0)
+ return;
+
+ if (!tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
+ return;
+
+ tablet->area.rect = tablet->area.want_rect;
+
+ evdev_log_debug(device,
+ "tablet-area: area is %.2f/%.2f - %.2f/%.2f\n",
+ tablet->area.rect.x1,
+ tablet->area.rect.y1,
+ tablet->area.rect.x2,
+ tablet->area.rect.y2);
+
+ const struct input_absinfo *absx = device->abs.absinfo_x;
+ const struct input_absinfo *absy = device->abs.absinfo_y;
+ tablet->area.x.minimum = axis_range_percentage(absx, tablet->area.rect.x1 * 100);
+ tablet->area.x.maximum = axis_range_percentage(absx, tablet->area.rect.x2 * 100);
+ tablet->area.y.minimum = axis_range_percentage(absy, tablet->area.rect.y1 * 100);
+ tablet->area.y.maximum = axis_range_percentage(absy, tablet->area.rect.y2 * 100);
+}
+
static void
tablet_apply_rotation(struct evdev_device *device)
{
return value * device->scroll.wheel_click_angle.x;
}
+static void
+apply_tablet_area(struct tablet_dispatch *tablet,
+ struct evdev_device *device,
+ struct device_coords *point)
+{
+ if (tablet->area.rect.x1 == 0.0 && tablet->area.rect.x2 == 1.0 &&
+ tablet->area.rect.y1 == 0.0 && tablet->area.rect.y2 == 1.0)
+ return;
+
+ /* The point is somewhere on the tablet in device coordinates,
+ * but we need it relative to the x/y offset.
+ * So clip it first, then offset it to our area min/max.
+ *
+ * Right now we're just clipping, we don't completely
+ * ignore events. What we should do is ignore events outside
+ * altogether and generate prox in/out events when we actually
+ * enter the area.
+ */
+ point->x = min(point->x, tablet->area.x.maximum);
+ point->y = min(point->y, tablet->area.y.maximum);
+
+ point->x = max(point->x, tablet->area.x.minimum);
+ point->y = max(point->y, tablet->area.y.minimum);
+}
+
static inline void
tablet_update_xy(struct tablet_dispatch *tablet,
struct evdev_device *device)
tablet->axes.point.y = value;
+ /* calibration and area are currently mutually exclusive so
+ * one of those is a noop */
evdev_transform_absolute(device, &tablet->axes.point);
+ apply_tablet_area(tablet, device, &tablet->axes.point);
}
}
}
}
-static inline int
-axis_range_percentage(const struct input_absinfo *a, double percent)
-{
- return (a->maximum - a->minimum) * percent/100.0 + a->minimum;
-}
-
static bool
tablet_get_quirked_pressure_thresholds(struct tablet_dispatch *tablet,
int *hi,
tip_state,
&tablet->axes,
i,
- state);
+ state,
+ &tablet->area.x,
+ &tablet->area.y);
}
}
tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
tablet->changed_axes,
- axes);
+ axes,
+ &tablet->area.x,
+ &tablet->area.y);
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
tablet->changed_axes,
- axes);
+ axes,
+ &tablet->area.x,
+ &tablet->area.y);
tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
tool,
LIBINPUT_TABLET_TOOL_TIP_DOWN,
tablet->changed_axes,
- axes);
+ axes,
+ &tablet->area.x,
+ &tablet->area.y);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
tablet_set_status(tablet, TABLET_TOOL_IN_CONTACT);
tool,
LIBINPUT_TABLET_TOOL_TIP_UP,
tablet->changed_axes,
- axes);
+ axes,
+ &tablet->area.x,
+ &tablet->area.y);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
tablet_unset_status(tablet, TABLET_TOOL_IN_CONTACT);
tool,
tip_state,
tablet->changed_axes,
- axes);
+ axes,
+ &tablet->area.x,
+ &tablet->area.y);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_reset_changed_axes(tablet);
axes->delta.x = 0;
if (tablet_send_proximity_out(tablet, tool, device, &axes, time)) {
tablet_change_to_left_handed(device);
tablet_apply_rotation(device);
+ tablet_change_area(device);
tablet_history_reset(tablet);
}
}
evdev_init_calibration(device, &tablet->calibration);
}
+static int
+tablet_area_has_rectangle(struct libinput_device *device)
+{
+ return 1;
+}
+
+static enum libinput_config_status
+tablet_area_set_rectangle(struct libinput_device *device,
+ const struct libinput_config_area_rectangle *rectangle)
+{
+ struct evdev_device *evdev = evdev_device(device);
+ struct tablet_dispatch *tablet = tablet_dispatch(evdev->dispatch);
+
+ if (rectangle->x1 >= rectangle->x2 || rectangle->y1 >= rectangle->y2)
+ return LIBINPUT_CONFIG_STATUS_INVALID;
+
+ if (rectangle->x1 < 0.0 || rectangle->x2 > 1.0 ||
+ rectangle->y1 < 0.0 || rectangle->y2 > 1.0)
+ return LIBINPUT_CONFIG_STATUS_INVALID;
+
+ tablet->area.want_rect = *rectangle;
+
+ tablet_change_area(evdev);
+
+ return LIBINPUT_CONFIG_STATUS_SUCCESS;
+}
+
+static struct libinput_config_area_rectangle
+tablet_area_get_rectangle(struct libinput_device *device)
+{
+ struct evdev_device *evdev = evdev_device(device);
+ struct tablet_dispatch *tablet = tablet_dispatch(evdev->dispatch);
+
+ return tablet->area.rect;
+}
+
+static struct libinput_config_area_rectangle
+tablet_area_get_default_rectangle(struct libinput_device *device)
+{
+ struct libinput_config_area_rectangle rect = {
+ 0.0, 0.0, 1.0, 1.0,
+ };
+ return rect;
+}
+
+static void
+tablet_init_area(struct tablet_dispatch *tablet,
+ struct evdev_device *device)
+{
+ tablet->area.rect = (struct libinput_config_area_rectangle) {
+ 0.0, 0.0, 1.0, 1.0,
+ };
+ tablet->area.want_rect = tablet->area.rect;
+ tablet->area.x = *device->abs.absinfo_x;
+ tablet->area.y = *device->abs.absinfo_y;
+
+ if (!libevdev_has_property(device->evdev, INPUT_PROP_DIRECT)) {
+ device->base.config.area = &tablet->area.config;
+ tablet->area.config.has_rectangle = tablet_area_has_rectangle;
+ tablet->area.config.set_rectangle = tablet_area_set_rectangle;
+ tablet->area.config.get_rectangle = tablet_area_get_rectangle;
+ tablet->area.config.get_default_rectangle = tablet_area_get_default_rectangle;
+ }
+}
+
static void
tablet_init_proximity_threshold(struct tablet_dispatch *tablet,
struct evdev_device *device)
tablet_fix_tilt(tablet, device);
tablet_init_calibration(tablet, device, is_display_tablet);
+ tablet_init_area(tablet, device);
tablet_init_proximity_threshold(tablet, device);
rc = tablet_init_accel(tablet, device);
if (rc != 0)
uint32_t cursor_proximity_threshold;
struct libinput_device_config_calibration calibration;
+ struct {
+ struct libinput_device_config_area config;
+ struct libinput_config_area_rectangle rect;
+ struct libinput_config_area_rectangle want_rect;
+ struct input_absinfo x;
+ struct input_absinfo y;
+ } area;
/* The paired touch device on devices with both pen & touch */
struct evdev_device *touch_device;
slot->tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
totem_slot_reset_changed_axes(totem, slot);
tablet_notify_tip(&device->base,
time,
slot->tool,
tip_state,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
slot->state = SLOT_STATE_UPDATE;
break;
case SLOT_STATE_UPDATE:
slot->tool,
tip_state,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
}
break;
case SLOT_STATE_END:
tip_state,
&axes,
BTN_0,
- btn_state);
+ btn_state,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
totem->button_state_previous = totem->button_state_now;
}
slot->tool,
tip_state,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
totem_slot_reset_changed_axes(totem, slot);
tablet_notify_proximity(&device->base,
time,
slot->tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
+
slot->state = SLOT_STATE_NONE;
break;
case SLOT_STATE_NONE:
tip_state,
&axes,
BTN_0,
- LIBINPUT_BUTTON_STATE_RELEASED);
+ LIBINPUT_BUTTON_STATE_RELEASED,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
totem->button_state_now = false;
totem->button_state_previous = false;
slot->tool,
LIBINPUT_TABLET_TOOL_TIP_UP,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
}
tablet_notify_proximity(&device->base,
now,
slot->tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
}
totem_set_touch_device_enabled(totem, true, now);
}
slot->tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
totem_slot_reset_changed_axes(totem, slot);
tablet_notify_tip(&device->base,
now,
slot->tool,
LIBINPUT_TABLET_TOOL_TIP_DOWN,
slot->changed_axes,
- &axes);
+ &axes,
+ device->abs.absinfo_x,
+ device->abs.absinfo_y);
slot->state = SLOT_STATE_UPDATE;
enable_touch = false;
}
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
- const struct tablet_axes *axes);
+ const struct tablet_axes *axes,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y);
void
tablet_notify_proximity(struct libinput_device *device,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_proximity_state state,
unsigned char *changed_axes,
- const struct tablet_axes *axes);
+ const struct tablet_axes *axes,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y);
void
tablet_notify_tip(struct libinput_device *device,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
- const struct tablet_axes *axes);
+ const struct tablet_axes *axes,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y);
void
tablet_notify_button(struct libinput_device *device,
enum libinput_tablet_tool_tip_state tip_state,
const struct tablet_axes *axes,
int32_t button,
- enum libinput_button_state state);
+ enum libinput_button_state state,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y);
void
tablet_pad_notify_button(struct libinput_device *device,
#include "libinput.h"
#include "libinput-private.h"
+#include "util-input-event.h"
#include "evdev.h"
#include "timer.h"
#include "quirks.h"
struct libinput_tablet_tool *tool;
enum libinput_tablet_tool_proximity_state proximity_state;
enum libinput_tablet_tool_tip_state tip_state;
+ struct {
+ struct input_absinfo x;
+ struct input_absinfo y;
+ } abs;
};
struct libinput_event_tablet_pad {
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event)
{
- struct evdev_device *device = evdev_device(event->base.device);
-
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
- return absinfo_convert_to_mm(device->abs.absinfo_x,
+ return absinfo_convert_to_mm(&event->abs.x,
event->axes.point.x);
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_y(struct libinput_event_tablet_tool *event)
{
- struct evdev_device *device = evdev_device(event->base.device);
-
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
- return absinfo_convert_to_mm(device->abs.absinfo_y,
+ return absinfo_convert_to_mm(&event->abs.y,
event->axes.point.y);
}
libinput_event_tablet_tool_get_x_transformed(struct libinput_event_tablet_tool *event,
uint32_t width)
{
- struct evdev_device *device = evdev_device(event->base.device);
-
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
- return evdev_device_transform_x(device,
- event->axes.point.x,
- width);
+ return absinfo_scale_axis(&event->abs.x, event->axes.point.x, width);
}
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_y_transformed(struct libinput_event_tablet_tool *event,
uint32_t height)
{
- struct evdev_device *device = evdev_device(event->base.device);
-
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
0,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
- return evdev_device_transform_y(device,
- event->axes.point.y,
- height);
+ return absinfo_scale_axis(&event->abs.y, event->axes.point.y, height);
}
LIBINPUT_EXPORT struct libinput_tablet_tool *
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
- const struct tablet_axes *axes)
+ const struct tablet_axes *axes,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y)
{
struct libinput_event_tablet_tool *axis_event;
.proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
.tip_state = tip_state,
.axes = *axes,
+ .abs.x = *x,
+ .abs.y = *y,
};
memcpy(axis_event->changed_axes,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_proximity_state proximity_state,
unsigned char *changed_axes,
- const struct tablet_axes *axes)
+ const struct tablet_axes *axes,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y)
{
struct libinput_event_tablet_tool *proximity_event;
.tip_state = LIBINPUT_TABLET_TOOL_TIP_UP,
.proximity_state = proximity_state,
.axes = *axes,
+ .abs.x = *x,
+ .abs.y = *y,
};
memcpy(proximity_event->changed_axes,
changed_axes,
struct libinput_tablet_tool *tool,
enum libinput_tablet_tool_tip_state tip_state,
unsigned char *changed_axes,
- const struct tablet_axes *axes)
+ const struct tablet_axes *axes,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y)
{
struct libinput_event_tablet_tool *tip_event;
.tip_state = tip_state,
.proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
.axes = *axes,
+ .abs.x = *x,
+ .abs.y = *y,
};
memcpy(tip_event->changed_axes,
changed_axes,
enum libinput_tablet_tool_tip_state tip_state,
const struct tablet_axes *axes,
int32_t button,
- enum libinput_button_state state)
+ enum libinput_button_state state,
+ const struct input_absinfo *x,
+ const struct input_absinfo *y)
{
struct libinput_event_tablet_tool *button_event;
int32_t seat_button_count;
.proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
.tip_state = tip_state,
.axes = *axes,
+ .abs.x = *x,
+ .abs.y = *y,
};
post_device_event(device,
if (!libinput_device_config_area_has_rectangle(device))
return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
+ if (rectangle->x1 >= rectangle->x2 || rectangle->y1 >= rectangle->y2)
+ return LIBINPUT_CONFIG_STATUS_INVALID;
+
+ if (rectangle->x1 < 0.0 || rectangle->x2 > 1.0 ||
+ rectangle->y1 < 0.0 || rectangle->y2 > 1.0)
+ return LIBINPUT_CONFIG_STATUS_INVALID;
+
return device->config.area->set_rectangle(device, rectangle);
}
}
END_TEST
+START_TEST(tablet_area_has_rectangle)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput_device *d = dev->libinput_device;
+ enum libinput_config_status status;
+ int rc;
+ struct libinput_config_area_rectangle rect;
+
+ int has_area = !libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT);
+
+ rc = libinput_device_config_area_has_rectangle(d);
+ litest_assert_int_eq(rc, has_area);
+ rect = libinput_device_config_area_get_rectangle(d);
+ litest_assert_double_eq(rect.x1, 0.0);
+ litest_assert_double_eq(rect.y1, 0.0);
+ litest_assert_double_eq(rect.x2, 1.0);
+ litest_assert_double_eq(rect.y2, 1.0);
+
+ rect = libinput_device_config_area_get_default_rectangle(d);
+ litest_assert_double_eq(rect.x1, 0.0);
+ litest_assert_double_eq(rect.y1, 0.0);
+ litest_assert_double_eq(rect.x2, 1.0);
+ litest_assert_double_eq(rect.y2, 1.0);
+
+ status = libinput_device_config_area_set_rectangle(d, &rect);
+ if (has_area)
+ litest_assert_enum_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ else
+ litest_assert_enum_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
+}
+END_TEST
+
+START_TEST(tablet_area_set_rectangle_invalid)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput_device *d = dev->libinput_device;
+ int rc;
+ struct libinput_config_area_rectangle rect;
+
+ int has_area = !libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT);
+ if (!has_area)
+ return LITEST_NOT_APPLICABLE;
+
+ rect.x1 = 1.0;
+ rect.x2 = 0.9;
+ rect.y1 = 0.0;
+ rect.y2 = 1.0;
+
+ rc = libinput_device_config_area_set_rectangle(d, &rect);
+ litest_assert_enum_eq(rc, LIBINPUT_CONFIG_STATUS_INVALID);
+
+ rect.x1 = 0.9;
+ rect.x2 = 1.0;
+ rect.y1 = 1.0;
+ rect.y2 = 0.9;
+
+ rc = libinput_device_config_area_set_rectangle(d, &rect);
+ litest_assert_enum_eq(rc, LIBINPUT_CONFIG_STATUS_INVALID);
+
+ rect.x1 = 0.9;
+ rect.x2 = 0.9;
+ rect.y1 = 0.9;
+ rect.y2 = 1.0;
+
+ rc = libinput_device_config_area_set_rectangle(d, &rect);
+ litest_assert_enum_eq(rc, LIBINPUT_CONFIG_STATUS_INVALID);
+
+ rect.x1 = 0.9;
+ rect.x2 = 1.0;
+ rect.y1 = 0.9;
+ rect.y2 = 0.9;
+
+ rc = libinput_device_config_area_set_rectangle(d, &rect);
+ litest_assert_enum_eq(rc, LIBINPUT_CONFIG_STATUS_INVALID);
+
+ rect.x1 = 0.9;
+ rect.x2 = 1.5;
+ rect.y1 = 0.0;
+ rect.y2 = 1.0;
+
+ rc = libinput_device_config_area_set_rectangle(d, &rect);
+ litest_assert_enum_eq(rc, LIBINPUT_CONFIG_STATUS_INVALID);
+
+ rect.x1 = 0.0;
+ rect.x2 = 1.0;
+ rect.y1 = 0.9;
+ rect.y2 = 1.4;
+
+ rc = libinput_device_config_area_set_rectangle(d, &rect);
+ litest_assert_enum_eq(rc, LIBINPUT_CONFIG_STATUS_INVALID);
+
+}
+END_TEST
+
+static void
+get_tool_xy(struct libinput *li, double *x, double *y)
+{
+ struct libinput_event *event = libinput_get_event(li);
+ struct libinput_event_tablet_tool *tev;
+
+ litest_assert_ptr_notnull(event);
+
+ switch (libinput_event_get_type(event)) {
+ case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
+ tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+ break;
+ case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
+ tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ break;
+ default:
+ abort();
+ }
+
+ *x = libinput_event_tablet_tool_get_x_transformed(tev, 100);
+ *y = libinput_event_tablet_tool_get_y_transformed(tev, 100);
+ libinput_event_destroy(event);
+}
+
+START_TEST(tablet_area_set_rectangle)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_device *d = dev->libinput_device;
+ struct axis_replacement axes[] = {
+ { ABS_DISTANCE, 10 },
+ { ABS_PRESSURE, 0 },
+ { -1, -1 }
+ };
+ double x, y;
+ double *scaled, *unscaled;
+ bool use_vertical = !!_i; /* ranged test */
+
+ if (libevdev_has_property(dev->evdev, INPUT_PROP_DIRECT))
+ return LITEST_NOT_APPLICABLE;
+
+ struct libinput_config_area_rectangle rect;
+ if (use_vertical) {
+ rect = (struct libinput_config_area_rectangle){
+ 0.25, 0.0, 0.75, 1.0,
+ };
+ scaled = &x;
+ unscaled = &y;
+ } else {
+ rect = (struct libinput_config_area_rectangle){
+ 0.0, 0.25, 1.0, 0.75,
+ };
+ scaled = &y;
+ unscaled = &x;
+ }
+
+ enum libinput_config_status status = libinput_device_config_area_set_rectangle(d, &rect);
+ litest_assert_enum_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+
+ litest_drain_events(li);
+
+ /* move vertically through the center */
+ litest_tablet_proximity_in(dev, 5, 5, axes);
+ libinput_dispatch(li);
+ get_tool_xy(li, &x, &y);
+ litest_assert_double_eq_epsilon(*scaled, 0.0, 2);
+ litest_assert_double_eq_epsilon(*unscaled, 5.0, 2);
+
+ for (int i = 10; i <= 100; i += 5) {
+ /* Negate any smoothing */
+ litest_tablet_motion(dev, i, i, axes);
+ litest_tablet_motion(dev, i - 1, i, axes);
+ litest_tablet_motion(dev, i, i - 1, axes);
+ litest_drain_events(li);
+
+ litest_tablet_motion(dev, i, i, axes);
+ libinput_dispatch(li);
+ get_tool_xy(li, &x, &y);
+ if (i <= 25)
+ litest_assert_double_eq(*scaled, 0.0);
+ else if (i > 75)
+ litest_assert_double_eq_epsilon(*scaled, 100.0, 1);
+ else
+ litest_assert_double_eq_epsilon(*scaled, (i - 25) * 2, 1);
+ litest_assert_double_eq_epsilon(*unscaled, i, 2);
+ }
+
+ /* Push through any smoothing */
+ litest_tablet_motion(dev, 100, 100, axes);
+ litest_tablet_motion(dev, 100, 100, axes);
+ libinput_dispatch(li);
+ litest_drain_events(li);
+
+ litest_tablet_proximity_out(dev);
+ litest_timeout_tablet_proxout();
+ libinput_dispatch(li);
+ get_tool_xy(li, &x, &y);
+ litest_assert_double_eq_epsilon(x, 100, 1);
+ litest_assert_double_eq_epsilon(y, 100, 1);
+
+}
+END_TEST
+
static void
assert_pressure(struct libinput *li, enum libinput_event_type type, double expected_pressure)
{
struct range with_timeout = { 0, 2 };
struct range xyaxes = { ABS_X, ABS_Y + 1 };
struct range tilt_cases = {TILT_MINIMUM, TILT_MAXIMUM + 1};
+ struct range vert_horiz = { 0, 2 };
litest_add(tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
litest_add(tool_user_data, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
litest_add(tablet_calibration_set_matrix, LITEST_TABLET, LITEST_TOTEM|LITEST_PRECALIBRATED);
litest_add(tablet_calibration_set_matrix_delta, LITEST_TABLET, LITEST_TOTEM|LITEST_PRECALIBRATED);
+ litest_add(tablet_area_has_rectangle, LITEST_TABLET, LITEST_ANY);
+ litest_add(tablet_area_set_rectangle_invalid, LITEST_TABLET, LITEST_ANY);
+ litest_add_ranged(tablet_area_set_rectangle, LITEST_TABLET, LITEST_ANY, &vert_horiz);
+
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);