summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2017-03-23 10:18:19 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2017-03-23 10:18:19 +1000
commit078d5cb332c756102a7fce7099a6d63724c099d2 (patch)
tree8332f768219215dbdc89c16cd5a8c06deb5ae8b9
parent3afe8bc9145a7af1c49a56f1e2ce9c5eeded6480 (diff)
parent411a3a4766144c93795c2bda9aa9f89a3602c896 (diff)
Merge branch 'wip/tablet-wobbly-lines-v2'
-rw-r--r--src/evdev-tablet.c537
-rw-r--r--src/evdev-tablet.h11
-rw-r--r--src/libinput-private.h24
-rw-r--r--test/test-tablet.c78
4 files changed, 440 insertions, 210 deletions
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index bde6f60..f87ccfe 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -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;
- }
- point.y = tablet->axes.point.y;
- evdev_transform_absolute(device, &point);
- evdev_transform_relative(device, &delta);
-
- *delta_out = delta;
- *point_out = point;
+ evdev_transform_absolute(device, &tablet->axes.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)
+
+ if (device->left_handed.enabled) {
+ tablet->axes.tilt.x *= -1;
tablet->axes.tilt.y *= -1;
+ }
}
- tilt.y = tablet->axes.tilt.y;
-
- return tilt;
}
-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);
}
+}
+
+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;
- return 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 double
-tablet_handle_wheel(struct tablet_dispatch *tablet,
- struct evdev_device *device,
- int *wheel_discrete)
+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;
-
- if (memcmp(tmp, tablet->changed_axes, sizeof(tmp)) == 0)
- return false;
+ bool rc = 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);
+ if (memcmp(tmp, tablet->changed_axes, sizeof(tmp)) == 0) {
+ axes = tablet->axes;
+ goto out;
+ }
+ 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 */
- 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;
+ tablet_update_rotation(tablet, device);
- /* 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);
- }
+ 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;
- axes.wheel = tablet_handle_wheel(tablet, device, &axes.wheel_discrete);
+ 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,91 +1356,198 @@ tablet_update_proximity_state(struct tablet_dispatch *tablet,
tablet_set_status(tablet, TABLET_TOOL_LEAVING_PROXIMITY);
}
-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)
+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)
{
- struct tablet_axes axes = {0};
+ if (!tablet_has_status(tablet, TABLET_TOOL_ENTERING_PROXIMITY))
+ return false;
- /* 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)) {
- /* 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.
- */
- axes = tablet->axes;
+ 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);
- /* 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;
- }
+ tablet_reset_changed_axes(tablet);
+ axes->delta.x = 0;
+ axes->delta.y = 0;
- 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);
- }
+ 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,
- &tablet->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);
- } else if (tablet_has_status(tablet, TABLET_TOOL_LEAVING_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,
- &tablet->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);
- } else if (tablet_has_status(tablet, TABLET_AXES_UPDATED)) {
- enum libinput_tablet_tool_tip_state tip_state;
- 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_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_events(struct tablet_dispatch *tablet,
+ struct libinput_tablet_tool *tool,
+ struct evdev_device *device,
+ uint64_t time)
+{
+ struct tablet_axes axes = {0};
+
+ 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.
+ */
+ axes = tablet->axes;
+
+ /* Dont' send an axis event, but we may have a tip event
+ * update */
tablet_unset_status(tablet, TABLET_AXES_UPDATED);
+ } else {
+ tablet_check_notify_axes(tablet, device, tool, &axes, time);
}
-out:
- memset(tablet->changed_axes, 0, sizeof(tablet->changed_axes));
+ assert(tablet->axes.delta.x == 0);
+ assert(tablet->axes.delta.y == 0);
+
+ 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);
+
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
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 2b2b1a7..43ed897 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -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];
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 205dbf8..a1d5000 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -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;
diff --git a/test/test-tablet.c b/test/test-tablet.c
index 7e2545d..215a9f6 100644
--- a/test/test-tablet.c
+++ b/test/test-tablet.c
@@ -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,