From: Egbert Eich <eich@suse.de>
Date: Sat Apr 9 12:01:12 2016 +0200
Subject: [PATCH 2/2]Add delay between button press and release to kiosk mode.
Patch-mainline: never
Git-commit: 00cf5b2c856d2be7e6f9d1e3ea53e3fa7eaad0d1
References: FATE#319647, bsc#967836
Signed-off-by: Egbert Eich <eich@suse.com>

This allows to notice the visual feedback of a UI on a button
press.

Signed-off-by: Egbert Eich <eich@suse.de>
---
 xf86-input-evdev-2.2.5/include/evdev-properties.h |   1 +
 xf86-input-evdev-2.2.5/man/evdev.man              |  13 ++
 xf86-input-evdev-2.2.5/src/evdev.c                |   7 +-
 xf86-input-evdev-2.2.5/src/evdev.h                |   8 +-
 xf86-input-evdev-2.2.5/src/kioskTouch.c           | 240 +++++++++++++++++++---
 5 files changed, 238 insertions(+), 31 deletions(-)

diff --git a/xf86-input-evdev-2.2.5/include/evdev-properties.h b/xf86-input-evdev-2.2.5/include/evdev-properties.h
index 7b6d831..2a77a0c 100644
--- a/xf86-input-evdev-2.2.5/include/evdev-properties.h
+++ b/xf86-input-evdev-2.2.5/include/evdev-properties.h
@@ -53,6 +53,7 @@
 /* Kiosk Touch mode */
 #define EVDEV_PROP_KIOSK_TOUCH "Evdev Kiosk Touch Mode"
 #define EVDEV_PROP_KIOSK_BUTTON "Evdev Kiosk Touch Button"
+#define EVDEV_PROP_KIOSK_BUTTON_DELAY "Evdev Kiosk Touch Button Delay"
 
 /* Axis inversion */
 /* BOOL, 2 values [x, y], 1 inverts axis */
diff --git a/xf86-input-evdev-2.2.5/man/evdev.man b/xf86-input-evdev-2.2.5/man/evdev.man
index 6012493..763de15 100644
--- a/xf86-input-evdev-2.2.5/man/evdev.man
+++ b/xf86-input-evdev-2.2.5/man/evdev.man
@@ -186,6 +186,16 @@ Specifies the Kiosk Touch button number to use. Button
 range: 0-255.
 Default: "0". Property:
 "Evdev Kiosk Touch Button".
+.TP 7
+.BI "Option \*qKioskTouchButtonDelay\*q \*q" "N" \*q
+Specifies the delay between a button press and release event in ms. A delay will help
+to notice a visual feedback on a button press event. During the delay no motion events
+are generated. Instead the final location is stored and a motion event to this location
+is sent after the button release has been sent at the end of the delay period. Button
+.I N
+range: 0-65535.
+Default: "0". Property:
+"Evdev Kiosk Touch Button Delay".
 
 .SH SUPPORTED PROPERTIES
 The following properties are provided by the
@@ -234,6 +244,9 @@ value.
 .TP 7
 .BI "Evdev Kiosk Touch Button"
 1 8-bit positive value.
+.TP 7
+.BI "Evdev Kiosk Touch Button Delay"
+1 16-bit positive value.
 
 .SH AUTHORS
 Kristian Høgsberg.
diff --git a/xf86-input-evdev-2.2.5/src/evdev.c b/xf86-input-evdev-2.2.5/src/evdev.c
index 7bf869d..7a909bd 100644
--- a/xf86-input-evdev-2.2.5/src/evdev.c
+++ b/xf86-input-evdev-2.2.5/src/evdev.c
@@ -499,7 +499,6 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
                 abs = 0;
                 rel = 1;
             }
