fsm now per device instead of a global struct

This commit is contained in:
suraj 2026-03-10 22:41:59 +05:30
parent 07337e906b
commit 7c5cdadcda
4 changed files with 77 additions and 78 deletions

View file

@ -38,27 +38,6 @@
#include "evdev-mt-touchpad.h"
void
tp_edge_motion_init(struct tp_dispatch *tp);
enum edge_motion_state { STATE_IDLE, STATE_DRAG_ACTIVE, STATE_EDGE_MOTION };
struct edge_motion_fsm {
enum edge_motion_state current_state;
usec_t last_motion_time;
uint32_t current_edge;
double motion_dx;
double motion_dy;
uint32_t continuous_motion_count;
struct tp_dispatch *tp;
struct libinput_timer timer;
};
static struct edge_motion_fsm fsm = {
.current_state = STATE_IDLE,
.tp = NULL,
};
#define EDGE_MOTION_CONFIG_SPEED_MM_S 70.0
#define EDGE_MOTION_CONFIG_MIN_INTERVAL_US 8000
#define EDGE_MOTION_CONFIG_EDGE_THRESHOLD_MM 5.0
@ -89,12 +68,12 @@ calculate_motion_vector(uint32_t edge, double *dx, double *dy)
static void
inject_accumulated_motion(struct tp_dispatch *tp, usec_t time)
{
if (usec_is_zero(fsm.last_motion_time)) {
fsm.last_motion_time = time;
if (usec_is_zero(tp->edge_motion.last_motion_time)) {
tp->edge_motion.last_motion_time = time;
return;
}
usec_t time_since_last = usec_sub(time, fsm.last_motion_time);
usec_t time_since_last = usec_sub(time, tp->edge_motion.last_motion_time);
double dist_mm = EDGE_MOTION_CONFIG_SPEED_MM_S *
((double)usec_as_uint64_t(time_since_last) / 1000000.0);
@ -102,8 +81,8 @@ inject_accumulated_motion(struct tp_dispatch *tp, usec_t time)
return;
struct device_float_coords raw = {
.x = fsm.motion_dx * dist_mm * tp->accel.x_scale_coeff,
.y = fsm.motion_dy * dist_mm * tp->accel.y_scale_coeff
.x = tp->edge_motion.motion_dx * dist_mm * tp->accel.x_scale_coeff,
.y = tp->edge_motion.motion_dy * dist_mm * tp->accel.y_scale_coeff
};
struct normalized_coords delta =
@ -111,8 +90,8 @@ inject_accumulated_motion(struct tp_dispatch *tp, usec_t time)
pointer_notify_motion(&tp->device->base, time, &delta, &raw);
fsm.last_motion_time = time;
fsm.continuous_motion_count++;
tp->edge_motion.last_motion_time = time;
tp->edge_motion.continuous_motion_count++;
}
static uint32_t
@ -138,50 +117,44 @@ detect_touch_edge(const struct tp_dispatch *tp, const struct tp_touch *t)
static void
tp_edge_motion_handle_timeout(usec_t now, void *data)
{
struct edge_motion_fsm *fsm_ptr = data;
struct tp_dispatch *tp = data;
if (fsm_ptr->current_state != STATE_EDGE_MOTION)
if (tp->edge_motion.state != EDGE_MOTION_STATE_EDGE_MOTION)
return;
inject_accumulated_motion(fsm_ptr->tp, now);
inject_accumulated_motion(tp, now);
libinput_timer_set(
&fsm_ptr->timer,
&tp->edge_motion.timer,
usec_add(now, usec_from_uint64_t(EDGE_MOTION_CONFIG_MIN_INTERVAL_US)));
}
void
tp_edge_motion_init(struct tp_dispatch *tp)
tp_init_edge_motion(struct tp_dispatch *tp)
{
if (fsm.tp)
return;
tp->edge_motion.state = EDGE_MOTION_STATE_IDLE;
tp->edge_motion.last_motion_time = usec_from_uint64_t(0);
tp->edge_motion.current_edge = EDGE_NONE;
tp->edge_motion.motion_dx = 0.0;
tp->edge_motion.motion_dy = 0.0;
tp->edge_motion.continuous_motion_count = 0;
memset(&fsm, 0, sizeof(fsm));
fsm.current_state = STATE_IDLE;
fsm.tp = tp;
libinput_timer_init(&fsm.timer,
libinput_timer_init(&tp->edge_motion.timer,
tp_libinput_context(tp),
"edge drag motion",
tp_edge_motion_handle_timeout,
&fsm);
tp);
}
void
tp_edge_motion_cleanup(void)
tp_remove_edge_motion(struct tp_dispatch *tp)
{
if (fsm.tp)
libinput_timer_destroy(&fsm.timer);
memset(&fsm, 0, sizeof(fsm));
fsm.current_state = STATE_IDLE;
libinput_timer_cancel(&tp->edge_motion.timer);
libinput_timer_destroy(&tp->edge_motion.timer);
}
int
tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time)
{
if (!fsm.tp)
tp_edge_motion_init(tp);
bool drag_active = false;
switch (tp->tap.state) {
@ -209,40 +182,41 @@ tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time)
}
}
enum edge_motion_state next_state = STATE_IDLE;
enum tp_edge_motion_state next_state = EDGE_MOTION_STATE_IDLE;
if (drag_active) {
next_state = (detected_edge != EDGE_NONE) ? STATE_EDGE_MOTION
: STATE_DRAG_ACTIVE;
next_state = (detected_edge != EDGE_NONE) ? EDGE_MOTION_STATE_EDGE_MOTION
: EDGE_MOTION_STATE_DRAG_ACTIVE;
}
if (next_state != fsm.current_state) {
fsm.current_state = next_state;
fsm.current_edge = detected_edge;
if (next_state != tp->edge_motion.state) {
tp->edge_motion.state = next_state;
tp->edge_motion.current_edge = detected_edge;
if (fsm.current_state != STATE_EDGE_MOTION)
fsm.continuous_motion_count = 0;
if (tp->edge_motion.state != EDGE_MOTION_STATE_EDGE_MOTION)
tp->edge_motion.continuous_motion_count = 0;
switch (fsm.current_state) {
case STATE_IDLE:
case STATE_DRAG_ACTIVE:
libinput_timer_cancel(&fsm.timer);
switch (tp->edge_motion.state) {
case EDGE_MOTION_STATE_IDLE:
case EDGE_MOTION_STATE_DRAG_ACTIVE:
libinput_timer_cancel(&tp->edge_motion.timer);
tp->edge_motion.current_edge = EDGE_NONE;
break;
case STATE_EDGE_MOTION:
calculate_motion_vector(fsm.current_edge,
&fsm.motion_dx,
&fsm.motion_dy);
fsm.last_motion_time = time;
tp_edge_motion_handle_timeout(time, &fsm);
case EDGE_MOTION_STATE_EDGE_MOTION:
calculate_motion_vector(tp->edge_motion.current_edge,
&tp->edge_motion.motion_dx,
&tp->edge_motion.motion_dy);
tp->edge_motion.last_motion_time = time;
tp_edge_motion_handle_timeout(time, tp);
break;
}
} else if (fsm.current_state == STATE_EDGE_MOTION &&
detected_edge != fsm.current_edge) {
fsm.current_edge = detected_edge;
calculate_motion_vector(fsm.current_edge,
&fsm.motion_dx,
&fsm.motion_dy);
} else if (tp->edge_motion.state == EDGE_MOTION_STATE_EDGE_MOTION &&
detected_edge != tp->edge_motion.current_edge) {
tp->edge_motion.current_edge = detected_edge;
calculate_motion_vector(tp->edge_motion.current_edge,
&tp->edge_motion.motion_dx,
&tp->edge_motion.motion_dy);
}
return (fsm.current_state == STATE_EDGE_MOTION);
return (tp->edge_motion.state == EDGE_MOTION_STATE_EDGE_MOTION);
}

View file

@ -1293,7 +1293,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, usec_t time)
}
/* Log 1-finger drag state changes */
filter_motion = tp_edge_motion_handle_drag_state(tp, time);
filter_motion |= tp_edge_motion_handle_drag_state(tp, time);
/**
* In any state where motion exceeding the move threshold would
@ -1597,7 +1597,6 @@ void
tp_remove_tap(struct tp_dispatch *tp)
{
libinput_timer_cancel(&tp->tap.timer);
tp_edge_motion_cleanup();
}
void

View file

@ -1960,6 +1960,7 @@ tp_interface_remove(struct evdev_dispatch *dispatch)
tp_remove_buttons(tp);
tp_remove_sendevents(tp);
tp_remove_edge_scroll(tp);
tp_remove_edge_motion(tp);
tp_remove_gesture(tp);
}
@ -3783,6 +3784,7 @@ tp_init(struct tp_dispatch *tp, struct evdev_device *device)
tp_init_palmdetect(tp, device);
tp_init_sendevents(tp, device);
tp_init_scroll(tp, device);
tp_init_edge_motion(tp);
tp_init_gesture(tp);
tp_init_thumb(tp);

View file

@ -140,6 +140,12 @@ enum tp_tap_touch_state {
TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */
};
enum tp_edge_motion_state {
EDGE_MOTION_STATE_IDLE,
EDGE_MOTION_STATE_DRAG_ACTIVE,
EDGE_MOTION_STATE_EDGE_MOTION,
};
/* For edge scrolling, so we only care about right and bottom. For edge motion, we
* require all four edges */
enum tp_edge {
@ -565,6 +571,21 @@ struct tp_dispatch {
struct evdev_device *tablet_device;
bool tablet_left_handed_state;
} left_handed;
struct {
enum tp_edge_motion_state state;
usec_t last_motion_time;
uint32_t current_edge;
double motion_dx;
double motion_dy;
uint32_t continuous_motion_count;
struct libinput_timer timer;
} edge_motion;
};
static inline struct tp_dispatch *
@ -726,11 +747,14 @@ tp_edge_scroll_touch_active(const struct tp_dispatch *tp, const struct tp_touch
uint32_t
tp_touch_get_edge(const struct tp_dispatch *tp, const struct tp_touch *t);
void
tp_init_edge_motion(struct tp_dispatch *tp);
int
tp_edge_motion_handle_drag_state(struct tp_dispatch *tp, usec_t time);
void
tp_edge_motion_cleanup(void);
tp_remove_edge_motion(struct tp_dispatch *tp);
void
tp_init_gesture(struct tp_dispatch *tp);