Merge branch 'wip/tablet-wobbly-lines-v2'

This commit is contained in:
Peter Hutterer 2017-03-23 10:18:19 +10:00
commit 078d5cb332
4 changed files with 454 additions and 224 deletions

View file

@ -76,6 +76,56 @@ tablet_force_button_presses(struct tablet_dispatch *tablet)
}
}
static inline size_t
tablet_history_size(const struct tablet_dispatch *tablet)
{
return ARRAY_LENGTH(tablet->history.samples);
}
static inline void
tablet_history_reset(struct tablet_dispatch *tablet)
{
tablet->history.count = 0;
}
static inline void
tablet_history_push(struct tablet_dispatch *tablet,
const struct tablet_axes *axes)
{
unsigned int index = (tablet->history.index + 1) %
tablet_history_size(tablet);
tablet->history.samples[index] = *axes;
tablet->history.index = index;
tablet->history.count = min(tablet->history.count + 1,
tablet_history_size(tablet));
if (tablet->history.count < tablet_history_size(tablet))
tablet_history_push(tablet, axes);
}
/**
* Return a previous axis state, where index of 0 means "most recent", 1 is
* "one before most recent", etc.
*/
static inline const struct tablet_axes*
tablet_history_get(const struct tablet_dispatch *tablet, unsigned int index)
{
size_t sz = tablet_history_size(tablet);
assert(index < sz);
assert(index < tablet->history.count);
index = (tablet->history.index + sz - index) % sz;
return &tablet->history.samples[index];
}
static inline void
tablet_reset_changed_axes(struct tablet_dispatch *tablet)
{
memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
}
static bool
tablet_device_has_axis(struct tablet_dispatch *tablet,
enum libinput_tablet_tool_axis axis)
@ -339,17 +389,14 @@ normalize_wheel(struct tablet_dispatch *tablet,
}
static inline void
tablet_handle_xy(struct tablet_dispatch *tablet,
struct evdev_device *device,
struct device_coords *point_out,
struct device_coords *delta_out)
tablet_update_xy(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
struct device_coords point;
struct device_coords delta = { 0, 0 };
const struct input_absinfo *absinfo;
int value;
if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X)) {
if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) ||
bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y)) {
absinfo = libevdev_get_abs_info(device->evdev, ABS_X);
if (device->left_handed.enabled)
@ -357,14 +404,8 @@ tablet_handle_xy(struct tablet_dispatch *tablet,
else
value = absinfo->value;
if (!tablet_has_status(tablet,
TABLET_TOOL_ENTERING_PROXIMITY))
delta.x = value - tablet->axes.point.x;
tablet->axes.point.x = value;
}
point.x = tablet->axes.point.x;
if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y)) {
absinfo = libevdev_get_abs_info(device->evdev, ABS_Y);
if (device->left_handed.enabled)
@ -372,31 +413,35 @@ tablet_handle_xy(struct tablet_dispatch *tablet,
else
value = absinfo->value;
if (!tablet_has_status(tablet,
TABLET_TOOL_ENTERING_PROXIMITY))
delta.y = value - tablet->axes.point.y;
tablet->axes.point.y = value;
evdev_transform_absolute(device, &tablet->axes.point);
}
point.y = tablet->axes.point.y;
evdev_transform_absolute(device, &point);
evdev_transform_relative(device, &delta);
*delta_out = delta;
*point_out = point;
}
static inline struct normalized_coords
tool_process_delta(struct libinput_tablet_tool *tool,
const struct evdev_device *device,
const struct device_coords *delta,
uint64_t time)
tablet_tool_process_delta(struct tablet_dispatch *tablet,
struct libinput_tablet_tool *tool,
const struct evdev_device *device,
struct tablet_axes *axes,
uint64_t time)
{
const struct normalized_coords zero = { 0.0, 0.0 };
struct device_coords delta = { 0, 0 };
struct device_float_coords accel;
accel.x = 1.0 * delta->x;
accel.y = 1.0 * delta->y;
if (!tablet_has_status(tablet,
TABLET_TOOL_ENTERING_PROXIMITY) &&
(bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X) ||
bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_Y))) {
delta.x = axes->point.x - tablet->last_smooth_point.x;
delta.y = axes->point.y - tablet->last_smooth_point.y;
}
tablet->last_smooth_point = axes->point;
accel.x = 1.0 * delta.x;
accel.y = 1.0 * delta.y;
if (device_float_is_zero(accel))
return zero;
@ -407,8 +452,8 @@ tool_process_delta(struct libinput_tablet_tool *tool,
time);
}
static inline double
tablet_handle_pressure(struct tablet_dispatch *tablet,
static inline void
tablet_update_pressure(struct tablet_dispatch *tablet,
struct evdev_device *device,
struct libinput_tablet_tool *tool)
{
@ -419,12 +464,10 @@ tablet_handle_pressure(struct tablet_dispatch *tablet,
absinfo = libevdev_get_abs_info(device->evdev, ABS_PRESSURE);
tablet->axes.pressure = normalize_pressure(absinfo, tool);
}
return tablet->axes.pressure;
}
static inline double
tablet_handle_distance(struct tablet_dispatch *tablet,
static inline void
tablet_update_distance(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
const struct input_absinfo *absinfo;
@ -434,12 +477,10 @@ tablet_handle_distance(struct tablet_dispatch *tablet,
absinfo = libevdev_get_abs_info(device->evdev, ABS_DISTANCE);
tablet->axes.distance = normalize_distance(absinfo);
}
return tablet->axes.distance;
}
static inline double
tablet_handle_slider(struct tablet_dispatch *tablet,
static inline void
tablet_update_slider(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
const struct input_absinfo *absinfo;
@ -449,40 +490,36 @@ tablet_handle_slider(struct tablet_dispatch *tablet,
absinfo = libevdev_get_abs_info(device->evdev, ABS_WHEEL);
tablet->axes.slider = normalize_slider(absinfo);
}
return tablet->axes.slider;
}
static inline struct tilt_degrees
tablet_handle_tilt(struct tablet_dispatch *tablet,
static inline void
tablet_update_tilt(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
struct tilt_degrees tilt;
const struct input_absinfo *absinfo;
/* mouse rotation resets tilt to 0 so always fetch both axes if
* either has changed */
if (bit_is_set(tablet->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_TILT_X)) {
LIBINPUT_TABLET_TOOL_AXIS_TILT_X) ||
bit_is_set(tablet->changed_axes,
LIBINPUT_TABLET_TOOL_AXIS_TILT_Y)) {
absinfo = libevdev_get_abs_info(device->evdev, ABS_TILT_X);
tablet->axes.tilt.x = adjust_tilt(absinfo);
if (device->left_handed.enabled)
tablet->axes.tilt.x *= -1;
}
tilt.x = tablet->axes.tilt.x;
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 = adjust_tilt(absinfo);
if (device->left_handed.enabled)
tablet->axes.tilt.y *= -1;
}
tilt.y = tablet->axes.tilt.y;
return tilt;
if (device->left_handed.enabled) {
tablet->axes.tilt.x *= -1;
tablet->axes.tilt.y *= -1;
}
}
}
static inline double
tablet_handle_artpen_rotation(struct tablet_dispatch *tablet,
static inline void
tablet_update_artpen_rotation(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
const struct input_absinfo *absinfo;
@ -494,12 +531,10 @@ tablet_handle_artpen_rotation(struct tablet_dispatch *tablet,
/* artpen has 0 with buttons pointing east */
tablet->axes.rotation = convert_to_degrees(absinfo, 90);
}
return tablet->axes.rotation;
}
static inline double
tablet_handle_mouse_rotation(struct tablet_dispatch *tablet,
static inline void
tablet_update_mouse_rotation(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
if (bit_is_set(tablet->changed_axes,
@ -508,28 +543,76 @@ tablet_handle_mouse_rotation(struct tablet_dispatch *tablet,
LIBINPUT_TABLET_TOOL_AXIS_TILT_Y)) {
convert_tilt_to_rotation(tablet);
}
return tablet->axes.rotation;
}
static inline double
tablet_handle_wheel(struct tablet_dispatch *tablet,
struct evdev_device *device,
int *wheel_discrete)
static inline void
tablet_update_rotation(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
/* We must check ROTATION_Z after TILT_X/Y so that the tilt axes are
* already normalized and set if we have the mouse/lens tool */
if (tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_MOUSE ||
tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_LENS) {
tablet_update_mouse_rotation(tablet, device);
clear_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_X);
clear_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_Y);
tablet->axes.tilt.x = 0;
tablet->axes.tilt.y = 0;
tablet->axes.rotation = tablet->axes.rotation;
/* tilt is already converted to left-handed, so mouse
* rotation is converted to left-handed automatically */
} else {
tablet_update_artpen_rotation(tablet, device);
if (device->left_handed.enabled) {
double r = tablet->axes.rotation;
tablet->axes.rotation = fmod(180 + r, 360);
}
}
}
static inline void
tablet_update_wheel(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
int a;
a = LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL;
if (bit_is_set(tablet->changed_axes, a)) {
*wheel_discrete = tablet->axes.wheel_discrete;
/* tablet->axes.wheel_discrete is already set */
tablet->axes.wheel = normalize_wheel(tablet,
tablet->axes.wheel_discrete);
} else {
tablet->axes.wheel = 0;
*wheel_discrete = 0;
tablet->axes.wheel_discrete = 0;
}
}
static void
tablet_smoothen_axes(const struct tablet_dispatch *tablet,
struct tablet_axes *axes)
{
size_t i;
size_t count = tablet_history_size(tablet);
struct tablet_axes smooth = { 0 };
for (i = 0; i < count; i++) {
const struct tablet_axes *a = tablet_history_get(tablet, i);
smooth.point.x += a->point.x;
smooth.point.y += a->point.y;
smooth.tilt.x += a->tilt.x;
smooth.tilt.y += a->tilt.y;
}
return tablet->axes.wheel;
axes->point.x = smooth.point.x/count;
axes->point.y = smooth.point.y/count;
axes->tilt.x = smooth.tilt.x/count;
axes->tilt.y = smooth.tilt.y/count;
}
static bool
@ -541,41 +624,44 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
{
struct tablet_axes axes = {0};
const char tmp[sizeof(tablet->changed_axes)] = {0};
struct device_coords delta;
bool rc = false;
if (memcmp(tmp, tablet->changed_axes, sizeof(tmp)) == 0)
return false;
tablet_handle_xy(tablet, device, &axes.point, &delta);
axes.pressure = tablet_handle_pressure(tablet, device, tool);
axes.distance = tablet_handle_distance(tablet, device);
axes.slider = tablet_handle_slider(tablet, device);
axes.tilt = tablet_handle_tilt(tablet, device);
axes.delta = tool_process_delta(tool, device, &delta, time);
/* We must check ROTATION_Z after TILT_X/Y so that the tilt axes are
* already normalized and set if we have the mouse/lens tool */
if (tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_MOUSE ||
tablet->current_tool_type == LIBINPUT_TABLET_TOOL_TYPE_LENS) {
axes.rotation = tablet_handle_mouse_rotation(tablet, device);
clear_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_X);
clear_bit(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_TILT_Y);
axes.tilt.x = 0;
axes.tilt.y = 0;
/* tilt is already converted to left-handed, so mouse
* rotation is converted to left-handed automatically */
} else {
axes.rotation = tablet_handle_artpen_rotation(tablet, device);
if (device->left_handed.enabled)
axes.rotation = fmod(180 + axes.rotation, 360);
if (memcmp(tmp, tablet->changed_axes, sizeof(tmp)) == 0) {
axes = tablet->axes;
goto out;
}
axes.wheel = tablet_handle_wheel(tablet, device, &axes.wheel_discrete);
tablet_update_xy(tablet, device);
tablet_update_pressure(tablet, device, tool);
tablet_update_distance(tablet, device);
tablet_update_slider(tablet, device);
tablet_update_tilt(tablet, device);
tablet_update_wheel(tablet, device);
/* We must check ROTATION_Z after TILT_X/Y so that the tilt axes are
* already normalized and set if we have the mouse/lens tool */
tablet_update_rotation(tablet, device);
axes.point = tablet->axes.point;
axes.pressure = tablet->axes.pressure;
axes.distance = tablet->axes.distance;
axes.slider = tablet->axes.slider;
axes.tilt = tablet->axes.tilt;
axes.wheel = tablet->axes.wheel;
axes.wheel_discrete = tablet->axes.wheel_discrete;
axes.rotation = tablet->axes.rotation;
rc = true;
out:
tablet_history_push(tablet, &tablet->axes);
tablet_smoothen_axes(tablet, &axes);
/* The delta relies on the last *smooth* point, so we do it last */
axes.delta = tablet_tool_process_delta(tablet, tool, device, &axes, time);
*axes_out = axes;
return true;
return rc;
}
static void
@ -1270,22 +1356,169 @@ tablet_update_proximity_state(struct tablet_dispatch *tablet,
tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
}
static inline bool
tablet_send_proximity_in(struct tablet_dispatch *tablet,
struct libinput_tablet_tool *tool,
struct evdev_device *device,
struct tablet_axes *axes,
uint64_t time)
{
if (!tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY))
return false;
tablet_notify_proximity(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
tablet->changed_axes,
axes);
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_reset_changed_axes(tablet);
axes->delta.x = 0;
axes->delta.y = 0;
return true;
}
static inline bool
tablet_send_proximity_out(struct tablet_dispatch *tablet,
struct libinput_tablet_tool *tool,
struct evdev_device *device,
struct tablet_axes *axes,
uint64_t time)
{
if (!tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY))
return false;
tablet_notify_proximity(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
tablet->changed_axes,
axes);
tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
tablet_reset_changed_axes(tablet);
axes->delta.x = 0;
axes->delta.y = 0;
return true;
}
static inline bool
tablet_send_tip(struct tablet_dispatch *tablet,
struct libinput_tablet_tool *tool,
struct evdev_device *device,
struct tablet_axes *axes,
uint64_t time)
{
if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT)) {
tablet_notify_tip(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_TIP_DOWN,
tablet->changed_axes,
axes);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
tablet_set_status(tablet, TABLET_TOOL_IN_CONTACT);
tablet_reset_changed_axes(tablet);
axes->delta.x = 0;
axes->delta.y = 0;
return true;
}
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT)) {
tablet_notify_tip(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_TIP_UP,
tablet->changed_axes,
axes);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
tablet_unset_status(tablet, TABLET_TOOL_IN_CONTACT);
tablet_reset_changed_axes(tablet);
axes->delta.x = 0;
axes->delta.y = 0;
return true;
}
return false;
}
static inline void
tablet_send_axes(struct tablet_dispatch *tablet,
struct libinput_tablet_tool *tool,
struct evdev_device *device,
struct tablet_axes *axes,
uint64_t time)
{
enum libinput_tablet_tool_tip_state tip_state;
if (!tablet_has_status(tablet, TABLET_AXES_UPDATED))
return;
if (tablet_has_status(tablet,
TABLET_TOOL_IN_CONTACT))
tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN;
else
tip_state = LIBINPUT_TABLET_TOOL_TIP_UP;
tablet_notify_axis(&device->base,
time,
tool,
tip_state,
tablet->changed_axes,
axes);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_reset_changed_axes(tablet);
axes->delta.x = 0;
axes->delta.y = 0;
}
static inline void
tablet_send_buttons(struct tablet_dispatch *tablet,
struct libinput_tablet_tool *tool,
struct evdev_device *device,
uint64_t time)
{
if (tablet_has_status(tablet, TABLET_BUTTONS_RELEASED)) {
tablet_notify_buttons(tablet,
device,
time,
tool,
LIBINPUT_BUTTON_STATE_RELEASED);
tablet_unset_status(tablet, TABLET_BUTTONS_RELEASED);
}
if (tablet_has_status(tablet, TABLET_BUTTONS_PRESSED)) {
tablet_notify_buttons(tablet,
device,
time,
tool,
LIBINPUT_BUTTON_STATE_PRESSED);
tablet_unset_status(tablet, TABLET_BUTTONS_PRESSED);
}
}
static void
tablet_send_axis_proximity_tip_down_events(struct tablet_dispatch *tablet,
struct evdev_device *device,
struct libinput_tablet_tool *tool,
uint64_t time)
tablet_send_events(struct tablet_dispatch *tablet,
struct libinput_tablet_tool *tool,
struct evdev_device *device,
uint64_t time)
{
struct tablet_axes axes = {0};
/* We need to make sure that we check that the tool is not out of
* proximity before we send any axis updates. This is because many
* tablets will send axis events with incorrect values if the tablet
* tool is close enough so that the tablet can partially detect that
* it's there, but can't properly receive any data from the tool. */
if (tablet_has_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY))
goto out;
else if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
/* Tool is leaving proximity, we can't rely on the last axis
* information (it'll be mostly 0), so we just get the
* current state and skip over updating the axes.
@ -1295,66 +1528,26 @@ tablet_send_axis_proximity_tip_down_events(struct tablet_dispatch *tablet,
/* Dont' send an axis event, but we may have a tip event
* update */
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
} else if (!tablet_check_notify_axes(tablet,
device,
tool,
&axes,
time)) {
goto out;
} else {
tablet_check_notify_axes(tablet, device, tool, &axes, time);
}
if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY)) {
tablet_notify_proximity(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN,
tablet->changed_axes,
&axes);
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
}
assert(tablet->axes.delta.x == 0);
assert(tablet->axes.delta.y == 0);
if (tablet_has_status(tablet, TABLET_TOOL_ENTERING_CONTACT)) {
tablet_notify_tip(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_TIP_DOWN,
tablet->changed_axes,
&tablet->axes);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
tablet_set_status(tablet, TABLET_TOOL_IN_CONTACT);
} else if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_CONTACT)) {
tablet_notify_tip(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_TIP_UP,
tablet->changed_axes,
&tablet->axes);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_CONTACT);
tablet_unset_status(tablet, TABLET_TOOL_IN_CONTACT);
} else if (tablet_has_status(tablet, TABLET_AXES_UPDATED)) {
enum libinput_tablet_tool_tip_state tip_state;
tablet_send_proximity_in(tablet, tool, device, &axes, time);
if (!tablet_send_tip(tablet, tool, device, &axes, time))
tablet_send_axes(tablet, tool, device, &axes, time);
if (tablet_has_status(tablet,
TABLET_TOOL_IN_CONTACT))
tip_state = LIBINPUT_TABLET_TOOL_TIP_DOWN;
else
tip_state = LIBINPUT_TABLET_TOOL_TIP_UP;
tablet_notify_axis(&device->base,
time,
tool,
tip_state,
tablet->changed_axes,
&axes);
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
}
out:
memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
tablet_unset_status(tablet, TABLET_TOOL_ENTERING_CONTACT);
tablet_reset_changed_axes(tablet);
tablet_send_buttons(tablet, tool, device, time);
if (tablet_send_proximity_out(tablet, tool, device, &axes, time)) {
tablet_change_to_left_handed(device);
tablet_history_reset(tablet);
}
}
static void
@ -1397,43 +1590,7 @@ tablet_flush(struct tablet_dispatch *tablet,
sanitize_tablet_axes(tablet, tool);
}
tablet_send_axis_proximity_tip_down_events(tablet,
device,
tool,
time);
if (tablet_has_status(tablet, TABLET_BUTTONS_RELEASED)) {
tablet_notify_buttons(tablet,
device,
time,
tool,
LIBINPUT_BUTTON_STATE_RELEASED);
tablet_unset_status(tablet, TABLET_BUTTONS_RELEASED);
}
if (tablet_has_status(tablet, TABLET_BUTTONS_PRESSED)) {
tablet_notify_buttons(tablet,
device,
time,
tool,
LIBINPUT_BUTTON_STATE_PRESSED);
tablet_unset_status(tablet, TABLET_BUTTONS_PRESSED);
}
if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY)) {
memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
tablet_notify_proximity(&device->base,
time,
tool,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT,
tablet->changed_axes,
&tablet->axes);
tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
tablet_unset_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
tablet_change_to_left_handed(device);
}
tablet_send_events(tablet, tool, device, time);
}
static inline void