-            EvdevKioskTouchMotionEvents(pInfo, abs);
 
             if (rel) {
                 int post_deltas[REL_CNT] = {0}; /* axis-mapped deltas */
@@ -571,6 +570,7 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
                     v[1] = (pEvdev->absinfo[ABS_Y].maximum - v[1] +
                             pEvdev->absinfo[ABS_Y].minimum);
 
+                EvdevKioskTouchMotionEvents(pInfo, abs, v);
                 xf86PostMotionEventP(pInfo->dev, TRUE, 0, pEvdev->num_vals, v);
             }
 
@@ -1378,6 +1378,7 @@ EvdevOn(DeviceIntPtr device)
         xf86FlushInput(pInfo->fd);
         xf86AddEnabledDevice(pInfo);
         EvdevMBEmuOn(pInfo);
+        EvdevKioskTouchOn(pInfo);
         pEvdev->flags |= EVDEV_INITIALIZED;
         device->public.on = TRUE;
     }
@@ -1404,8 +1405,10 @@ EvdevProc(DeviceIntPtr device, int what)
         return EvdevOn(device);
 
     case DEVICE_OFF:
-        if (pEvdev->flags & EVDEV_INITIALIZED)
+        if (pEvdev->flags & EVDEV_INITIALIZED) {
             EvdevMBEmuFinalize(pInfo);
+            EvdevKioskTouchFinalize(pInfo);
+        }
         if (pInfo->fd != -1)
         {
             if (pEvdev->grabDevice && ioctl(pInfo->fd, EVIOCGRAB, (void *)0))
diff --git a/xf86-input-evdev-2.2.5/src/evdev.h b/xf86-input-evdev-2.2.5/src/evdev.h
index 8d29078..eae82df 100644
--- a/xf86-input-evdev-2.2.5/src/evdev.h
+++ b/xf86-input-evdev-2.2.5/src/evdev.h
@@ -164,6 +164,9 @@ typedef struct {
         unsigned int        button;
         unsigned int        abs;
         unsigned int        state;
+        unsigned int        delay;
+        int                 v[2],old_v[2];
+        Time                expires;
     } kioskTouch;
 
     unsigned char btnmap[32];           /* config-file specified button mapping */
@@ -212,9 +215,12 @@ BOOL EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value
 
 /* Kiosk Touch */
 void EvdevKioskTouchPreInit(InputInfoPtr pInfo);
-void EvdevKioskTouchMotionEvents(InputInfoPtr pInfo, unsigned int abs);
+void EvdevKioskTouchMotionEvents(InputInfoPtr pInfo, unsigned int abs, int *v);
 BOOL EvdevKioskTouchFilterButton(InputInfoPtr pInfo, unsigned int button, int value);
 void EvdevKioskTouchSynthButton(InputInfoPtr pInfo);
+void EvdevKioskTouchOn(InputInfoPtr pInfo);
+void EvdevKioskTouchFinalize(InputInfoPtr pInfo);
+
 
 #ifdef HAVE_PROPERTIES
 void EvdevMBEmuInitProperty(DeviceIntPtr);
diff --git a/xf86-input-evdev-2.2.5/src/kioskTouch.c b/xf86-input-evdev-2.2.5/src/kioskTouch.c
index 5a1d4ff..0349ed5 100644
--- a/xf86-input-evdev-2.2.5/src/kioskTouch.c
+++ b/xf86-input-evdev-2.2.5/src/kioskTouch.c
@@ -36,15 +36,19 @@
 #include <evdev-properties.h>
 #include "evdev.h"
 
-#define DEBUG(x) x;
+//#define DEBUG(x) x;
+#define DEBUG(x)
 
 #ifdef HAVE_PROPERTIES
 static Atom prop_ktouch        = 0; /* Kiosk touch emulation on/off property */
 static Atom prop_ktouch_button = 0; /* Kiosk touch emulation button property */
+static Atom prop_ktouch_button_delay = 0; /* Kiosk touch emulation button delay property */
 #endif
 
 #define KTOUCH_STATE_ACTIVE 1U << 0
 #define KTOUCH_STATE_SYNTH  1U << 1
+#define KTOUCH_STATE_DELAY 1U << 2
+#define KTOUCH_STATE_DELAY_MOTION 1U << 3
 
 void
 EvdevKioskTouchPreInit(InputInfoPtr pInfo)
@@ -77,22 +81,69 @@ EvdevKioskTouchPreInit(InputInfoPtr pInfo)
          val = 0;
     }
     pEvdev->kioskTouch.button = val;
