diff options
author | Nicolas Bruguier <nicolas.bruguier@supersonicimagine.fr> | 2009-05-19 21:50:49 +0200 |
---|---|---|
committer | Nicolas Bruguier <nicolas.bruguier@supersonicimagine.fr> | 2009-05-19 21:50:49 +0200 |
commit | d4d578a0481aa54f1df920b0a2903b8679256679 (patch) | |
tree | 150759f32e6ca7077b066ac96f0f231e0b3f5f1e |
Initial import
-rw-r--r-- | .gitignore | 29 | ||||
-rw-r--r-- | COPYING | 44 | ||||
-rw-r--r-- | Makefile.am | 40 | ||||
-rw-r--r-- | README | 20 | ||||
-rwxr-xr-x | autogen.sh | 12 | ||||
-rw-r--r-- | configure.ac | 85 | ||||
-rw-r--r-- | include/Makefile.am | 2 | ||||
-rw-r--r-- | include/evtouch2-properties.h | 89 | ||||
-rw-r--r-- | man/Makefile.am | 60 | ||||
-rw-r--r-- | man/evtouch2.man | 206 | ||||
-rw-r--r-- | src/Makefile.am | 39 | ||||
-rw-r--r-- | src/evtouch2.c | 1649 | ||||
-rw-r--r-- | src/evtouch2.h | 148 | ||||
-rw-r--r-- | src/libtouch.c | 922 | ||||
-rw-r--r-- | src/libtouch.h | 79 | ||||
-rw-r--r-- | xorg-evtouch2.pc.in | 6 |
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 @@ -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 @@ -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} |