From: Egbert Eich <eich@suse.de>
Date: Tue Mar 8 21:17:55 2016 +0100
Subject: [PATCH 1/2]Add a 'kiosk mode' for touch screens
Patch-mainline: never
Git-commit: f29f5d5cc247013552809e43dff2e12b5e22a86e
References: FATE#319647, bsc#967836
Signed-off-by: Egbert Eich <eich@suse.com>

This mode provides either a 'click-on-touch' or
'click-on-release'. The button to track can be
specified with an option.

Signed-off-by: Egbert Eich <eich@suse.de>
---
 xf86-input-evdev-2.2.5/include/evdev-properties.h |   4 +
 xf86-input-evdev-2.2.5/man/evdev.man              |  20 ++
 xf86-input-evdev-2.2.5/src/Makefile.am            |   3 +-
 xf86-input-evdev-2.2.5/src/evdev.c                |  22 +-
 xf86-input-evdev-2.2.5/src/evdev.h                |  27 +++
 xf86-input-evdev-2.2.5/src/kioskTouch.c           | 241 ++++++++++++++++++++++
 6 files changed, 301 insertions(+), 16 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 31f6c66..7b6d831 100644
--- a/xf86-input-evdev-2.2.5/include/evdev-properties.h
+++ b/xf86-input-evdev-2.2.5/include/evdev-properties.h
@@ -50,6 +50,10 @@
 /* CARD8, either 1 value or pairs, value range 0-32, 0 to disable a value*/
 #define EVDEV_PROP_DRAGLOCK "Evdev Drag Lock Buttons"
 
+/* Kiosk Touch mode */
+#define EVDEV_PROP_KIOSK_TOUCH "Evdev Kiosk Touch Mode"
+#define EVDEV_PROP_KIOSK_BUTTON "Evdev Kiosk Touch Button"
+
 /* Axis inversion */
 /* BOOL, 2 values [x, y], 1 inverts axis */
 #define EVDEV_PROP_INVERT_AXES "Evdev Axis Inversion"
diff --git a/xf86-input-evdev-2.2.5/man/evdev.man b/xf86-input-evdev-2.2.5/man/evdev.man
index 9efa2a8..6012493 100644
--- a/xf86-input-evdev-2.2.5/man/evdev.man
+++ b/xf86-input-evdev-2.2.5/man/evdev.man
@@ -172,6 +172,20 @@ is mapped to the negative Y axis motion and button number
 .I N2
 is mapped to the positive Y axis motion.  Default: "4 5". Property:
 "Evdev Wheel Emulation Axes".
+.TP 7
+.BI "Option \*qKioskTouchMode\*q \*q" "N" \*q
+Specifies the Kiosk Touch mode to use. Mode
+.I N
+sets the mode: 0 - off, 1 - click on touch, 2 - click on release.
+Default: "0". Property:
+"Evdev Kiosk Touch Mode".
+.TP 7
+.BI "Option \*qKioskTouchButton\*q \*q" "N" \*q
+Specifies the Kiosk Touch button number to use. Button
+.I N
+range: 0-255.
+Default: "0". Property:
+"Evdev Kiosk Touch Button".
 
 .SH SUPPORTED PROPERTIES
 The following properties are provided by the
@@ -214,6 +228,12 @@ value.
 .TP 7
 .BI "Evdev Wheel Emulation Timeout"
 1 16-bit positive value.
+.TP 7
+.BI "Evdev Kiosk Touch Mode"
+1 8-bit positive value.
+.TP 7
+.BI "Evdev Kiosk Touch Button"
+1 8-bit positive value.
 
 .SH AUTHORS
 Kristian Høgsberg.
diff --git a/xf86-input-evdev-2.2.5/src/Makefile.am b/xf86-input-evdev-2.2.5/src/Makefile.am
index 2b6c800..e7a38ed 100644
--- a/xf86-input-evdev-2.2.5/src/Makefile.am
+++ b/xf86-input-evdev-2.2.5/src/Makefile.am
@@ -36,5 +36,6 @@ INCLUDES=-I$(top_srcdir)/include/
                                @DRIVER_NAME@.h \
                                emuMB.c \
                                emuWheel.c \
-                               draglock.c
+                               draglock.c \
+                               kioskTouch.c
 
