The touchpad input driver includes a function that identifies "stable" movements. It is very simple, but seems to work sufficiently well with most kinds of inputs. There is an exception: some touchpads regularly report intermediate zero coordinate-deltas when a touch is moving very slowly. The filter state is cleared when it shouldn't be, which may ruin slow scrolling.
This patch relaxes the filter conditions. Zero deltas only reset the state if a given time interval (55ms) has passed since the last change of the touch position. Moreover, as long as the contact count and the button state don't change, the check is skipped after scrolling has started (which makes it easier to correct a position). Any objections? Index: dev/wscons/wstpad.c =================================================================== RCS file: /cvs/src/sys/dev/wscons/wstpad.c,v retrieving revision 1.17 diff -u -p -r1.17 wstpad.c --- dev/wscons/wstpad.c 7 May 2018 21:58:42 -0000 1.17 +++ dev/wscons/wstpad.c 4 Nov 2018 12:45:06 -0000 @@ -60,6 +60,7 @@ #define CLICKDELAY_MS 20 #define FREEZE_MS 100 +#define MATCHINTERVAL_MS 55 enum tpad_handlers { SOFTBUTTON_HDLR, @@ -121,6 +122,7 @@ struct tpad_touch { int y; int dir; int matches; + struct timespec stop; struct { int x; int y; @@ -296,20 +298,32 @@ dircmp(int dir1, int dir2) } void -wstpad_set_direction(struct tpad_touch *t, int dx, int dy, int ratio) +wstpad_set_direction(struct wstpad *tp, struct tpad_touch *t, int dx, int dy) { int dir; + static const struct timespec interval = + { .tv_sec = 0, .tv_nsec = MATCHINTERVAL_MS * 1000000 }; if (t->state != TOUCH_UPDATE) { t->dir = -1; t->matches = 0; } else { - dir = direction(dx, dy, ratio); - if (t->dir >= 0 && dir >= 0 && dircmp(t->dir, dir) <= 1) - t->matches++; - else - t->matches = 1; - t->dir = dir; + dir = direction(dx, dy, tp->ratio); + if (dir >= 0) { + if (t->dir >= 0 && dircmp(t->dir, dir) <= 1) + t->matches++; + else + t->matches = 1; + t->dir = dir; + + timespecadd(&tp->time, &interval, &t->stop); + + } else if (t->dir >= 0) { + if (timespeccmp(&tp->time, &t->stop, >=)) { + t->dir = -1; + t->matches = 0; + } + } } } @@ -367,6 +381,9 @@ chk_scroll_state(struct wstpad *tp) tp->scroll.dw = 0; return (0); } + if (tp->t->matches < STABLE && !(tp->scroll.dz || tp->scroll.dw)) + return (0); + return (tp->dx || tp->dy); } @@ -433,7 +450,8 @@ wstpad_f2scroll(struct wsmouseinput *inp return; if ((dx > 0 && !EAST(dir)) || (dx < 0 && !WEST(dir))) return; - if (t2->matches < imin(STABLE, tp->t->matches / 4)) + if (t2->matches < STABLE && + !(tp->scroll.dz || tp->scroll.dw)) return; centered |= CENTERED(t2); } @@ -900,7 +918,7 @@ wstpad_mt_inputs(struct wsmouseinput *in t->orig.y = t->y; memcpy(&t->orig.time, &tp->time, sizeof(struct timespec)); t->flags = edge_flags(tp, t->x, t->y); - wstpad_set_direction(t, 0, 0, tp->ratio); + wstpad_set_direction(tp, t, 0, 0); } /* TOUCH_UPDATE */ @@ -928,9 +946,9 @@ wstpad_mt_inputs(struct wsmouseinput *in dy = normalize_abs(&input->filter.v, mts->pos.y) - t->y; t->y += dy; t->flags &= (~EDGES | edge_flags(tp, t->x, t->y)); - wstpad_set_direction(t, dx, dy, tp->ratio); + wstpad_set_direction(tp, t, dx, dy); } else if ((1 << slot) & inactive) { - wstpad_set_direction(t, 0, 0, tp->ratio); + wstpad_set_direction(tp, t, 0, 0); } } @@ -1035,7 +1053,7 @@ wstpad_touch_inputs(struct wsmouseinput t->flags &= (~EDGES | edge_flags(tp, t->x, t->y)); } - wstpad_set_direction(t, tp->dx, tp->dy, input->filter.ratio); + wstpad_set_direction(tp, t, tp->dx, tp->dy); } }