summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Bruguier <nicolas.bruguier@supersonicimagine.fr>2009-05-19 21:50:49 +0200
committerNicolas Bruguier <nicolas.bruguier@supersonicimagine.fr>2009-05-19 21:50:49 +0200
commitd4d578a0481aa54f1df920b0a2903b8679256679 (patch)
tree150759f32e6ca7077b066ac96f0f231e0b3f5f1e
Initial import
-rw-r--r--.gitignore29
-rw-r--r--COPYING44
-rw-r--r--Makefile.am40
-rw-r--r--README20
-rwxr-xr-xautogen.sh12
-rw-r--r--configure.ac85
-rw-r--r--include/Makefile.am2
-rw-r--r--include/evtouch2-properties.h89
-rw-r--r--man/Makefile.am60
-rw-r--r--man/evtouch2.man206
-rw-r--r--src/Makefile.am39
-rw-r--r--src/evtouch2.c1649
-rw-r--r--src/evtouch2.h148
-rw-r--r--src/libtouch.c922
-rw-r--r--src/libtouch.h79
-rw-r--r--xorg-evtouch2.pc.in6
16 files changed, 3430 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8b4bf1d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,29 @@
+*.patch
+ChangeLog
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libtool
+ltmain.sh
+man/evdev.4
+missing
+.deps
+.libs
+*.lo
+*.la
+stamp-h1
+xf86-input-evdev-*.tar.*
+*.pc
+*~
+tags
+*.anjuta
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..076536c
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,44 @@
+Various copyright notices found in this driver:
+
+Copyright 2004 by Kenan Esau <kenan.esau@conan.de>, Baltmannsweiler,
+Germany.
+
+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 names of copyright holders not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. The copyright holders
+make no representations about the suitability of this
+software for any purpose. It is provided "as is" without express or
+implied warranty.
+
+THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
+
+Copyright © 2005-2009 by SuperSonic Imagine, SA
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..10e3e0b
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,40 @@
+# Copyright 2005 Adam Jackson.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+AUTOMAKE_OPTIONS = foreign
+
+# Ensure headers are installed below $(prefix) for distcheck
+DISTCHECK_CONFIGURE_FLAGS = --with-sdkdir='$${includedir}/xorg'
+
+SUBDIRS = src man include
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = xorg-evtouch2.pc
+
+EXTRA_DIST = ChangeLog
+
+MAINTAINERCLEANFILES=ChangeLog
+
+.PHONY: ChangeLog
+
+ChangeLog:
+ $(CHANGELOG_CMD)
+
+dist-hook: ChangeLog
diff --git a/README b/README
new file mode 100644
index 0000000..e98a027
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+xf86-input-evtouch2 - Touchscreen input driver for the Xorg X server
+
+Please submit bugs & patches to the Xorg bugzilla:
+
+ https://bugs.freedesktop.org/enter_bug.cgi?product=xorg
+
+All questions regarding this software should be directed at the
+Xorg mailing list:
+
+ http://lists.freedesktop.org/mailman/listinfo/xorg
+
+The master development code repository can be found at:
+
+ git://anongit.freedesktop.org/git/xorg/driver/xf86-input-evtouch2
+
+ http://cgit.freedesktop.org/xorg/driver/xf86-input-evtouch2
+
+For more information on the git code manager, see:
+
+ http://wiki.x.org/wiki/GitPage
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..904cd67
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..6d47cf0
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,85 @@
+# Copyright 2009 Nicolas Bruguier.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Process this file with autoconf to produce a configure script
+
+AC_PREREQ(2.57)
+AC_INIT([xf86-input-evtouch2],
+ 0.1.0,
+ [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
+ xf86-input-evtouch2)
+
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_AUX_DIR(.)
+AM_INIT_AUTOMAKE([dist-bzip2])
+
+AM_MAINTAINER_MODE
+
+# Require xorg-macros: XORG_CWARNFLAGS, XORG_CHANGELOG
+m4_ifndef([XORG_MACROS_VERSION], [AC_FATAL([must install xorg-macros 1.2 or later before running autoconf/autogen])])
+XORG_MACROS_VERSION(1.2)
+AM_CONFIG_HEADER([config.h])
+
+# Checks for programs.
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_PROG_CC
+XORG_CWARNFLAGS
+
+AH_TOP([#include "xorg-server.h"])
+
+AC_ARG_WITH(xorg-module-dir,
+ AC_HELP_STRING([--with-xorg-module-dir=DIR],
+ [Default xorg module directory [[default=$libdir/xorg/modules]]]),
+ [moduledir="$withval"],
+ [moduledir="$libdir/xorg/modules"])
+inputdir=${moduledir}/input
+AC_SUBST(inputdir)
+
+# Checks for extensions
+XORG_DRIVER_CHECK_EXT(XINPUT, inputproto)
+
+# Checks for pkg-config packages. We need to be able to override sdkdir
+# to satisfy silly distcheck requirements.
+PKG_CHECK_MODULES(XORG, xorg-server xproto $REQUIRED_MODULES)
+XORG_CFLAGS="$CWARNFLAGS $XORG_CFLAGS"
+AC_ARG_WITH([sdkdir], [],
+ [sdkdir="$withval"],
+ [sdkdir=`$PKG_CONFIG --variable=sdkdir xorg-server`])
+AC_SUBST([sdkdir])
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_HEADER_STDC
+
+DRIVER_NAME=evtouch2
+AC_SUBST([DRIVER_NAME])
+
+XORG_MANPAGE_SECTIONS
+XORG_RELEASE_VERSION
+XORG_CHANGELOG
+
+AC_OUTPUT([Makefile
+ src/Makefile
+ man/Makefile
+ include/Makefile
+ xorg-evtouch2.pc])
+
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..3f7fae5
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = evtouch2-properties.h
+sdk_HEADERS = evtouch2-properties.h
diff --git a/include/evtouch2-properties.h b/include/evtouch2-properties.h
new file mode 100644
index 0000000..df054e6
--- /dev/null
+++ b/include/evtouch2-properties.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2005-2009 by SuperSonic Imagine, SA
+ *
+ * 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 Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes 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.
+ *
+ * Authors:
+ * Nicolas Bruguier (nicolas.bruguier@supersonicimagine.fr)
+ */
+
+
+#ifndef _EVTOUCH2_PROPERTIES_H_
+#define _EVTOUCH2_PROPERTIES_H_
+
+/* Screen number */
+/* CARD16 */
+#define EVTOUCH2_PROP_SCREEN "Evtouch2 Screen (Read Only)"
+
+/* Touch has button click */
+/* CARD8 */
+#define EVTOUCH2_PROP_TOUCH_BUTTON "Evtouch2 Touch Button Emulation"
+
+/* Middle mouse button emulation */
+/* BOOL */
+#define EVTOUCH2_PROP_EMULATE3 "Evtouch2 Middle Button Emulation"
+/* CARD16 */
+#define EVTOUCH2_PROP_EMULATE3_TIMEOUT "Evtouch2 Middle Button Timeout"
+
+/* Axis inversion */
+/* BOOL, 2 values [x, y], 1 inverts axis */
+#define EVTOUCH2_PROP_INVERT_AXES "Evtouch2 Axis Inversion"
+
+/* Swap x and y axis. */
+/* BOOL */
+#define EVTOUCH2_PROP_SWAP_AXES "Evtouch2 Axes Swap"
+
+/* Rotation */
+/* CARD8 */
+#define EVTOUCH2_PROP_ROTATION "Evtouch2 Rotation"
+
+/* Pan viewport */
+/* CARD32, 4 values [x, y, width, height], or no values for unset */
+#define EVTOUCH2_PROP_PAN_VIEWPORT "Evtouch2 Pan Viewport"
+
+/* Run-time calibration */
+/* BOOL */
+#define EVTOUCH2_PROP_CALIBRATION "Evtouch2 Start/Stop Calibration"
+/* CARD32, 4 values [minx, maxx, miny, maxy], or no values for unset */
+#define EVTOUCH2_PROP_CALIBRATION_MAX_MIN "Evtouch2 Axis Calibration"
+/* CARD32, 18 values, or no values for unset */
+#define EVTOUCH2_PROP_CALIBRATION_DIFF "Evtouch2 Axis Diff Calibration"
+
+/* Debug Level property */
+/* CARD8 */
+#define EVTOUCH2_PROP_DEBUG_LEVEL "Evtouch2 Debug Level"
+
+/* Tap Timeout property */
+/* CARD16 */
+#define EVTOUCH2_PROP_TAP_TIMEOUT "Evtouch2 Tap Timeout"
+
+/* LongTouch Timeout property */
+/* CARD16 */
+#define EVTOUCH2_PROP_LONGTOUCH_TIMEOUT "Evtouch2 Long Touch Timeout"
+
+/* Move Limit property */
+/* CARD16 */
+#define EVTOUCH2_PROP_MOVE_LIMIT "Evtouch2 Move Limit"
+
+/* State property */
+/* CARD16, 2 values [button, action] */
+#define EVTOUCH2_PROP_STATE "Evtouch2 %s Button and Action"
+
+#endif
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..76c51fc
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,60 @@
+# Copyright © 2005-2009 by SuperSonic Imagine, SA
+#
+# 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.
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the copyright holders shall
+# not be used in advertising or otherwise to promote the sale, use or
+# other dealings in this Software without prior written authorization
+# from the copyright holders.
+#
+# Authors:
+# Nicolas Bruguier (nicolas.bruguier@supersonicimagine.fr)
+#
+
+drivermandir = $(DRIVER_MAN_DIR)
+
+driverman_PRE = @DRIVER_NAME@.man
+
+driverman_DATA = $(driverman_PRE:man=@DRIVER_MAN_SUFFIX@)
+
+EXTRA_DIST = @DRIVER_NAME@.man
+
+CLEANFILES = $(driverman_DATA)
+
+SED = sed
+
+# Strings to replace in man pages
+XORGRELSTRING = @PACKAGE_STRING@
+ XORGMANNAME = X Version 11
+
+MAN_SUBSTS = \
+ -e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
+ -e 's|__xservername__|Xorg|g' \
+ -e 's|__xconfigfile__|xorg.conf|g' \
+ -e 's|__projectroot__|$(prefix)|g' \
+ -e 's|__appmansuffix__|$(APP_MAN_SUFFIX)|g' \
+ -e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' \
+ -e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \
+ -e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \
+ -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'
+
+SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man
+
+.man.$(DRIVER_MAN_SUFFIX):
+ sed $(MAN_SUBSTS) < $< > $@
diff --git a/man/evtouch2.man b/man/evtouch2.man
new file mode 100644
index 0000000..b6ad1f1
--- /dev/null
+++ b/man/evtouch2.man
@@ -0,0 +1,206 @@
+.\" shorthand for double quote that works everywhere.
+.ds q \N'34'
+.TH EVDEV __drivermansuffix__ __vendorversion__
+.SH NAME
+evdev \- Generic Linux input driver
+.SH SYNOPSIS
+.nf
+.B "Section \*qInputDevice\*q"
+.BI " Identifier \*q" devname \*q
+.B " Driver \*qevdev\*q"
+.BI " Option \*qDevice\*q \*q" devpath \*q
+.BI " Option \*qEmulate3Buttons\*q \*q" True \*q
+.BI " Option \*qEmulate3Timeout\*q \*q" 50 \*q
+.BI " Option \*qGrabDevice\*q \*q" False \*q
+\ \ ...
+.B EndSection
+.fi
+.SH DESCRIPTION
+.B evdev
+is an __xservername__ input driver for Linux\'s generic event devices. It
+therefore supports all input devices that the kernel knows about, including
+most mice and keyboards.
+.PP
+The
+.B evdev
+driver can serve as both a pointer and a keyboard input device, and may be
+used as both the core keyboard and the core pointer. Multiple input devices
+are supported by multiple instances of this driver, with one Load
+directive for evdev in the Module section of your __xconfigfile__ for each
+input device that will use this driver.
+.PP
+.SH SUPPORTED HARDWARE
+In general, any input device that the kernel has a driver for can be accessed
+through the
+.B evdev
+driver. See the Linux kernel documentation for a complete list.
+.PP
+.SH CONFIGURATION DETAILS
+Please refer to __xconfigfile__(__filemansuffix__) for general configuration
+details and for options that can be used with all input drivers. This
+section only covers configuration details specific to this driver.
+.PP
+The following driver
+.B Options
+are supported:
+.TP 7
+.BI "Option \*qButtonMapping\*q \*q" string \*q
+Sets the button mapping for this device. The mapping is a space-separated list
+of button mappings that correspond in order to the physical buttons on the
+device (i.e. the first number is the mapping for button 1, etc.). The default
+mapping is "1 2 3 ... 32". A mapping of 0 deactivates the button. Multiple
+buttons can have the same mapping.
+For example, a left-handed mouse with deactivated scroll-wheel would use a
+mapping of "3 2 1 0 0". Invalid mappings are ignored and the default mapping
+is used. Buttons not specified in the user's mapping use the default mapping.
+.TP 7
+.BI "Option \*qDevice\*q \*q" string \*q
+Specifies the device through which the device can be accessed. This will
+generally be of the form \*q/dev/input/eventX\*q, where X is some integer.
+The mapping from device node to hardware is system-dependent.
+.TP 7
+.BI "Option \*qDragLockButtons\*q \*q" "L1 B2 L3 B4" \*q
+Sets \*qdrag lock buttons\*q that simulate holding a button down, so
+that low dexterity people do not have to hold a button down at the
+same time they move a mouse cursor. Button numbers occur in pairs,
+with the lock button number occurring first, followed by the button
+number that is the target of the lock button. Property: "Evdev
+Drag Lock Buttons".
+.TP 7
+.BI "Option \*qDragLockButtons\*q \*q" "M1" \*q
+Sets a \*qmaster drag lock button\*q that acts as a \*qMeta Key\*q
+indicating that the next button pressed is to be
+\*qdrag locked\*q. Property: "Evdev Drag Lock Buttons".
+.TP 7
+.TP 7
+.BI "Option \*qEmulate3Buttons\*q \*q" boolean \*q
+Enable/disable the emulation of the third (middle) mouse button for mice
+which only have two physical buttons. The third button is emulated by
+pressing both buttons simultaneously. Default: on, until a middle mouse
+button event is registered. Property: "Evdev Middle Button Emulation".
+.TP 7
+.BI "Option \*qEmulate3Timeout\*q \*q" integer \*q
+Sets the timeout (in milliseconds) that the driver waits before deciding
+if two buttons where pressed "simultaneously" when 3 button emulation is
+enabled. Default: 50. Property: "Evdev Middle Button Timeout".
+.BI "Option \*qEmulateWheel\*q \*q" boolean \*q
+Enable/disable "wheel" emulation. Wheel emulation means emulating button
+press/release events when the mouse is moved while a specific real button
+is pressed. Wheel button events (typically buttons 4 and 5) are
+usually used for scrolling. Wheel emulation is useful for getting wheel-like
+behaviour with trackballs. It can also be useful for mice with 4 or
+more buttons but no wheel. See the description of the
+.BR EmulateWheelButton ,
+.BR EmulateWheelInertia ,
+.BR EmulateWheelTimeout ,
+.BR XAxisMapping ,
+and
+.B YAxisMapping
+options. Default: off. Property "Evdev Wheel Emulation".
+.TP 7
+.BI "Option \*qEmulateWheelButton\*q \*q" integer \*q
+Specifies which button must be held down to enable wheel emulation mode.
+While this button is down, X and/or Y pointer movement will generate button
+press/release events as specified for the
+.B XAxisMapping
+and
+.B YAxisMapping
+settings. Default: 4. Property: "Evdev Wheel Emulation Button".
+.TP 7
+.BI "Option \*qEmulateWheelInertia\*q \*q" integer \*q
+Specifies how far (in pixels) the pointer must move to generate button
+press/release events in wheel emulation mode. Default: 10. Property: "Evdev
+Wheel Emulation Inertia".
+.TP 7
+.BI "Option \*qEmulateWheelTimeout\*q \*q" integer \*q
+Specifies the time in milliseconds the
+.BR EmulateWheelButton
+must be pressed before wheel emulation is started. If the
+.BR EmulateWheelButton
+is released before this timeout, the original button press/release event
+is sent. Default: 200. Property: "Evdev Wheel Emulation Timeout".
+.TP 7
+.BI "Option \*qGrabDevice\*q \*q" boolean \*q
+Force a grab on the event device. Doing so will ensure that no other driver
+can initialise the same device and it will also stop the device from sending
+events to /dev/kbd or /dev/input/mice. Events from this device will not be
+sent to virtual devices (e.g. rfkill or the Macintosh mouse button emulation).
+Default: disabled.
+.TP 7
+.BI "Option \*qInvertX\*q \*q" Bool \*q
+.TP 7
+.BI "Option \*qInvertY\*q \*q" Bool \*q
+Invert the given axis. Default: off. Property: "Evdev Axis Inversion".
+.TP 7
+.BI "Option \*qReopenAttempts\*q \*q" integer \*q
+Number of reopen attempts after a read error occurs on the device (e.g. after
+waking up from suspend). In between each attempt is a 100ms wait. Default: 10.
+.TP 7
+.BI "Option \*qSwapAxes\*q \*q" Bool \*q
+Swap x/y axes. Default: off. Property: "Evdev Axes Swap".
+.TP 7
+.BI "Option \*qXAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the X direction in wheel
+emulation mode. Button number
+.I N1
+is mapped to the negative X axis motion and button number
+.I N2
+is mapped to the positive X axis motion. Default: no mapping. Property:
+"Evdev Wheel Emulation Axes".
+.TP 7
+.BI "Option \*qYAxisMapping\*q \*q" "N1 N2" \*q
+Specifies which buttons are mapped to motion in the Y direction in wheel
+emulation mode. Button number
+.I N1
+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".
+
+.SH SUPPORTED PROPERTIES
+The following properties are provided by the
+.B evdev
+driver.
+.TP 7
+.BI "Evdev Axis Calibration"
+4 32-bit values, order min-x, max-x, min-y, max-y or 0 values to disable
+run-time axis calibration. This feature is required for devices that need to
+scale to a different coordinate system than originally reported to the X
+server, such as touchscreens that require run-time calibration.
+.TP 7
+.BI "Evdev Axis Inversion"
+2 boolean values (8 bit, 0 or 1), order X, Y. 1 inverts the axis.
+.TP 7
+.BI "Evdev Axis Swap"
+1 boolean value (8 bit, 0 or 1). 1 swaps x/y axes.
+.TP 7
+.BI "Evdev Drag Lock Buttons"
+8-bit. Either 1 value or pairs of values. Value range 0-32, 0 disables a
+value.
+.TP 7
+.BI "Evdev Middle Button Emulation"
+1 boolean value (8 bit, 0 or 1).
+.TP 7
+.BI "Evdev Middle Button Timeout"
+1 16-bit positive value.
+.TP 7
+.BI "Evdev Wheel Emulation"
+1 boolean value (8 bit, 0 or 1).
+.TP 7
+.BI "Evdev Wheel Emulation Axes"
+4 8-bit values, order X up, X down, Y up, Y down. 0 disables a value.
+.TP 7
+.BI "Evdev Wheel Emulation Button"
+1 8-bit value, allowed range 0-32, 0 disables the button.
+.TP 7
+.BI "Evdev Wheel Emulation Inertia"
+1 16-bit positive value.
+.TP 7
+.BI "Evdev Wheel Emulation Timeout"
+1 16-bit positive value.
+
+.SH AUTHORS
+Kristian Høgsberg.
+.SH "SEE ALSO"
+__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__),
+README.mouse.
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..2927994
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,39 @@
+# Copyright © 2005-2009 by SuperSonic Imagine, SA
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# on the rights to use, copy, modify, merge, publish, distribute, sub
+# license, and/or sell copies of the Software, and to permit persons to whom
+# the Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# this is obnoxious:
+# -module lets us name the module exactly how we want
+# -avoid-version prevents gratuitous .0.0.0 version numbers on the end
+# _ladir passes a dummy rpath to libtool so the thing will actually link
+# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc.
+AM_CFLAGS = $(XORG_CFLAGS)
+
+@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
+@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
+@DRIVER_NAME@_drv_ladir = @inputdir@
+
+INCLUDES=-I$(top_srcdir)/include/
+
+@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \
+ @DRIVER_NAME@.h \
+ libtouch.c \
+ libtouch.h
+
diff --git a/src/evtouch2.c b/src/evtouch2.c
new file mode 100644
index 0000000..1d947ce
--- /dev/null
+++ b/src/evtouch2.c
@@ -0,0 +1,1649 @@
+/*
+ * Copyright 2004 by Kenan Esau <kenan.esau@conan.de>, Baltmannsweiler, Germany.
+ * Copyright © 2005-2009 by SuperSonic Imagine, SA
+ *
+ * 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 names of copyright holders not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. The copyright holders
+ * make no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Kenan Esau <kenan.esau@conan.de>
+ * Nicolas Bruguier <nicolas.bruguier@supersonicimagine.fr>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <X11/extensions/XIproto.h>
+#include <xf86.h>
+#include <xf86_OSlib.h>
+#include <xf86Xinput.h>
+
+#define DBG(lvl, f) {if ((lvl) <= debug_level) f;}
+#define MAX(a, b) (a > b ? a : b)
+#define MIN(a, b) (a < b ? a : b)
+
+/*****************************************************************************
+ * Local Headers
+ ****************************************************************************/
+#include <linux/input.h>
+#include <exevents.h>
+#include <xisb.h>
+#include <randrstr.h>
+
+#include "libtouch.h"
+#include "evtouch2.h"
+
+#ifdef HAVE_PROPERTIES
+#include <X11/Xatom.h>
+#include <evtouch2-properties.h>
+#include <xserver-properties.h>
+#endif
+
+/*****************************************************************************
+ * Variables without includable headers
+ ****************************************************************************/
+
+/*****************************************************************************
+ * Local Variables
+ ****************************************************************************/
+static InputInfoPtr
+EVTouch2PreInit(InputDriverPtr drv, IDevPtr dev, int flags);
+static void
+EVTouch2PtrCtrl(DeviceIntPtr device, PtrCtrl *ctrl);
+static Bool
+EVTouch2ConvertProc ( LocalDevicePtr local,
+ int first,
+ int num,
+ int v0,
+ int v1,
+ int v2,
+ int v3,
+ int v4,
+ int v5,
+ int *x,
+ int *y );
+
+#ifdef HAVE_PROPERTIES
+static void EVTouch2InitProperty(DeviceIntPtr dev);
+static int EVTouch2SetProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkonly);
+static Atom prop_screen_num = 0;
+static Atom prop_debug_level = 0;
+static Atom prop_touch_button = 0;
+static Atom prop_emulate3 = 0;
+static Atom prop_emulate3_timeout = 0;
+static Atom prop_invert_axes = 0;
+static Atom prop_swap_axes = 0;
+static Atom prop_rotation = 0;
+static Atom prop_pan_viewport = 0;
+static Atom prop_calibration = 0;
+static Atom prop_calibration_axes = 0;
+static Atom prop_calibration_axes_diff = 0;
+#endif
+
+static int debug_level = 0;
+
+InputDriverRec EVTOUCH2 = {
+ 1,
+ "evtouch2",
+ NULL,
+ EVTouch2PreInit,
+ NULL,
+ NULL,
+ 0
+};
+
+static XF86ModuleVersionInfo EvTouch2VersionRec =
+{
+ "evtouch2",
+ "Nicolas Bruguier",
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ 0, 1, 0,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0}
+};
+
+
+static pointer
+EvTouch2Plug (pointer module,
+ pointer options,
+ int *errmaj,
+ int *errmin )
+{
+ DBGOUT(1, "EVTouch2: Plug\n");
+ xf86AddInputDriver(&EVTOUCH2, module, 0);
+ return module;
+}
+
+
+static void
+EvTouch2Unplug (pointer p)
+{
+ DBGOUT(1, "EVTouch2: Unplug\n");
+}
+
+_X_EXPORT XF86ModuleData evtouch2ModuleData =
+{
+ &EvTouch2VersionRec,
+ EvTouch2Plug,
+ EvTouch2Unplug
+};
+
+static const char *default_options[] =
+{
+ "BaudRate", "9600",
+ "StopBits", "1",
+ "DataBits", "8",
+ "Parity", "None",
+ "Vmin", "5",
+ "Vtime", "1",
+ "FlowControl", "None"
+};
+
+/*****************************************************************************
+ * Function Definitions
+ ****************************************************************************/
+static CARD32
+EVTouch2Emulate3Timer(OsTimerPtr timer, CARD32 now, pointer _local)
+{
+ int sigstate;
+ LocalDevicePtr local = (LocalDevicePtr)_local;
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) local->private;
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ sigstate = xf86BlockSIGIO();
+
+ xf86PostMotionEvent(local->dev, TRUE, 0, 2, priv->cur_x, priv->cur_y);
+
+ /*
+ * Emit a button press -- release is handled in EVTouch2LBRBEvent
+ */
+ if ( ( priv->touch_flags & LB_STAT ) &&
+ !( priv->touch_flags & RB_STAT ) )
+ {
+ DBGOUT(2, "EVTouch2: Left Press\n");
+ xf86PostButtonEvent (local->dev, TRUE,
+ 1, 1, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ }
+
+ if ( ( priv->touch_flags & RB_STAT ) &&
+ !( priv->touch_flags & LB_STAT ) )
+ {
+ DBGOUT(2, "EVTouch2: Right Press\n");
+ xf86PostButtonEvent (local->dev, TRUE,
+ 3, 1, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ }
+
+ /*
+ Handling "middle" button press
+ */
+ if ( ( priv->touch_flags & RB_STAT ) &&
+ ( priv->touch_flags & LB_STAT ) )
+ {
+ DBGOUT(2, "EVTouch2: Middle Press\n");
+ xf86PostButtonEvent (local->dev, TRUE,
+ 2, 1, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ }
+
+ priv->emulate3.timer_expired = TRUE;
+ xf86UnblockSIGIO(sigstate);
+
+ return 0;
+}
+
+static void
+EVTouch2DoBtnAction(EVTouch2PrivatePtr priv)
+{
+ int btn = 0;
+ LocalDevicePtr local = priv->local;
+
+ DBGOUT(2, "EVTouch2: %s btn_count=%d\n", __FUNCTION__, priv->btn_count);
+
+ for (btn = 0; btn < priv->btn_count; btn++)
+ {
+ DBGOUT(9, "EVTouch2: %s do_it = %d \n",
+ __FUNCTION__, priv->btn_actions[btn].do_it);
+ if (priv->btn_actions[btn].do_it != 0)
+ {
+ if (priv->emulate3.timer != NULL)
+ {
+ TimerFree(priv->emulate3.timer);
+ priv->emulate3.timer=NULL;
+ priv->emulate3.timer_expired = FALSE;
+ }
+
+ DBGOUT(2, "EVTouch2: %s btn = %d action = %d\n",
+ __FUNCTION__, btn,
+ priv->btn_actions[btn].action);
+
+ xf86PostButtonEvent (local->dev, TRUE, btn,
+ priv->btn_actions[btn].action,
+ 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+
+ priv->btn_actions[btn].do_it = 0;
+ priv->btn_actions[btn].action = 0;
+ }
+ }
+}
+
+static void
+EVTouch2SetBtnAction(EVTouch2PrivatePtr priv, int btn, int action)
+{
+ DBGOUT(2, "EVTouch2: %s btn = %d action = %d\n", __FUNCTION__,
+ btn, action);
+ if (btn < priv->btn_count)
+ {
+ priv->btn_actions[btn].do_it = 1;
+ priv->btn_actions[btn].action = action;
+ }
+}
+
+static void
+EVTouch2ProcessAbs(EVTouch2PrivatePtr priv)
+{
+ struct input_event *ev; /* packet being/just read */
+ int pos_changed = 0;
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ ev = &priv->ev;
+
+ if ( (ev->code == ABS_X) || (ev->code == ABS_Z) )
+ {
+ priv->raw_x = ev->value;
+ pos_changed = 1;
+ }
+
+ if ( (ev->code == ABS_Y) || (ev->code == ABS_RX) )
+ {
+ priv->raw_y = ev->value;
+ pos_changed = 1;
+ }
+
+ if (pos_changed == 1)
+ {
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 2
+ EVTouch2ConvertProc(priv->local, 0, 2,
+ priv->raw_x, priv->raw_y,
+ 0, 0, 0, 0,
+ &priv->cur_x, &priv->cur_y);
+#endif
+
+ libtouchSetPos(priv->libtouch, priv->cur_x, priv->cur_y);
+ return;
+ }
+
+ if (ev->code == ABS_WHEEL)
+ {
+ LocalDevicePtr local = priv->local;
+
+ if (ev->value > 0)
+ {
+ for (; ev->value > 0; ev->value--)
+ {
+ xf86PostButtonEvent (local->dev, TRUE,
+ 4, 1, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ xf86PostButtonEvent (local->dev, TRUE,
+ 4, 0, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ }
+ }
+ else if (ev->value < 0)
+ {
+ for (ev->value = -ev->value; ev->value > 0; ev->value--)
+ {
+ xf86PostButtonEvent (local->dev, TRUE,
+ 5, 1, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ xf86PostButtonEvent (local->dev, TRUE,
+ 5, 0, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ }
+ }
+ }
+}
+
+static void
+EVTouch2ProcessRel(EVTouch2PrivatePtr priv)
+{
+ struct input_event *ev; /* packet being/just read */
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ ev = &priv->ev;
+ if ( ev->code == REL_X )
+ {
+ priv->raw_x += ev->value;
+ if (priv->raw_x > priv->calibration.max_x)
+ priv->raw_x = priv->calibration.max_x;
+ if (priv->raw_x < priv->calibration.min_x)
+ priv->raw_x = priv->calibration.min_x;
+ }
+ if ( ev->code == REL_Y )
+ {
+ priv->raw_y += ev->value;
+ if (priv->raw_y > priv->calibration.max_y)
+ priv->raw_y = priv->calibration.max_y;
+ if (priv->raw_y < priv->calibration.min_y)
+ priv->raw_y = priv->calibration.min_y;
+ }
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 2
+ EVTouch2ConvertProc(priv->local, 0, 2,
+ priv->raw_x, priv->raw_y,
+ 0, 0, 0, 0,
+ &priv->cur_x, &priv->cur_y);
+#endif
+
+ libtouchSetPos(priv->libtouch, priv->cur_x, priv->cur_y);
+}
+
+static void
+EVTouch2LBRBEvent(EVTouch2PrivatePtr priv)
+{
+ struct input_event *ev; /* packet being/just read */
+ LocalDevicePtr local = priv->local;
+
+ ev = &priv->ev;
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ if (priv->emulate3.enabled)
+ {
+ if ((ev->value==1) && (priv->emulate3.timer==NULL))
+ priv->emulate3.timer = TimerSet(priv->emulate3.timer,
+ 0,
+ priv->emulate3.timeout,
+ EVTouch2Emulate3Timer,
+ local);
+
+ if ((ev->value == 1) &&
+ (priv->touch_button > 0 && (ev->code == BTN_TOUCH)))
+ {
+ if (priv->touch_button == 1)
+ priv->touch_flags |= LB_STAT;
+ else if (priv->touch_button == 2)
+ priv->touch_flags |= RB_STAT;
+ }
+ if ((ev->value == 1) && (ev->code == BTN_LEFT))
+ {
+ priv->touch_flags |= LB_STAT;
+ }
+ if ((ev->value == 1) && (ev->code == BTN_RIGHT))
+ {
+ priv->touch_flags |= RB_STAT;
+ }
+
+ if ((ev->value == 0) &&
+ (priv->touch_flags & RB_STAT) &&
+ (priv->touch_flags & LB_STAT))
+ {
+ DBGOUT(2, "EVTouch2: Middle Release\n");
+ priv->touch_flags &= ~LB_STAT;
+ priv->touch_flags &= ~RB_STAT;
+ EVTouch2SetBtnAction(priv, 2, BTN_RELEASE);
+ }
+ else if ((ev->value == 0) &&
+ (priv->touch_button > 0 && (ev->code == BTN_TOUCH)) &&
+ (priv->touch_flags & LB_STAT))
+ {
+ DBGOUT(2, "EVTouch2: Touch Release\n");
+ if (priv->touch_button == 1)
+ priv->touch_flags &= ~LB_STAT;
+ else if (priv->touch_button == 2)
+ priv->touch_flags &= ~RB_STAT;
+ EVTouch2SetBtnAction(priv, priv->touch_button, BTN_RELEASE);
+ }
+ else if ((ev->value == 0) && (ev->code == BTN_LEFT) &&
+ (priv->touch_flags & LB_STAT))
+ {
+ DBGOUT(2, "EVTouch2: Left Release\n");
+ priv->touch_flags &= ~LB_STAT;
+ EVTouch2SetBtnAction(priv, 1, BTN_RELEASE);
+ }
+ else if ((ev->value == 0) && (ev->code == BTN_RIGHT) &&
+ (priv->touch_flags & RB_STAT))
+ {
+ DBGOUT(2, "EVTouch2: Right Release\n");
+ priv->touch_flags &= ~RB_STAT;
+ EVTouch2SetBtnAction(priv, 3, BTN_RELEASE);
+ }
+ }
+ else
+ {
+ if (priv->touch_button > 0 && (ev->code == BTN_TOUCH))
+ {
+ EVTouch2SetBtnAction(priv, priv->touch_button, ev->value);
+ }
+
+ if (ev->code == BTN_LEFT)
+ {
+ EVTouch2SetBtnAction(priv, 1, ev->value);
+ }
+
+ if (ev->code == BTN_MIDDLE)
+ {
+ EVTouch2SetBtnAction(priv, 2, ev->value);
+ }
+
+ if (ev->code == BTN_RIGHT)
+ {
+ EVTouch2SetBtnAction(priv, 3, ev->value);
+ }
+ }
+}
+
+static void
+EVTouch2ProcessKey(EVTouch2PrivatePtr priv)
+{
+ struct input_event *ev; /* packet being/just read */
+
+ ev = &priv->ev;
+ DBGOUT(2, "EVTouch2: %s code = 0x%x\n", __FUNCTION__, ev->code);
+ if ((ev->code == BTN_LEFT) ||
+ (ev->code == BTN_RIGHT) ||
+ (ev->code == BTN_MIDDLE) ||
+ (priv->touch_button > 0 && (ev->code == BTN_TOUCH)))
+ {
+ /* give lb and rb-events some special treatment
+ (emulate3 or not, ...) */
+ EVTouch2LBRBEvent(priv);
+ return;
+ }
+
+ return;
+}
+
+static Bool
+EVTouch2QueryHardware (LocalDevicePtr local)
+{
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ return Success;
+}
+
+static Bool
+EVTouch2DeviceOn (DeviceIntPtr dev)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) (local->private);
+
+ local->fd = xf86OpenSerial(local->options);
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__ );
+
+ if (local->fd == -1)
+ {
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", local->name);
+ return (!Success);
+ }
+
+ priv->buffer = XisbNew(local->fd, 64);
+
+ DBG (9, XisbTrace (priv->buffer, 1));
+
+ if (!priv->buffer)
+ {
+ xf86CloseSerial(local->fd);
+ local->fd = -1;
+ return (!Success);
+ }
+
+ if (EVTouch2QueryHardware(local) != Success)
+ {
+ ErrorF ("Unable to query/initialize EVTouch hardware.\n");
+ return (!Success);
+ }
+
+ xf86FlushInput(local->fd);
+
+ if (ioctl(local->fd, EVIOCGRAB, (void *)1))
+ xf86Msg(X_ERROR, "%s: Unable to grab device (%s).\n",
+ local->name, strerror(errno));
+
+
+ xf86AddEnabledDevice(local);
+
+ dev->public.on = TRUE;
+
+ return (Success);
+}
+
+static Bool
+EVTouch2DeviceOff (DeviceIntPtr dev)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) (local->private);
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__ );
+
+ if (local->fd != -1)
+ {
+ ioctl(local->fd, EVIOCGRAB, (void *)0);
+ xf86RemoveEnabledDevice (local);
+ if (priv->buffer)
+ {
+ XisbFree(priv->buffer);
+ priv->buffer = NULL;
+ }
+ xf86CloseSerial(local->fd);
+ local->fd = -1;
+ }
+
+ dev->public.on = FALSE;
+
+ return (Success);
+}
+
+static Bool
+EVTouch2DeviceInit (DeviceIntPtr dev)
+{
+ ScrnInfoPtr pScrn;
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) (local->private);
+ unsigned char map[EVTOUCH2_MAX_BUTTONS];
+ int i;
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ for (i = 0; i < EVTOUCH2_MAX_BUTTONS; i++)
+ map[i] = i;
+
+ priv->btn_count = EVTOUCH2_MAX_BUTTONS;
+
+ /*
+ * these have to be here instead of in the SetupProc, because when the
+ * SetupProc is run at server startup, screenInfo is not setup yet
+ */
+
+ pScrn = xf86Screens[priv->screen.num];
+ priv->screen.width = pScrn->virtualX; /* It's the virtual screen size ! */
+ priv->screen.height = pScrn->virtualY;
+
+ DBGOUT(2, "EVTouch2: Phys W,H: %d %d\n",
+ priv->phys_width, priv->phys_height);
+ DBGOUT(2, "EVTouch2: Screen W,H: %d %d\n",
+ priv->screen.width, priv->screen.height);
+ DBGOUT(2, "EVTouch2: MaxValue H,V: %d %d\n",
+ pScrn->maxHValue, pScrn->maxVValue);
+
+ priv->screen.width = screenInfo.screens[priv->screen.num]->width;
+ priv->screen.height = screenInfo.screens[priv->screen.num]->height;
+
+ /*
+ * Device reports button press for 5 buttons.
+ */
+ if (InitButtonClassDeviceStruct (dev, EVTOUCH2_MAX_BUTTONS, map) == FALSE)
+ {
+ ErrorF("Unable to allocate EVTouch touchscreen ButtonClassDeviceStruct\n");
+ return BadAlloc;
+ }
+
+ DBGOUT(2, "EVTouch2: %s btn_count=%d\n", __FUNCTION__, priv->btn_count);
+ priv->btn_actions = xcalloc(priv->btn_count, sizeof(BtnAction));
+ memset(priv->btn_actions, 0, priv->btn_count * sizeof(BtnAction));
+
+ if (InitFocusClassDeviceStruct(dev) == FALSE)
+ {
+ ErrorF("Unable to allocate EVTouch touchscreen FocusClassDeviceStruct\n");
+ return !Success;
+ }
+
+ /*
+ * Device reports motions on 2 axes in absolute coordinates.
+ * Axes min and max values are reported in raw coordinates.
+ */
+ if (InitValuatorClassDeviceStruct(dev, 2,
+ local->history_size, Absolute) == FALSE)
+ {
+ ErrorF ("Unable to allocate EVTouch touchscreen ValuatorClassDeviceStruct\n");
+ return !Success;
+ }
+
+ xf86InitValuatorAxisStruct(dev, 0, 0, priv->screen.width,
+ 1024,
+ EVTOUCH2_AXIS_MIN_RES /* min_res */ ,
+ EVTOUCH2_AXIS_MAX_RES /* max_res */ );
+ xf86InitValuatorDefaults(dev, 0);
+ xf86InitValuatorAxisStruct(dev, 1, 0, priv->screen.height,
+ 1024,
+ EVTOUCH2_AXIS_MIN_RES /* min_res */ ,
+ EVTOUCH2_AXIS_MAX_RES /* max_res */ );
+ xf86InitValuatorDefaults(dev, 1);
+
+ /* Initial position of pointer on screen: Centered */
+ priv->cur_x = (priv->calibration.max_x - priv->calibration.min_x)/2;
+ priv->cur_y = (priv->calibration.max_y - priv->calibration.min_y)/2;
+ priv->raw_x = priv->cur_x;
+ priv->raw_y = priv->cur_y;
+ libtouchSetPos(priv->libtouch, priv->cur_x, priv->cur_y);
+
+ if (InitProximityClassDeviceStruct (dev) == FALSE)
+ {
+ ErrorF ("Unable to allocate EVTouch touchscreen ProximityClassDeviceStruct\n");
+ return !Success;
+ }
+
+ if (InitPtrFeedbackClassDeviceStruct(dev, EVTouch2PtrCtrl) == FALSE)
+ {
+ ErrorF ("unable to allocate EVTouch touchscreen PtrFeedbackClassDeviceStruct\n");
+ return !Success;
+ }
+
+ /*
+ * Allocate the motion events buffer.
+ */
+ xf86MotionHistoryAllocate (local);
+
+#ifdef HAVE_PROPERTIES
+ EVTouch2InitProperty(dev);
+ libtouchInitProperty(priv->libtouch, dev);
+ XIRegisterPropertyHandler(dev, EVTouch2SetProperty, NULL, NULL);
+#endif
+
+ return (Success);
+}
+
+static Bool
+EVTouch2DeviceControl (DeviceIntPtr dev,
+ int mode)
+{
+ Bool RetValue;
+
+ switch (mode)
+ {
+ case DEVICE_INIT:
+ RetValue = EVTouch2DeviceInit(dev);
+ break;
+ case DEVICE_ON:
+ RetValue = EVTouch2DeviceOn(dev);
+ break;
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ RetValue = EVTouch2DeviceOff(dev);
+ break;
+ default:
+ RetValue = BadValue;
+ }
+
+ return( RetValue );
+}
+
+static void
+EVTouch2NewPacket (EVTouch2PrivatePtr priv)
+{
+ memset(&priv->ev, 0, sizeof(struct input_event));
+}
+
+static Bool
+EVTouch2GetPacket (EVTouch2PrivatePtr priv)
+{
+ static int count = 0;
+ int c;
+ CARD32 now;
+
+ if (count == 0) EVTouch2NewPacket(priv);
+
+ while ((c = XisbRead(priv->buffer)) >= 0)
+ {
+ if (count == 0)
+ {
+ now = GetTimeInMillis();
+ libtouchSetTime(priv->libtouch, now);
+ }
+
+ ((char *)&priv->ev)[count] = c;
+ count ++;
+
+ if (sizeof(priv->ev) == count)
+ {
+ count = 0;
+ EVTouch2DumpPacketToLog(priv);
+
+ return Success;
+ }
+ }
+ return (!Success);
+}
+
+static void
+EVTouch2ReadInput (LocalDevicePtr local)
+{
+ struct input_event *ev; /* packet being/just read */
+
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) (local->private);
+
+ /*
+ * set blocking to -1 on the first call because we know there is data to
+ * read. Xisb automatically clears it after one successful read so that
+ * succeeding reads are preceeded buy a select with a 0 timeout to prevent
+ * read from blocking infinately.
+ */
+ XisbBlockDuration (priv->buffer, -1);
+ while (EVTouch2GetPacket (priv) == Success)
+ {
+ ev = &priv->ev;
+ DBGOUT(2, "EVTouch2: %s type:%x code: 0x%x value:%d\n",
+ __FUNCTION__, ev->type, ev->code, ev->value);
+
+ xf86XInputSetScreen(local,
+ priv->screen.num,
+ priv->cur_x,
+ priv->cur_y);
+
+ xf86PostProximityEvent(local->dev, 1, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+
+ switch (ev->type)
+ {
+ case EV_ABS:
+ EVTouch2ProcessAbs(priv);
+ break;
+ case EV_REL:
+ EVTouch2ProcessRel(priv);
+ break;
+ case EV_KEY:
+ xf86PostMotionEvent (local->dev, TRUE, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+
+ if (priv->ev.code == BTN_TOUCH)
+ {
+ if (priv->ev.value == 1)
+ {
+ priv->touch_flags |= TOUCHED;
+ DBGOUT(2, "EVTouch2: TOUCHED\n");
+ }
+ else
+ {
+ priv->touch_flags &= ~TOUCHED;
+ DBGOUT(2, "EVTouch2: UNTOUCHED\n");
+ }
+ }
+ EVTouch2ProcessKey(priv);
+ break;
+ case EV_SYN:
+ xf86PostMotionEvent (local->dev, TRUE, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+
+ if ( priv->touch_flags & TOUCHED )
+ libtouchTriggerSM(priv->libtouch, PEN_TOUCHED);
+ else
+ libtouchTriggerSM(priv->libtouch, PEN_UNTOUCHED);
+
+ EVTouch2DoBtnAction(priv);
+ break;
+ }
+
+ DBGOUT( 2, "EVTouch2: setting (x/y)=(%d/%d)\n",
+ priv->cur_x, priv->cur_y);
+ }
+}
+
+static Bool
+EVTouch2ConvertProc ( LocalDevicePtr local,
+ int first,
+ int num,
+ int v0,
+ int v1,
+ int v2,
+ int v3,
+ int v4,
+ int v5,
+ int *x,
+ int *y )
+{
+ /*
+ correction factors depending on current position of pointer
+ */
+ float cx[3];
+ float cy[3];
+ float dx = 0, dy = 0;
+
+ int max_x, max_y;
+ int xc, yc;
+ int screen_width = 0;
+ int screen_height = 0;
+#ifdef EVDBG
+ int i = 0;
+#endif
+
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) (local->private);
+ ScrnInfoPtr pScrn = xf86Screens[priv->screen.num];
+ Rotation rotation = RRGetRotation(pScrn->pScreen);
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+ DBGOUT(2, "EVTouch2: FIRST: v0=%d v1=%d\n", v0, v1);
+
+ /* write raw coordinates to fifo for calibration programm */
+ if ((priv->calibration.fifo > 0) && (priv->calibration.enabled))
+ {
+ int r;
+
+ DBGOUT(2, "EVTouch2: writing to FIFO\n");
+ r = write (priv->calibration.fifo, &v0, sizeof(v0));
+ r = write (priv->calibration.fifo, &v1, sizeof(v1));
+ }
+
+ /* correction of raw coordinates */
+ if (!priv->calibration.enabled)
+ {
+ int tmp = 0;
+
+ if (priv->swap_axes)
+ {
+ tmp = v0;
+ v0 = v1;
+ v1 = tmp;
+ }
+
+ DBGOUT(2, "EVTouch2: Scaling coordinates\n");
+ xc = v0 - priv->calibration.min_x;
+ yc = v1 - priv->calibration.min_y;
+
+ max_x = priv->calibration.max_x - priv->calibration.min_x;
+ max_y = priv->calibration.max_y - priv->calibration.min_y;
+
+ if (priv->rotate == EVTOUCH2_ROTATE_NONE)
+ {
+ if (priv->pan_viewport.enabled)
+ {
+ screen_width = priv->pan_viewport.width;
+ screen_height = priv->pan_viewport.height;
+ }
+ else
+ {
+ screen_width = pScrn->currentMode->HDisplay;
+ screen_height = pScrn->currentMode->VDisplay;
+ }
+ }
+ else
+ {
+ if (priv->pan_viewport.enabled)
+ {
+ screen_width = priv->pan_viewport.height;
+ screen_height = priv->pan_viewport.width;
+ }
+ else
+ {
+ screen_width = pScrn->currentMode->VDisplay;
+ screen_height = pScrn->currentMode->HDisplay;
+ }
+ }
+
+ if ( rotation == RR_Rotate_90 || rotation == RR_Rotate_270 )
+ {
+ int tmp = screen_width; screen_width = screen_height;
+ screen_height = tmp;
+ }
+
+ if (xc < (max_x / 2))
+ {
+ /*
+ left
+ */
+ if (yc>(max_y / 2))
+ {
+ /*
+ upper
+ */
+ cx[1] = ((float) xc / (max_x / 2) );
+ cx[0] = (float) 1 - cx[1];
+ cy[0] = ((float) (yc-(max_y/2)) / (max_y/2) );
+ cy[1] = (float) 1 - cy[0];
+
+ dx = ((float) (cx[1] * cy[0] * priv->calibration.diff[1][0]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[0][0]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[4][0]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[3][0]));
+
+ dy = ((float) (cx[1] * cy[0] * priv->calibration.diff[1][1]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[0][1]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[4][1]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[3][1]));
+ }
+ else
+ {
+ /*
+ lower
+ */
+ cx[1] = ((float) xc / (max_x/2) );
+ cx[0] = (float) 1 - cx[1];
+ cy[0] = ((float) yc / (max_y/2) );
+ cy[1] = (float) 1 - cy[0];
+
+ dx = ((float) (cx[1] * cy[0] * priv->calibration.diff[4][0]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[3][0]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[7][0]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[6][0]));
+
+ dy = ((float) (cx[1] * cy[0] * priv->calibration.diff[4][1]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[3][1]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[7][1]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[6][1]));
+ }
+ }
+ else
+ {
+ /*
+ right
+ */
+ if (yc>(max_y/2))
+ {
+ /*
+ upper
+ */
+ cx[1] = ((float) (xc-(max_x/2)) / (max_x/2) );
+ cx[0] = (float)1 - cx[1];
+ cy[0] = ((float) (yc-(max_y/2)) / (max_y/2) );
+ cy[1] = (float)1 - cy[0];
+
+ dx = ((float) (cx[1] * cy[0] * priv->calibration.diff[2][0]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[1][0]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[5][0]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[4][0]));
+
+ dy = ((float) (cx[1] * cy[0] * priv->calibration.diff[2][1]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[1][1]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[5][1]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[4][1]));
+ }
+ else
+ {
+ /*
+ lower
+ */
+ cx[1] = ((float) (xc-(max_x/2)) / (max_x/2) );
+ cx[0] = (float) 1 - cx[1];
+ cy[0] = ((float) yc / (max_y/2) );
+ cy[1] = (float) 1 - cy[0];
+
+ dx = ((float) (cx[1] * cy[0] * priv->calibration.diff[5][0]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[4][0]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[8][0]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[7][0]));
+
+ dy = ((float) (cx[1] * cy[0] * priv->calibration.diff[5][1]) +
+ (float)(cx[0] * cy[0] * priv->calibration.diff[4][1]) +
+ (float)(cx[1] * cy[1] * priv->calibration.diff[8][1]) +
+ (float)(cx[0] * cy[1] * priv->calibration.diff[7][1]));
+ }
+ }
+
+#ifdef EVDBG
+ for (i=0; i<3; i++)
+ xf86ErrorFVerb(2, "cx[%d]=%f cy[%d]=%f\n", i, cx[i]
+ ,i, cy[i]);
+
+ DBGOUT(2, "EVTouch2: dx=%f dy=%f\n", dx, dy);
+ if (priv->pan_viewport.enabled)
+ {
+ DBGOUT(2, "EVTouch2: Pan Viewport Position (x/y) (%d/%d)\n",
+ priv->pan_viewport.x, priv->pan_viewport.y);
+ DBGOUT(2, "EVTouch2: Pan Viewport Geometry (w x h) (%d x %d)\n",
+ priv->pan_viewport.width, priv->pan_viewport.height);
+ }
+#endif
+
+ xc = ( ((float)xc / max_x) * screen_width ) + dx;
+ yc = ( ((float)yc / max_y) * screen_height) + dy;
+
+ if (priv->swap_y == TRUE)
+ yc = screen_height - yc;
+
+ if (priv->pan_viewport.enabled)
+ {
+ xc += priv->pan_viewport.x;
+ yc += priv->pan_viewport.y;
+ }
+
+ /* ususally we DON'T swap x -- but if swap_x is 1
+ => go on and swap */
+ if (priv->swap_x == TRUE)
+ xc = screen_width - xc;
+
+ /* rotation mixes x and y up a bit */
+ if (priv->rotate == EVTOUCH2_ROTATE_CW)
+ {
+ tmp = xc;
+ xc = yc;
+ yc = screen_width - tmp;
+ }
+ else if (priv->rotate == EVTOUCH2_ROTATE_CCW)
+ {
+ tmp = xc;
+ xc = screen_height - yc;
+ yc = tmp;
+ }
+ else if (priv->rotate == EVTOUCH2_ROTATE_UD)
+ {
+ xc = screen_width - xc;
+ yc = screen_height - yc;
+ }
+
+ switch (rotation)
+ {
+ case RR_Rotate_0:
+ v0 = xc;
+ v1 = yc;
+ break;
+ case RR_Rotate_180:
+ v0 = screen_width - xc;
+ v1 = screen_height - yc;
+ break;
+ case RR_Rotate_90:
+ tmp = xc;
+ v0 = screen_height - yc;
+ v1 = tmp;
+ break;
+ case RR_Rotate_270:
+ tmp = xc;
+ v0 = yc;
+ v1 = screen_width - tmp;
+ break;
+ default:
+ break;
+ }
+ }
+
+ DBGOUT(2, "EVTouch2: FINAL: v0=%d v1=%d\n", v0, v1);
+
+ *x = v0;
+ *y = v1;
+
+ return (TRUE);
+}
+
+static InputInfoPtr
+EVTouch2PreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ InputInfoPtr local;
+ EVTouch2PrivatePtr priv;
+ ScrnInfoPtr pScrn;
+
+ int i = 0;
+ char *s;
+ char tmp_str[8];
+ int timeo = 0;
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ priv = xcalloc (1, sizeof (EVTouch2PrivateRec));
+ if (!priv)
+ return NULL;
+
+ local = xf86AllocateInput(drv, 0);
+ if (!local)
+ {
+ xfree(priv);
+ return NULL;
+ }
+
+ local->name = xstrdup(dev->identifier);
+ local->type_name = XI_TOUCHSCREEN;
+ local->device_control = EVTouch2DeviceControl;
+ local->read_input = EVTouch2ReadInput;
+ local->control_proc = NULL;
+ local->close_proc = NULL;
+ local->switch_mode = NULL;
+ local->conversion_proc = EVTouch2ConvertProc;
+ local->reverse_conversion_proc = NULL;
+ local->fd = -1;
+ local->dev = NULL;
+ local->private = priv;
+ priv->local = local;
+ local->private_flags = 0;
+ local->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+ local->conf_idev = dev;
+
+ xf86CollectInputOptions(local, default_options, NULL);
+
+ xf86OptionListReport(local->options);
+
+ priv->libtouch = xcalloc(1, sizeof(LibTouchRec));
+ libtouchInit(priv->libtouch, local);
+
+ priv->screen.num = xf86SetIntOption(local->options, "ScreenNumber", 0 );
+ priv->calibration.enabled = FALSE;
+
+ pScrn = xf86Screens[priv->screen.num];
+ priv->phys_width = pScrn->currentMode->HDisplay; /* physical screen resolution */
+ priv->phys_height = pScrn->currentMode->VDisplay;
+
+ priv->pan_viewport.x = 0;
+ priv->pan_viewport.y = 0;
+ priv->pan_viewport.width = 0;
+ priv->pan_viewport.height = 0;
+ s = xf86SetStrOption(local->options, "PanViewportGeometry", NULL );
+ if (s)
+ {
+ char* pos;
+ if ((pos = strstr(s, "x")) != NULL ||
+ (pos = strstr(s, "X")) != NULL)
+ {
+ pos[0] = '\0';
+ priv->pan_viewport.width = MAX(atoi(s), 0);
+ priv->pan_viewport.width = MIN(priv->pan_viewport.width,
+ priv->phys_width);
+ priv->pan_viewport.height = MAX(atoi(pos + 1), 0);
+ priv->pan_viewport.height = MIN(priv->pan_viewport.height,
+ priv->phys_height);
+ }
+ xfree(s);
+ }
+
+ s = xf86SetStrOption(local->options, "PanViewportPosition", NULL );
+ if (s)
+ {
+ char* pos;
+ if ((pos = strstr(s, ",")) != NULL)
+ {
+ pos[0] = '\0';
+ priv->pan_viewport.x = MAX(atoi(s), 0);
+ priv->pan_viewport.y = MAX(atoi(pos + 1), 0);
+ }
+ xfree(s);
+ }
+
+ priv->pan_viewport.enabled = priv->pan_viewport.width > 0 &&
+ priv->pan_viewport.height > 0;
+ if (priv->pan_viewport.enabled)
+ {
+ DBGOUT(2, "EVTouch2: Pan Viewport Position (X,Y) (%d,%d)\n",
+ priv->pan_viewport.x, priv->pan_viewport.y);
+ DBGOUT(2, "EVTouch2: Pan Viewport Geometry (W,H) (%d,%d)\n",
+ priv->pan_viewport.width, priv->pan_viewport.height);
+ }
+ else
+ {
+ priv->pan_viewport.x = 0;
+ priv->pan_viewport.y = 0;
+ priv->pan_viewport.width = 0;
+ priv->pan_viewport.height = 0;
+ }
+
+ priv->calibration.min_x = xf86SetIntOption(local->options, "MinX", 0 );
+ priv->calibration.max_x = xf86SetIntOption(local->options, "MaxX",
+ priv->phys_width);
+ priv->calibration.min_y = xf86SetIntOption(local->options, "MinY", 0 );
+ priv->calibration.max_y = xf86SetIntOption(local->options, "MaxY",
+ priv->phys_height);
+
+ priv->touch_button = xf86SetIntOption(local->options,
+ "TouchButtonEmulate", 1);
+
+ priv->emulate3.enabled = xf86SetBoolOption(local->options,
+ "Emulate3Buttons", FALSE);
+ priv->emulate3.timeout = xf86SetIntOption(local->options,
+ "Emulate3Timeout", 50);
+
+ debug_level = xf86SetIntOption(local->options, "DebugLevel", 0);
+ libtouchSetDebugLevel(debug_level);
+
+ timeo = xf86SetIntOption(local->options, "TapTimer", 90);
+ libtouchSetTapTimeo(priv->libtouch, timeo);
+
+ timeo = xf86SetIntOption(local->options, "LongtouchTimer", 160);
+ libtouchSetLongtouchTimeo(priv->libtouch, timeo);
+
+ libtouchSetMoveLimit(priv->libtouch,
+ xf86SetIntOption( local->options,
+ "MoveLimit", 180 ));
+
+ priv->rotate = EVTOUCH2_ROTATE_NONE;
+ s = xf86FindOptionValue(local->options, "Rotate");
+ if (s)
+ {
+ if (xf86NameCmp(s, "CW") == 0)
+ {
+ priv->rotate = EVTOUCH2_ROTATE_CW;
+ }
+ else if (xf86NameCmp(s, "CCW") == 0 )
+ {
+ priv->rotate = EVTOUCH2_ROTATE_CCW;
+ }
+ }
+
+ priv->swap_y = xf86SetBoolOption(local->options, "SwapY", FALSE);
+ priv->swap_x = xf86SetBoolOption(local->options, "SwapX", FALSE);
+ priv->swap_axes = xf86SetBoolOption(local->options, "SwapAxes", FALSE);
+
+ /*
+ get calibration parameters from XF86Config
+ */
+ for (i = 0; i < 9; i++)
+ {
+ sprintf(tmp_str, "x%d", i);
+ priv->calibration.diff[i][0] = xf86SetIntOption( local->options,
+ tmp_str, 0 );
+ sprintf(tmp_str, "y%d", i);
+ priv->calibration.diff[i][1] = xf86SetIntOption( local->options,
+ tmp_str, 0 );
+ DBGOUT(2, "(diff[%d][0]/diff[%d][1])=(%d/%d)\n", i, i,
+ priv->calibration.diff[i][0], priv->calibration.diff[i][1]);
+ }
+
+ priv->touch_flags = 0;
+ local->history_size = xf86SetIntOption( local->options, "HistorySize", 0 );
+
+ /* prepare to process touch packets */
+ EVTouch2NewPacket (priv);
+
+ /* this results in an xstrdup that must be freed later */
+ local->name = xf86SetStrOption( local->options, "DeviceName", "EVTouch2 TouchScreen" );
+ xf86ProcessCommonOptions(local, local->options);
+ local->flags |= XI86_CONFIGURED;
+
+ xf86CloseSerial(local->fd);
+ local->fd = -1;
+ return (local);
+}
+
+static void
+EVTouch2PtrCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ /* I have no clue what this does, except that registering it stops the
+ X server segfaulting in ProcGetPointerMapping()
+ Ho Hum.
+ */
+}
+
+#ifdef HAVE_PROPERTIES
+static void
+EVTouch2InitProperty(DeviceIntPtr dev)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) (local->private);
+ CARD32 pan_viewport[4];
+ CARD32 calibration_axes[4];
+ CARD32 calibration_axes_diff[18];
+ CARD8 invert_axes[2];
+ int rc, i, j, k;
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ /* Init screen property */
+ prop_screen_num = MakeAtom(EVTOUCH2_PROP_SCREEN,
+ strlen(EVTOUCH2_PROP_SCREEN),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_screen_num, XA_INTEGER, 16,
+ PropModeReplace, 1, &priv->screen.num,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_screen_num, FALSE);
+
+ /* Init debug level property */
+ prop_debug_level = MakeAtom(EVTOUCH2_PROP_DEBUG_LEVEL,
+ strlen(EVTOUCH2_PROP_DEBUG_LEVEL),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_debug_level, XA_INTEGER, 8,
+ PropModeReplace, 1, &debug_level,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_debug_level, FALSE);
+
+ /* Init touch button property */
+ prop_touch_button = MakeAtom(EVTOUCH2_PROP_TOUCH_BUTTON,
+ strlen(EVTOUCH2_PROP_TOUCH_BUTTON),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_touch_button, XA_INTEGER, 8,
+ PropModeReplace, 1, &priv->touch_button,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_touch_button, FALSE);
+
+ /* Init emulate middle properties */
+ prop_emulate3 = MakeAtom(EVTOUCH2_PROP_EMULATE3,
+ strlen(EVTOUCH2_PROP_EMULATE3),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_emulate3, XA_INTEGER, 8,
+ PropModeReplace, 1, &priv->emulate3.enabled,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_emulate3, FALSE);
+
+ prop_emulate3_timeout = MakeAtom(EVTOUCH2_PROP_EMULATE3_TIMEOUT,
+ strlen(EVTOUCH2_PROP_EMULATE3_TIMEOUT),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_emulate3_timeout, XA_INTEGER, 16,
+ PropModeReplace, 1, &priv->emulate3.timeout,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_emulate3_timeout, FALSE);
+
+ /* Init emulate invert axes property */
+ invert_axes[0] = priv->swap_x;
+ invert_axes[1] = priv->swap_y;
+ XISetDevicePropertyDeletable(dev, prop_emulate3_timeout, FALSE);
+
+ prop_invert_axes = MakeAtom(EVTOUCH2_PROP_INVERT_AXES,
+ strlen(EVTOUCH2_PROP_INVERT_AXES),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_invert_axes, XA_INTEGER, 8,
+ PropModeReplace, 2, invert_axes,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_invert_axes, FALSE);
+
+ /* Init swap axes property */
+ prop_swap_axes = MakeAtom(EVTOUCH2_PROP_SWAP_AXES,
+ strlen(EVTOUCH2_PROP_SWAP_AXES),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_swap_axes, XA_INTEGER, 8,
+ PropModeReplace, 1, &priv->swap_axes,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_swap_axes, FALSE);
+
+ /* Init rotation property */
+ prop_rotation = MakeAtom(EVTOUCH2_PROP_ROTATION,
+ strlen(EVTOUCH2_PROP_ROTATION),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_rotation, XA_INTEGER, 8,
+ PropModeReplace, 1, &priv->rotate,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_rotation, FALSE);
+
+ /* Init pan viewport property */
+ pan_viewport[0] = priv->pan_viewport.x;
+ pan_viewport[1] = priv->pan_viewport.y;
+ pan_viewport[2] = priv->pan_viewport.width;
+ pan_viewport[3] = priv->pan_viewport.height;
+
+ prop_pan_viewport = MakeAtom(EVTOUCH2_PROP_PAN_VIEWPORT,
+ strlen(EVTOUCH2_PROP_PAN_VIEWPORT),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_pan_viewport, XA_INTEGER, 32,
+ PropModeReplace, 4, pan_viewport,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_pan_viewport, FALSE);
+
+ /* Init calibration properties */
+ prop_calibration = MakeAtom(EVTOUCH2_PROP_CALIBRATION,
+ strlen(EVTOUCH2_PROP_CALIBRATION),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_calibration, XA_INTEGER, 8,
+ PropModeReplace, 1, &priv->calibration.enabled,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_calibration, FALSE);
+
+ calibration_axes[0] = priv->calibration.min_x;
+ calibration_axes[1] = priv->calibration.max_x;
+ calibration_axes[2] = priv->calibration.min_y;
+ calibration_axes[3] = priv->calibration.max_y;
+
+ prop_calibration_axes = MakeAtom(EVTOUCH2_PROP_CALIBRATION_MAX_MIN,
+ strlen(EVTOUCH2_PROP_CALIBRATION_MAX_MIN),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_calibration_axes, XA_INTEGER, 32,
+ PropModeReplace, 4, calibration_axes,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_calibration_axes, FALSE);
+
+ for (i = 0, k = 0; i < 9; i++)
+ for (j = 0; j < 2; j++, k++)
+ calibration_axes_diff[k] = priv->calibration.diff[i][j];
+
+ prop_calibration_axes_diff = MakeAtom(EVTOUCH2_PROP_CALIBRATION_DIFF,
+ strlen(EVTOUCH2_PROP_CALIBRATION_DIFF),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_calibration_axes_diff, XA_INTEGER, 32,
+ PropModeReplace, 18, calibration_axes_diff,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_calibration_axes_diff, FALSE);
+}
+
+static int
+EVTouch2SetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ EVTouch2PrivatePtr priv = (EVTouch2PrivatePtr) (local->private);
+
+ DBGOUT(2, "EVTouch2: %s\n", __FUNCTION__);
+
+ /* set touch button property */
+ if (atom == prop_touch_button)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ priv->touch_button = *((CARD8*)val->data);
+ }
+ /* set debug level property */
+ else if (atom == prop_debug_level)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ debug_level = *((CARD8*)val->data);
+ libtouchSetDebugLevel(debug_level);
+ }
+ }
+ /* set emulate middle button properties */
+ else if (atom == prop_emulate3)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ priv->emulate3.enabled = *((BOOL*)val->data);
+ }
+ else if (atom == prop_emulate3_timeout)
+ {
+ if (val->format != 16 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ priv->emulate3.timeout = *((CARD16*)val->data);
+ }
+ /* set invert axes property */
+ else if (atom == prop_invert_axes)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 2)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ CARD8 *vals = (CARD8*)val->data;
+ priv->swap_x = vals[0];
+ priv->swap_y = vals[1];
+ }
+ }
+ /* set rotation property */
+ else if (atom == prop_rotation)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ priv->rotate = *((CARD8*)val->data);
+ }
+ /* set swap axes property */
+ else if (atom == prop_swap_axes)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ priv->swap_axes = *((BOOL*)val->data);
+ }
+ /* set pan viewport property */
+ else if (atom == prop_pan_viewport)
+ {
+ if (val->format != 32 || val->type != XA_INTEGER)
+ return BadMatch;
+ if (val->size != 4 && val->size != 0)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ if (val->size == 0)
+ {
+ priv->pan_viewport.enabled = FALSE;
+ priv->pan_viewport.x = 0;
+ priv->pan_viewport.y = 0;
+ priv->pan_viewport.width = 0;
+ priv->pan_viewport.height = 0;
+ }
+ else if (val->size == 4)
+ {
+ CARD32 *vals = (CARD32*)val->data;
+
+ priv->pan_viewport.x = vals[0];
+ priv->pan_viewport.y = vals[1];
+ priv->pan_viewport.width = vals[2];
+ priv->pan_viewport.height = vals[3];
+ priv->pan_viewport.enabled = priv->pan_viewport.width > 0 &&
+ priv->pan_viewport.height > 0;
+ }
+ }
+ }
+ /* set calibration properties */
+ else if (atom == prop_calibration)
+ {
+ if (val->format != 8 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ priv->calibration.enabled = *((CARD8*)val->data);
+
+ if (priv->calibration.fifo > 0)
+ {
+ close (priv->calibration.fifo);
+ priv->calibration.fifo = -1;
+ }
+
+ if (priv->calibration.enabled)
+ {
+ char filename[256];
+ snprintf(filename, 256, "/tmp/evtouch2_calibrate_%d", dev->id);
+ priv->calibration.fifo = open(filename, O_RDWR, 0);
+ if (priv->calibration.fifo < 0)
+ {
+ xf86ErrorFVerb(2, "open FIFO FAILED\n");
+ priv->calibration.enabled = FALSE;
+ return !Success;
+ }
+ }
+ }
+ }
+ else if (atom == prop_calibration_axes)
+ {
+ if (val->format != 32 || val->type != XA_INTEGER || val->size != 4)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ CARD32 *vals = (CARD32*)val->data;
+
+ priv->calibration.min_x = vals[0];
+ priv->calibration.max_x = vals[1];
+ priv->calibration.min_y = vals[2];
+ priv->calibration.max_y = vals[3];
+ priv->calibration.enabled = FALSE;
+ }
+ }
+ else if (atom == prop_calibration_axes_diff)
+ {
+ if (val->format != 32 || val->type != XA_INTEGER || val->size != 18)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ CARD32 *vals = (CARD32*)val->data;
+ int i;
+
+ for (i = 0; i < 18; i+=2)
+ {
+ priv->calibration.diff[i/2][0] = vals[i];
+ priv->calibration.diff[i/2][1] = vals[i];
+ }
+ priv->calibration.enabled = FALSE;
+ }
+ }
+
+ return Success;
+}
+#endif
diff --git a/src/evtouch2.h b/src/evtouch2.h
new file mode 100644
index 0000000..7f5e8ef
--- /dev/null
+++ b/src/evtouch2.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2004 by Kenan Esau <kenan.esau@conan.de>, Baltmannsweiler,
+ * Copyright © 2005-2009 by SuperSonic Imagine, SA
+ *
+ * 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 names of copyright holders not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. The copyright holders
+ * make no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Kenan Esau <kenan.esau@conan.de>
+ * Nicolas Bruguier <nicolas.bruguier@supersonicimagine.fr>
+ */
+
+#ifndef _EVTOUCH2_H_
+#define _EVTOUCH2_H_
+
+#ifdef EVDBG
+#define DBGOUT(lvl, ...) (xf86ErrorFVerb(lvl, __VA_ARGS__))
+#else
+#define DBGOUT(lvl, ...)
+#endif
+
+/******************************************************************************
+ * Definitions
+ * structs, typedefs, #defines, enums
+ *****************************************************************************/
+#define EVTOUCH2_ROTATE_NONE 0
+#define EVTOUCH2_ROTATE_CW 1
+#define EVTOUCH2_ROTATE_CCW 2
+#define EVTOUCH2_ROTATE_UD 3
+
+#define EVTOUCH2_AXIS_MIN_RES 0
+#define EVTOUCH2_AXIS_MAX_RES 1024
+#define EVTOUCH2_PAN_BORDER 12
+
+#define EVTOUCH2_TIMEOUT 500
+
+#define EVTOUCH2_MAX_BUTTONS 5
+
+#define BTN_PRESS 1
+#define BTN_RELEASE 0
+
+typedef struct _BtnActionRec
+{
+ int do_it; /* if != 0 -> commit action */
+ int action; /* button-press (1) or -release (0) */
+} BtnAction, *BtnActionPtr;
+
+typedef struct _EVTouch2PrivateRec
+{
+ /* calibration */
+ struct
+ {
+ Bool enabled;
+ int diff[9][2];
+ int min_x; /* Minimum x reported by calibration */
+ int max_x; /* Maximum x */
+ int min_y; /* Minimum y reported by calibration */
+ int max_y; /* Maximum y */
+ int fifo; /* fd of the fifo used for communication with the calibration programm*/
+ } calibration;
+
+ /* touch button press number */
+ int touch_button;
+
+ /* emulate middle button */
+ struct
+ {
+ Bool enabled;
+ int timeout;
+ OsTimerPtr timer;
+ Bool timer_expired;
+ } emulate3;
+
+ /* pointers position */
+ int cur_x;
+ int cur_y;
+ int raw_x;
+ int raw_y;
+
+ /* pointers to the current viewport coordinates */
+ int rotate; /* 90 deg CW, -90 deg CCW, default is 0 */
+ Bool swap_axes; /* swap axes */
+ Bool swap_y; /* swap the y axis */
+ Bool swap_x; /* swap the x axis */
+ int phys_width; /* Physical X-Resolution */
+ int phys_height; /* Physical Y-Resolution */
+
+ /* pointers to the current pan viewport coordinates */
+ struct
+ {
+ Bool enabled; /* indicates that there a viewport */
+ int x; /* viewport x position */
+ int y; /* viewport y position */
+ int width; /* viewport width */
+ int height; /* viewport height */
+ } pan_viewport;
+
+ unsigned char touch_flags; /* 1 - touched, 2 - x-coord received
+ 4 - y-coord received */
+ BtnActionPtr btn_actions;
+ int btn_count; /* how many buttons does the device support */
+
+ struct
+ {
+ int num; /* Screen associated with the device */
+ int width; /* Width of the associated X screen */
+ int height; /* Height of the screen */
+ } screen;
+
+ XISBuffer *buffer;
+ struct input_event ev; /* packet being/just read */
+
+ LibTouchRecPtr libtouch;
+ LocalDevicePtr local;
+} EVTouch2PrivateRec, *EVTouch2PrivatePtr;
+
+
+/******************************************************************************
+ * Declarations
+ *****************************************************************************/
+
+#ifdef LOG_RAW_PACKET
+#define EVTouch2DumpPacketToLog(priv) ( xf86ErrorFVerb(2, "EVTOUCH2PCKT type=0x%02x code=0x%02x value=0x%02x\n", \
+ priv->ev.type, priv->ev.code, priv->ev.value ) )
+#else
+#define EVTouch2DumpPacketToLog(priv)
+#endif
+
+/*
+ * DO NOT PUT ANYTHING AFTER THIS ENDIF
+ */
+#endif
diff --git a/src/libtouch.c b/src/libtouch.c
new file mode 100644
index 0000000..468d3b1
--- /dev/null
+++ b/src/libtouch.c
@@ -0,0 +1,922 @@
+/*
+ * Copyright 2004 by Kenan Esau <kenan.esau@conan.de>, Baltmannsweiler, Germany.
+ * Copyright © 2005-2009 by SuperSonic Imagine, SA
+ *
+ * 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 names of copyright holders not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. The copyright holders
+ * make no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Kenan Esau <kenan.esau@conan.de>
+ * Nicolas Bruguier <nicolas.bruguier@supersonicimagine.fr>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <misc.h>
+#include <os.h>
+#include <string.h>
+
+#include <xf86.h>
+#ifndef NEED_XF86_TYPES
+#define NEED_XF86_TYPES
+#endif
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <X11/Xatom.h>
+
+#include "evtouch2-properties.h"
+#include "libtouch.h"
+
+#ifdef DBG
+#undef DBG
+#endif
+
+static int debug_level = 0;
+#define DBG(lvl, f) {if ((lvl) <= debug_level) f;}
+
+typedef struct state
+{
+ void (*enter_state)(LibTouchRecPtr priv);
+ int (*handle_state)(LibTouchRecPtr priv);
+ void (*action)(LibTouchRecPtr priv, int btn, int x, int y);
+ int btn;
+} state_t;
+
+
+typedef enum states
+{
+ S_UNTOUCHED = 0,
+ S_TOUCHED = 1,
+ S_LONGTOUCHED = 2,
+ S_MOVING = 3,
+ S_MAYBETAPPED = 4,
+ S_ONEANDAHALFTAP = 5
+} state_name_t;
+
+
+static void
+btn_down_action(LibTouchRecPtr priv, int btn, int x, int y)
+{
+ DBG(4, ErrorF("LibTouch: Issuing Button %d down\n", btn));
+ xf86PostButtonEvent(priv->local->dev, TRUE,
+ btn, 1, 0, 2, x, y);
+ priv->pressed_btn_stat |= 1 << btn;
+}
+
+static void
+btn_up_action(LibTouchRecPtr priv, int btn, int x, int y)
+{
+ DBG(4, ErrorF("LibTouch: Issuing Button %d up\n", btn));
+ xf86PostButtonEvent(priv->local->dev, TRUE,
+ btn, 0, 0, 2, x, y);
+ priv->pressed_btn_stat &= ~(1 << btn);
+}
+
+static void
+btn_click_action(LibTouchRecPtr priv, int btn, int x, int y)
+{
+ btn_down_action(priv, btn, x, y);
+ btn_up_action(priv, btn, x, y);
+}
+
+static void enter_untouched(LibTouchRecPtr priv);
+static int handle_untouched(LibTouchRecPtr priv);
+static void enter_touched(LibTouchRecPtr priv);
+static int handle_touched(LibTouchRecPtr priv);
+static void enter_longtouched(LibTouchRecPtr priv);
+static int handle_longtouched(LibTouchRecPtr priv);
+static void enter_moving(LibTouchRecPtr priv);
+static int handle_moving(LibTouchRecPtr priv);
+static void enter_maybetap(LibTouchRecPtr priv);
+static int handle_maybetap(LibTouchRecPtr priv);
+static void enter_oneandahalftap(LibTouchRecPtr priv);
+static int handle_oneandahalftap(LibTouchRecPtr priv);
+
+static void dump_configuration(void);
+
+state_t state_ar[] =
+{
+ {enter_untouched, handle_untouched, NULL, 0},
+ {enter_touched, handle_touched, NULL, 0},
+ {enter_longtouched, handle_longtouched, btn_down_action, 1},
+ {enter_moving, handle_moving, NULL, 0},
+ {enter_maybetap, handle_maybetap, btn_click_action, 1},
+ {enter_oneandahalftap, handle_oneandahalftap, btn_down_action, 3},
+ {NULL, NULL, NULL, -1},
+};
+
+#ifdef HAVE_PROPERTIES
+#define LIBTOUCH_NB_STATE_PROPERTIES 6
+static Atom prop_tap_timeout = 0;
+static Atom prop_longtouch_timeout = 0;
+static Atom prop_move_limit = 0;
+static Atom prop_state[LIBTOUCH_NB_STATE_PROPERTIES] =
+{
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+#endif
+
+char *state_str[] =
+{
+ "S_UNTOUCHED",
+ "S_TOUCHED",
+ "S_LONGTOUCHED",
+ "S_MOVING",
+ "S_MAYBETAPPED",
+ "S_ONEANDAHALFTAP",
+ NULL,
+};
+
+char *state_action_str[] =
+{
+ "untouched_action",
+ "touched_action",
+ "longtouched_action",
+ "moving_action",
+ "maybetapped_action",
+ "oneandahalftap_action",
+ NULL,
+};
+
+char *state_button_str[] =
+{
+ "untouched_button",
+ "touched_button",
+ "longtouched_button",
+ "moving_button",
+ "maybetapped_button",
+ "oneandahalftap_button",
+ NULL,
+};
+
+char *action_str[] =
+{
+ "down",
+ "up",
+ "click",
+ NULL,
+};
+
+void (*action_handler[])(LibTouchRecPtr, int, int, int) =
+{
+ btn_down_action,
+ btn_up_action,
+ btn_click_action,
+ NULL,
+};
+
+void
+libtouchSetDebugLevel(int level)
+{
+ debug_level = level;
+}
+
+void
+libtouchSetTapTimeo(LibTouchRecPtr libtouch, int timeo)
+{
+ libtouch->tap_timeo = timeo;
+}
+
+void
+libtouchSetLongtouchTimeo(LibTouchRecPtr libtouch, int timeo)
+{
+ libtouch->longtouch_timeo = timeo;
+}
+
+void
+libtouchSetMoveLimit(LibTouchRecPtr libtouch, int move_limit)
+{
+ libtouch->move_limit = move_limit;
+}
+
+void
+libtouchInit(LibTouchRecPtr libtouch, LocalDevicePtr local)
+{
+ int state_action_idx = 0;
+ int state_button_idx = 0;
+ int action_idx = 0;
+ int btn;
+
+ char *str;
+
+ memset(libtouch, 0, sizeof(LibTouchRec));
+
+ libtouch->now = GetTimeInMillis();
+ libtouch->past = libtouch->now;
+ libtouch->local = local;
+ libtouch->move_limit = 30;
+
+ /*
+ Actions: up, down, click
+
+ Example(s):
+ longtouch_action "down"
+ longtouch_button 1
+
+ tap_action "click"
+ tap_button 2
+
+ oneandahalftap_action "down"
+ oneandahalftap_button 3
+ */
+
+ /* parse buttons */
+ for (state_button_idx = 0;
+ state_button_str[state_button_idx] != NULL;
+ state_button_idx++)
+ {
+ btn = xf86SetIntOption(local->options,
+ state_button_str[state_button_idx], -1);
+ if (btn != -1) state_ar[state_button_idx].btn = btn;
+ }
+
+ /* parse actions for the states */
+ for (state_action_idx = 0;
+ state_action_str[state_action_idx] != NULL;
+ state_action_idx++)
+ {
+ DBG(4, ErrorF("LibTouch: Finding Option %s\n",
+ state_action_str[state_action_idx]));
+ str = xf86FindOptionValue(local->options,
+ state_action_str[state_action_idx]);
+ if (str == NULL)
+ continue;
+
+ for (action_idx = 0; action_str[action_idx] != NULL; action_idx++)
+ {
+ if (xf86NameCmp(str, action_str[action_idx]) == 0)
+ {
+ state_ar[state_action_idx].action = action_handler[action_idx];
+ break;
+ }
+ }
+ }
+
+ dump_configuration();
+}
+
+#ifdef HAVE_PROPERTIES
+void
+libtouchInitProperty(LibTouchRecPtr libtouch, DeviceIntPtr dev)
+{
+ int rc, i, j;
+ char tmp[256];
+ CARD8 prop[2];
+
+ /* Init tap timeout property */
+ prop_tap_timeout = MakeAtom(EVTOUCH2_PROP_TAP_TIMEOUT,
+ strlen(EVTOUCH2_PROP_TAP_TIMEOUT),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_tap_timeout, XA_INTEGER, 16,
+ PropModeReplace, 1, &libtouch->tap_timeo,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_tap_timeout, FALSE);
+
+
+ /* Init longtouch timeout property */
+ prop_longtouch_timeout = MakeAtom(EVTOUCH2_PROP_LONGTOUCH_TIMEOUT,
+ strlen(EVTOUCH2_PROP_LONGTOUCH_TIMEOUT),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_longtouch_timeout, XA_INTEGER, 16,
+ PropModeReplace, 1, &libtouch->longtouch_timeo,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_longtouch_timeout, FALSE);
+
+ /* Init move limit property */
+ prop_move_limit = MakeAtom(EVTOUCH2_PROP_MOVE_LIMIT,
+ strlen(EVTOUCH2_PROP_MOVE_LIMIT),
+ TRUE);
+
+ rc = XIChangeDeviceProperty(dev, prop_move_limit, XA_INTEGER, 16,
+ PropModeReplace, 1, &libtouch->move_limit,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_move_limit, FALSE);
+
+ /* Init state properties */
+ for (i = 0; i < LIBTOUCH_NB_STATE_PROPERTIES; i++)
+ {
+ prop[0] = state_ar[i].btn;
+ prop[1] = 0;
+ for (j = 0; action_handler[j]; j++)
+ {
+ if (state_ar[i].action == action_handler[j])
+ {
+ prop[1] = j + 1;
+ break;
+ }
+ }
+
+ memset(tmp, 0, 256);
+ snprintf(tmp, 256, EVTOUCH2_PROP_STATE, state_str[i]);
+ prop_state[i] = MakeAtom(tmp, strlen(tmp), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_state[i], XA_INTEGER, 8,
+ PropModeReplace, 2, prop,
+ FALSE);
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_state[i], FALSE);
+ }
+}
+
+int
+libtouchSetProperty(LibTouchRecPtr libtouch, Atom atom,
+ XIPropertyValuePtr val, BOOL checkonly)
+{
+ int i, j;
+
+ /* Set tap timeout property */
+ if (atom == prop_tap_timeout)
+ {
+ if (val->format != 16 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ libtouch->tap_timeo = *((CARD16*)val->data);
+ }
+ /* Set long touch timeout property */
+ else if (atom == prop_longtouch_timeout)
+ {
+ if (val->format != 16 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ libtouch->longtouch_timeo = *((CARD16*)val->data);
+ }
+ /* Set move limit property */
+ else if (atom == prop_move_limit)
+ {
+ if (val->format != 16 || val->type != XA_INTEGER || val->size != 1)
+ return BadMatch;
+
+ if (!checkonly)
+ libtouch->move_limit = *((CARD16*)val->data);
+ }
+ else
+ {
+ /* Set state properties */
+ for (i = 0; i < LIBTOUCH_NB_STATE_PROPERTIES; i++)
+ {
+ if (atom == prop_state[i])
+ {
+ if (val->format != 8 || val->type != XA_INTEGER ||
+ val->size != 2)
+ return BadMatch;
+
+ if (!checkonly)
+ {
+ CARD8 *vals = (CARD8*)val->data;
+
+ state_ar[i].btn = vals[0] > 0 ? vals[0] : 0;
+ state_ar[i].action = NULL;
+ for (j = 0; action_handler[j]; j++)
+ {
+ if (j == vals[1])
+ {
+ state_ar[i].action = action_handler[j];
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ return Success;
+}
+#endif
+
+void
+libtouchSetYPos(LibTouchRecPtr libtouch, int y)
+{
+ libtouch->old_y = libtouch->cur_y;
+ libtouch->cur_y = y;
+ libtouch->ypos_changed = 1;
+}
+
+void
+libtouchSetXPos(LibTouchRecPtr libtouch, int x)
+{
+ libtouch->old_x = libtouch->cur_x;
+ libtouch->cur_x = x;
+ libtouch->xpos_changed = 1;
+}
+
+void
+libtouchSetPos(LibTouchRecPtr libtouch, int x, int y)
+{
+ libtouchSetXPos(libtouch, x);
+ libtouchSetYPos(libtouch, y);
+}
+
+void
+libtouchSetTime(LibTouchRecPtr libtouch, CARD32 now)
+{
+ libtouch->now = now;
+}
+
+static void
+dump_configuration(void)
+{
+ int i = 0;
+ int n = 0;
+ char *str = NULL;
+
+ for(i = 0; state_ar[i].enter_state != NULL; i++)
+ {
+ ErrorF("State: %s\t", state_str[i]);
+
+ if (state_ar[i].action == NULL)
+ str = "No Action";
+ else
+ {
+ for(n = 0; action_handler[n] != NULL; n++)
+ {
+ if (action_handler[n] == state_ar[i].action)
+ {
+ str = action_str[n];
+ break;
+ }
+ }
+ }
+
+ ErrorF("Action: %s\t\tButton: %d\n", str, state_ar[i].btn);
+ }
+}
+
+static void
+issue_btn_event(LibTouchRecPtr priv, int state, int x, int y)
+{
+ if (state_ar[state].action != NULL)
+ state_ar[state].action(priv, state_ar[state].btn, x, y);
+}
+
+
+static int
+delta(int x1, int x2)
+{
+ return (x1 > x2) ? x1 - x2 : x2 - x1;
+}
+
+
+static void
+disable_timers(LibTouchRecPtr priv)
+{
+ int sigstate;
+
+ sigstate = xf86BlockSIGIO();
+ if (priv->tap_timer)
+ TimerFree(priv->tap_timer);
+ priv->tap_timer = NULL;
+ priv->tap_timer_expired = FALSE;
+
+ if (priv->longtouch_timer)
+ TimerFree(priv->longtouch_timer);
+ priv->longtouch_timer = NULL;
+ priv->longtouch_timer_expired = FALSE;
+ xf86UnblockSIGIO(sigstate);
+}
+
+
+static CARD32
+tap_timer_func(OsTimerPtr timer, CARD32 now, pointer _priv)
+{
+ int sigstate;
+ LibTouchRecPtr priv = (LibTouchRecPtr)_priv;
+
+ sigstate = xf86BlockSIGIO();
+ libtouchSetTime(priv, now);
+ priv->tap_timer_expired = TRUE;
+ libtouchTriggerSM(priv, PEN_UNKNOWN);
+ xf86UnblockSIGIO(sigstate);
+
+ return 0;
+}
+
+
+static CARD32
+longtouch_timer_func(OsTimerPtr timer, CARD32 now, pointer _priv)
+{
+ int sigstate;
+ LibTouchRecPtr priv = (LibTouchRecPtr)_priv;
+
+ sigstate = xf86BlockSIGIO();
+ libtouchSetTime(priv, now);
+ priv->longtouch_timer_expired = TRUE;
+ libtouchTriggerSM(priv, PEN_UNKNOWN);
+ xf86UnblockSIGIO(sigstate);
+
+ return 0;
+}
+
+
+static void
+enter_untouched(LibTouchRecPtr priv)
+{
+ int i = 0;
+ int bit_size = sizeof(priv->pressed_btn_stat) * 8;
+
+ priv->touch_flags = 0;
+ disable_timers(priv);
+
+ /* do an untouch for all pressed buttons */
+ for (i = 0; i < bit_size; i++)
+ {
+ if (priv->pressed_btn_stat & (1 << i))
+ {
+ DBG(4, ErrorF("LibTouch: Issuing Button-release %d\n", i));
+ xf86PostButtonEvent(priv->local->dev, TRUE,
+ i, 0, 0, 2,
+ priv->cur_x,
+ priv->cur_y);
+ }
+ }
+
+ priv->pressed_btn_stat = 0;
+}
+
+static int
+handle_untouched(LibTouchRecPtr priv)
+{
+ static int rc = S_UNTOUCHED;
+ int tmp = 0;
+
+ DBG(4, ErrorF("LibTouch: %s\n", __FUNCTION__));
+ if (priv->pen == PEN_TOUCHED)
+ {
+ priv->touch_flags |= TOUCHED;
+ priv->touch_time = priv->now;
+ rc = S_TOUCHED;
+ DBG(4, ErrorF("LibTouch: untouched: rc = S_TOUCHED\n"));
+ }
+
+ if (priv->xpos_changed)
+ {
+ if ( !(priv->touch_flags & X_COORD))
+ {
+ priv->touch_x = priv->cur_x;
+ DBG(4, ErrorF("LibTouch: untouched: touch_x = %d\n",
+ priv->touch_x));
+ priv->touch_flags |= X_COORD;
+ }
+ }
+
+ if (priv->ypos_changed)
+ {
+ if ( !(priv->touch_flags & Y_COORD))
+ {
+ priv->touch_y = priv->cur_y;
+ DBG(4, ErrorF("LibTouch: untouched: touch_y = %d\n",
+ priv->touch_y));
+ priv->touch_flags |= Y_COORD;
+ }
+ }
+
+ if ((priv->touch_flags & TOUCHED) &&
+ (priv->touch_flags & X_COORD) &&
+ (priv->touch_flags & Y_COORD))
+ {
+ tmp = rc;
+ DBG(4, ErrorF("LibTouch: untouched: rc = %d\n", rc));
+ rc = S_UNTOUCHED;
+ return tmp;
+ }
+
+ DBG(4, ErrorF("LibTouch: untouched: rc = S_UNTOUCHED\n"));
+
+ return S_UNTOUCHED;
+}
+
+static void
+enter_touched(LibTouchRecPtr priv)
+{
+ disable_timers(priv);
+ priv->longtouch_timer = TimerSet(priv->longtouch_timer, 0,
+ priv->longtouch_timeo,
+ longtouch_timer_func, priv);
+}
+
+
+static int
+handle_touched(LibTouchRecPtr priv)
+{
+ int dx = 0;
+ int dy = 0;
+
+ if (priv->pen == PEN_UNTOUCHED)
+ {
+ priv->untouch_time = priv->now;
+ priv->touch_flags &= ~(TOUCHED | X_COORD | Y_COORD);
+ return S_MAYBETAPPED;
+ }
+
+ if (priv->longtouch_timer_expired)
+ {
+ TimerFree(priv->longtouch_timer);
+ priv->longtouch_timer = NULL;
+ priv->longtouch_timer_expired = FALSE;
+ return S_LONGTOUCHED;
+ }
+
+ if (priv->xpos_changed)
+ {
+ if (priv->cur_x != priv->old_x)
+ {
+ dx = delta(priv->touch_x, priv->cur_x);
+ if (dx > priv->move_limit)
+ return S_MOVING;
+ }
+ }
+
+ if (priv->ypos_changed)
+ {
+ if (priv->cur_y != priv->old_y)
+ {
+ dy = delta(priv->touch_y, priv->cur_y);
+ if (dy > priv->move_limit)
+ return S_MOVING;
+ }
+ }
+
+ return S_TOUCHED;
+}
+
+static void
+enter_moving(LibTouchRecPtr priv)
+{
+ disable_timers(priv);
+}
+
+static int
+handle_moving(LibTouchRecPtr priv)
+{
+ if (priv->pen == PEN_UNTOUCHED)
+ return S_UNTOUCHED;
+
+ return S_MOVING;
+}
+
+
+static void
+enter_longtouched(LibTouchRecPtr priv)
+{
+ disable_timers(priv);
+ DBG(4, ErrorF("LibTouch: Issuing Button-press 1\n"));
+ issue_btn_event(priv, S_LONGTOUCHED, priv->cur_x, priv->cur_y);
+}
+
+
+static int
+handle_longtouched(LibTouchRecPtr priv)
+{
+ static int rc = S_LONGTOUCHED;
+ int tmp = 0;
+ int dx = 0;
+ int dy = 0;
+
+ if (priv->pen == PEN_UNTOUCHED)
+ {
+ priv->untouch_time = priv->now;
+ priv->touch_flags &= ~(TOUCHED | X_COORD | Y_COORD);
+ rc = S_UNTOUCHED;
+ }
+ else
+ {
+ if (priv->cur_x != priv->old_x)
+ {
+ dx = delta(priv->touch_x, priv->cur_x);
+ if (dx > priv->move_limit)
+ rc = S_MOVING;
+ }
+
+ if (priv->cur_y != priv->old_y)
+ {
+ dy = delta(priv->touch_y, priv->cur_y);
+ if (dy > priv->move_limit)
+ rc = S_MOVING;
+ }
+ }
+
+ tmp = rc;
+ rc = S_LONGTOUCHED;
+ return tmp;
+}
+
+
+static void
+enter_maybetap(LibTouchRecPtr priv)
+{
+ disable_timers(priv);
+ priv->tap_timer = TimerSet(priv->tap_timer, 0,
+ priv->tap_timeo,
+ tap_timer_func, priv);
+}
+
+
+static int
+handle_maybetap(LibTouchRecPtr priv)
+{
+ int dx = 0;
+ int dy = 0;
+
+ if (priv->tap_timer_expired)
+ {
+ TimerFree(priv->tap_timer);
+ priv->tap_timer = NULL;
+ priv->tap_timer_expired = FALSE;
+
+ issue_btn_event(priv, S_MAYBETAPPED, priv->touch_x, priv->touch_y);
+
+ return S_UNTOUCHED;
+ }
+
+ if (priv->pen == PEN_TOUCHED)
+ {
+ /*FIXME: touched again -> clear all current timers
+ and set up a new taptimer AND longtouch-timer and
+ switch to ONEANDAHALFTAP-state
+ */
+ disable_timers(priv);
+ priv->touch_flags |= TOUCHED;
+ priv->touch_time = priv->now;
+ }
+
+ if (priv->xpos_changed)
+ {
+ dx = delta(priv->touch_x, priv->cur_x);
+ if (dx > priv->move_limit)
+ {
+ DBG(4, ErrorF("LibTouch: touch_x = %d cur_x = %d\n",
+ priv->touch_x, priv->cur_x));
+ }
+ priv->last_touch_x = priv->touch_x;
+ priv->touch_x = priv->cur_x;
+ priv->touch_flags |= X_COORD;
+ }
+
+ if (priv->ypos_changed)
+ {
+ dy = delta(priv->touch_y, priv->cur_y);
+ if (dy > priv->move_limit)
+ {
+ DBG(4, ErrorF("LibTouch: touch_y = %d cur_y = %d\n",
+ priv->touch_y, priv->cur_y));
+ }
+ priv->last_touch_y = priv->touch_y;
+ priv->touch_y = priv->cur_y;
+ priv->touch_flags |= Y_COORD;
+ }
+
+ if ((priv->touch_flags & TOUCHED) &&
+ (priv->touch_flags & X_COORD) && (priv->touch_flags & Y_COORD))
+ {
+ dx = delta(priv->touch_x, priv->last_touch_x);
+ dy = delta(priv->touch_y, priv->last_touch_y);
+
+ if ((dx > priv->move_limit) || (dy > priv->move_limit))
+ {
+ issue_btn_event(priv, S_MAYBETAPPED,
+ priv->last_touch_x,
+ priv->last_touch_y);
+
+ return S_TOUCHED; /* touch on another place */
+ }
+ else
+ return S_ONEANDAHALFTAP;
+ }
+
+ return S_MAYBETAPPED;
+}
+
+
+static void
+enter_oneandahalftap(LibTouchRecPtr priv)
+{
+ disable_timers(priv);
+ priv->longtouch_timer = TimerSet(priv->longtouch_timer, 0,
+ priv->longtouch_timeo,
+ longtouch_timer_func, priv);
+}
+
+
+static int
+handle_oneandahalftap(LibTouchRecPtr priv)
+{
+ int dx = 0;
+ int dy = 0;
+ static int event_issued = 0;
+
+ if (priv->pen == PEN_UNTOUCHED)
+ {
+ priv->touch_flags = 0;
+ if ((event_issued == 0) &&
+ (priv->longtouch_timer_expired == FALSE))
+ {
+ disable_timers(priv);
+ issue_btn_event(priv, S_MAYBETAPPED,
+ priv->last_touch_x,
+ priv->last_touch_y);
+ issue_btn_event(priv, S_MAYBETAPPED,
+ priv->last_touch_x,
+ priv->last_touch_y);
+ }
+
+ event_issued = 0;
+ return S_UNTOUCHED;
+ }
+
+ if ((priv->xpos_changed) || (priv->ypos_changed))
+ {
+ dx = delta(priv->touch_x, priv->cur_x);
+ dy = delta(priv->touch_y, priv->cur_y);
+
+ if ((dx > priv->move_limit) ||
+ (dy > priv->move_limit))
+ {
+ event_issued = 0;
+ return S_MOVING;
+ }
+ else
+ return S_ONEANDAHALFTAP;
+ }
+
+ if ((event_issued == 0) &&
+ (priv->longtouch_timer_expired))
+ {
+ TimerFree(priv->longtouch_timer);
+ priv->longtouch_timer = NULL;
+ priv->longtouch_timer_expired = FALSE;
+ event_issued = 1;
+
+ issue_btn_event(priv, S_ONEANDAHALFTAP, priv->cur_x, priv->cur_y);
+
+ return S_ONEANDAHALFTAP;
+ }
+
+ return S_ONEANDAHALFTAP;
+}
+
+
+void
+libtouchTriggerSM(LibTouchRecPtr libtouch, LibTouchState_t pen)
+{
+ static int state_idx = S_UNTOUCHED;
+ int next_state_idx;
+
+ if (pen != PEN_UNKNOWN)
+ libtouch->pen = pen;
+
+ DBG(4, ErrorF("LibTouch: Triggering SM pen = 0x%02x\n", pen));
+
+ next_state_idx = state_ar[state_idx].handle_state(libtouch);
+ if ((next_state_idx != state_idx) &&
+ (state_ar[next_state_idx].enter_state != NULL))
+ {
+ state_ar[next_state_idx].enter_state(libtouch);
+ }
+
+ DBG(4, ErrorF("LibTouch: Next State %d = %s\n", next_state_idx,
+ state_str[next_state_idx]));
+
+ state_idx = next_state_idx;
+ libtouch->past = libtouch->now;
+ libtouch->xpos_changed = 0;
+ libtouch->ypos_changed = 0;
+}
diff --git a/src/libtouch.h b/src/libtouch.h
new file mode 100644
index 0000000..c8b4545
--- /dev/null
+++ b/src/libtouch.h
@@ -0,0 +1,79 @@
+#ifndef _libtouch_H_
+#define _libtouch_H_
+#include <os.h>
+
+#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3
+#define HAVE_PROPERTIES 1
+#endif
+
+#define TOUCHED 0x01
+#define X_COORD 0x02
+#define Y_COORD 0x04
+#define LB_STAT 0x08 /* LB up / down */
+#define RB_STAT 0x10 /* RB up / down (both needed for 3-btn emu) */
+
+typedef enum touchState
+{
+ PEN_TOUCHED = 1,
+ PEN_UNTOUCHED = 2,
+ PEN_UNKNOWN = 3
+} LibTouchState_t;
+
+typedef struct _libtouch
+{
+ int cur_x;
+ int cur_y;
+ int ypos_changed;
+ int xpos_changed;
+ int old_x;
+ int old_y;
+
+ LibTouchState_t pen;
+
+ OsTimerPtr tap_timer;
+ int tap_timeo;
+ Bool tap_timer_expired;
+
+ OsTimerPtr longtouch_timer;
+ int longtouch_timeo;
+ Bool longtouch_timer_expired;
+
+ int drag_timer;
+ unsigned char pressed_btn_stat;
+
+ int move_limit;
+
+ int untouch_time;
+ int touch_time;
+ int touch_x;
+ int touch_y;
+ int last_touch_x;
+ int last_touch_y;
+ unsigned char touch_flags; /* 1 - touched, 2 - x-coord received
+ 4 - y-coord received */
+
+ CARD32 past;
+ CARD32 now;
+ LocalDevicePtr local;
+} LibTouchRec, *LibTouchRecPtr;
+
+void libtouchSetDebugLevel(int level);
+void libtouchSetTapTimeo(LibTouchRecPtr libtouch, int timeo);
+void libtouchSetLongtouchTimeo(LibTouchRecPtr libtouch, int timeo);
+void libtouchSetMoveLimit(LibTouchRecPtr libtouch, int move_limit);
+
+void libtouchInit(LibTouchRecPtr libtouch, LocalDevicePtr local);
+
+#ifdef HAVE_PROPERTIES
+void libtouchInitProperty(LibTouchRecPtr libtouch, DeviceIntPtr dev);
+int libtouchSetProperty(LibTouchRecPtr libtouch, Atom atom,
+ XIPropertyValuePtr val, BOOL checkonly);
+#endif
+
+void libtouchSetTime(LibTouchRecPtr libtouch, CARD32 now);
+void libtouchSetPos(LibTouchRecPtr libtouch, int x, int y);
+void libtouchTriggerSM(LibTouchRecPtr libtouch, LibTouchState_t touch);
+void libtouchSetXPos(LibTouchRecPtr libtouch, int x);
+void libtouchSetYPos(LibTouchRecPtr libtouch, int y);
+
+#endif
diff --git a/xorg-evtouch2.pc.in b/xorg-evtouch2.pc.in
new file mode 100644
index 0000000..6fc8c48
--- /dev/null
+++ b/xorg-evtouch2.pc.in
@@ -0,0 +1,6 @@
+sdkdir=@sdkdir@
+
+Name: xorg-evtouch2
+Description: X.Org evtouch2 input driver.
+Version: @PACKAGE_VERSION@
+Cflags: -I${sdkdir}