Add test/ directory for uinput-based test devices.

Three test devices provided:
btn0 .... Provides BTN_0, BTN_1, BTN_2 instead of BTN_LEFT, BTN_MIDDLE,
          BTN_RIGHT.
abs ..... Provdes x/y absolute axes, jumps between 100/100 and 120/120.
absrel .. Provides relative x/y axes and absolute x/y axes at the same time.

Signed-off-by: Peter Hutterer <peter.hutterer@redhat.com>
This commit is contained in:
Peter Hutterer
2008-10-29 16:54:16 +10:30
parent 64554e4799
commit d5cf24d3f0
8 changed files with 569 additions and 1 deletions

View File

@@ -19,7 +19,12 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
AUTOMAKE_OPTIONS = foreign
SUBDIRS = src man include
if BUILD_TEST
test_dir=test
endif
SUBDIRS = src man include $(test_dir)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = xorg-evdev.pc

View File

@@ -52,6 +52,21 @@ AC_ARG_WITH(xorg-module-dir,
inputdir=${moduledir}/input
AC_SUBST(inputdir)
# Enable building everything in the test/ directory. These are uinput-based
# devices that resemble random hardware that may or may not look like a mouse,
# keyboard, etc.
AC_ARG_ENABLE(testdevices,
AC_HELP_STRING([--enable-testdevices], [Build uinput-based test devices]),
[BUILD_TEST="yes"],
[BUILD_TEST="no"])
AM_CONDITIONAL([BUILD_TEST], [test "x$BUILD_TEST" = "xyes"])
if test "x$BUILD_TEST" = "xyes"; then
AC_CHECK_FUNC([dlopen], [],
AC_CHECK_LIB([dl], [dlopen], DLOPEN_LIBS="-ldl"))
AC_SUBST([DLOPEN_LIBS])
fi
# Checks for extensions
XORG_DRIVER_CHECK_EXT(XINPUT, inputproto)
@@ -75,4 +90,5 @@ AC_OUTPUT([Makefile
src/Makefile
man/Makefile
include/Makefile
test/Makefile
xorg-evdev.pc])

35
test/Makefile.am Normal file
View File

@@ -0,0 +1,35 @@
# Copyright 2008 Red Hat, Inc.
#
# 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
# THE AUTHORS 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.
noinst_PROGRAMS=fakedev btn0 absrel abs
fakedev_SOURCES=fakedev.c fakedev.h
fakedev_LDFLAGS=$(DLOPEN_LIBS) -rdynamic
LFLAGS=-shared -fPIC
btn0_SOURCES=btn0.c
btn0_LDFLAGS=$(LFLAGS)
absrel_SOURCES=absrel.c
absrel_LDFLAGS=$(LFLAGS)
abs_SOURCES=abs.c
abs_LDFLAGS=$(LFLAGS)

84
test/abs.c Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* 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:
* Peter Hutterer (peter.hutterer@redhat.com)
*/
/* creates a device with ABS_X, ABS_Y, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT. */
#include <stdio.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include "fakedev.h"
int abs_setup(struct uinput_user_dev* dev, int fd)
{
if (ioctl(fd, UI_SET_EVBIT, EV_ABS) == -1) goto error;
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) == -1) goto error;
/* buttons */
if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) == -1) goto error;
if (ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE) == -1) goto error;
if (ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT) == -1) goto error;
/* axes */
if (ioctl(fd, UI_SET_ABSBIT, ABS_X) == -1) goto error;
if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) == -1) goto error;
dev->absmin[ABS_X] = 0;
dev->absmax[ABS_X] = 120;
dev->absmin[ABS_Y] = 0;
dev->absmax[ABS_Y] = 120;
return 0;
error:
perror("ioctl failed.");
return -1;
}
int abs_run(int fd)
{
absmove(fd, 100, 100);
sleep(1);
absmove(fd, 120, 120);
sleep(1);
return 0;
}
struct test_device abs_dev = {
.name = "Abs test device",
.setup = abs_setup,
.run = abs_run,
};
struct test_device* get_device()
{
return &abs_dev;
}

