summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikolai Kondrashov <spbnick@gmail.com>2009-04-23 23:25:54 +0400
committerPeter Hutterer <peter.hutterer@who-t.net>2009-04-24 08:17:57 +1000
commitb01d96b9cf682b796adaeb6c79a2f29c0eac7864 (patch)
tree57200e84d5e17789e1a349bcc73cd795deb39fe9
parentfc51ae892e77fddca7b3aad5a9e23c49fe2d3bc8 (diff)
Added tablet pen test device
Added tablet pen test device (pen.c) which is supposed to reproduce GIMP misbehaviour regarding the (absence of) button pressure coordinates handling and possibly invalid usage of BTN_TOUCH by evdev. Fixed missing device error message. Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/Makefile.am3
-rw-r--r--src/fakedev.c3
-rw-r--r--src/pen.c179
3 files changed, 183 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index a59c33c..7f84057 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,7 +22,7 @@ LIBNAME=libfakedev.a
AM_LDFLAGS = $(LIBNAME)
-noinst_PROGRAMS=btn0 absrel abs dummy synaptics allbtn wacom
+noinst_PROGRAMS=btn0 absrel abs pen dummy synaptics allbtn wacom
noinst_LIBRARIES=$(LIBNAME)
libfakedev_a_SOURCES=fakedev.c fakedev.h
@@ -30,6 +30,7 @@ libfakedev_a_SOURCES=fakedev.c fakedev.h
btn0_SOURCES=btn0.c
absrel_SOURCES=absrel.c
abs_SOURCES=abs.c
+pen_SOURCES=pen.c
dummy_SOURCES=dummy.c
synaptics_SOURCES=synaptics.c
allbtn_SOURCES=allbtn.c
diff --git a/src/fakedev.c b/src/fakedev.c
index 9df98d9..f95ea2f 100644
--- a/src/fakedev.c
+++ b/src/fakedev.c
@@ -155,7 +155,8 @@ int main (int argc, char **argv)
dev = get_device();
if (init_uinput(dev) < 0) {
- fprintf(stderr, "Failed to initialize /dev/uinput. Exiting.\n");
+ fprintf(stderr,
+ "Failed to initialize /dev/input/uinput. Exiting.\n");
return -1;
}
diff --git a/src/pen.c b/src/pen.c
new file mode 100644
index 0000000..eb3de2f
--- /dev/null
+++ b/src/pen.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright © 2009 Nikolai Kondrashov
+ *
+ * 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:
+ * Nikolai Kondrashov (spbnick@gmail.com)
+ */
+
+
+/*
+ * Creates a tablet pen device with ABS_X, ABS_Y, ABS_PRESSURE, BTN_LEFT and
+ * BTN_TOUCH.
+ *
+ * Scenario:
+ *
+ * 1. Move the pen in a square around the center without pressure.
+ * 2. Send the following event sequence in order to trigger the GIMP-on-evdev
+ * bug:
+ *
+ * EV_KEY BTN_LEFT 1
+ * EV_ABS ABS_X (middle - half square size)
+ * EV_ABS ABS_Y (middle - half square size)
+ * EV_ABS ABS_PRESSURE (maximum)
+ * EV_KEY BTN_TOUCH 1
+ * EV_SYN SYN_REPORT
+ *
+ * Move the pen in a square around the center (previous pressure remains).
+ *
+ * 3. Send the following event sequence in order to turn off the "tool" flag
+ * in the evdev driver and stop it from interpreting further input:
+ *
+ * EV_KEY BTN_LEFT 0
+ * EV_KEY BTN_TOUCH 0
+ * EV_ABS ABS_PRESSURE 0
+ * EV_SYN SYN_REPORT
+ *
+ * 4. Move the pen in a square around the center.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/input.h>
+#include <linux/uinput.h>
+
+#include "fakedev.h"
+
+#define X_MAX 32767
+#define Y_MAX 32767
+#define PRESSURE_MAX 1023
+
+#define X_MIDDLE ((X_MAX + 1) / 2)
+#define Y_MIDDLE ((Y_MAX + 1) / 2)
+
+#define SQUARE_SIZE ((X_MAX + 1) / 8)
+#define HALF_SQUARE_SIZE (SQUARE_SIZE / 2)
+
+#define SQUARE_LEFT (X_MIDDLE - HALF_SQUARE_SIZE)
+#define SQUARE_RIGHT (X_MIDDLE + HALF_SQUARE_SIZE)
+#define SQUARE_TOP (Y_MIDDLE - HALF_SQUARE_SIZE)
+#define SQUARE_BOTTOM (Y_MIDDLE + HALF_SQUARE_SIZE)
+
+static int pen_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_KEY) == -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_TOUCH) == -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;
+ if (ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE) == -1) goto error;
+
+
+ dev->absmin[ABS_X] = 0;
+ dev->absmax[ABS_X] = X_MAX;
+
+ dev->absmin[ABS_Y] = 0;
+ dev->absmax[ABS_Y] = Y_MAX;
+
+ dev->absmin[ABS_PRESSURE] = 0;
+ dev->absmax[ABS_PRESSURE] = PRESSURE_MAX;
+
+ return 0;
+
+error:
+ perror("ioctl failed.");
+ return -1;
+}
+
+static int pen_run(int fd)
+{
+ /* Move the pen in a square around the center, without the pressure */
+ send_event(fd, EV_ABS, ABS_X, SQUARE_LEFT);
+ send_event(fd, EV_ABS, ABS_Y, SQUARE_TOP);
+ send_event(fd, EV_ABS, ABS_PRESSURE, 0);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_X, SQUARE_RIGHT);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_Y, SQUARE_BOTTOM);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_X, SQUARE_LEFT);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+
+ /* Trigger GIMP-on-evdev bug and start drawing */
+ send_event(fd, EV_KEY, BTN_LEFT, 1);
+ send_event(fd, EV_ABS, ABS_Y, SQUARE_TOP);
+ send_event(fd, EV_ABS, ABS_PRESSURE, PRESSURE_MAX);
+ send_event(fd, EV_KEY, BTN_TOUCH, 1);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(2);
+
+ /* Move the pen in a square around the center */
+ send_event(fd, EV_ABS, ABS_X, SQUARE_RIGHT);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_Y, SQUARE_BOTTOM);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_X, SQUARE_LEFT);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_Y, SQUARE_TOP);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+
+ /*
+ * Turn off the evdev "tool" flag and stop it from interpreting further
+ * input. Lift the pen.
+ */
+ send_event(fd, EV_KEY, BTN_LEFT, 0);
+ send_event(fd, EV_ABS, ABS_PRESSURE, 0);
+ send_event(fd, EV_KEY, BTN_TOUCH, 0);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(2);
+
+ /* Move the pen in a square around the center */
+ send_event(fd, EV_ABS, ABS_X, SQUARE_RIGHT);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_Y, SQUARE_BOTTOM);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_X, SQUARE_LEFT);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(1);
+ send_event(fd, EV_ABS, ABS_Y, SQUARE_TOP);
+ send_event(fd, EV_SYN, SYN_REPORT, 0);
+ sleep(2);
+
+ return 0;
+}
+
+static struct test_device pen_dev = {
+ .name = "Tablet pen test device",
+ .setup = pen_setup,
+ .run = pen_run,
+};
+
+
+struct test_device* get_device(void)
+{
+ return &pen_dev;
+}