diff options
-rw-r--r-- | Makefile.am | 7 | ||||
-rw-r--r-- | configure.ac | 16 | ||||
-rw-r--r-- | test/Makefile.am | 35 | ||||
-rw-r--r-- | test/abs.c | 84 | ||||
-rw-r--r-- | test/absrel.c | 91 | ||||
-rw-r--r-- | test/btn0.c | 87 | ||||
-rw-r--r-- | test/fakedev.c | 199 | ||||
-rw-r--r-- | test/fakedev.h | 51 |
8 files changed, 569 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 99f7160..d8397f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/configure.ac b/configure.ac index 4233a22..4ba5a8a 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..4b417b8 --- /dev/null +++ b/test/Makefile.am @@ -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) diff --git a/test/abs.c b/test/abs.c new file mode 100644 index 0000000..8529190 --- /dev/null +++ b/test/abs.c @@ -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; +} diff --git a/test/absrel.c b/test/absrel.c new file mode 100644 index 0000000..3ae2a1c --- /dev/null +++ b/test/absrel.c @@ -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; +} + diff --git a/test/btn0.c b/test/btn0.c new file mode 100644 index 0000000..f6572a5 --- /dev/null +++ b/test/btn0.c @@ -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; +} diff --git a/test/fakedev.c b/test/fakedev.c new file mode 100644 index 0000000..a3a1b81 --- /dev/null +++ b/test/fakedev.c @@ -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; +} + diff --git a/test/fakedev.h b/test/fakedev.h new file mode 100644 index 0000000..465722a --- /dev/null +++ b/test/fakedev.h @@ -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 |