diff --git a/include/wacom-properties.h b/include/wacom-properties.h index 9cec2114..4c4eb650 100644 --- a/include/wacom-properties.h +++ b/include/wacom-properties.h @@ -122,4 +122,13 @@ #define WACOM_PROP_XI_TYPE_PAD "PAD" #define WACOM_PROP_XI_TYPE_TOUCH "TOUCH" +/* BOOL, 1 value */ +#define WACOM_PROP_DEJITTER_ENABLED "Wacom DeJitter Enabled" + +/* 32 bit, 1 value */ +#define WACOM_PROP_DEJITTER_THRESHOLD "Wacom DeJitter Threshold" + +/* 32 bit, 1 value */ +#define WACOM_PROP_DEJITTER_TIME_THRESHOLD "Wacom DeJitter Time Threshold" + #endif diff --git a/man/xsetwacom.man b/man/xsetwacom.man index fe6807b3..4d65221a 100644 --- a/man/xsetwacom.man +++ b/man/xsetwacom.man @@ -97,6 +97,21 @@ device's native orientation, regardless of the actual rotation currently applied. Input outside of these coordinates will be clipped to the edges of the area defined. Default: 0 0 x2 y2; with x2 and y2 tablet specific. .TP +\fBDeJitterEnable\fR on|off +Enable or disable the de-jittering feature. When enabled, the device will +attempt to suppress small, erratic movements based on the thresholds defined +below. Default: off. +.TP +\fBDeJitterThreshold\fR distance +Set the spatial threshold for de-jittering in device units. Movements below +this distance will be suppressed if de-jittering is enabled. Default: 150, +range: 0 to 1000. +.TP +\fBDeJitterTimeThreshold\fR milliseconds +Set the time threshold for de-jittering in milliseconds. Movements that occur +within this time and below the spatial threshold will be suppressed. Default: +100 ms, range: 0 to 10000 ms. +.TP \fBResetArea Set the tablet input area to the default set. The set is defined device's native orientation, regardless of the actual rotation currently diff --git a/src/wcmCommon.c b/src/wcmCommon.c index 06669e8a..1d4dad9f 100644 --- a/src/wcmCommon.c +++ b/src/wcmCommon.c @@ -880,6 +880,58 @@ void wcmSendEvents(WacomDevicePtr priv, const WacomDeviceState* ds) wcmAxisSet(&axes, WACOM_AXIS_PRESSURE, ds->pressure); } + bool supressing = false; + if (priv->wcmDejitterEnabled) + { + CARD32 now = GetTimeInMillis(); + const int Thresh = priv->wcmDejitterThreshold == 0 ? 150 : priv->wcmDejitterThreshold; + const int TimeThresh = priv->wcmDejitterTimeThreshold == 0 ? 100 : priv->wcmDejitterTimeThreshold; + if (ds->buttons > 0) + { + if (priv->dejitterState.is_suppresed) + { + int dx = priv->dejitterState.x - x; + int dy = priv->dejitterState.y - y; + if (now < priv->dejitterState.suppress_start + TimeThresh && + dx * dx + dy * dy < Thresh * Thresh) + { + DBG(10, priv, "suppressing\n"); + x = priv->dejitterState.x; + y = priv->dejitterState.y; + wcmAxisSet(&axes, WACOM_AXIS_X, x); + wcmAxisSet(&axes, WACOM_AXIS_Y, y); + supressing = true; + } + } + else + { + DBG(10, priv, "start suppressing\n"); + priv->dejitterState.is_suppresed = true; + priv->dejitterState.x = x; + priv->dejitterState.y = y; + priv->dejitterState.suppress_start = now; + } + } + else + { + if (priv->dejitterState.is_suppresed) + { + DBG(10, priv, "stop suppressing\n"); + priv->dejitterState.is_suppresed = false; + int dx = priv->dejitterState.x - x; + int dy = priv->dejitterState.y - y; + if (now < priv->dejitterState.suppress_start + TimeThresh && + dx * dx + dy * dy < Thresh * Thresh) + { + x = priv->dejitterState.x; + y = priv->dejitterState.y; + wcmAxisSet(&axes, WACOM_AXIS_X, x); + wcmAxisSet(&axes, WACOM_AXIS_Y, y); + } + } + } + } + if (type == PAD_ID) { wcmAxisSet(&axes, WACOM_AXIS_STRIP_X, ds->stripx); @@ -925,28 +977,31 @@ void wcmSendEvents(WacomDevicePtr priv, const WacomDeviceState* ds) ds->proximity, dump, id, serial, is_button ? "true" : "false", ds->buttons); - /* when entering prox, replace the zeroed-out oldState with a copy of - * the current state to prevent jumps. reset the prox and button state - * to zero to properly detect changes. - */ - if(!priv->oldState.proximity) + if (!supressing) { - int old_key_state = priv->oldState.keys; - - wcmUpdateOldState(priv, ds, x, y); - priv->oldState.proximity = 0; - priv->oldState.buttons = 0; - - /* keys can happen without proximity */ - priv->oldState.keys = old_key_state; - } - - if (type == PAD_ID) - wcmSendPadEvents(priv, ds, &axes); - else { - /* don't move the cursor if in gesture mode (except drag mode) */ - if ((type != TOUCH_ID) || wcmTouchNeedSendEvents(priv->common)) + /* when entering prox, replace the zeroed-out oldState with a copy of + * the current state to prevent jumps. reset the prox and button state + * to zero to properly detect changes. + */ + if (!priv->oldState.proximity) + { + int old_key_state = priv->oldState.keys; + + wcmUpdateOldState(priv, ds, x, y); + priv->oldState.proximity = 0; + priv->oldState.buttons = 0; + + /* keys can happen without proximity */ + priv->oldState.keys = old_key_state; + } + + if (type == PAD_ID) + wcmSendPadEvents(priv, ds, &axes); + else { + /* don't move the cursor if in gesture mode (except drag mode) */ + if ((type != TOUCH_ID) || wcmTouchNeedSendEvents(priv->common)) wcmSendNonPadEvents(priv, ds, &axes); + } } if (ds->proximity) diff --git a/src/x11/xf86WacomProperties.c b/src/x11/xf86WacomProperties.c index 66802b55..8107e144 100644 --- a/src/x11/xf86WacomProperties.c +++ b/src/x11/xf86WacomProperties.c @@ -61,6 +61,9 @@ static Atom prop_panscroll_threshold; #ifdef DEBUG static Atom prop_debuglevels; #endif +static Atom prop_dejitter_enabled; +static Atom prop_dejitter_threshold; +static Atom prop_dejitter_time_threshold; /** * Calculate a user-visible pressure level from a driver-internal pressure @@ -295,6 +298,15 @@ void InitWcmDeviceProperties(WacomDevicePtr priv) prop_debuglevels = InitWcmAtom(pInfo->dev, WACOM_PROP_DEBUGLEVELS, XA_INTEGER, 8, 2, values); #endif + values[0] = priv->wcmDejitterEnabled; + prop_dejitter_enabled = InitWcmAtom(pInfo->dev, WACOM_PROP_DEJITTER_ENABLED, XA_INTEGER, 8, 1, values); + + values[0] = priv->wcmDejitterThreshold; + prop_dejitter_threshold = InitWcmAtom(pInfo->dev, WACOM_PROP_DEJITTER_THRESHOLD, XA_INTEGER, 32, 1, values); + + values[0] = priv->wcmDejitterTimeThreshold; + prop_dejitter_time_threshold = InitWcmAtom(pInfo->dev, WACOM_PROP_DEJITTER_TIME_THRESHOLD, XA_INTEGER, 32, 1, values); + XIRegisterPropertyHandler(pInfo->dev, wcmSetProperty, wcmGetProperty, wcmDeleteProperty); } @@ -945,6 +957,42 @@ static int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr pr if (!checkonly) common->wcmPanscrollThreshold = values[0]; + } else if (property == prop_dejitter_enabled) + { + CARD8 *values = (CARD8*)prop->data; + + if (prop->size != 1 || prop->format != 8) + return BadValue; + + if ((values[0] != 0) && (values[0] != 1)) + return BadValue; + + if (!checkonly && priv->wcmDejitterEnabled != values[0]) + priv->wcmDejitterEnabled = values[0]; + } else if (property == prop_dejitter_threshold) + { + INT32 *values = (INT32*)prop->data; + + if (prop->size != 1 || prop->format != 32) + return BadValue; + + if (values[0] > 1000) + return BadValue; + + if (!checkonly && priv->wcmDejitterThreshold != values[0]) + priv->wcmDejitterThreshold = values[0]; + } else if (property == prop_dejitter_time_threshold) + { + INT32 *values = (INT32*)prop->data; + + if (prop->size != 1 || prop->format != 32) + return BadValue; + + if (values[0] > 10000) + return BadValue; + + if (!checkonly && priv->wcmDejitterTimeThreshold != values[0]) + priv->wcmDejitterTimeThreshold = values[0]; } else { Atom *handler = NULL; diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h index 370ea81f..08568581 100644 --- a/src/xf86WacomDefs.h +++ b/src/xf86WacomDefs.h @@ -218,6 +218,14 @@ struct _WacomDeviceState unsigned int keys; /* bitmask for IDX_KEY_CONTROLPANEL, etc. */ }; +struct _WacomDejitterState +{ + int x; + int y; + bool is_suppresed; + CARD32 suppress_start; +}; + static const struct _WacomDeviceState OUTPROX_STATE = { .abswheel = INT_MAX, .abswheel2 = INT_MAX @@ -310,6 +318,10 @@ struct _WacomDeviceRec WacomTimerPtr serial_timer; /* timer used for serial number property update */ WacomTimerPtr tap_timer; /* timer used for tap timing */ WacomTimerPtr touch_timer; /* timer used for touch switch property update */ + struct _WacomDejitterState dejitterState; + int wcmDejitterEnabled; + int wcmDejitterThreshold; + int wcmDejitterTimeThreshold; ValuatorMask *valuator_mask; /* reusable valuator mask for sending events without reallocation */ }; diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c index c8f7a21b..11d298ca 100644 --- a/tools/xsetwacom.c +++ b/tools/xsetwacom.c @@ -550,6 +550,31 @@ static param_t parameters[] = .arg_count = 1, .prop_flags = PROP_FLAG_WRITEONLY | PROP_FLAG_OUTPUT, }, + { + .name = "DeJitterEnable", + .desc = "Enable or disable de-jittering (default is off).", + .prop_name = WACOM_PROP_DEJITTER_ENABLED, + .prop_format = 8, + .prop_offset = 0, + .arg_count = 1, + .prop_flags = PROP_FLAG_BOOLEAN, + }, + { + .name = "DeJitterThreshold", + .desc = "Set the spatial threshold for de-jittering (default is 150).", + .prop_name = WACOM_PROP_DEJITTER_THRESHOLD, + .prop_format = 32, + .prop_offset = 0, + .arg_count = 1, + }, + { + .name = "DeJitterTimeThreshold", + .desc = "Set the time threshold (in ms) for de-jittering (default is 100).", + .prop_name = WACOM_PROP_DEJITTER_TIME_THRESHOLD, + .prop_format = 32, + .prop_offset = 0, + .arg_count = 1, + }, { .name = "all", .desc = "Get value for all parameters. ",