diff options
author | Peter Hutterer <peter.hutterer@redhat.com> | 2008-10-29 16:54:16 +1030 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@redhat.com> | 2008-10-30 16:51:55 +1030 |
commit | d5cf24d3f0075a467e026592bfbb76b207dea8eb (patch) | |
tree | f47fcb6e72a6d087b40731376835569a36dd02e0 /test/fakedev.c | |
parent | 64554e4799a697d37dfd8be480f8eee636b9bea1 (diff) |
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>
Diffstat (limited to 'test/fakedev.c')
-rw-r--r-- | test/fakedev.c | 199 |
1 files changed, 199 insertions, 0 deletions
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; +} + |