From: Egbert Eich <e...@suse.com>

Worn out devices send a non-zero pressure even when not in contact
with the tablet. To compensate for this the driver detects if the
pressure sent by the device immediately after indicating proximity
is non-zero. It subtracts this value from any pressure value sent
later and rescales the pressure range to the full device range.
If it later on sees the pressure value fall below this initial value
it will readjust it this lower value.
The downside of this is that when the pen is pushed onto the tablet
really fast the initial pressure reading may be non-zero also the
pen isn't worn. This can lead to lost events.
This patch tries to address this:
If the first pressure reading is != 0 it is recorded. If the recorded
maximum value is >0 but a later pressure reading is higher the maximum
value is replaced. If no button press event is generated the 'normal'
way it is checked of the recorded maximum would trigger one when
minPressure decreases.
Once a 'normal' button event is generated or an 'alternative' button
event is generated and minPressure doesn't decrease any more the
recorded maximum is set to 0 which will disable the checks until the
next prox in.

Signed-off-by: Egbert Eich <e...@suse.com>
---
v3: Removed some left-overs from earlier versions of the algorithm.

 src/wcmCommon.c     | 61 ++++++++++++++++++++++++++++++++++++++++++++---------
 src/xf86Wacom.h     |  2 +-
 src/xf86WacomDefs.h |  1 +
 test/wacom-tests.c  | 11 ++++------
 4 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/src/wcmCommon.c b/src/wcmCommon.c
index afc09f9..86f9d10 100644
--- a/src/wcmCommon.c
+++ b/src/wcmCommon.c
@@ -1066,11 +1066,11 @@ rebasePressure(const WacomDevicePtr priv, const 
WacomDeviceState *ds)
  * @see rebasePressure
  */
 TEST_NON_STATIC int
-normalizePressure(const WacomDevicePtr priv, const WacomDeviceState *ds)
+normalizePressure(const WacomDevicePtr priv, const int raw_pressure)
 {
        WacomCommonPtr common = priv->common;
        double pressure;
-       int p = ds->pressure;
+       int p = raw_pressure;
        int range_left;
 
        /* normalize pressure to 0..FILTER_PRESSURE_RES */
@@ -1094,16 +1094,16 @@ normalizePressure(const WacomDevicePtr priv, const 
WacomDeviceState *ds)
  * Returns the state of all buttons, but buttons other than button 1 are
  * unmodified.
  */
+#define PRESSURE_BUTTON 1
 static int
-setPressureButton(const WacomDevicePtr priv, const WacomDeviceState *ds)
+setPressureButton(const WacomDevicePtr priv, int buttons, const int pressure)
 {
        WacomCommonPtr common = priv->common;
-       int button = 1;
-       int buttons = ds->buttons;
+       int button = PRESSURE_BUTTON;
 
        /* button 1 Threshold test */
        /* set button1 (left click) on/off */
-       if (ds->pressure < common->wcmThreshold)
+       if (pressure < common->wcmThreshold)
        {
                buttons &= ~button;
                if (priv->oldButtons & button) /* left click was on */
@@ -1111,7 +1111,7 @@ setPressureButton(const WacomDevicePtr priv, const 
WacomDeviceState *ds)
                        /* don't set it off if it is within the tolerance
                           and threshold is larger than the tolerance */
                        if ((common->wcmThreshold > THRESHOLD_TOLERANCE) &&
-                           (ds->pressure > common->wcmThreshold - 
THRESHOLD_TOLERANCE))
+                           (pressure > common->wcmThreshold - 
THRESHOLD_TOLERANCE))
                                buttons |= button;
                }
        }
