diff options
-rw-r--r-- | include/synaptics-properties.h | 3 | ||||
-rw-r--r-- | man/synaptics.man | 18 | ||||
-rw-r--r-- | src/eventcomm.c | 8 | ||||
-rw-r--r-- | src/properties.c | 17 | ||||
-rw-r--r-- | src/synaptics.c | 55 | ||||
-rw-r--r-- | src/synapticsstr.h | 3 |
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 */ |