diff --git a/xf86-input-evdev-2.2.5/src/evdev.c b/xf86-input-evdev-2.2.5/src/evdev.c
index f376ce6..7bf869d 100644
--- a/xf86-input-evdev-2.2.5/src/evdev.c
+++ b/xf86-input-evdev-2.2.5/src/evdev.c
@@ -79,19 +79,6 @@
 
 #define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
 
-/* evdev flags */
-#define EVDEV_KEYBOARD_EVENTS	(1 << 0)
-#define EVDEV_BUTTON_EVENTS	(1 << 1)
-#define EVDEV_RELATIVE_EVENTS	(1 << 2)
-#define EVDEV_ABSOLUTE_EVENTS	(1 << 3)
-#define EVDEV_TOUCHPAD		(1 << 4)
-#define EVDEV_INITIALIZED	(1 << 5) /* WheelInit etc. called already? */
-#define EVDEV_TOUCHSCREEN	(1 << 6)
-#define EVDEV_CALIBRATED	(1 << 7) /* run-time calibrated? */
-#define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
-#define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
-
-
 #define MIN_KEYCODE 8
 #define GLYPHS_PER_KEY 2
 #define AltMask		Mod1Mask
@@ -463,6 +450,9 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
                     if (EvdevWheelEmuFilterButton(pInfo, button, value))
                         break;
 
+                    if (EvdevKioskTouchFilterButton(pInfo, button, value))
+                        break;
+
                     if (EvdevMBEmuFilterEvent(pInfo, button, value))
                         break;
 
@@ -509,6 +499,7 @@ 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 */
@@ -583,6 +574,7 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
                 xf86PostMotionEventP(pInfo->dev, TRUE, 0, pEvdev->num_vals, v);
             }
 
+            EvdevKioskTouchSynthButton(pInfo);
 	    if (pEvdev->is_cooltouch) {
 		if (!pEvdev->touching && (pEvdev->touch_ev_rec & 1)) {
 		    button = EvdevUtilButtonEventToButtonNumber(pEvdev, BTN_LEFT);
@@ -650,8 +642,6 @@ EvdevReadInput(InputInfoPtr pInfo)
     }
 }
 
-#define TestBit(bit, array) ((array[(bit) / LONG_BITS]) & (1L << ((bit) % LONG_BITS)))
-
 static void
 EvdevPtrCtrlProc(DeviceIntPtr device, PtrCtrl *ctrl)
 {
@@ -1333,6 +1323,7 @@ EvdevInit(DeviceIntPtr device)
     EvdevMBEmuInitProperty(device);
     EvdevWheelEmuInitProperty(device);
     EvdevDragLockInitProperty(device);
+    EvdevKioskTouchInitProperty(device);
 #endif
 
     return Success;
@@ -1917,6 +1908,7 @@ EvdevPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
         EvdevWheelEmuPreInit(pInfo);
         EvdevDragLockPreInit(pInfo);
     }
+    EvdevKioskTouchPreInit(pInfo);
 
     return pInfo;
 }
diff --git a/xf86-input-evdev-2.2.5/src/evdev.h b/xf86-input-evdev-2.2.5/src/evdev.h
index 6efb777..8d29078 100644
--- a/xf86-input-evdev-2.2.5/src/evdev.h
+++ b/xf86-input-evdev-2.2.5/src/evdev.h
@@ -87,6 +87,20 @@ typedef struct {
     int traveled_distance;
 } WheelAxis, *WheelAxisPtr;
 
+/* evdev flags */
+#define EVDEV_KEYBOARD_EVENTS	(1 << 0)
+#define EVDEV_BUTTON_EVENTS	(1 << 1)
+#define EVDEV_RELATIVE_EVENTS	(1 << 2)
+#define EVDEV_ABSOLUTE_EVENTS	(1 << 3)
+#define EVDEV_TOUCHPAD		(1 << 4)
+#define EVDEV_INITIALIZED	(1 << 5) /* WheelInit etc. called already? */
+#define EVDEV_TOUCHSCREEN	(1 << 6)
+#define EVDEV_CALIBRATED	(1 << 7) /* run-time calibrated? */
+#define EVDEV_UNIGNORE_ABSOLUTE (1 << 9) /* explicitly unignore abs axes */
+#define EVDEV_UNIGNORE_RELATIVE (1 << 10) /* explicitly unignore rel axes */
+
+#define TestBit(bit, array) ((array[(bit) / LONG_BITS]) & (1L << ((bit) % LONG_BITS)))
+
 typedef struct {
     const char *device;
     int grabDevice;         /* grab the event device? */
@@ -145,6 +159,12 @@ typedef struct {
         int                 min_y;
         int                 max_y;
     } calibration;
+    struct {
+        int                 mode; /* 0: 0ff, 1: click on touch, 2: click on release */
+        unsigned int        button;
+        unsigned int        abs;
+        unsigned int        state;
+    } kioskTouch;
 
     unsigned char btnmap[32];           /* config-file specified button mapping */
 
@@ -190,9 +210,16 @@ BOOL EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv);
 void EvdevDragLockPreInit(InputInfoPtr pInfo);
 BOOL EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value);
 