+    val = xf86SetIntOption(pInfo->options, "KioskTouchButtonDelay", 0);
+    pEvdev->kioskTouch.delay = val;
     pEvdev->kioskTouch.state = 0;
     pEvdev->kioskTouch.abs = 0;
-    xf86Msg(X_INFO, "%s: KioskTouchpad mode initialized to %s - button: %d\n",
+    xf86Msg(X_INFO, "%s: KioskTouchpad mode initialized to %s - button: %d delay: %d\n",
             pInfo->name, (pEvdev->kioskTouch.mode == 0) ? "disabled" :
             (pEvdev->kioskTouch.mode == 1 ? "click-on-touch" : "click-on-release"),
-            pEvdev->kioskTouch.button);
+            pEvdev->kioskTouch.button, pEvdev->kioskTouch.delay);
 }
 
 void
-EvdevKioskTouchMotionEvents(InputInfoPtr pInfo,  unsigned int abs)
+EvdevKioskTouchMotionEvents(InputInfoPtr pInfo,  unsigned int abs, int *v)
 {
     EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
 
     if (pEvdev->kioskTouch.mode == 1) {
+        DEBUG((ErrorF("EvdevKioskTouchMotionEvents: %x\n",abs)))
         pEvdev->kioskTouch.abs |= abs;
+        if (pEvdev->kioskTouch.state &  KTOUCH_STATE_DELAY) {
+            pEvdev->kioskTouch.v[0] = v[0];
+            v[0] = pEvdev->kioskTouch.old_v[0];
+            pEvdev->kioskTouch.v[1] = v[1];
+            v[1] = pEvdev->kioskTouch.old_v[1];
+            pEvdev->kioskTouch.state |= KTOUCH_STATE_DELAY_MOTION;
+        } else {
+            pEvdev->kioskTouch.old_v[0] = v[0];
+            pEvdev->kioskTouch.old_v[1] = v[1];
+        }
+    }
+}
+
+static BOOL
+EvdevKioskTouchMode2(InputInfoPtr pInfo)
+{
+    EvdevPtr     pEvdev = (EvdevPtr)pInfo->private;
+
+    if (pEvdev->kioskTouch.mode == 2 &&
+             (pEvdev->kioskTouch.state & KTOUCH_STATE_ACTIVE) == KTOUCH_STATE_ACTIVE) {
+        xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 1, 0, 0);
+        xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
+        pEvdev->kioskTouch.state &= ~KTOUCH_STATE_ACTIVE;
+        return 1;
+    }
+    return 0;
+}
+
+
+static BOOL
+EvdevKioskTouchStopButtonTimer(InputInfoPtr pInfo)
+{
+    EvdevPtr     pEvdev = (EvdevPtr)pInfo->private;
+
+    if ((pEvdev->kioskTouch.state & KTOUCH_STATE_DELAY) == 0)
+        return FALSE;
+
+    pEvdev->kioskTouch.state &= ~KTOUCH_STATE_DELAY;
+    xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
+    if (pEvdev->kioskTouch.state & KTOUCH_STATE_DELAY_MOTION) {
+        DEBUG((ErrorF("%s: Sending delayed motion\n",__FUNCTION__)))
+        pEvdev->kioskTouch.state &= ~KTOUCH_STATE_DELAY_MOTION;
+        xf86PostMotionEventP(pInfo->dev, TRUE, 0, 2, pEvdev->kioskTouch.v);
     }
+    return TRUE;
 }
 
 BOOL
