Xorg input driver (#53)

* add xf86 input driver.

* cleanup.

* rewrite to unix socket PoC.

* add input rebuild.

* lint & docs.

* add input driver struct.

* comments, lint, socket name from config.

* add touch events to webrtc.

* switch to uint32.

* misc update logging & linting,

* fix screen size

* set touchscreen as core pointer.

* add touch to ws control.

* SendCoreEvents.

* extract to own xinput folder.

* add debounce.

* switch pressure to uint8.

* check buffer size.

* send touch events with system init.
This commit is contained in:
Miroslav Šedivý
2023-08-17 16:14:59 +02:00
committed by GitHub
parent 4cb1b3e925
commit ea5517b270
35 changed files with 1507 additions and 82 deletions

67
xorg/xf86-input-neko/.gitignore vendored Normal file
View File

@ -0,0 +1,67 @@
# Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
# generated files
aclocal.m4
config.h.in
config.guess
configure
config.sub
depcomp
install-sh
ltmain.sh
Makefile
Makefile.in
src/Makefile
src/Makefile.in
missing
autom4te.cache/
compile
config.h
config.h.in~
config.log
config.status
libtool
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
src/.deps/
stamp-h1
src/.libs/
*.pc
# build folder
build/

View File

@ -0,0 +1,9 @@
#
# Create new Xorg input device for Neko
#
Section "InputDevice"
Identifier "dummy_touchscreen"
Option "SocketName" "/tmp/xf86-input-neko.sock"
Driver "neko"
EndSection

View File

@ -0,0 +1,27 @@
The MIT License
Copyright 1999 Frederic Lepied, France
Copyright 2005 Adam Jackson
Copyright 2005 Sun Microsystems, Inc.
Copyright 2006 Sascha Hauer, Pengutronix
Copyright 2007 Clement Chauplannaz, Thales e-Transactions
Copyright 2017 Martin Kepplinger
Copyright 2023 Miroslav Sedivy
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 the rights
to use, copy, modify, merge, publish, distribute, sublicense, 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 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
AUTHORS OR COPYRIGHT HOLDERS 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.

View File

@ -0,0 +1,22 @@
FROM debian:bullseye-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
apt-get update; \
apt-get install -y \
gcc pkgconf autoconf automake libtool make xorg-dev xutils-dev \
&& rm -rf /var/lib/apt/lists/*;
WORKDIR /app
COPY ./ /app/
RUN set -eux; \
./autogen.sh --prefix=/usr; \
./configure; \
make -j$(nproc); \
make install;
# docker build -t xf86-input-neko .
# docker run -v $PWD/build:/app/build --rm xf86-input-neko make install DESTDIR=/app/build

View File

@ -0,0 +1,30 @@
# 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
SUBDIRS = src
ACLOCAL_AMFLAGS = -I m4
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = xorg-neko.pc
dist_xorgconf_DATA = 80-neko.conf
EXTRA_DIST = README.md

View File

@ -0,0 +1,19 @@
# xf86-input-neko
[X.org](https://x.org/) [neko](http://github.com/demodesk/neko) input driver
### how to use
xf86-input-neko assumes you have only one virtual touchscreen device available, see
`80-neko.conf`. If there are multiple in your system, please specify one config
section for each.
xf86-input-neko aims to make [neko](http://github.com/demodesk/neko) easy to use and doesn't
offer special configuration options.
* `./configure --prefix=/usr`
* `make`
* `sudo make install`
Done.
To _uninstall_, again go inside the extracted directory, and do
sudo make uninstall

View File

@ -0,0 +1,8 @@
#!/bin/sh
if [ -f Makefile ]; then
echo "Making make distclean..."
make distclean
fi
echo "Removing autogenned files..."
rm -f config.guess config.sub configure install-sh missing mkinstalldirs Makefile.in ltmain.sh stamp-h.in */Makefile.in ltconfig stamp-h config.h.in* aclocal.m4 compile depcomp
echo "Done."

22
xorg/xf86-input-neko/autogen.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
autoreconf -f -i -I $(pwd)/m4
exit $?
echo -n "Libtoolize..."
libtoolize --force --copy
echo "Done."
echo -n "Aclocal..."
aclocal
echo "Done."
echo -n "Autoheader..."
autoheader
echo "Done."
echo -n "Automake..."
automake --add-missing --copy
echo "Done."
echo -n "Autoconf..."
autoconf
echo "Done."
#./configure $*
echo "Now you can do ./configure, make, make install."

View File

@ -0,0 +1,109 @@
# Copyright 2005 Adam Jackson.
# Copyright 2017 Martin Kepplinger.
#
# 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.59)
AC_INIT([xf86-input-neko],[0.0.1],[https://github.com/demodesk/neko/issues],[xf86-input-neko],[https://github.com/demodesk/neko])
AC_CONFIG_SRCDIR([Makefile.am])
AC_CONFIG_AUX_DIR(.)
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([dist-bzip2 dist-xz])
DRIVER_NAME=neko
AC_SUBST([DRIVER_NAME])
AC_CONFIG_HEADERS(config.h)
# Checks for programs.
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
AC_PROG_CC
# Initialize libtool
LT_INIT
m4_ifndef([XORG_MACROS_VERSION],
[m4_fatal([you must install xorg-macros before running autoconf/autogen.
Hint: either install from source, git://anongit.freedesktop.org/xorg/util/macros or,
depending on you distribution, try package 'xutils-dev' or 'xorg-x11-util-macros'])])
XORG_DEFAULT_OPTIONS
AH_TOP([#include "xorg-server.h"])
#AC_DEFINE(XFree86LOADER,1,[Stub define for loadable drivers])
#
#AC_ARG_ENABLE(XINPUT, AS_HELP_STRING([--enable-xinput],
# [Build XInput support (default: yes)]),
# [XINPUT=$enableval],[XINPUT=yes])
#AM_CONDITIONAL(XINPUT, test "x$XINPUT" = "xyes")
#if test "x$XINPUT" = "xyes" ; then
# AC_DEFINE(XINPUT,1,[Enable XInput support])
#fi
#
#AC_ARG_ENABLE(XKB, AS_HELP_STRING([--enable-xkb],
# [Build XKB support (default: yes)]),
# [XKB=$enableval],[XKB=yes])
#AM_CONDITIONAL(XKB, test "x$XKB" = "xyes")
#if test "x$XKB" = "xyes" ; then
# AC_DEFINE(XKB,1,[Enable XKB support])
#fi
AC_ARG_WITH(xorg-module-dir,
AS_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)
AC_ARG_WITH(xorg-conf-dir,
AC_HELP_STRING([--with-xorg-conf-dir=DIR],
[Default xorg.conf.d directory [[default=${prefix}/share/X11/xorg.conf.d/]]]),
[xorgconfdir="$withval"],
[xorgconfdir='${prefix}/share/X11/xorg.conf.d'])
AC_SUBST(xorgconfdir)
# Checks for extensions
XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
XORG_DRIVER_CHECK_EXT(XINPUT, inputproto)
# Checks for pkg-config packages
PKG_CHECK_MODULES(XORG, xorg-server xproto $REQUIRED_MODULES)
sdkdir=$(pkg-config --variable=sdkdir xorg-server)
CFLAGS="$CFLAGS $XORG_CFLAGS "' -I$(top_srcdir)/src'
CFLAGS="-O2 -Wall -W -fPIC $CFLAGS"
AC_SUBST([CFLAGS])
# Checks for libraries.
#AC_CHECK_LIB(ts, ts_open, [], [
# echo "Error! You need to have libts."
# exit -1
# ])
# Checks for header files.
AC_HEADER_STDC
AC_CONFIG_FILES([Makefile
src/Makefile
xorg-neko.pc])
AC_OUTPUT

View File

121
xorg/xf86-input-neko/release.sh Executable file
View File

@ -0,0 +1,121 @@
#!/bin/bash
: 'Copyright (C) 2017, Martin Kepplinger <martink@posteo.de>
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
the rights to use, copy, modify, merge, publish, distribute, sublicense,
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 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
AUTHORS OR COPYRIGHT HOLDERS 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.'
# Script to build release-archives with. This requires a checkout from git.
# Before running it, change the version in configure.ac. Only do this. Do
# *not* commit this change. This script will do it.
# WARNING: This script is very dangerous! It may delete any untracked files.
have_version=0
usage()
{
echo "Usage: $0 -v version"
}
args=$(getopt -o v:s -- "$@")
if [ $? -ne 0 ] ; then
usage
exit 1
fi
eval set -- "$args"
while [ $# -gt 0 ]
do
case "$1" in
-v)
version=$2
have_version=1
shift
;;
--)
shift
break
;;
*)
echo "Invalid option: $1"
usage
exit 1
;;
esac
shift
done
# Do we have a desired version number?
if [ "$have_version" -gt 0 ] ; then
echo "trying to build version $version"
else
echo "please specify a version"
usage
exit 1
fi
# Version number sanity check
if grep ${version} configure.ac
then
echo "configurations seems ok"
else
echo "please check your configure.ac"
exit 1
fi
# Check that we are on master
branch=$(git rev-parse --abbrev-ref HEAD)
echo "we are on branch $branch"
if [ ! "${branch}" = "master" ] ; then
echo "you don't seem to be on the master branch"
exit 1
fi
if git diff-index --quiet HEAD --; then
# no changes
echo "there are no uncommitted changes (version bump)"
exit 1
fi
echo "======================================================"
echo " are you fine with the following version bump?"
echo "======================================================"
git diff
echo "======================================================"
read -p " Press enter to continue"
echo "======================================================"
./autogen.sh && ./configure && make distcheck
./autogen-clean.sh
git clean -d -f
git commit -a -m "xf86-input-neko ${version}"
git tag -s ${version} -m "xf86-input-neko ${version}"
./autogen.sh && ./configure && make distcheck
sha256sum xf86-input-neko-${version}.tar.xz > xf86-input-neko-${version}.tar.xz.sha256
sha256sum xf86-input-neko-${version}.tar.gz > xf86-input-neko-${version}.tar.gz.sha256
sha256sum xf86-input-neko-${version}.tar.bz2 > xf86-input-neko-${version}.tar.bz2.sha256
sha512sum xf86-input-neko-${version}.tar.xz > xf86-input-neko-${version}.tar.xz.sha512
sha512sum xf86-input-neko-${version}.tar.gz > xf86-input-neko-${version}.tar.gz.sha512
sha512sum xf86-input-neko-${version}.tar.bz2 > xf86-input-neko-${version}.tar.bz2.sha512
gpg -b -a xf86-input-neko-${version}.tar.xz
gpg -b -a xf86-input-neko-${version}.tar.gz
gpg -b -a xf86-input-neko-${version}.tar.bz2

View File

@ -0,0 +1,31 @@
# 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.
# 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.
@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la
@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version
@DRIVER_NAME@_drv_ladir = @inputdir@
@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c

View File

@ -0,0 +1,502 @@
/*
* (c) 2017 Martin Kepplinger <martink@posteo.de>
* (c) 2007 Clement Chauplannaz, Thales e-Transactions <chauplac@gmail.com>
* (c) 2006 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* (c) 2023 Miroslav Sedivy
*
* derived from the xf86-input-void driver
* Copyright 1999 by Frederic Lepied, France. <Lepied@XFree86.org>
*
* 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 Frederic Lepied not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Frederic Lepied makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* FREDERIC LEPIED DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL FREDERIC LEPIED 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.
*
* SPDX-License-Identifier: MIT
* License-Filename: COPYING
*/
/* neko input driver */
// https://www.x.org/releases/X11R7.7/doc/xorg-server/Xinput.html
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define DEF_SOCKET_NAME "/tmp/xf86-input-neko.sock"
#define BUFFER_SIZE 12
#include <stdio.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <misc.h>
#include <xf86.h>
#if !defined(DGUX)
#include <xisb.h>
#endif
#include <xf86_OSproc.h>
#include <xf86Xinput.h>
#include <exevents.h> /* Needed for InitValuator/Proximity stuff */
#include <X11/keysym.h>
#include <mipointer.h>
#include <xserver-properties.h>
#include <pthread.h>
#define MAXBUTTONS 11 /* > 10 */
#define TOUCH_NUM_AXES 3 /* x, y, pressure */
#define TOUCH_MAX_SLOTS 10
struct neko_message
{
uint16_t type;
uint32_t touchId;
int32_t x;
int32_t y;
uint8_t pressure;
};
struct neko_priv
{
pthread_t thread;
/* config */
int height;
int width;
int pmax;
ValuatorMask *valuators;
uint16_t slots;
/* socket */
struct sockaddr_un addr;
int listen_socket;
char *socket_name;
};
// from binary representation to struct
static void
UnpackNekoMessage(struct neko_message *msg, unsigned char *buffer)
{
msg->type = buffer[0]; // TODO: use full 16bit type
msg->touchId = buffer[1] | (buffer[2] << 8); // TODO: use full 32bit touchId
msg->x = buffer[3] | (buffer[4] << 8) | (buffer[5] << 16) | (buffer[6] << 24);
msg->y = buffer[7] | (buffer[8] << 8) | (buffer[9] << 16) | (buffer[10] << 24);
msg->pressure = buffer[11];
}
static void
ReadInput(InputInfoPtr pInfo)
{
struct neko_priv *priv = (struct neko_priv *) (pInfo->private);
struct neko_message msg;
int ret;
int data_socket;
unsigned char buffer[BUFFER_SIZE];
for (;;)
{
/* Wait for incoming connection. */
data_socket = accept(priv->listen_socket, NULL, NULL);
/* Handle error conditions. */
if (data_socket == -1)
{
xf86IDrvMsg(pInfo, X_ERROR, "unable to accept connection\n");
break;
}
xf86IDrvMsg(pInfo, X_INFO, "accepted connection\n");
for(;;)
{
/* Wait for next data packet. */
ret = read(data_socket, buffer, BUFFER_SIZE);
/* Handle error conditions. */
if (ret == -1)
{
xf86IDrvMsg(pInfo, X_ERROR, "unable to read data\n");
break;
}
/* Connection closed by client. */
if (ret == 0)
{
xf86IDrvMsg(pInfo, X_INFO, "connection closed\n");
break;
}
/* Ensure message is long enough. */
if (ret != BUFFER_SIZE)
{
xf86IDrvMsg(pInfo, X_ERROR, "invalid message size\n");
break;
}
UnpackNekoMessage(&msg, buffer);
ValuatorMask *m = priv->valuators;
valuator_mask_zero(m);
// do not send valuators if x and y are -1
if (msg.x != -1 && msg.y != -1)
{
valuator_mask_set_double(m, 0, msg.x);
valuator_mask_set_double(m, 1, msg.y);
valuator_mask_set_double(m, 2, msg.pressure);
}
// TODO: extend to other types, such as keyboard and mouse
xf86PostTouchEvent(pInfo->dev, msg.touchId, msg.type, 0, m);
}
/* Close socket. */
close(data_socket);
xf86IDrvMsg(pInfo, X_INFO, "closed connection\n");
}
}
static void
PointerCtrl(__attribute__ ((unused)) DeviceIntPtr device,
__attribute__ ((unused)) PtrCtrl *ctrl)
{
}
static int
DeviceControl(DeviceIntPtr device, int what)
{
// device pInfo
InputInfoPtr pInfo = device->public.devicePrivate;
// custom private data
struct neko_priv *priv = pInfo->private;
switch (what) {
case DEVICE_INIT:
device->public.on = FALSE;
unsigned char map[MAXBUTTONS + 1];
Atom labels[MAXBUTTONS];
Atom axis_labels[TOUCH_NUM_AXES];
// init button map
memset(map, 0, sizeof(map));
for (int i = 0; i < MAXBUTTONS; i++)
{
map[i + 1] = i + 1;
}
// init labels
memset(labels, 0, ARRAY_SIZE(labels) * sizeof(Atom));
labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
labels[7] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_SIDE);
labels[8] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_EXTRA);
labels[9] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_FORWARD);
labels[10] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_BACK);
// init axis labels
memset(axis_labels, 0, ARRAY_SIZE(axis_labels) * sizeof(Atom));
axis_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_X);
axis_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y);
axis_labels[2] = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_PRESSURE);
/* initialize mouse emulation valuators */
if (InitPointerDeviceStruct((DevicePtr)device,
map,
MAXBUTTONS, labels,
PointerCtrl,
GetMotionHistorySize(),
TOUCH_NUM_AXES, axis_labels) == FALSE)
{
xf86IDrvMsg(pInfo, X_ERROR,
"unable to allocate PointerDeviceStruct\n");
return !Success;
}
/*
This function is provided to initialize an XAxisInfoRec, and should be
called for core and extension devices that have valuators. The space
for the XAxisInfoRec is allocated by the InitValuatorClassDeviceStruct
function, but is not initialized.
InitValuatorAxisStruct should be called once for each axis of motion
reported by the device. Each invocation should be passed the axis
number (starting with 0), the minimum value for that axis, the maximum
value for that axis, and the resolution of the device in counts per meter.
If the device reports relative motion, 0 should be reported as the
minimum and maximum values.
InitValuatorAxisStruct(dev, axnum, minval, maxval, resolution)
DeviceIntPtr dev;
int axnum;
int minval;
int maxval;
int resolution;
*/
xf86InitValuatorAxisStruct(device, 0,
XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_X),
0, /* min val */
priv->width - 1, /* max val */
priv->width, /* resolution */
0, /* min_res */
priv->width, /* max_res */
Absolute);
xf86InitValuatorAxisStruct(device, 1,
XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_POSITION_Y),
0, /* min val */
priv->height - 1, /* max val */
priv->height, /* resolution */
0, /* min_res */
priv->height, /* max_res */
Absolute);
xf86InitValuatorAxisStruct(device, 2,
XIGetKnownProperty(AXIS_LABEL_PROP_ABS_MT_PRESSURE),
0, /* min val */
priv->pmax, /* max val */
priv->pmax + 1, /* resolution */
0, /* min_res */
priv->pmax + 1, /* max_res */
Absolute);
/*
The mode field is either XIDirectTouch for directinput touch devices
such as touchscreens or XIDependentTouch for indirect input devices such
as touchpads. For XIDirectTouch devices, touch events are sent to window
at the position the touch occured. For XIDependentTouch devices, touch
events are sent to the window at the position of the device's sprite.
The num_touches field defines the maximum number of simultaneous touches
the device supports. A num_touches of 0 means the maximum number of
simultaneous touches is undefined or unspecified. This field should be
used as a guide only, devices will lie about their capabilities.
*/
if (InitTouchClassDeviceStruct(device,
priv->slots,
XIDirectTouch,
TOUCH_NUM_AXES) == FALSE)
{
xf86IDrvMsg(pInfo, X_ERROR,
"unable to allocate TouchClassDeviceStruct\n");
return !Success;
}
break;
case DEVICE_ON:
xf86IDrvMsg(pInfo, X_INFO, "DEVICE ON\n");
device->public.on = TRUE;
if (priv->thread == 0)
{
/* start thread */
pthread_create(&priv->thread, NULL, (void *)ReadInput, pInfo);
}
break;
case DEVICE_OFF:
case DEVICE_CLOSE:
xf86IDrvMsg(pInfo, X_INFO, "DEVICE OFF\n");
device->public.on = FALSE;
break;
}
return Success;
}
static int
PreInit(__attribute__ ((unused)) InputDriverPtr drv,
InputInfoPtr pInfo,
__attribute__ ((unused)) int flags)
{
struct neko_priv *priv;
int ret;
priv = calloc(1, sizeof (struct neko_priv));
if (!priv)
{
xf86IDrvMsg(pInfo, X_ERROR, "%s: out of memory\n", __FUNCTION__);
return BadValue;
}
pInfo->type_name = (char*)XI_TOUCHSCREEN;
pInfo->device_control = DeviceControl;
pInfo->read_input = NULL;
pInfo->control_proc = NULL;
pInfo->switch_mode = NULL; /* Only support Absolute mode */
pInfo->private = priv;
pInfo->fd = -1;
/* get socket name from config */
priv->socket_name = xf86SetStrOption(pInfo->options, "SocketName", DEF_SOCKET_NAME);
/*
* In case the program exited inadvertently on the last run,
* remove the socket.
*/
unlink(priv->socket_name);
/* Create local socket. */
priv->listen_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (priv->listen_socket == -1)
{
xf86IDrvMsg(pInfo, X_ERROR, "unable to create socket\n");
return BadValue;
}
/*
* For portability clear the whole structure, since some
* implementations have additional (nonstandard) fields in
* the structure.
*/
memset(&priv->addr, 0, sizeof(struct sockaddr_un));
/* Bind socket to socket name. */
priv->addr.sun_family = AF_UNIX;
strncpy(priv->addr.sun_path, priv->socket_name, sizeof(priv->addr.sun_path) - 1);
ret = bind(priv->listen_socket, (const struct sockaddr *) &priv->addr, sizeof(struct sockaddr_un));
if (ret == -1)
{
xf86IDrvMsg(pInfo, X_ERROR, "unable to bind socket\n");
return BadValue;
}
/*
* Prepare for accepting connections. The backlog size is set
* to 5. So while one request is being processed other requests
* can be waiting.
*/
ret = listen(priv->listen_socket, 5);
if (ret == -1)
{
xf86IDrvMsg(pInfo, X_ERROR, "unable to listen on socket\n");
return BadValue;
}
/* process generic options */
xf86CollectInputOptions(pInfo, NULL);
xf86ProcessCommonOptions(pInfo, pInfo->options);
/* create valuators */
priv->valuators = valuator_mask_new(TOUCH_NUM_AXES);
if (!priv->valuators)
{
xf86IDrvMsg(pInfo, X_ERROR, "%s: out of memory\n", __FUNCTION__);
return BadValue;
}
priv->slots = TOUCH_MAX_SLOTS;
priv->width = 0xffff;
priv->height = 0xffff;
priv->pmax = 255;
priv->thread = 0;
/* Return the configured device */
return Success;
}
static void
UnInit(__attribute__ ((unused)) InputDriverPtr drv,
InputInfoPtr pInfo,
__attribute__ ((unused)) int flags)
{
struct neko_priv *priv = (struct neko_priv *)(pInfo->private);
/* close socket */
close(priv->listen_socket);
/* remove socket file */
unlink(priv->socket_name);
if (priv->thread)
{
/* cancel thread */
pthread_cancel(priv->thread);
/* wait for thread to finish */
pthread_join(priv->thread, NULL);
/* ensure thread is not cancelled again */
priv->thread = 0;
}
valuator_mask_free(&priv->valuators);
DeviceControl(pInfo->dev, DEVICE_OFF);
free(pInfo->private);
pInfo->private = NULL;
xf86DeleteInput(pInfo, 0);
}
/**
* X module information and plug / unplug routines
*/
_X_EXPORT InputDriverRec NEKO =
{
.driverVersion = 1,
.driverName = "neko",
.Identify = NULL,
.PreInit = PreInit,
.UnInit = UnInit,
.module = NULL
};
static pointer
Plug(pointer module,
__attribute__ ((unused)) pointer options,
__attribute__ ((unused)) int *errmaj,
__attribute__ ((unused)) int *errmin)
{
xf86AddInputDriver(&NEKO, module, 0);
return module;
}
static void
Unplug(__attribute__ ((unused)) pointer module)
{
}
static XF86ModuleVersionInfo versionRec =
{
.modname = "neko",
.vendor = MODULEVENDORSTRING,
._modinfo1_ = MODINFOSTRING1,
._modinfo2_ = MODINFOSTRING2,
.xf86version = XORG_VERSION_CURRENT,
.majorversion = PACKAGE_VERSION_MAJOR,
.minorversion = PACKAGE_VERSION_MINOR,
.patchlevel = PACKAGE_VERSION_PATCHLEVEL,
.abiclass = ABI_CLASS_XINPUT,
.abiversion = ABI_XINPUT_VERSION,
.moduleclass = MOD_CLASS_XINPUT,
.checksum = {0, 0, 0, 0} /* signature, to be patched into the file by a tool */
};
_X_EXPORT XF86ModuleData nekoModuleData =
{
.vers = &versionRec,
.setup = Plug,
.teardown = Unplug
};

View File

@ -0,0 +1,5 @@
Name: xorg-neko
Description: X.Org neko input driver.
Version: @PACKAGE_VERSION@
Libs: -L${libdir}
Cflags: -I${includedir}