@@ -1169,6 +1169,7 @@ static void commonDispatchDevice(WacomCommonPtr common, 
unsigned int channel,
        WacomDeviceState* ds = &pChannel->valid.states[0];
        WacomDevicePtr priv = NULL;
        WacomDeviceState filtered;
+       int raw_pressure = 0;
 
        /* device_type should have been retrieved and set in the respective
         * models, wcmISDV4.c or wcmUSB.c. Once it comes here, something
@@ -1242,11 +1243,51 @@ static void commonDispatchDevice(WacomCommonPtr common, 
unsigned int channel,
 
        if ((IsPen(priv) || IsTouch(priv)) && common->wcmMaxZ)
        {
+               int prev_min_pressure = priv->oldProximity ? priv->minPressure 
: 0;
+
                detectPressureIssue(priv, common, &filtered);
+
+               raw_pressure = filtered.pressure;
+               if (!priv->oldProximity)
+                       priv->maxRawPressure = raw_pressure;
+
                priv->minPressure = rebasePressure(priv, &filtered);
-               filtered.pressure = normalizePressure(priv, &filtered);
-               if (IsPen(priv))
-                       filtered.buttons = setPressureButton(priv, &filtered);
+
+               filtered.pressure = normalizePressure(priv, filtered.pressure);
+               if (IsPen(priv)) {
+                       filtered.buttons = setPressureButton(priv,
+                                                            filtered.buttons,
+                                                            filtered.pressure);
+
+                       /* Here we run some heuristics to avoid losing button 
events if the
+                        * pen gets pushed onto the tablet so quickly that the 
first pressure
+                        * event read is non-zero and is thus interpreted as a 
pressure bias */
+                       if (filtered.buttons & PRESSURE_BUTTON) {
+                               /* If we triggered 'normally' reset max 
pressure to
+                                * avoid to trigger again while this device is 
in proximity */
+                               priv->maxRawPressure = 0;
+                       } else if (priv->maxRawPressure) {
+                               int norm_max_pressure;
+
+                               /* If we haven't triggered normally we record 
the maximal pressure
+                                * and see if this would have triggered with a 
lowered bias. */
+                               if (priv->maxRawPressure < raw_pressure)
+                                       priv->maxRawPressure = raw_pressure;
+                               norm_max_pressure = normalizePressure(priv, 
priv->maxRawPressure);
+                               filtered.buttons = setPressureButton(priv, 
filtered.buttons,
+                                                                    
norm_max_pressure);
+
+                               /* If minPressure is not decrementing any more 
or a button
+                                * press has been generated or minPressure has 
just become zero
+                                * reset maxRawPressure to avoid that worn 
devices
+                                * won't report a button release until going 
out of proximity */
+                               if ((filtered.buttons & PRESSURE_BUTTON &&
+                                    priv->minPressure == prev_min_pressure) ||
+                                   !priv->minPressure)
+                                       priv->maxRawPressure = 0;
+
+                       }
+               }
                filtered.pressure = applyPressureCurve(priv,&filtered);
        }
        else if (IsCursor(priv) && !priv->oldCursorHwProx)
diff --git a/src/xf86Wacom.h b/src/xf86Wacom.h
index c0448f2..c96e2ee 100644
--- a/src/xf86Wacom.h
+++ b/src/xf86Wacom.h
@@ -205,7 +205,7 @@ extern int wcmSetType(InputInfoPtr pInfo, const char *type);
 extern int getScrollDelta(int current, int old, int wrap, int flags);
 extern int getWheelButton(int delta, int action_up, int action_dn);
 extern int rebasePressure(const WacomDevicePtr priv, const WacomDeviceState 
*ds);
-extern int normalizePressure(const WacomDevicePtr priv, const WacomDeviceState 
*ds);
+extern int normalizePressure(const WacomDevicePtr priv, const int 
raw_pressure);
 extern enum WacomSuppressMode wcmCheckSuppress(WacomCommonPtr common,
                                                const WacomDeviceState* dsOrig,
                                                WacomDeviceState* dsNew);
diff --git a/src/xf86WacomDefs.h b/src/xf86WacomDefs.h
index afe6543..c5890b6 100644
--- a/src/xf86WacomDefs.h
+++ b/src/xf86WacomDefs.h
@@ -305,6 +305,7 @@ struct _WacomDeviceRec
        int minPressure;        /* the minimum pressure a pen may hold */
        int oldMinPressure;     /* to record the last minPressure before going 
out of proximity */
        unsigned int eventCnt;  /* count number of events while in proximity */
+       int maxRawPressure;     /* maximum 'raw' pressure seen until first 
button event */
        WacomToolPtr tool;         /* The common tool-structure for this device 
*/
 
        int isParent;           /* set to 1 if the device is not 
auto-hotplugged */
diff --git a/test/wacom-tests.c b/test/wacom-tests.c
index f44d3ab..a245021 100644
--- a/test/wacom-tests.c
+++ b/test/wacom-tests.c
@@ -179,7 +179,6 @@ test_normalize_pressure(void)
        InputInfoRec pInfo = {0};
        WacomDeviceRec priv = {0};
        WacomCommonRec common = {0};
-       WacomDeviceState ds = {0};
        int pressure, prev_pressure = -1;
        int i, j;
 
@@ -198,9 +197,9 @@ test_normalize_pressure(void)
 
                for (i = 0; i <= common.wcmMaxZ; i++)
                {
-                       ds.pressure = i;
+                       pressure = i;
 
-                       pressure = normalizePressure(&priv, &ds);
+                       pressure = normalizePressure(&priv, pressure);
                        assert(pressure >= 0);
                        assert(pressure <= FILTER_PRESSURE_RES);
 
@@ -216,14 +215,12 @@ test_normalize_pressure(void)
         * minPressure and ignores actual pressure. This would be a bug in the
         * driver code, but we might as well test for it. */
        priv.minPressure = 10;
-       ds.pressure = 0;
 
-       prev_pressure = normalizePressure(&priv, &ds);
+       prev_pressure = normalizePressure(&priv, 0);
        for (i = 0; i < priv.minPressure; i++)
        {
-               ds.pressure = i;
 
-               pressure = normalizePressure(&priv, &ds);
+               pressure = normalizePressure(&priv, i);
 
                assert(pressure >= 0);
                assert(pressure < FILTER_PRESSURE_RES);
-- 
1.8.4.5


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their
applications. Written by three acclaimed leaders in the field,
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/13534_NeoTech
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to