@@ -104,41 +155,70 @@ EvdevKioskTouchFilterButton(InputInfoPtr pInfo, unsigned int button, int value)
     if (button && button == pEvdev->kioskTouch.button) {
         switch (pEvdev->kioskTouch.mode) {
         case 0:
-            DEBUG((ErrorF("EvdevKioskTouchFilterButton: mode 1 button %d value %d\n", \
-                          button, value)))
+            DEBUG((ErrorF("EvdevKioskTouchFilterButton: mode 0 button %d value %d\n", \
+                          button, value)));
             if (value == 1)
                 pEvdev->kioskTouch.state = KTOUCH_STATE_ACTIVE;
             else
                 pEvdev->kioskTouch.state = 0;
             return FALSE;
         case 1:
+            DEBUG((ErrorF("EvdevKioskTouchFilterButton: mode 1 button %d value %d "\
+                          "abs:%x\n", button, value, pEvdev->kioskTouch.abs)));
             ret = TRUE;
             if (value == 1) {
                 if ((pEvdev->kioskTouch.abs & (ABS_X | ABS_Y)) == (ABS_X | ABS_Y)) {
-                    DEBUG((ErrorF("Sending ButtonDown/ButtonUp\n")))
+                    DEBUG((ErrorF("Sending ButtonDown\n")))
                     xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
-                    xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
+                    if (pEvdev->kioskTouch.delay > 0) {
+                        pEvdev->kioskTouch.state |= KTOUCH_STATE_DELAY;
+                        pEvdev->kioskTouch.expires = GetTimeInMillis ()
+                            + pEvdev->kioskTouch.delay;
+                    } else {
+                        DEBUG((ErrorF("Sending ButtonUp\n")))
+                        xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
+                    }
                 } else {
                     pEvdev->kioskTouch.state |= KTOUCH_STATE_SYNTH;
                 }
             } else if (value == 0) {
+                DEBUG((ErrorF("EvdevKioskTouchFilterButton: Filter Button UP\n")))
                 if (pEvdev->kioskTouch.state & KTOUCH_STATE_SYNTH) {
                     xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+                    pEvdev->kioskTouch.state = 0;
+                        pEvdev->kioskTouch.abs = 0;
                     ret = FALSE;
-                }
-                pEvdev->kioskTouch.state = 0;
-                pEvdev->kioskTouch.abs = 0;
+                } else {
+                    if (pEvdev->kioskTouch.state & KTOUCH_STATE_DELAY)
+                        EvdevKioskTouchStopButtonTimer(pInfo);
+                    pEvdev->kioskTouch.state = 0;
+                    pEvdev->kioskTouch.abs = 0;
+		}
             }
             return ret;
         case 2:
             DEBUG((ErrorF("EvdevKioskTouchFilterButton: mode 2 button %d value %d\n", \
                           button, value)))
-            if (value == 1)
+            if (value == 1) {
+                pEvdev->kioskTouch.state |= KTOUCH_STATE_ACTIVE;
+                if (pEvdev->kioskTouch.state & KTOUCH_STATE_DELAY)
+                    EvdevKioskTouchStopButtonTimer(pInfo);
                 return TRUE;
-            else if (value == 0) {
-                DEBUG((ErrorF("Sending ButtonDown\n")))
-                xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
-	    }
+            } else if (value == 0) {
+                if ((pEvdev->kioskTouch.state & KTOUCH_STATE_ACTIVE) == 0)
+                    return FALSE;
+                pEvdev->kioskTouch.state &= ~KTOUCH_STATE_ACTIVE;
+                if (pEvdev->kioskTouch.delay > 0) {
+                    pEvdev->kioskTouch.state |= KTOUCH_STATE_DELAY;
+                    pEvdev->kioskTouch.expires = GetTimeInMillis ()
+                        + pEvdev->kioskTouch.delay;
+                    xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+                    return TRUE;
+                } else {
+                    DEBUG((ErrorF("Sending ButtonDown\n")))
+                    xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+                }
+            }
             return FALSE;
         default:
             return FALSE;
@@ -148,6 +228,78 @@ EvdevKioskTouchFilterButton(InputInfoPtr pInfo, unsigned int button, int value)
     return FALSE;
 }
 
