Limit the movement to 20 mm per event

Touchpads are limited by a fixed sampling rate (usually 80Hz). Some finger
changes may happen too fast for this sampling rate, resulting in two distinct
event sequences:
* finger 1 up and finger 2 down in the same EV_SYN frame. Synaptics sees one
  finger down before and after and the changed coordinates
* finger 1 up and finger 2 down _between_ two EV_SYN frames. Synaptics sees one
  touchpoint move from f1 position to f2 position.

That move causes a large cursor jump. The former could be solved (with
difficulty) by adding fake EV_SYN handling after releasing touchpoints but
that won't fix the latter case.

So as a solution for now limit the finger movement to 20mm per event.
Tests on a T440 and an x220 showed that this is just above what a reasonable
finger movement would trigger. If a movement is greater than that limit, reset
it to 0/0.

On devices without resolution, use 0.25 of the touchpad's diagonal instead.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
(cherry picked from commit 41b2312c00)
This commit is contained in:
Peter Hutterer
2014-09-16 08:52:56 +10:00
parent c3df19df67
commit c3c68e3cbb
2 changed files with 35 additions and 0 deletions

View File

@@ -756,6 +756,23 @@ set_default_parameters(InputInfoPtr pInfo)
pars->resolution_vert = 1;
}
/* Touchpad sampling rate is too low to detect all movements.
A user may lift one finger and put another one down within the same
EV_SYN or even between samplings so the driver doesn't notice at all.
We limit the movement to 20 mm within one event, that is more than
recordings showed is needed (17mm on a T440).
*/
if (pars->resolution_horiz > 1 &&
pars->resolution_vert > 1)
pars->maxDeltaMM = 20;
else {
/* on devices without resolution set the vector length to 0.25 of
the touchpad diagonal */
pars->maxDeltaMM = diag * 0.25;
}
/* Warn about (and fix) incorrectly configured TopEdge/BottomEdge parameters */
if (pars->top_edge > pars->bottom_edge) {
int tmp = pars->top_edge;
@@ -2217,6 +2234,13 @@ get_delta(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
*dy = integral;
}
/* Vector length, but not sqrt'ed, we only need it for comparison */
static inline double
vlenpow2(double x, double y)
{
return x * x + y * y;
}
/**
* Compute relative motion ('deltas') including edge motion.
*/
@@ -2226,6 +2250,7 @@ ComputeDeltas(SynapticsPrivate * priv, const struct SynapticsHwState *hw,
{
enum MovingState moving_state;
double dx, dy;
double vlen;
int delay = 1000000000;
dx = dy = 0;
@@ -2271,6 +2296,14 @@ ComputeDeltas(SynapticsPrivate * priv, const struct SynapticsHwState *hw,
out:
priv->prevFingers = hw->numFingers;
vlen = vlenpow2(dx/priv->synpara.resolution_horiz,
dy/priv->synpara.resolution_vert);
if (vlen > priv->synpara.maxDeltaMM * priv->synpara.maxDeltaMM) {
dx = 0;
dy = 0;
}
*dxP = dx;
*dyP = dy;

View File

@@ -226,6 +226,8 @@ typedef struct _SynapticsParameters {
int area_left_edge, area_right_edge, area_top_edge, area_bottom_edge; /* area coordinates absolute */
int softbutton_areas[4][4]; /* soft button area coordinates, 0 => right, 1 => middle , 2 => secondary right, 3 => secondary middle button */
int hyst_x, hyst_y; /* x and y width of hysteresis box */
int maxDeltaMM; /* maximum delta movement (vector length) in mm */
} SynapticsParameters;
struct _SynapticsPrivateRec {