+/* Kiosk Touch */
+void EvdevKioskTouchPreInit(InputInfoPtr pInfo);
+void EvdevKioskTouchMotionEvents(InputInfoPtr pInfo, unsigned int abs);
+BOOL EvdevKioskTouchFilterButton(InputInfoPtr pInfo, unsigned int button, int value);
+void EvdevKioskTouchSynthButton(InputInfoPtr pInfo);
+
 #ifdef HAVE_PROPERTIES
 void EvdevMBEmuInitProperty(DeviceIntPtr);
 void EvdevWheelEmuInitProperty(DeviceIntPtr);
 void EvdevDragLockInitProperty(DeviceIntPtr);
+void EvdevKioskTouchInitProperty(DeviceIntPtr);
 #endif
 #endif
diff --git a/xf86-input-evdev-2.2.5/src/kioskTouch.c b/xf86-input-evdev-2.2.5/src/kioskTouch.c
new file mode 100644
index 0000000..5a1d4ff
--- /dev/null
+++ b/xf86-input-evdev-2.2.5/src/kioskTouch.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2016 Egbert Eich
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the authors
+ * not be used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  The authors make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/Xatom.h>
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <xorgVersion.h>
+
+#include <evdev-properties.h>
+#include "evdev.h"
+
+#define DEBUG(x) 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 */
+#endif
+
+#define KTOUCH_STATE_ACTIVE 1U << 0
+#define KTOUCH_STATE_SYNTH  1U << 1
+
+void
+EvdevKioskTouchPreInit(InputInfoPtr pInfo)
+{
+    EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+    int val;
+
+    if (!(pEvdev->flags & EVDEV_ABSOLUTE_EVENTS) ||
+        (pEvdev->flags & EVDEV_RELATIVE_EVENTS) ||
+        (pEvdev->flags & EVDEV_TOUCHPAD) ||
+	!(pEvdev->flags & EVDEV_BUTTON_EVENTS) ||
+        !TestBit(ABS_X, pEvdev->abs_bitmask) ||
+        !TestBit(ABS_Y, pEvdev->abs_bitmask) ||
+        pEvdev->is_cooltouch) {
+        pEvdev->kioskTouch.mode = -1;
+        return;
+    }
+    val = xf86SetIntOption(pInfo->options, "KioskTouchMode", 0);
+    if (val < 0 || val > 2) {
+        xf86Msg(X_WARNING, "%s: Invalid KioskTouchMode value: %d\n",
+                pInfo->name, val);
+        pEvdev->kioskTouch.mode = 0;
+    } else {
+        pEvdev->kioskTouch.mode = val;
+    }
+    val = xf86SetIntOption(pInfo->options, "KioskTouchButton", 1);
+    if (val > 255) {
+         xf86Msg(X_WARNING, "%s: Invalid KioskTouchButton value: %d\n",
+                pInfo->name, val);
+         val = 0;
+    }
+    pEvdev->kioskTouch.button = val;
+    pEvdev->kioskTouch.state = 0;
+    pEvdev->kioskTouch.abs = 0;
+    xf86Msg(X_INFO, "%s: KioskTouchpad mode initialized to %s - button: %d\n",
+            pInfo->name, (pEvdev->kioskTouch.mode == 0) ? "disabled" :
+            (pEvdev->kioskTouch.mode == 1 ? "click-on-touch" : "click-on-release"),
+            pEvdev->kioskTouch.button);
+}
+
+void
+EvdevKioskTouchMotionEvents(InputInfoPtr pInfo,  unsigned int abs)
+{
+    EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+
+    if (pEvdev->kioskTouch.mode == 1) {
+        pEvdev->kioskTouch.abs |= abs;
+    }
+}
+
+BOOL
+EvdevKioskTouchFilterButton(InputInfoPtr pInfo, unsigned int button, int value)
+{
+    EvdevPtr pEvdev = (EvdevPtr)pInfo->private;
+    int ret;
+
+    if (button && button == pEvdev->kioskTouch.button) {
+        switch (pEvdev->kioskTouch.mode) {
+        case 0:
+            DEBUG((ErrorF("EvdevKioskTouchFilterButton: mode 1 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:
+            ret = TRUE;
+            if (value == 1) {
+                if ((pEvdev->kioskTouch.abs & (ABS_X | ABS_Y)) == (ABS_X | ABS_Y)) {
+                    DEBUG((ErrorF("Sending ButtonDown/ButtonUp\n")))
+                    xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+                    xf86PostButtonEvent(pInfo->dev, 0, button, 0, 0, 0);
+                } else {
+                    pEvdev->kioskTouch.state |= KTOUCH_STATE_SYNTH;
+                }
+            } else if (value == 0) {
+                if (pEvdev->kioskTouch.state & KTOUCH_STATE_SYNTH) {
+                    xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+                    ret = FALSE;
+                }
+                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)
+                return TRUE;
+            else if (value == 0) {
+                DEBUG((ErrorF("Sending ButtonDown\n")))
+                xf86PostButtonEvent(pInfo->dev, 0, button, 1, 0, 0);
+	    }
+            return FALSE;
+        default:
+            return FALSE;
+        }
+    }
+
+    return FALSE;
+}
+
+void EvdevKioskTouchSynthButton(InputInfoPtr pInfo)
+{
+    EvdevPtr     pEvdev = pInfo->private;
+
+    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")))
+        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_SYNTH;
+    }
+}
+
+#ifdef HAVE_PROPERTIES
+static int
+EvdevKioskTouchSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+                           BOOL checkonly)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevPtr     pEvdev = pInfo->private;
+
+    if (atom == prop_ktouch)
+    {
+        if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+            return BadMatch;
+
+        if (!checkonly) {
+            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;
+                pEvdev->kioskTouch.state = 0;
+                pEvdev->kioskTouch.abs = 0;
+            }
+        }
+    } else if (atom == prop_ktouch_button) {
+
+        if (val->format != 8 || val->size != 1 || val->type != XA_INTEGER)
+            return BadMatch;
+
+        if (!checkonly) {
+            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;
+                pEvdev->kioskTouch.state = 0;
+                pEvdev->kioskTouch.abs = 0;
+            }
+        }
+    }
+
+    return Success;
+}
+
+void
+EvdevKioskTouchInitProperty(DeviceIntPtr dev)
+{
+    InputInfoPtr pInfo  = dev->public.devicePrivate;
+    EvdevPtr     pEvdev = pInfo->private;
+    int          rc;
+
+    if (pEvdev->kioskTouch.mode < 0)
+        return;
+
+    prop_ktouch = MakeAtom(EVDEV_PROP_KIOSK_TOUCH, strlen(EVDEV_PROP_KIOSK_TOUCH), TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_ktouch, XA_INTEGER, 8,
+                                PropModeReplace, 1,
+                                &pEvdev->kioskTouch.mode,
+                                FALSE);
+    if (rc != Success)
+        return;
+    XISetDevicePropertyDeletable(dev, prop_ktouch, FALSE);
+
+    prop_ktouch_button = MakeAtom(EVDEV_PROP_KIOSK_BUTTON, strlen(EVDEV_PROP_KIOSK_BUTTON),
+                                 TRUE);
+    rc = XIChangeDeviceProperty(dev, prop_ktouch_button, XA_INTEGER, 8,
+                                PropModeReplace, 1,
+                                &pEvdev->kioskTouch.button,
+                                FALSE);
+    if (rc != Success)
+        return;
+    XISetDevicePropertyDeletable(dev, prop_ktouch_button, FALSE);
+
+    XIRegisterPropertyHandler(dev, EvdevKioskTouchSetProperty, NULL, NULL);
+}
+#endif