+static void
+EvdevKioskTouchWakeupHandler(pointer data,
+                             int i,
+                             pointer LastSelectMask)
+{
+    InputInfoPtr pInfo = (InputInfoPtr)data;
+    EvdevPtr     pEvdev = (EvdevPtr)pInfo->private;
+    int ms;
+
+    if (pEvdev->kioskTouch.state & KTOUCH_STATE_DELAY) {
+        ms = pEvdev->kioskTouch.expires - GetTimeInMillis();
+        if (ms <= 0) {
+            int	sigstate;
+
+            sigstate = xf86BlockSIGIO ();
+            pEvdev->kioskTouch.state &= ~KTOUCH_STATE_DELAY;
+            DEBUG((ErrorF("Delayed ButtonUP\n")))
+            xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
+            if (pEvdev->kioskTouch.state & KTOUCH_STATE_DELAY_MOTION) {
+                 pEvdev->kioskTouch.state &= ~KTOUCH_STATE_DELAY_MOTION;
+                 DEBUG(ErrorF("%s: Sending delayed motion\n",__FUNCTION__))
+                 xf86PostMotionEventP(pInfo->dev, TRUE, 0, 2, pEvdev->kioskTouch.v);
+            }
+            xf86UnblockSIGIO (sigstate);
+        }
+    }
+}
+
+static void
+EvdevKioskTouchBlockHandler(pointer data,
+                            struct timeval **waitTime,
+                            pointer LastSelectMask)
+{
+    InputInfoPtr pInfo = (InputInfoPtr)data;
+    EvdevPtr     pEvdev = (EvdevPtr)pInfo->private;
+    int ms;
+
+    if (pEvdev->kioskTouch.state & KTOUCH_STATE_DELAY) {
+        ms = pEvdev->kioskTouch.expires - GetTimeInMillis ();
+        if (ms <= 0)
+            ms = 0;
+        AdjustWaitForDelay (waitTime, ms);
+    }
+}
+
+void
+EvdevKioskTouchOn(InputInfoPtr pInfo)
+{
+    EvdevPtr     pEvdev = (EvdevPtr)pInfo->private;
+
+    if (pEvdev->kioskTouch.mode == -1)
+        return;
+
+    RegisterBlockAndWakeupHandlers (EvdevKioskTouchBlockHandler,
+                                    EvdevKioskTouchWakeupHandler,
+                                    (pointer)pInfo);
+}
+
+void
+EvdevKioskTouchFinalize(InputInfoPtr pInfo)
+{
+    EvdevPtr     pEvdev = (EvdevPtr)pInfo->private;
+
+    if (pEvdev->kioskTouch.mode == -1)
+        return;
+
+    RemoveBlockAndWakeupHandlers (EvdevKioskTouchBlockHandler,
+                                  EvdevKioskTouchWakeupHandler,
+                                  (pointer)pInfo);
+
+}
+
 void EvdevKioskTouchSynthButton(InputInfoPtr pInfo)
 {
     EvdevPtr     pEvdev = pInfo->private;
@@ -155,9 +307,15 @@ void EvdevKioskTouchSynthButton(InputInfoPtr pInfo)
     if (pEvdev->kioskTouch.mode == 1 &&
         pEvdev->kioskTouch.state & KTOUCH_STATE_SYNTH &&
         (pEvdev->kioskTouch.abs & (ABS_X | ABS_Y)) == (ABS_X | ABS_Y)) {
-        DEBUG((ErrorF("Synthing ButtonDown/ButtonUp\n")))
+        DEBUG((ErrorF("Synthing ButtonDown\n")))
         xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 1, 0, 0);
-        xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
+         if (pEvdev->kioskTouch.delay > 0) {
+             pEvdev->kioskTouch.state |= KTOUCH_STATE_DELAY;
+             pEvdev->kioskTouch.expires = GetTimeInMillis () + pEvdev->kioskTouch.delay;
+         } else {
+             DEBUG((ErrorF("Synthing ButtonUP\n")))
+             xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
+         }
         pEvdev->kioskTouch.state &= ~KTOUCH_STATE_SYNTH;
     }
 }