91
test/absrel.c Normal file
View File

@@ -0,0 +1,91 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* 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:
* Peter Hutterer (peter.hutterer@redhat.com)
*/
/* creates a device with ABS_X, ABS_Y, REL_X, REL_Y, BTN_LEFT, BTN_MIDDLE,
BTN_RIGHT. */
#include <stdio.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include "fakedev.h"
int absrel_setup(struct uinput_user_dev* dev, int fd)
{
if (ioctl(fd, UI_SET_EVBIT, EV_REL) == -1) goto error;
if (ioctl(fd, UI_SET_EVBIT, EV_ABS) == -1) goto error;
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) == -1) goto error;
/* buttons */
if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) == -1) goto error;
if (ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE) == -1) goto error;
if (ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT) == -1) goto error;
/* axes */
if (ioctl(fd, UI_SET_RELBIT, REL_X) == -1) goto error;
if (ioctl(fd, UI_SET_RELBIT, REL_Y) == -1) goto error;
if (ioctl(fd, UI_SET_ABSBIT, ABS_X) == -1) goto error;
if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) == -1) goto error;
dev->absmin[ABS_X] = 0;
dev->absmax[ABS_X] = 1000;
dev->absmin[ABS_Y] = 0;
dev->absmax[ABS_Y] = 1000;
return 0;
error:
perror("ioctl failed.");
return -1;
}
int absrel_run(int fd)
{
absmove(fd, 100, 100);
sleep(1);
absmove(fd, 120, 120);
sleep(1);
move(fd, 10, 10);
return 0;
}
struct test_device absrel_dev = {
.name = "Abs/Rel test device",
.setup = absrel_setup,
.run = absrel_run,
};
struct test_device* get_device()
{
return &absrel_dev;
}

87
test/btn0.c Normal file
View File

@@ -0,0 +1,87 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* 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:
* Peter Hutterer (peter.hutterer@redhat.com)
*/
/* Creates a device that has REL_X REL_Y BTN_0 BTN_1 BTN_2
*
* Moves the device around in a 10px square and clicks after each completed
* circle.
*/
#include <stdio.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include "fakedev.h"
int btn0_setup(struct uinput_user_dev *dev, int fd)
{
if (ioctl(fd, UI_SET_EVBIT, EV_KEY) == -1) goto error;
if (ioctl(fd, UI_SET_EVBIT, EV_REL) == -1) goto error;
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) == -1) goto error;
/* buttons */
if (ioctl(fd, UI_SET_KEYBIT, BTN_0) == -1) goto error;
if (ioctl(fd, UI_SET_KEYBIT, BTN_1) == -1) goto error;
if (ioctl(fd, UI_SET_KEYBIT, BTN_2) == -1) goto error;
/* axes */
if (ioctl(fd, UI_SET_RELBIT, REL_X) == -1) goto error;
if (ioctl(fd, UI_SET_RELBIT, REL_Y) == -1) goto error;
return 0;
error:
perror("ioctl failed.");
return -1;
}
int btn0_run(int fd)
{
move(fd, -10, 0);
usleep(1000);
move(fd, 0, -10);
usleep(1000);
move(fd, 10, 0);
usleep(1000);
move(fd, 0, 10);
usleep(1000);
click(fd, BTN_0, 1);
usleep(1000);
click(fd, BTN_0, 0);
return 0;
}
struct test_device btn0_dev = {
.name = "BTN_0 test device",
.setup = btn0_setup,
.run = btn0_run,
};
struct test_device* get_device()
{
return &btn0_dev;
}

199
test/fakedev.c Normal file
View File

