diff options
-rw-r--r-- | sys/dev/pckbc/pms.c | 9 | ||||
-rw-r--r-- | sys/dev/usb/ubcmtp.c | 9 | ||||
-rw-r--r-- | sys/dev/wscons/wsconsio.h | 39 | ||||
-rw-r--r-- | sys/dev/wscons/wsmouse.c | 20 | ||||
-rw-r--r-- | sys/dev/wscons/wsmouseinput.h | 12 | ||||
-rw-r--r-- | sys/dev/wscons/wstpad.c | 131 |
6 files changed, 159 insertions, 61 deletions
diff --git a/sys/dev/pckbc/pms.c b/sys/dev/pckbc/pms.c index 0aeeedfcd73..80f6cfa1d25 100644 --- a/sys/dev/pckbc/pms.c +++ b/sys/dev/pckbc/pms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pms.c,v 1.74 2017/03/06 09:06:20 mpi Exp $ */ +/* $OpenBSD: pms.c,v 1.75 2017/05/08 20:55:29 bru Exp $ */ /* $NetBSD: psm.c,v 1.11 2000/06/05 22:20:57 sommerfeld Exp $ */ /*- @@ -236,6 +236,10 @@ static struct wsmouse_param synaptics_params[] = { { WSMOUSECFG_PRESSURE_HI, SYNAPTICS_PRESSURE_HI } }; +static struct wsmouse_param elantech_v4_params[] = { + { WSMOUSECFG_STRONG_HYSTERESIS, 0 } +}; + int pmsprobe(struct device *, void *, void *); void pmsattach(struct device *, struct device *, void *); int pmsactivate(struct device *, int); @@ -2042,7 +2046,8 @@ pms_enable_elantech_v4(struct pms_softc *sc) sc->elantech = NULL; goto err; } - if (wsmouse_configure(sc->sc_wsmousedev, NULL, 0)) { + if (wsmouse_configure(sc->sc_wsmousedev, + elantech_v4_params, nitems(elantech_v4_params))) { free(sc->elantech, M_DEVBUF, 0); sc->elantech = NULL; printf("%s: setup failed\n", DEVNAME(sc)); diff --git a/sys/dev/usb/ubcmtp.c b/sys/dev/usb/ubcmtp.c index fcc946dc167..86ef3f3c6f4 100644 --- a/sys/dev/usb/ubcmtp.c +++ b/sys/dev/usb/ubcmtp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ubcmtp.c,v 1.15 2017/04/08 02:57:25 deraadt Exp $ */ +/* $OpenBSD: ubcmtp.c,v 1.16 2017/05/08 20:55:29 bru Exp $ */ /* * Copyright (c) 2013-2014, joshua stein <jcs@openbsd.org> @@ -131,6 +131,10 @@ struct ubcmtp_finger { /* Use a constant, synaptics-compatible pressure value for now. */ #define DEFAULT_PRESSURE 40 +static struct wsmouse_param ubcmtp_params[] = { + { WSMOUSECFG_STRONG_HYSTERESIS, 0 } +}; + struct ubcmtp_limit { int limit; int min; @@ -531,7 +535,8 @@ ubcmtp_configure(struct ubcmtp_softc *sc) hw->mt_slots = UBCMTP_MAX_FINGERS; hw->flags = WSMOUSEHW_MT_TRACKING; - return wsmouse_configure(sc->sc_wsmousedev, NULL, 0); + return wsmouse_configure(sc->sc_wsmousedev, + ubcmtp_params, nitems(ubcmtp_params)); } int diff --git a/sys/dev/wscons/wsconsio.h b/sys/dev/wscons/wsconsio.h index bd1db85e00b..7094d523b4e 100644 --- a/sys/dev/wscons/wsconsio.h +++ b/sys/dev/wscons/wsconsio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: wsconsio.h,v 1.79 2017/03/16 10:03:27 mpi Exp $ */ +/* $OpenBSD: wsconsio.h,v 1.80 2017/05/08 20:55:29 bru Exp $ */ /* $NetBSD: wsconsio.h,v 1.74 2005/04/28 07:15:44 martin Exp $ */ /* @@ -303,31 +303,34 @@ enum wsmousecfg { WSMOUSECFG_X_HYSTERESIS,/* retard value for X coordinates */ WSMOUSECFG_Y_HYSTERESIS,/* retard value for Y coordinates */ WSMOUSECFG_DECELERATION,/* threshold (distance) for deceleration */ + WSMOUSECFG_STRONG_HYSTERESIS, /* apply the filter continuously */ + WSMOUSECFG_SMOOTHING, /* smoothing factor (0-7) */ /* * Touchpad features */ - WSMOUSECFG_SOFTBUTTONS = 64, /* has "soft" buttons */ - WSMOUSECFG_SOFTMBTN, /* coordinates of middle-button area */ - WSMOUSECFG_TOPBUTTONS, - WSMOUSECFG_TWOFINGERSCROLL, - WSMOUSECFG_EDGESCROLL, - WSMOUSECFG_HORIZSCROLL, /* enable horizontal scrolling */ - WSMOUSECFG_SWAPSIDES, - WSMOUSECFG_DISABLE, + WSMOUSECFG_SOFTBUTTONS = 64, /* 2 soft-buttons at the bottom edge */ + WSMOUSECFG_SOFTMBTN, /* add a middle-button area */ + WSMOUSECFG_TOPBUTTONS, /* 3 soft-buttons at the top edge */ + WSMOUSECFG_TWOFINGERSCROLL, /* enable two-finger scrolling */ + WSMOUSECFG_EDGESCROLL, /* enable edge scrolling */ + WSMOUSECFG_HORIZSCROLL, /* enable horizontal edge scrolling */ + WSMOUSECFG_SWAPSIDES, /* invert soft-button/scroll areas */ + WSMOUSECFG_DISABLE, /* disable all output except for + clicks in the top-button area */ /* * Touchpad options */ - WSMOUSECFG_LEFT_EDGE = 128, /* ratios of the left edge */ - WSMOUSECFG_RIGHT_EDGE, /* ratios of the right edge */ - WSMOUSECFG_TOP_EDGE, /* ratios of the top edge */ - WSMOUSECFG_BOTTOM_EDGE, /* ratios of the bottom edge */ - WSMOUSECFG_CENTERWIDTH, /* width of the middle-button area */ - WSMOUSECFG_HORIZSCROLLDIST, - WSMOUSECFG_VERTSCROLLDIST, - WSMOUSECFG_F2WIDTH, - WSMOUSECFG_F2PRESSURE, + WSMOUSECFG_LEFT_EDGE = 128, /* ratio: left edge / total width */ + WSMOUSECFG_RIGHT_EDGE, /* ratio: right edge / total width */ + WSMOUSECFG_TOP_EDGE, /* ratio: top edge / total height */ + WSMOUSECFG_BOTTOM_EDGE, /* ratio: bottom edge / total height */ + WSMOUSECFG_CENTERWIDTH, /* ratio: center width / total width */ + WSMOUSECFG_HORIZSCROLLDIST, /* distance mapped to a scroll event */ + WSMOUSECFG_VERTSCROLLDIST, /* distance mapped to a scroll event */ + WSMOUSECFG_F2WIDTH, /* width limit for single touches */ + WSMOUSECFG_F2PRESSURE, /* pressure limit for single touches */ }; #define WSMOUSECFG_MAX 32 /* max size of param array per ioctl */ diff --git a/sys/dev/wscons/wsmouse.c b/sys/dev/wscons/wsmouse.c index d3ebd7741af..bb731213673 100644 --- a/sys/dev/wscons/wsmouse.c +++ b/sys/dev/wscons/wsmouse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wsmouse.c,v 1.38 2017/03/16 10:03:27 mpi Exp $ */ +/* $OpenBSD: wsmouse.c,v 1.39 2017/05/08 20:55:29 bru Exp $ */ /* $NetBSD: wsmouse.c,v 1.35 2005/02/27 00:27:52 perry Exp $ */ /* @@ -1352,6 +1352,14 @@ wsmouse_get_params(struct device *sc, case WSMOUSECFG_DECELERATION: params[i].value = input->filter.dclr; break; + case WSMOUSECFG_STRONG_HYSTERESIS: + params[i].value = + !!(input->filter.mode & STRONG_HYSTERESIS); + break; + case WSMOUSECFG_SMOOTHING: + params[i].value = + input->filter.mode & SMOOTHING_MASK; + break; default: error = wstpad_get_param(input, key, ¶ms[i].value); if (error != 0) @@ -1422,6 +1430,16 @@ wsmouse_set_params(struct device *sc, case WSMOUSECFG_DY_MAX: input->filter.v.dmax = val; break; + case WSMOUSECFG_STRONG_HYSTERESIS: + if (val) + input->filter.mode |= STRONG_HYSTERESIS; + else + input->filter.mode &= ~STRONG_HYSTERESIS; + break; + case WSMOUSECFG_SMOOTHING: + input->filter.mode &= ~SMOOTHING_MASK; + input->filter.mode |= (val & SMOOTHING_MASK); + break; default: needreset = 1; error = wstpad_set_param(input, key, val); diff --git a/sys/dev/wscons/wsmouseinput.h b/sys/dev/wscons/wsmouseinput.h index 5b828636637..2eeaa74fdf7 100644 --- a/sys/dev/wscons/wsmouseinput.h +++ b/sys/dev/wscons/wsmouseinput.h @@ -1,4 +1,4 @@ -/* $OpenBSD: wsmouseinput.h,v 1.6 2017/03/16 10:03:27 mpi Exp $ */ +/* $OpenBSD: wsmouseinput.h,v 1.7 2017/05/08 20:55:29 bru Exp $ */ /* * Copyright (c) 2015, 2016 Ulf Brosziewski @@ -103,9 +103,11 @@ struct axis_filter { int rmdr; /* Invert coordinates. */ int inv; - /* Hysteresis limit and accumulated deltas. */ + /* Hysteresis limit, accumulated deltas, and weighted delta average. */ int hysteresis; int acc; + int avg; + int avg_rmdr; /* A [*.12] coefficient for "magnitudes", used for deceleration. */ int mag_scale; int dclr_rmdr; @@ -136,6 +138,7 @@ struct wsmouseinput { int dclr; /* deceleration threshold */ int mag; /* weighted average of delta magnitudes */ + u_int mode; /* hysteresis type, smoothing factor */ int ratio; /* X/Y ratio */ @@ -159,6 +162,11 @@ struct wsmouseinput { #define TRACK_INTERVAL (1 << 17) #define CONFIGURED (1 << 18) +/* filter.mode (bit 0-2: smoothing factor, bit 3: hysteresis type) */ +#define STRONG_HYSTERESIS (1 << 3) +#define SMOOTHING_MASK 7 +#define FILTER_MODE_DEFAULT STRONG_HYSTERESIS + struct evq_access { struct wseventvar *evar; struct timespec ts; diff --git a/sys/dev/wscons/wstpad.c b/sys/dev/wscons/wstpad.c index 6104d97d30a..a7f3e7a47f9 100644 --- a/sys/dev/wscons/wstpad.c +++ b/sys/dev/wscons/wstpad.c @@ -762,28 +762,7 @@ wstpad_track_interval(struct wsmouseinput *input, struct timespec *time) input->intv.track = 1; } -/* - * If hysteresis values are set, the sum of the output motion deltas will - * lag behind the input deltas within a window bounded by +[hysteresis] - * and -[hysteresis]. It may suppress accidental movements when a touch - * starts or ends, or when small corrections with changing directions are - * being made. In the synaptics driver the default threshold is 0.5 percent - * of the diagonal of the touchpad surface, the wstpad default is about - * 0.36 percent. The fields filter.h.acc and filter.v.acc accumulate the - * deltas up to the threshold values. - */ -void -wstpad_hysteresis(int *acc, int *delta, int hysteresis) -{ - *acc += *delta; - if (*acc > hysteresis) - *delta = *acc - hysteresis; - else if (*acc < -hysteresis) - *delta = *acc + hysteresis; - else - *delta = 0; - *acc -= *delta; -} + /* * The default acceleration options of X don't work convincingly with @@ -797,7 +776,7 @@ wstpad_hysteresis(int *acc, int *delta, int hysteresis) * by the factor 2/8, deltas with magnitudes from 7 to 11 by factors * ranging from 3/8 to 7/8. */ -void +int wstpad_decelerate(struct wsmouseinput *input, int *dx, int *dy) { int h = abs(*dx) * input->filter.h.mag_scale; @@ -819,10 +798,95 @@ wstpad_decelerate(struct wsmouseinput *input, int *dx, int *dy) input->filter.v.dclr_rmdr = (v >= 0 ? v & 7 : -(-v & 7)); *dx = h / 8; *dy = v / 8; + return (1); } + return (0); } /* + * The hysteresis filter may suppress noise and accidental pointer + * movements. The "strong" variant applies independently to the axes, + * and it is applied continuously. It takes effect whenever the + * orientation on an axis changes, which makes pointer paths more stable. + * The "weak" variant is more precise and does not affect paths, it just + * filters noise at the start- and stop-points of a movement. + */ +void +wstpad_strong_hysteresis(int *dx, int *dy, + int *h_acc, int *v_acc, int h_threshold, int v_threshold) +{ + *h_acc += *dx; + *v_acc += *dy; + if (*h_acc > h_threshold) + *dx = *h_acc - h_threshold; + else if (*h_acc < -h_threshold) + *dx = *h_acc + h_threshold; + else + *dx = 0; + *h_acc -= *dx; + if (*v_acc > v_threshold) + *dy = *v_acc - v_threshold; + else if (*v_acc < -v_threshold) + *dy = *v_acc + v_threshold; + else + *dy = 0; + *v_acc -= *dy; +} + +void +wstpad_weak_hysteresis(int *dx, int *dy, + int *h_acc, int *v_acc, int h_threshold, int v_threshold) +{ + *h_acc += *dx; + *v_acc += *dy; + if ((*dx > 0 && *h_acc < *dx) + || (*dx < 0 && *h_acc > *dx)) + *h_acc = *dx; + if ((*dy > 0 && *v_acc < *dy) + || (*dy < 0 && *v_acc > *dy)) + *v_acc = *dy; + if (abs(*h_acc) < h_threshold + && abs(*v_acc) < v_threshold) + *dx = *dy = 0; +} + +void +wstpad_filter(struct wsmouseinput *input, int *dx, int *dy) +{ + struct axis_filter *h = &input->filter.h; + struct axis_filter *v = &input->filter.v; + int strength = input->filter.mode & 7; + + if ((h->dmax && (abs(*dx) > h->dmax)) + || (v->dmax && (abs(*dy) > v->dmax))) + *dx = *dy = 0; + + if (h->hysteresis || v->hysteresis) { + if (input->filter.mode & STRONG_HYSTERESIS) + wstpad_strong_hysteresis(dx, dy, &h->acc, + &v->acc, h->hysteresis, v->hysteresis); + else + wstpad_weak_hysteresis(dx, dy, &h->acc, + &v->acc, h->hysteresis, v->hysteresis); + } + + if (input->filter.dclr && wstpad_decelerate(input, dx, dy)) + /* Strong smoothing may hamper the precision at low speeds. */ + strength = imin(strength, 2); + + if (strength) { + /* Use a weighted decaying average for smoothing. */ + *dx = *dx * (8 - strength) + h->avg * strength + h->avg_rmdr; + *dy = *dy * (8 - strength) + v->avg * strength + v->avg_rmdr; + h->avg_rmdr = (*dx >= 0 ? *dx & 7 : -(-*dx & 7)); + v->avg_rmdr = (*dy >= 0 ? *dy & 7 : -(-*dy & 7)); + *dx = h->avg = *dx / 8; + *dy = v->avg = *dy / 8; + } +} + + +/* * Compatibility-mode conversions. This function transforms and filters * the coordinate inputs, extended functionality is provided by * wstpad_process_input. @@ -830,8 +894,6 @@ wstpad_decelerate(struct wsmouseinput *input, int *dx, int *dy) void wstpad_compat_convert(struct wsmouseinput *input, struct evq_access *evq) { - struct axis_filter *h = &input->filter.h; - struct axis_filter *v = &input->filter.v; int dx, dy; if (input->flags & TRACK_INTERVAL) @@ -840,19 +902,15 @@ wstpad_compat_convert(struct wsmouseinput *input, struct evq_access *evq) dx = (input->motion.sync & SYNC_X) ? input->motion.x_delta : 0; dy = (input->motion.sync & SYNC_Y) ? input->motion.y_delta : 0; - if ((h->dmax && (abs(dx) > h->dmax)) - || (v->dmax && (abs(dy) > v->dmax))) - dx = dy = 0; + if ((input->touch.sync & SYNC_CONTACTS) + || input->mt.ptr != input->mt.prev_ptr) { + input->filter.h.acc = input->filter.v.acc = 0; + input->filter.h.avg = input->filter.v.avg = 0; + } + + wstpad_filter(input, &dx, &dy); if (dx || dy) { - if (input->touch.sync & SYNC_CONTACTS) - h->acc = v->acc = 0; - if (h->hysteresis) - wstpad_hysteresis(&h->acc, &dx, h->hysteresis); - if (v->hysteresis) - wstpad_hysteresis(&v->acc, &dy, v->hysteresis); - if (input->filter.dclr) - wstpad_decelerate(input, &dx, &dy); input->motion.dx = dx; input->motion.dy = dy; if ((dx || dy) && !(input->motion.sync & SYNC_DELTAS)) { @@ -987,6 +1045,7 @@ wstpad_configure(struct wsmouseinput *input) input->filter.v.scale = input->filter.h.scale; input->filter.h.hysteresis = h_unit; input->filter.v.hysteresis = v_unit; + input->filter.mode = FILTER_MODE_DEFAULT; input->filter.dclr = h_unit - h_unit / 5; wstpad_init_deceleration(input); |