@@ -176,12 +334,17 @@ EvdevKioskTouchSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
             return BadMatch;
 
         if (!checkonly) {
-            int new_mode = *((CARD8*)val->data);
+            int new_mode =  *((CARD8*)val->data);
             if (new_mode != pEvdev->kioskTouch.mode) {
-                if (pEvdev->kioskTouch.mode == 0 &&
-                    pEvdev->kioskTouch.state & KTOUCH_STATE_ACTIVE)
-                    xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
-		pEvdev->kioskTouch.mode = pEvdev->kioskTouch.mode;
+                if (pEvdev->kioskTouch.mode == 0) {
+                    if (pEvdev->kioskTouch.state & KTOUCH_STATE_ACTIVE)
+                        xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button,
+                                            0, 0, 0);
+                } else {
+                    if (!EvdevKioskTouchMode2(pInfo))
+                        EvdevKioskTouchStopButtonTimer(pInfo);
+                }
+                pEvdev->kioskTouch.mode = new_mode;
                 pEvdev->kioskTouch.state = 0;
                 pEvdev->kioskTouch.abs = 0;
             }
@@ -192,16 +355,27 @@ EvdevKioskTouchSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
             return BadMatch;
 
         if (!checkonly) {
-            int new_button = *((CARD8*)val->data);
+            int new_button =  *((CARD8*)val->data);
             if (new_button != pEvdev->kioskTouch.button) {
-                if (pEvdev->kioskTouch.mode == 0 &&
-                    pEvdev->kioskTouch.state & KTOUCH_STATE_ACTIVE)
-                    xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
-		pEvdev->kioskTouch.button =  pEvdev->kioskTouch.button;
+                if (pEvdev->kioskTouch.mode == 0) {
+                    if (pEvdev->kioskTouch.state & KTOUCH_STATE_ACTIVE)
+                        xf86PostButtonEvent(pInfo->dev, 0, pEvdev->kioskTouch.button, 0, 0, 0);
+                } else {
+                    if (!EvdevKioskTouchMode2(pInfo))
+                        EvdevKioskTouchStopButtonTimer(pInfo);
+                }
+		pEvdev->kioskTouch.button = new_button;
                 pEvdev->kioskTouch.state = 0;
                 pEvdev->kioskTouch.abs = 0;
             }
         }
+    } else if (atom == prop_ktouch_button_delay) {
+        if (val->format != 16 || val->size != 1 || val->type != XA_INTEGER)
+            return BadMatch;
+
+        if (!checkonly) {
+            pEvdev->kioskTouch.delay = *((CARD16*)val->data);
+        }
     }
 
     return Success;
@@ -236,6 +410,16 @@ EvdevKioskTouchInitProperty(DeviceIntPtr dev)
         return;
     XISetDevicePropertyDeletable(dev, prop_ktouch_button, FALSE);
 
+    prop_ktouch_button_delay =
+        MakeAtom(EVDEV_PROP_KIOSK_BUTTON_DELAY, strlen(EVDEV_PROP_KIOSK_BUTTON_DELAY), TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_ktouch_button_delay, XA_INTEGER, 16,
+                                PropModeReplace, 1,
+                                &pEvdev->kioskTouch.delay,
+                                FALSE);
+    if (rc != Success)
+        return;
+    XISetDevicePropertyDeletable(dev, prop_ktouch_button_delay, FALSE);
+
     XIRegisterPropertyHandler(dev, EvdevKioskTouchSetProperty, NULL, NULL);
 }
 #endif
