summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/synaptics-properties.h3
-rw-r--r--man/synaptics.man18
-rw-r--r--src/eventcomm.c8
-rw-r--r--src/properties.c17
-rw-r--r--src/synaptics.c55
-rw-r--r--src/synapticsstr.h3
6 files changed, 96 insertions, 8 deletions
diff --git a/include/synaptics-properties.h b/include/synaptics-properties.h
index 9c6a2ee..bdb2112 100644
--- a/include/synaptics-properties.h
+++ b/include/synaptics-properties.h
@@ -155,4 +155,7 @@
/* 32 bit, 4 values, left, right, top, bottom */
#define SYNAPTICS_PROP_AREA "Synaptics Area"
+/* 32 Bit Integer, 2 values, horizontal hysteresis, vertical hysteresis */
+#define SYNAPTICS_PROP_NOISE_CANCELLATION "Synaptics Noise Cancellation"
+
#endif /* _SYNAPTICS_PROPERTIES_H_ */
diff --git a/man/synaptics.man b/man/synaptics.man
index 3f1ca9d..16ae7f6 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -222,6 +222,17 @@ Motion Factor"
Greatest setting for pressure motion factor. Property: "Synaptics Pressure
Motion Factor"
.TP
+.BI "Option \*qHorizHysteresis\*q \*q" integer \*q
+The minimum horizontal HW distance required to generate motion events. Can be
+specified as a percentage. Increase if noise motion is a problem for you. Zero
+is disabled.
+Default: 0.5 percent of the diagonal or (in case of evdev) the appropriate
+"fuzz" as advertised by the device.
+.TP
+.BI "Option \*qVertHysteresis\*q \*q" integer \*q
+The minimum vertical HW distance required to generate motion events. See
+\fBHorizHysteresis\fR.
+.TP
.BI "Option \*qUpDownScrolling\*q \*q" boolean \*q
If on, the up/down buttons generate button 4/5 events.
.
@@ -707,6 +718,13 @@ scrolling to circular scrolling. That is, if CornerCoasting is
active, scrolling will stop, and circular scrolling will not start,
when the finger leaves the corner.
+.SS Noise cancellation
+The synaptics has a built-in nose canellation based on hysteresis. This means
+that incoming coordinates actually shift a box of predefined dimensions such
+that it covers the incoming coordinate, and only the boxes own center is used
+as input. Obviously, the smaller the box the better, but the likelyhood of
+noise motion coming through also increases.
+
.SS Trackstick mode
Trackstick emulation mode is entered when pressing the finger hard on
the touchpad.
diff --git a/src/eventcomm.c b/src/eventcomm.c
index 4593bba..1a31c54 100644
--- a/src/eventcomm.c
+++ b/src/eventcomm.c
@@ -184,6 +184,11 @@ event_query_axis_ranges(InputInfoPtr pInfo)
abs.minimum, abs.maximum);
priv->minx = abs.minimum;
priv->maxx = abs.maximum;
+ /* The kernel's fuzziness concept seems a bit weird, but it can more or
+ * less be applied as hysteresis directly, i.e. no factor here. Though,
+ * we don't trust a zero fuzz as it probably is just a lazy value. */
+ if (abs.fuzz > 0)
+ priv->synpara.hyst_x = abs.fuzz;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
priv->resx = abs.resolution;
#endif
@@ -198,6 +203,9 @@ event_query_axis_ranges(InputInfoPtr pInfo)
abs.minimum, abs.maximum);
priv->miny = abs.minimum;
priv->maxy = abs.maximum;
+ /* don't trust a zero fuzz */
+ if (abs.fuzz > 0)
+ priv->synpara.hyst_y = abs.fuzz;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30)
priv->resy = abs.resolution;
#endif
diff --git a/src/properties.c b/src/properties.c
index 5400928..23b5a6a 100644
--- a/src/properties.c
+++ b/src/properties.c
@@ -82,6 +82,7 @@ Atom prop_gestures = 0;
Atom prop_capabilities = 0;
Atom prop_resolution = 0;
Atom prop_area = 0;
+Atom prop_noise_cancellation = 0;
static Atom
InitAtom(DeviceIntPtr dev, char *name, int format, int nvalues, int *values)
@@ -278,6 +279,12 @@ InitDeviceProperties(InputInfoPtr pInfo)
values[2] = para->area_top_edge;
values[3] = para->area_bottom_edge;
prop_area = InitAtom(pInfo->dev, SYNAPTICS_PROP_AREA, 32, 4, values);
+
+ values[0] = para->hyst_x;
+ values[1] = para->hyst_y;
+ prop_noise_cancellation = InitAtom(pInfo->dev,
+ SYNAPTICS_PROP_NOISE_CANCELLATION, 32, 2, values);
+
}
int
@@ -649,6 +656,16 @@ SetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
para->area_right_edge = area[1];
para->area_top_edge = area[2];
para->area_bottom_edge = area[3];
+ } else if (property == prop_noise_cancellation) {
+ INT32 *hyst;
+ if (prop->size != 2 || prop->format != 32 || prop->type != XA_INTEGER)
+ return BadMatch;
+
+ hyst = (INT32*)prop->data;
+ if (hyst[0] < 0 || hyst[1] < 0)
+ return BadValue;
+ para->hyst_x = hyst[0];
+ para->hyst_y = hyst[1];
}
return Success;
diff --git a/src/synaptics.c b/src/synaptics.c
index 03092f2..276c024 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -387,18 +387,19 @@ calculate_edge_widths(SynapticsPrivate *priv, int *l, int *r, int *t, int *b)
* the log message.
*/
static int set_percent_option(pointer options, const char* optname,
- const int range, const int offset)
+ const int range, const int offset,
+ const int default_value)
{
int result;
#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
- int percent = xf86CheckPercentOption(options, optname, -1);
+ double percent = xf86CheckPercentOption(options, optname, -1);
- if (percent != -1) {
+ if (percent >= 0.0) {
percent = xf86SetPercentOption(options, optname, -1);
result = percent/100.0 * range + offset;
} else
#endif
- result = xf86SetIntOption(options, optname, 0);
+ result = xf86SetIntOption(options, optname, default_value);
return result;
}
@@ -427,6 +428,7 @@ static void set_default_parameters(InputInfoPtr pInfo)
int horizResolution = 1;
int vertResolution = 1;
int width, height, diag, range;
+ int horizHyst, vertHyst;
/* read the parameters */
if (priv->synshm)
@@ -458,6 +460,10 @@ static void set_default_parameters(InputInfoPtr pInfo)
edgeMotionMaxSpeed = diag * .080;
accelFactor = 200.0 / diag; /* trial-and-error */
+ /* hysteresis, assume >= 0 is a detected value (e.g. evdev fuzz) */
+ horizHyst = pars->hyst_x >= 0 ? pars->hyst_x : diag * 0.005;
+ vertHyst = pars->hyst_y >= 0 ? pars->hyst_y : diag * 0.005;
+
range = priv->maxp - priv->minp;
/* scaling based on defaults and a pressure of 256 */
@@ -513,10 +519,13 @@ static void set_default_parameters(InputInfoPtr pInfo)
pars->top_edge = xf86SetIntOption(opts, "TopEdge", t);
pars->bottom_edge = xf86SetIntOption(opts, "BottomEdge", b);
- pars->area_top_edge = set_percent_option(opts, "AreaTopEdge", height, priv->miny);
- pars->area_bottom_edge = set_percent_option(opts, "AreaBottomEdge", height, priv->miny);
- pars->area_left_edge = set_percent_option(opts, "AreaLeftEdge", width, priv->minx);
- pars->area_right_edge = set_percent_option(opts, "AreaRightEdge", width, priv->minx);
+ pars->area_top_edge = set_percent_option(opts, "AreaTopEdge", height, priv->miny, 0);
+ pars->area_bottom_edge = set_percent_option(opts, "AreaBottomEdge", height, priv->miny, 0);
+ pars->area_left_edge = set_percent_option(opts, "AreaLeftEdge", width, priv->minx, 0);
+ pars->area_right_edge = set_percent_option(opts, "AreaRightEdge", width, priv->minx, 0);
+
+ pars->hyst_x = set_percent_option(opts, "HorizHysteresis", width, 0, horizHyst);
+ pars->hyst_y = set_percent_option(opts, "VertHysteresis", height, 0, vertHyst);
pars->finger_low = xf86SetIntOption(opts, "FingerLow", fingerLow);
pars->finger_high = xf86SetIntOption(opts, "FingerHigh", fingerHigh);
@@ -722,6 +731,8 @@ SynapticsPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
priv->tap_button = 0;
priv->tap_button_state = TBS_BUTTON_UP;
priv->touch_on.millis = 0;
+ priv->synpara.hyst_x = -1;
+ priv->synpara.hyst_y = -1;
/* read hardware dimensions */
ReadDevDimensions(pInfo);
@@ -1713,6 +1724,26 @@ estimate_delta(double x0, double x1, double x2, double x3)
return x0 * 0.3 + x1 * 0.1 - x2 * 0.1 - x3 * 0.3;
}
+/**
+ * Applies hysteresis. center is shifted such that it is in range with
+ * in by the margin again. The new center is returned.
+ * @param in the current value
+ * @param center the current center
+ * @param margin the margin to center in which no change is applied
+ * @return the new center (which might coincide with the previous)
+ */
+static int hysteresis(int in, int center, int margin) {
+ int diff = in - center;
+ if (abs(diff) <= margin) {
+ diff = 0;
+ } else if (diff > margin) {
+ diff -= margin;
+ } else if (diff < -margin) {
+ diff += margin;
+ }
+ return center + diff;
+}
+
static int
ComputeDeltas(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
edge_type edge, int *dxP, int *dyP, Bool inside_area)
@@ -2364,6 +2395,14 @@ HandleState(InputInfoPtr pInfo, struct SynapticsHwState *hw)
if (para->touchpad_off == 1)
return delay;
+ /* apply hysteresis before doing anything serious. This cancels
+ * out a lot of noise which might surface in strange phenomena
+ * like flicker in scrolling or noise motion. */
+ priv->hyst_center_x = hysteresis(hw->x, priv->hyst_center_x, para->hyst_x);
+ priv->hyst_center_y = hysteresis(hw->y, priv->hyst_center_y, para->hyst_y);
+ hw->x = priv->hyst_center_x;
+ hw->y = priv->hyst_center_y;
+
inside_active_area = is_inside_active_area(priv, hw->x, hw->y);
/* now we know that these _coordinates_ aren't in the area.
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 9ad8638..066b3f3 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -160,6 +160,7 @@ typedef struct _SynapticsParameters
unsigned int resolution_horiz; /* horizontal resolution of touchpad in units/mm */
unsigned int resolution_vert; /* vertical resolution of touchpad in units/mm */
int area_left_edge, area_right_edge, area_top_edge, area_bottom_edge; /* area coordinates absolute */
+ int hyst_x, hyst_y; /* x and y width of hysteresis box */
} SynapticsParameters;
@@ -183,6 +184,8 @@ typedef struct _SynapticsPrivateRec
Bool absolute_events; /* post absolute motion events instead of relative */
SynapticsMoveHistRec move_hist[SYNAPTICS_MOVE_HISTORY]; /* movement history */
int hist_index; /* Last added entry in move_hist[] */
+ int hyst_center_x; /* center x of hysteresis*/
+ int hyst_center_y; /* center y of hysteresis*/
int scroll_y; /* last y-scroll position */
int scroll_x; /* last x-scroll position */
double scroll_a; /* last angle-scroll position */