Blob Blame History Raw
From d958ab79d21b57141415650daac88f9369a1c861 Mon Sep 17 00:00:00 2001
From: Jason Gerecke <killertofu@gmail.com>
Date: Wed, 31 May 2017 10:57:12 +1000
Subject: [PATCH] Introduce "Pressure2K" config option for incompatible
 software

It appears that some software may not be entirely compatible with the
expanded 65K pressure level range that was introduced in version 0.34.0.
Although our driver advertises the larger range in XI2 (and toolkits
like GTK+2/3 and Qt3/4/5 make use of it), there have been reports of
other software (e.g. The Foundry's "NUKE") misbehaving.

As a workaround, this patch introduces a new boolean config option named
"Pressure2K". If enabled, it causes the driver to revert to its prior
behavior of using a pressure range of 0-2047. This option is disabled by
default, but can be turned on by adding the following configuration
snippet to a new file in the /etc/X11/xorg.conf.d directory:

Section "InputClass"
    Identifier "Wacom pressure compatibility"
    MatchDriver "wacom"
    Option "Pressure2K" "true"
EndSection

Ref: https://sourceforge.net/p/linuxwacom/mailman/message/35857403/
Ref: 3e56ce4429 (Increase full-scale pressure range from 0..2047 to 0..65535)
Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
---
 man/wacom.man           | 21 +++++++++++++++++++++
 src/wcmCommon.c         | 16 ++++++++--------
 src/wcmConfig.c         |  1 +
 src/wcmFilter.c         |  2 +-
 src/wcmValidateDevice.c |  5 +++++
 src/wcmXCommand.c       | 22 ++++++++++++----------
 src/xf86Wacom.c         |  2 +-
 src/xf86WacomDefs.h     |  5 +++--
 8 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/man/wacom.man b/man/wacom.man
index cd33438..3693c94 100644
--- a/man/wacom.man
+++ b/man/wacom.man
@@ -185,6 +185,14 @@ slightly raised curve (softer) might be "0,5,95,100".
 The pressure curve is only applicable to devices of type stylus or eraser,
 other devices do not honor this setting.
 .TP 4
+.B Option \fI"Pressure2K"\fP \fI"bool"\fP
+reduces the pressure range to the range of 0 to 2048 for backwards
+compatibility with applications that have this range hardcoded.
+See section
+.B BUGS.
+This option should not be used unless the user runs one or more
+applications that rely on a hardcoded pressure range.
+.TP 4
 .B Option \fI"DebugLevel"\fP \fI"number"\fP
 sets the level of debugging info for tool-specific messages.  There are 12
 levels, specified by the integers between 1 and 12.  All debug messages with
@@ -303,6 +311,19 @@ two separated fingers side by side, bring together i.e. pinch.
 \fBZoom out:\fR
 two fingers side by side, spread.  Not all applications support zoom.
 .PP
+.SH "BUGS"
+.SS "Pressure range increase leads to unexpected behavior"
+In version 0.34, the driver's pressure range increased from
+2048 steps to 65536 steps. The pressure axis range is advertised through the
+X Input Protocol but some applications have the previous pressure range
+hardcoded and cannot handle pressure values above 2048. This is an
+application bug but for backwards-compatibility with such applications, this
+driver provides the
+.B Pressure2K
+option to reduce the range to 2048 steps. Note that this setting applies to
+the device. Once applied, all applications will see the reduced pressure
+range. It is not possible to provide this setting on a per-application
+basis.
 .SH "SEE ALSO"
 __xservername__(__appmansuffix__), xorg.conf(__filemansuffix__),
 xorg.conf.d(__filemansuffix__), X(__miscmansuffix__)
diff --git a/src/wcmCommon.c b/src/wcmCommon.c
index f6cfd3d..dc6ecbd 100644
--- a/src/wcmCommon.c
+++ b/src/wcmCommon.c
@@ -1056,7 +1056,7 @@ rebasePressure(const WacomDevicePtr priv, const WacomDeviceState *ds)
 
 /**
  * Instead of reporting the raw pressure, we normalize
- * the pressure from 0 to FILTER_PRESSURE_RES. This is
+ * the pressure from 0 to maxCurve. This is
  * mainly to deal with the case where heavily used
  * stylus may have a "pre-loaded" initial pressure. To
  * do so, we keep the in-prox pressure and subtract it
@@ -1081,14 +1081,14 @@ normalizePressure(const WacomDevicePtr priv, const int raw_pressure)
 		p -= priv->minPressure;
 		range_left -= priv->minPressure;
 	}
-	/* normalize pressure to 0..FILTER_PRESSURE_RES */
+	/* normalize pressure to 0..maxCurve */
 	if (range_left >= 1)
 		pressure = xf86ScaleAxis(p,
-					 FILTER_PRESSURE_RES, 0,
+					 priv->maxCurve, 0,
 					 range_left,
 					 0);
 	else
-		pressure = FILTER_PRESSURE_RES;
+		pressure = priv->maxCurve;
 
 	return (int)pressure;
 }
