diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2017-03-23 10:18:19 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2017-03-23 10:18:19 +1000 |
commit | 078d5cb332c756102a7fce7099a6d63724c099d2 (patch) | |
tree | 8332f768219215dbdc89c16cd5a8c06deb5ae8b9 | |
parent | 3afe8bc9145a7af1c49a56f1e2ce9c5eeded6480 (diff) | |
parent | 411a3a4766144c93795c2bda9aa9f89a3602c896 (diff) |
Merge branch 'wip/tablet-wobbly-lines-v2'
-rw-r--r-- | src/evdev-tablet.c | 537 | ||||
-rw-r--r-- | src/evdev-tablet.h | 11 | ||||
-rw-r--r-- | src/libinput-private.h | 24 | ||||
-rw-r--r-- | test/test-tablet.c | 78 |
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, |