View file

@ -30,6 +30,8 @@
#define LIBINPUT_TOOL_NONE 0
#define LIBINPUT_TABLET_TOOL_TYPE_MAX LIBINPUT_TABLET_TOOL_TYPE_LENS
#define TABLET_HISTORY_LENGTH 4
enum tablet_status {
TABLET_NONE = 0,
TABLET_AXES_UPDATED = 1 << 0,
@ -53,7 +55,14 @@ struct tablet_dispatch {
struct evdev_device *device;
unsigned int status;
unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
struct tablet_axes axes;
struct tablet_axes axes; /* for assembling the current state */
struct device_coords last_smooth_point;
struct {
unsigned int index;
unsigned int count;
struct tablet_axes samples[TABLET_HISTORY_LENGTH];
} history;
unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)];
int current_value[LIBINPUT_TABLET_TOOL_AXIS_MAX + 1];
int prev_value[LIBINPUT_TABLET_TOOL_AXIS_MAX + 1];

View file

@ -99,18 +99,6 @@ struct wheel_tilt_flags {
bool vertical, horizontal;
};
struct tablet_axes {
struct device_coords point;
struct normalized_coords delta;
double distance;
double pressure;
struct tilt_degrees tilt;
double rotation;
double slider;
double wheel;
int wheel_discrete;
};
struct libinput_interface_backend {
int (*resume)(struct libinput *libinput);
void (*suspend)(struct libinput *libinput);
@ -335,6 +323,18 @@ enum libinput_tablet_tool_axis {
#define LIBINPUT_TABLET_TOOL_AXIS_MAX LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL
struct tablet_axes {
struct device_coords point;
struct normalized_coords delta;
double distance;
double pressure;
struct tilt_degrees tilt;
double rotation;
double slider;
double wheel;
int wheel_discrete;
};
struct libinput_tablet_tool {
struct list link;
uint32_t serial;

View file

@ -1013,6 +1013,13 @@ START_TEST(proximity_has_axes)
litest_axis_set_value(axes, ABS_DISTANCE, 20);
litest_axis_set_value(axes, ABS_TILT_X, 15);
litest_axis_set_value(axes, ABS_TILT_Y, 25);
/* work around axis smoothing */
litest_tablet_motion(dev, 20, 30, axes);
litest_tablet_motion(dev, 20, 29, axes);
litest_tablet_motion(dev, 20, 31, axes);
litest_drain_events(li);
litest_tablet_motion(dev, 20, 30, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
@ -1044,8 +1051,10 @@ START_TEST(proximity_has_axes)
x = libinput_event_tablet_tool_get_x(tablet_event);
y = libinput_event_tablet_tool_get_y(tablet_event);
litest_assert_double_eq(x, last_x);
litest_assert_double_eq(y, last_y);
litest_assert_double_ge(x, last_x - 1);
litest_assert_double_le(x, last_x + 1);
litest_assert_double_ge(y, last_y - 1);
litest_assert_double_le(y, last_y + 1);
if (libinput_tablet_tool_has_distance(tool)) {
ck_assert(!libinput_event_tablet_tool_distance_has_changed(
@ -1428,6 +1437,16 @@ START_TEST(left_handed)
libinput_event_destroy(event);
/* work around smoothing */
litest_axis_set_value(axes, ABS_DISTANCE, 9);
litest_tablet_motion(dev, 100, 0, axes);
litest_axis_set_value(axes, ABS_DISTANCE, 7);
litest_tablet_motion(dev, 100, 0, axes);
litest_axis_set_value(axes, ABS_DISTANCE, 10);
litest_tablet_motion(dev, 100, 0, axes);
litest_drain_events(li);
litest_axis_set_value(axes, ABS_DISTANCE, 5);
litest_tablet_motion(dev, 100, 0, axes);
libinput_dispatch(li);
@ -1468,6 +1487,16 @@ START_TEST(left_handed)
libinput_event_destroy(event);
/* work around smoothing */
litest_axis_set_value(axes, ABS_DISTANCE, 9);
litest_tablet_motion(dev, 100, 0, axes);
litest_axis_set_value(axes, ABS_DISTANCE, 7);
litest_tablet_motion(dev, 100, 0, axes);
litest_axis_set_value(axes, ABS_DISTANCE, 10);
litest_tablet_motion(dev, 100, 0, axes);
litest_drain_events(li);
litest_axis_set_value(axes, ABS_DISTANCE, 5);
litest_tablet_motion(dev, 100, 0, axes);
libinput_dispatch(li);
@ -1768,6 +1797,7 @@ START_TEST(motion_outside_bounds)
struct libinput_event *event;
struct libinput_event_tablet_tool *tablet_event;
double val;
int i;
struct axis_replacement axes[] = {
{ ABS_DISTANCE, 10 },
@ -1778,6 +1808,15 @@ START_TEST(motion_outside_bounds)
litest_tablet_proximity_in(dev, 50, 50, axes);
litest_drain_events(li);
/* Work around smoothing */
for (i = 5; i > 0; i--) {
litest_event(dev, EV_ABS, ABS_X, 0 + 5 * i);
litest_event(dev, EV_ABS, ABS_Y, 1000);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
}
litest_drain_events(li);
/* On the 24HD x/y of 0 is outside the limit */
litest_event(dev, EV_ABS, ABS_X, 0);
litest_event(dev, EV_ABS, ABS_Y, 1000);
@ -1797,6 +1836,15 @@ START_TEST(motion_outside_bounds)
libinput_event_destroy(event);
/* Work around smoothing */
for (i = 5; i > 0; i--) {
litest_event(dev, EV_ABS, ABS_X, 1000);
litest_event(dev, EV_ABS, ABS_Y, 0 + 5 * i);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
}
litest_drain_events(li);
/* On the 24HD x/y of 0 is outside the limit */
litest_event(dev, EV_ABS, ABS_X, 1000);
litest_event(dev, EV_ABS, ABS_Y, 0);
@ -3341,12 +3389,18 @@ START_TEST(tablet_pressure_min_max)
litest_tablet_motion(dev, 5, 100, axes);
litest_drain_events(li);
/* need to fill the motion history */
litest_axis_set_value(axes, ABS_PRESSURE, 100);
litest_tablet_motion(dev, 5, 100, axes);
litest_tablet_motion(dev, 6, 100, axes);
litest_tablet_motion(dev, 7, 100, axes);
litest_tablet_motion(dev, 8, 100, axes);
litest_drain_events(li);
litest_tablet_motion(dev, 5, 100, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_AXIS);
ck_assert(libinput_event_tablet_tool_pressure_has_changed(tev));
p = libinput_event_tablet_tool_get_pressure(tev);
ck_assert_double_ge(p, 1.0);
libinput_event_destroy(event);
@ -3630,7 +3684,12 @@ START_TEST(tilt_x)
for (tilt = 0; tilt <= 100; tilt += 5) {
litest_axis_set_value(axes, ABS_TILT_X, tilt);
/* work around smoothing */
litest_tablet_motion(dev, 10, 10, axes);
litest_tablet_motion(dev, 10, 11, axes);
litest_tablet_motion(dev, 10, 10, axes);
litest_drain_events(li);
litest_tablet_motion(dev, 10, 11, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
tev = litest_is_tablet_event(event,
@ -3699,6 +3758,11 @@ START_TEST(tilt_y)
for (tilt = 0; tilt <= 100; tilt += 5) {
litest_axis_set_value(axes, ABS_TILT_Y, tilt);
/* work around smoothing */
litest_tablet_motion(dev, 10, 11, axes);
litest_tablet_motion(dev, 10, 10, axes);
litest_tablet_motion(dev, 10, 11, axes);
litest_drain_events(li);
litest_tablet_motion(dev, 10, 10, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
@ -3815,7 +3879,7 @@ START_TEST(relative_delta)
ck_assert(dy == 0.0);
libinput_event_destroy(event);
litest_tablet_motion(dev, 10, 10, axes);
litest_tablet_motion(dev, 5, 10, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
tev = litest_is_tablet_event(event,
@ -3837,7 +3901,7 @@ START_TEST(relative_delta)
ck_assert(dy > 0.0);
libinput_event_destroy(event);
litest_tablet_motion(dev, 10, 10, axes);
litest_tablet_motion(dev, 10, 5, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
tev = litest_is_tablet_event(event,
@ -3888,7 +3952,7 @@ START_TEST(relative_calibration)
ck_assert(dy == 0.0);
libinput_event_destroy(event);
litest_tablet_motion(dev, 10, 10, axes);
litest_tablet_motion(dev, 5, 10, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
tev = litest_is_tablet_event(event,
@ -3910,7 +3974,7 @@ START_TEST(relative_calibration)
ck_assert(dy < 0.0);
libinput_event_destroy(event);
litest_tablet_motion(dev, 10, 10, axes);
litest_tablet_motion(dev, 10, 5, axes);
libinput_dispatch(li);
event = libinput_get_event(li);
tev = litest_is_tablet_event(event,