@@ -1117,8 +1117,8 @@ setPressureButton(const WacomDevicePtr priv, int buttons, const int pressure)
 		{
 			/* don't set it off if it is within the tolerance
 			   and threshold is larger than the tolerance */
-			if ((common->wcmThreshold > THRESHOLD_TOLERANCE) &&
-			    (pressure > common->wcmThreshold - THRESHOLD_TOLERANCE))
+			if ((common->wcmThreshold > (priv->maxCurve * THRESHOLD_TOLERANCE)) &&
+			    (pressure > common->wcmThreshold - (priv->maxCurve * THRESHOLD_TOLERANCE)))
 				buttons |= button;
 		}
 	}
@@ -1350,7 +1350,7 @@ int wcmInitTablet(InputInfoPtr pInfo, const char* id, float version)
 	if (common->wcmThreshold <= 0 && IsPen(priv))
 	{
 		/* Threshold for counting pressure as a button */
-		common->wcmThreshold = DEFAULT_THRESHOLD;
+		common->wcmThreshold = priv->maxCurve * DEFAULT_THRESHOLD;
 
 		xf86Msg(X_PROBED, "%s: using pressure threshold of %d for button 1\n",
 			pInfo->name, common->wcmThreshold);
@@ -1401,7 +1401,7 @@ static int applyPressureCurve(WacomDevicePtr pDev, const WacomDeviceStatePtr pSt
 	/* clip the pressure */
 	int p = max(0, pState->pressure);
 
-	p = min(FILTER_PRESSURE_RES, p);
+	p = min(pDev->maxCurve, p);
 
 	/* apply pressure curve function */
 	if (pDev->pPressCurve == NULL)
diff --git a/src/wcmConfig.c b/src/wcmConfig.c
index 0924c43..6b269bb 100644
--- a/src/wcmConfig.c
+++ b/src/wcmConfig.c
@@ -63,6 +63,7 @@ static int wcmAllocate(InputInfoPtr pInfo)
 	priv->pInfo = pInfo;
 	priv->common = common;       /* common info pointer */
 	priv->oldCursorHwProx = 0;   /* previous cursor hardware proximity */
+	priv->maxCurve = FILTER_PRESSURE_RES;
 	priv->nPressCtrl [0] = 0;    /* pressure curve x0 */
 	priv->nPressCtrl [1] = 0;    /* pressure curve y0 */
 	priv->nPressCtrl [2] = 100;  /* pressure curve x1 */
diff --git a/src/wcmFilter.c b/src/wcmFilter.c
index aca5cd9..e7ddb37 100644
--- a/src/wcmFilter.c
+++ b/src/wcmFilter.c
@@ -78,7 +78,7 @@ void wcmSetPressureCurve(WacomDevicePtr pDev, int x0, int y0,
 
 	if (pDev->pPressCurve)
 		filterCurveToLine(pDev->pPressCurve,
-				FILTER_PRESSURE_RES,
+				pDev->maxCurve,
 				0.0, 0.0,               /* bottom left  */
 				x0/100.0, y0/100.0,     /* control point 1 */
 				x1/100.0, y1/100.0,     /* control point 2 */
diff --git a/src/wcmValidateDevice.c b/src/wcmValidateDevice.c
index d2a7723..0da5076 100644
--- a/src/wcmValidateDevice.c
+++ b/src/wcmValidateDevice.c
@@ -875,6 +875,11 @@ Bool wcmPreInitParseOptions(InputInfoPtr pInfo, Bool is_primary,
 	}
 	free(s);
 
+	if (xf86SetBoolOption(pInfo->options, "Pressure2K", 0)) {
+		xf86Msg(X_CONFIG, "%s: Using 2K pressure levels\n", pInfo->name);
+		priv->maxCurve = 2048;
+	}
+
 	/*Serials of tools we want hotpluged*/
 	if (wcmParseSerials (pInfo) != 0)
 		goto error;
diff --git a/src/wcmXCommand.c b/src/wcmXCommand.c
index 0e1d657..e18fb8f 100644
--- a/src/wcmXCommand.c
+++ b/src/wcmXCommand.c
@@ -106,21 +106,23 @@ static Atom prop_debuglevels;
 /**
  * Calculate a user-visible pressure level from a driver-internal pressure
  * level. Pressure settings exposed to the user assume a range of 0-2047
- * while the driver scales everything to a range of 0-FILTER_PRESSURE_RES.
+ * while the driver scales everything to a range of 0-maxCurve.
  */
-static inline int wcmInternalToUserPressure(int pressure)
+static inline int wcmInternalToUserPressure(InputInfoPtr pInfo, int pressure)
 {
-	return pressure / (FILTER_PRESSURE_RES / 2048);
+	WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
+	return pressure / (priv->maxCurve / 2048);
 }
 
 /**
  * Calculate a driver-internal pressure level from a user-visible pressure
  * level. Pressure settings exposed to the user assume a range of 0-2047
- * while the driver scales everything to a range of 0-FILTER_PRESSURE_RES.
+ * while the driver scales everything to a range of 0-maxCurve.
  */
-static inline int wcmUserToInternalPressure(int pressure)
+static inline int wcmUserToInternalPressure(InputInfoPtr pInfo, int pressure)
 {
-	return pressure * (FILTER_PRESSURE_RES / 2048);
+	WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
+	return pressure * (priv->maxCurve / 2048);
 }
 
 /**
@@ -276,7 +278,7 @@ void InitWcmDeviceProperties(InputInfoPtr pInfo)
 	}
 
 	values[0] = (!common->wcmMaxZ) ? 0 : common->wcmThreshold;
-	values[0] = wcmInternalToUserPressure(values[0]);
+	values[0] = wcmInternalToUserPressure(pInfo, values[0]);
 	prop_threshold = InitWcmAtom(pInfo->dev, WACOM_PROP_PRESSURE_THRESHOLD, XA_INTEGER, 32, 1, values);
 
 	values[0] = common->wcmSuppress;
@@ -846,7 +848,7 @@ int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
 			common->wcmCursorProxoutDist = value;
 	} else if (property == prop_threshold)
 	{
-		const INT32 MAXIMUM = wcmInternalToUserPressure(FILTER_PRESSURE_RES);
+		const INT32 MAXIMUM = wcmInternalToUserPressure(pInfo, priv->maxCurve);
 		INT32 value;
 
 		if (prop->size != 1 || prop->format != 32)
@@ -855,11 +857,11 @@ int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
 		value = *(INT32*)prop->data;
 
 		if (value == -1)
-			value = DEFAULT_THRESHOLD;
+			value = priv->maxCurve * DEFAULT_THRESHOLD;
 		else if ((value < 1) || (value > MAXIMUM))
 			return BadValue;
 		else
-			value = wcmUserToInternalPressure(value);
+			value = wcmUserToInternalPressure(pInfo, value);
 
 		if (!checkonly)
 			common->wcmThreshold = value;
diff --git a/src/xf86Wacom.c b/src/xf86Wacom.c
index a511fd2..738690f 100644
--- a/src/xf86Wacom.c
+++ b/src/xf86Wacom.c
@@ -200,7 +200,7 @@ static int wcmInitAxes(DeviceIntPtr pWcm)
 	if (!IsPad(priv))
 	{
 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_PRESSURE);
-		max = FILTER_PRESSURE_RES;
+		max = priv->maxCurve;
 	}
 
 	wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index b10a114..ec34211 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -182,8 +182,8 @@ struct _WacomModel
 
 #define FILTER_PRESSURE_RES	65536	/* maximum points in pressure curve */
 /* Tested result for setting the pressure threshold to a reasonable value */
-#define THRESHOLD_TOLERANCE (FILTER_PRESSURE_RES / 125)
-#define DEFAULT_THRESHOLD (FILTER_PRESSURE_RES / 75)
+#define THRESHOLD_TOLERANCE (0.008f)
+#define DEFAULT_THRESHOLD (0.013f)
 
 #define WCM_MAX_BUTTONS		32	/* maximum number of tablet buttons */
 #define WCM_MAX_X11BUTTON	127	/* maximum button number X11 can handle */
@@ -285,6 +285,7 @@ struct _WacomDeviceRec
 	struct _WacomDeviceState oldState; /* previous state information */
 	int oldCursorHwProx;	/* previous cursor hardware proximity */
 
+	int maxCurve;		/* maximum pressure curve value */
 	int *pPressCurve;       /* pressure curve */
 	int nPressCtrl[4];      /* control points for curve */
 	int minPressure;	/* the minimum pressure a pen may hold */
-- 
2.13.0