summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/pckbc/pms.c9
-rw-r--r--sys/dev/usb/ubcmtp.c9
-rw-r--r--sys/dev/wscons/wsconsio.h39
-rw-r--r--sys/dev/wscons/wsmouse.c20
-rw-r--r--sys/dev/wscons/wsmouseinput.h12
-rw-r--r--sys/dev/wscons/wstpad.c131
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, &params[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);