@@ -0,0 +1,199 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* 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:
* Peter Hutterer (peter.hutterer@redhat.com)
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <dlfcn.h>
#include "fakedev.h"
/* "public interfaces" */
void send_event(int fd, int type, int code, int value)
{
struct input_event event;
event.type = type;
event.code = code;
event.value = value;
gettimeofday(&event.time, NULL);
if (write(fd, &event, sizeof(event)) < sizeof(event))
perror("Send event failed.");
}
void move(int fd, int x, int y)
{
if (!x && !y)
return;
send_event(fd, EV_REL, REL_X, x);
send_event(fd, EV_REL, REL_Y, y);
send_event(fd, EV_SYN, SYN_REPORT, 0);
}
void absmove(int fd, int x, int y)
{
send_event(fd, EV_ABS, ABS_X, x);
send_event(fd, EV_ABS, ABS_Y, y);
send_event(fd, EV_SYN, SYN_REPORT, 0);
}
void click(int fd, int btn, int down)
{
send_event(fd, EV_KEY, btn, down);
send_event(fd, EV_SYN, SYN_REPORT, 0);
}
/* end public interfaces */
static int fd = -1;
static int stop = 0;
static void sighandler(int signum)
{
printf("Stopping.\n");
stop = 1;
}
static void init_signal(void)
{
struct sigaction action;
sigset_t mask;
sigfillset(&mask);
action.sa_handler = sighandler;
action.sa_mask = mask;
action.sa_flags = 0;
sigaction(SIGTERM, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigprocmask(SIG_UNBLOCK, &mask, 0);
}
static int init_uinput(struct test_device* test_dev)
{
struct uinput_user_dev dev;
fd = open("/dev/input/uinput", O_RDWR);
if (fd < 0)
goto error;
memset(&dev, 0, sizeof(dev));
strcpy(dev.name, test_dev->name);
dev.id.bustype = 0;
dev.id.vendor = 0x1F;
dev.id.product = 0x1F;
dev.id.version = 0;
test_dev->setup(&dev, fd);
if (write(fd, &dev, sizeof(dev)) < sizeof(dev))
goto error;
if (ioctl(fd, UI_DEV_CREATE, NULL) == -1) goto error;
return 0;
error:
fprintf(stderr, "Error: %s\n", strerror(errno));
if (fd != -1)
close(fd);
return -1;
}
static void cleanup_uinput(void)
{
if (fd == -1)
return;
ioctl(fd, UI_DEV_DESTROY, NULL);
close(fd);
fd = -1;
}
int main (int argc, char **argv)
{
struct test_device *dev;
void *dlhandle = NULL;
struct test_device* (*get_device)(void);
if (argc <= 1)
{
fprintf(stderr, "Usage: %s test_dev\n", argv[0]);
return -1;
}
printf("Loading %s.\n", argv[1]);
dlhandle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
if (!dlhandle)
{
fprintf(stderr, "Error: %s\n", dlerror());
return -1;
}
*(void**)(&get_device) = dlsym(dlhandle, "get_device");
if (!get_device)
{
fprintf(stderr, "Error getting the symbol: %s.\n", dlerror());
return -1;
}
dev = (*get_device)();
if (init_uinput(dev) < 0) {
fprintf(stderr, "Failed to initialize /dev/uinput. Exiting.\n");
return -1;
}
init_signal();
printf("Device created. Press CTRL+C to terminate.\n");
while (!stop) {
if (dev->run(fd))
break;
}
cleanup_uinput();
return 0;
}

51
test/fakedev.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* 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:
* Peter Hutterer (peter.hutterer@redhat.com)
*/
#ifndef _EVDEV_TEST_H
#define _EVDEV_TEST_H
#include <linux/uinput.h>
struct test_device {
char *name; /* device name */
/**
* Called to setup the device. Call ioctls to set your EVBITs, KEYBITs,
* etc. here. Return 0 on success or non-zero to exit.
*/
int (*setup)(struct uinput_user_dev* dev, int fd);
/**
* Called during each run of the main loop. Generate events by calling
* move(), click(), etc.
* Return 0 on success, or non-zero to stop the main loop.
*/
int (*run)(int fd);
};
extern void move (int fd, int x, int y);
extern void absmove (int fd, int x, int y);
extern void click (int fd, int btn, int down);
#endif