summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/input
diff options
context:
space:
mode:
authorrpaulo <rpaulo@FreeBSD.org>2009-12-08 00:52:59 +0000
committerrpaulo <rpaulo@FreeBSD.org>2009-12-08 00:52:59 +0000
commit3062d21178bf3337d5d700f21d96869e301fa505 (patch)
treede9c20f6e7179ef6d3b364fac9cc27eb35a6c797 /sys/dev/usb/input
parent2b1df305a4414b19e22c0f0c0464bae709144085 (diff)
downloadFreeBSD-src-3062d21178bf3337d5d700f21d96869e301fa505.zip
FreeBSD-src-3062d21178bf3337d5d700f21d96869e301fa505.tar.gz
Improve response to multi-touch taps.
Submitted by: Rohit Grover <rgrover1 at gmail.com>
Diffstat (limited to 'sys/dev/usb/input')
-rw-r--r--sys/dev/usb/input/atp.c165
1 files changed, 117 insertions, 48 deletions
diff --git a/sys/dev/usb/input/atp.c b/sys/dev/usb/input/atp.c
index 1489f9c..6c0ce2c 100644
--- a/sys/dev/usb/input/atp.c
+++ b/sys/dev/usb/input/atp.c
@@ -437,7 +437,7 @@ static void atp_detect_pspans(int *, u_int, u_int, atp_pspan *,
/* movement detection */
static boolean_t atp_match_stroke_component(atp_stroke_component *,
- const atp_pspan *);
+ const atp_pspan *, atp_stroke_type);
static void atp_match_strokes_against_pspans(struct atp_softc *,
atp_axis, atp_pspan *, u_int, u_int);
static boolean_t atp_update_strokes(struct atp_softc *,
@@ -458,6 +458,7 @@ static boolean_t atp_compute_stroke_movement(atp_stroke *);
/* tap detection */
static __inline void atp_setup_reap_time(struct atp_softc *, struct timeval *);
static void atp_reap_zombies(struct atp_softc *, u_int *, u_int *);
+static void atp_convert_to_slide(struct atp_softc *, atp_stroke *);
/* updating fifo */
static void atp_reset_buf(struct atp_softc *sc);
@@ -725,7 +726,7 @@ atp_interpret_sensor_data(const int8_t *sensor_data, u_int num, atp_axis axis,
for (i = 0, di = (axis == Y) ? 1 : 2; i < 8; di += 5, i++) {
arr[i] = sensor_data[di];
arr[i+8] = sensor_data[di+2];
- if (axis == X && num > 16)
+ if (axis == X && num > 16)
arr[i+16] = sensor_data[di+40];
}
@@ -879,23 +880,43 @@ atp_detect_pspans(int *p, u_int num_sensors,
*/
static boolean_t
atp_match_stroke_component(atp_stroke_component *component,
- const atp_pspan *pspan)
+ const atp_pspan *pspan, atp_stroke_type stroke_type)
{
- int delta_mickeys = pspan->loc - component->loc;
+ int delta_mickeys;
+ u_int min_pressure;
+
+ delta_mickeys = pspan->loc - component->loc;
if (abs(delta_mickeys) > atp_max_delta_mickeys)
return (FALSE); /* the finger span is too far out; no match */
component->loc = pspan->loc;
+
+ /*
+ * A sudden and significant increase in a pspan's cumulative
+ * pressure indicates the incidence of a new finger
+ * contact. This usually revises the pspan's
+ * centre-of-gravity, and hence the location of any/all
+ * matching stroke component(s). But such a change should
+ * *not* be interpreted as a movement.
+ */
+ if (pspan->cum > ((3 * component->cum_pressure) >> 1))
+ delta_mickeys = 0;
+
component->cum_pressure = pspan->cum;
if (pspan->cum > component->max_cum_pressure)
component->max_cum_pressure = pspan->cum;
/*
- * If the cumulative pressure drops below a quarter of the max,
- * then disregard the component's movement.
+ * Disregard the component's movement if its cumulative
+ * pressure drops below a fraction of the maximum; this
+ * fraction is determined based on the stroke's type.
*/
- if (component->cum_pressure < (component->max_cum_pressure >> 2))
+ if (stroke_type == ATP_STROKE_TOUCH)
+ min_pressure = (3 * component->max_cum_pressure) >> 2;
+ else
+ min_pressure = component->max_cum_pressure >> 2;
+ if (component->cum_pressure < min_pressure)
delta_mickeys = 0;
component->delta_mickeys = delta_mickeys;
@@ -930,7 +951,8 @@ atp_match_strokes_against_pspans(struct atp_softc *sc, atp_axis axis,
continue; /* skip matched pspans */
if (atp_match_stroke_component(
- &stroke->components[axis], &pspans[j])) {
+ &stroke->components[axis], &pspans[j],
+ stroke->type)) {
/* There is a match. */
stroke->components[axis].matched = TRUE;
@@ -1065,19 +1087,23 @@ atp_update_strokes(struct atp_softc *sc, atp_pspan *pspans_x,
for (i = 0; i < sc->sc_n_strokes; i++) {
atp_stroke *stroke = &sc->sc_strokes[i];
- printf(" %s%clc:%u,dm:%d,pnd:%d,mv:%d%c"
- ",%clc:%u,dm:%d,pnd:%d,mv:%d%c",
+ printf(" %s%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c"
+ ",%clc:%u,dm:%d,pnd:%d,cum:%d,max:%d,mv:%d%c",
(stroke->flags & ATSF_ZOMBIE) ? "zomb:" : "",
(stroke->type == ATP_STROKE_TOUCH) ? '[' : '<',
stroke->components[X].loc,
stroke->components[X].delta_mickeys,
stroke->components[X].pending,
+ stroke->components[X].cum_pressure,
+ stroke->components[X].max_cum_pressure,
stroke->components[X].movement,
(stroke->type == ATP_STROKE_TOUCH) ? ']' : '>',
(stroke->type == ATP_STROKE_TOUCH) ? '[' : '<',
stroke->components[Y].loc,
stroke->components[Y].delta_mickeys,
stroke->components[Y].pending,
+ stroke->components[Y].cum_pressure,
+ stroke->components[Y].max_cum_pressure,
stroke->components[Y].movement,
(stroke->type == ATP_STROKE_TOUCH) ? ']' : '>');
}
@@ -1218,51 +1244,94 @@ atp_advance_stroke_state(struct atp_softc *sc, atp_stroke *stroke,
if (atp_compute_stroke_movement(stroke))
*movement = TRUE;
+ if (stroke->type != ATP_STROKE_TOUCH)
+ return;
+
/* Convert touch strokes to slides upon detecting movement or age. */
- if (stroke->type == ATP_STROKE_TOUCH) {
- struct timeval tdiff;
+ if (stroke->cum_movement >= atp_slide_min_movement) {
+ atp_convert_to_slide(sc, stroke);
+ } else {
+ /* If a touch stroke is found to be older than the
+ * touch-timeout threshold, it should be converted to
+ * a slide; except if there is a co-incident sibling
+ * with a later creation time.
+ *
+ * When multiple fingers make contact with the
+ * touchpad, they are likely to be separated in their
+ * times of incidence. During a multi-finger tap,
+ * therefore, the last finger to make
+ * contact--i.e. the one with the latest
+ * 'ctime'--should be used to determine how the
+ * touch-siblings get treated; otherwise older
+ * siblings may lapse the touch-timeout and get
+ * converted into slides prematurely. The following
+ * loop determines if there exists another touch
+ * stroke with a larger 'ctime' than the current
+ * stroke (NOTE: zombies with a larger 'ctime' are
+ * also considered) .
+ */
- /* Compute the stroke's age. */
- getmicrotime(&tdiff);
- if (timevalcmp(&tdiff, &stroke->ctime, >))
- timevalsub(&tdiff, &stroke->ctime);
- else {
- /*
- * If we are here, it is because getmicrotime
- * reported the current time as being behind
- * the stroke's start time; getmicrotime can
- * be imprecise.
- */
- tdiff.tv_sec = 0;
- tdiff.tv_usec = 0;
- }
+ u_int i;
+ for (i = 0; i < sc->sc_n_strokes; i++) {
+ if ((&sc->sc_strokes[i] == stroke) ||
+ (sc->sc_strokes[i].type != ATP_STROKE_TOUCH))
+ continue;
- if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) ||
- ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) &&
- (tdiff.tv_usec > atp_touch_timeout)) ||
- (stroke->cum_movement >= atp_slide_min_movement)) {
- /* Switch this stroke to being a slide. */
- stroke->type = ATP_STROKE_SLIDE;
-
- /* Are we at the beginning of a double-click-n-drag? */
- if ((sc->sc_n_strokes == 1) &&
- ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) &&
- timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) {
- struct timeval delta;
- struct timeval window = {
- atp_double_tap_threshold / 1000000,
- atp_double_tap_threshold % 1000000
- };
-
- delta = stroke->ctime;
- timevalsub(&delta, &sc->sc_reap_time);
- if (timevalcmp(&delta, &window, <=))
- sc->sc_state |= ATP_DOUBLE_TAP_DRAG;
+ if (timevalcmp(&sc->sc_strokes[i].ctime,
+ &stroke->ctime, >))
+ break;
+ }
+ if (i == sc->sc_n_strokes) {
+ /* Found no other touch stroke with a larger 'ctime'. */
+ struct timeval tdiff;
+
+ /* Compute the stroke's age. */
+ getmicrotime(&tdiff);
+ if (timevalcmp(&tdiff, &stroke->ctime, >))
+ timevalsub(&tdiff, &stroke->ctime);
+ else {
+ /*
+ * If we are here, it is because getmicrotime
+ * reported the current time as being behind
+ * the stroke's start time; getmicrotime can
+ * be imprecise.
+ */
+ tdiff.tv_sec = 0;
+ tdiff.tv_usec = 0;
}
+
+ if ((tdiff.tv_sec > (atp_touch_timeout / 1000000)) ||
+ ((tdiff.tv_sec == (atp_touch_timeout / 1000000)) &&
+ (tdiff.tv_usec >=
+ (atp_touch_timeout % 1000000))))
+ atp_convert_to_slide(sc, stroke);
}
}
}
+/* Switch a given touch stroke to being a slide. */
+void
+atp_convert_to_slide(struct atp_softc *sc, atp_stroke *stroke)
+{
+ stroke->type = ATP_STROKE_SLIDE;
+
+ /* Are we at the beginning of a double-click-n-drag? */
+ if ((sc->sc_n_strokes == 1) &&
+ ((sc->sc_state & ATP_ZOMBIES_EXIST) == 0) &&
+ timevalcmp(&stroke->ctime, &sc->sc_reap_time, >)) {
+ struct timeval delta;
+ struct timeval window = {
+ atp_double_tap_threshold / 1000000,
+ atp_double_tap_threshold % 1000000
+ };
+
+ delta = stroke->ctime;
+ timevalsub(&delta, &sc->sc_reap_time);
+ if (timevalcmp(&delta, &window, <=))
+ sc->sc_state |= ATP_DOUBLE_TAP_DRAG;
+ }
+}
+
/*
* Terminate a stroke. While SLIDE strokes are dropped, TOUCH strokes
* are retained as zombies so as to reap all their siblings together;
@@ -1723,7 +1792,7 @@ atp_intr(struct usb_xfer *xfer, usb_error_t error)
*/
status_bits = sc->sensor_data[sc->sc_params->data_len - 1];
if ((sc->sc_params->prot == ATP_PROT_GEYSER3 &&
- (status_bits & ATP_STATUS_BASE_UPDATE)) ||
+ (status_bits & ATP_STATUS_BASE_UPDATE)) ||
!(sc->sc_state & ATP_VALID)) {
memcpy(sc->base_x, sc->cur_x,
sc->sc_params->n_xsensors * sizeof(*(sc->base_x)));
OpenPOWER on IntegriCloud