mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 04:22:05 +00:00
tests: Add unit test for touch event handling
For now, it just generates a simple horizontal slide (by writing to /dev/uinput) and checks that the stage gets the events at the expected coordinates. The test won't run if it doesn't have read/write permissions to /dev/uinput. It also adds OS_LINUX to config.h.
This commit is contained in:
parent
ebb61dea1f
commit
b339b845cb
@ -436,6 +436,11 @@ AS_IF([test "x$CLUTTER_BACKENDS" = "x"],
|
|||||||
AC_MSG_ERROR([No backend enabled. You need to enable at least one backend.])
|
AC_MSG_ERROR([No backend enabled. You need to enable at least one backend.])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
AS_IF([test "x$platform_linux" = "xyes"],
|
||||||
|
[
|
||||||
|
AC_DEFINE([OS_LINUX], [1], [Define to 1 if building for Linux])
|
||||||
|
])
|
||||||
|
|
||||||
# additional input backends
|
# additional input backends
|
||||||
|
|
||||||
AC_ARG_ENABLE([tslib-input],
|
AC_ARG_ENABLE([tslib-input],
|
||||||
|
@ -82,6 +82,11 @@ units_sources += \
|
|||||||
cally-text.c \
|
cally-text.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
# events tests
|
||||||
|
units_sources += \
|
||||||
|
events-touch.c \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
test_conformance_SOURCES = $(common_sources) $(units_sources)
|
test_conformance_SOURCES = $(common_sources) $(units_sources)
|
||||||
|
|
||||||
if OS_WIN32
|
if OS_WIN32
|
||||||
|
379
tests/conform/events-touch.c
Normal file
379
tests/conform/events-touch.c
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Red Hat, Inc.
|
||||||
|
* Copyright (C) 2012 Collabora Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <clutter/clutter.h>
|
||||||
|
|
||||||
|
#if defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/uinput.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <clutter/x11/clutter-x11.h>
|
||||||
|
|
||||||
|
#include "test-conform-common.h"
|
||||||
|
|
||||||
|
#define ABS_MAX_X 32768
|
||||||
|
#define ABS_MAX_Y 32768
|
||||||
|
|
||||||
|
#define TOUCH_POINTS 10
|
||||||
|
|
||||||
|
static ClutterPoint gesture_points[] = {
|
||||||
|
{ 100., 100. },
|
||||||
|
{ 110., 100. },
|
||||||
|
{ 120., 100. },
|
||||||
|
{ 130., 100. },
|
||||||
|
{ 140., 100. },
|
||||||
|
{ 150., 100. },
|
||||||
|
{ 160., 100. },
|
||||||
|
{ 170., 100. },
|
||||||
|
{ 180., 100. },
|
||||||
|
{ 190., 100. },
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _State State;
|
||||||
|
|
||||||
|
struct _State
|
||||||
|
{
|
||||||
|
gboolean pass;
|
||||||
|
ClutterPoint gesture_points_to_check[TOUCH_POINTS];
|
||||||
|
int gesture_points;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int fd = -1;
|
||||||
|
|
||||||
|
static void send_event(int fd, int type, int code, int value, int sec, int usec)
|
||||||
|
{
|
||||||
|
static int sec_offset = -1;
|
||||||
|
static long last_time = -1;
|
||||||
|
long newtime;
|
||||||
|
struct input_event event;
|
||||||
|
|
||||||
|
event.type = type;
|
||||||
|
event.code = code;
|
||||||
|
event.value = value;
|
||||||
|
|
||||||
|
if (sec_offset == -1)
|
||||||
|
sec_offset = sec;
|
||||||
|
|
||||||
|
sec -= sec_offset;
|
||||||
|
newtime = sec * 1000000 + usec;
|
||||||
|
|
||||||
|
if (last_time > 0)
|
||||||
|
usleep(newtime - last_time);
|
||||||
|
|
||||||
|
gettimeofday(&event.time, NULL);
|
||||||
|
|
||||||
|
if (write(fd, &event, sizeof(event)) < sizeof(event))
|
||||||
|
perror("Send event failed.");
|
||||||
|
|
||||||
|
last_time = newtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
event_cb (ClutterActor *actor, ClutterEvent *event, State *state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (event->type != CLUTTER_TOUCH_BEGIN &&
|
||||||
|
event->type != CLUTTER_TOUCH_UPDATE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
state->gesture_points_to_check[state->gesture_points].x = ceil (event->touch.x);
|
||||||
|
state->gesture_points_to_check[state->gesture_points].y = ceil (event->touch.y);
|
||||||
|
state->gesture_points++;
|
||||||
|
|
||||||
|
if (state->gesture_points == TOUCH_POINTS)
|
||||||
|
{
|
||||||
|
for (i = 0; i < TOUCH_POINTS; i++)
|
||||||
|
{
|
||||||
|
if (state->gesture_points_to_check[i].x != gesture_points[i].x ||
|
||||||
|
state->gesture_points_to_check[i].y != gesture_points[i].y)
|
||||||
|
{
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_print ("error: expected (%d, %d) but found (%d, %d) at position %d\n",
|
||||||
|
(int) gesture_points[i].x, (int) gesture_points[i].y,
|
||||||
|
(int) state->gesture_points_to_check[i].x,
|
||||||
|
(int) state->gesture_points_to_check[i].y,
|
||||||
|
i);
|
||||||
|
state->pass = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clutter_main_quit ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
screen_coords_to_device (int screen_x, int screen_y,
|
||||||
|
int *device_x, int *device_y)
|
||||||
|
{
|
||||||
|
int display_width = DisplayWidth (clutter_x11_get_default_display (),
|
||||||
|
clutter_x11_get_default_screen ());
|
||||||
|
int display_height = DisplayHeight (clutter_x11_get_default_display (),
|
||||||
|
clutter_x11_get_default_screen ());
|
||||||
|
|
||||||
|
*device_x = (screen_x * ABS_MAX_X) / display_width;
|
||||||
|
*device_y = (screen_y * ABS_MAX_Y) / display_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
perform_gesture (gpointer data)
|
||||||
|
{
|
||||||
|
State *state = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < TOUCH_POINTS; i++)
|
||||||
|
{
|
||||||
|
int x = gesture_points[i].x;
|
||||||
|
int y = gesture_points[i].y;
|
||||||
|
|
||||||
|
screen_coords_to_device (x, y, &x, &y);
|
||||||
|
|
||||||
|
send_event(fd, EV_ABS, ABS_MT_SLOT, 0, 1, i * 100);
|
||||||
|
send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, 1, 1, i * 100 + 10);
|
||||||
|
|
||||||
|
send_event(fd, EV_ABS, ABS_MT_POSITION_X, x, 1, i * 100 + 20);
|
||||||
|
send_event(fd, EV_ABS, ABS_MT_POSITION_Y, y, 1, i * 100 + 30);
|
||||||
|
send_event(fd, EV_SYN, SYN_MT_REPORT, 0, 1, i * 100 + 40);
|
||||||
|
send_event(fd, EV_SYN, SYN_REPORT, 0, 1, i * 100 + 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1, 1, TOUCH_POINTS * 100 + 10);
|
||||||
|
send_event(fd, EV_SYN, SYN_MT_REPORT, 0, 1, TOUCH_POINTS * 100 + 20);
|
||||||
|
send_event(fd, EV_SYN, SYN_REPORT, 0, 1, TOUCH_POINTS * 100 + 30);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
setup (struct uinput_user_dev *dev, int fd)
|
||||||
|
{
|
||||||
|
strcpy (dev->name, "eGalax Touch Screen");
|
||||||
|
dev->id.bustype = 0x18;
|
||||||
|
dev->id.vendor = 0xeef;
|
||||||
|
dev->id.product = 0x20;
|
||||||
|
dev->id.version = 0x1;
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_EVBIT, EV_SYN) == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_EVBIT, EV_KEY) == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_KEYBIT, BTN_TOUCH) == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_EVBIT, EV_ABS) == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_X) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_X;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = ABS_MAX_X;
|
||||||
|
dev->absfuzz[idx] = 1;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_Y) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_Y;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = ABS_MAX_Y;
|
||||||
|
dev->absfuzz[idx] = 1;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_PRESSURE) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_PRESSURE;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = 0;
|
||||||
|
dev->absfuzz[idx] = 0;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_MT_TOUCH_MAJOR;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = 255;
|
||||||
|
dev->absfuzz[idx] = 1;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_WIDTH_MAJOR) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_MT_WIDTH_MAJOR;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = 255;
|
||||||
|
dev->absfuzz[idx] = 1;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_POSITION_X) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_MT_POSITION_X;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = ABS_MAX_X;
|
||||||
|
dev->absfuzz[idx] = 1;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_MT_POSITION_Y;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = ABS_MAX_Y;
|
||||||
|
dev->absfuzz[idx] = 1;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID) == -1)
|
||||||
|
goto error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int idx = ABS_MT_TRACKING_ID;
|
||||||
|
dev->absmin[idx] = 0;
|
||||||
|
dev->absmax[idx] = 5;
|
||||||
|
dev->absfuzz[idx] = 0;
|
||||||
|
dev->absflat[idx] = 0;
|
||||||
|
|
||||||
|
if (dev->absmin[idx] == dev->absmax[idx])
|
||||||
|
dev->absmax[idx]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
perror ("ioctl failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_uinput ()
|
||||||
|
{
|
||||||
|
struct uinput_user_dev dev;
|
||||||
|
|
||||||
|
fd = open ("/dev/uinput", O_RDWR);
|
||||||
|
if (fd < 0 && errno == ENODEV)
|
||||||
|
fd = open ("/dev/input/uinput", O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
memset (&dev, 0, sizeof (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:
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_print ("error: %s\n", strerror (errno));
|
||||||
|
|
||||||
|
if (fd != -1)
|
||||||
|
close (fd);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 */
|
||||||
|
|
||||||
|
void
|
||||||
|
events_touch (void)
|
||||||
|
{
|
||||||
|
#if defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2
|
||||||
|
ClutterActor *stage;
|
||||||
|
State state;
|
||||||
|
|
||||||
|
state.pass = TRUE;
|
||||||
|
state.gesture_points = 0;
|
||||||
|
|
||||||
|
stage = clutter_stage_new ();
|
||||||
|
g_signal_connect (stage, "event", G_CALLBACK (event_cb), &state);
|
||||||
|
clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), TRUE);
|
||||||
|
clutter_actor_show (stage);
|
||||||
|
|
||||||
|
g_assert (init_uinput () == 0);
|
||||||
|
|
||||||
|
clutter_threads_add_timeout (500, perform_gesture, &state);
|
||||||
|
|
||||||
|
clutter_main ();
|
||||||
|
|
||||||
|
if (g_test_verbose ())
|
||||||
|
g_print ("end result: %s\n", state.pass ? "pass" : "FAIL");
|
||||||
|
|
||||||
|
g_assert (state.pass);
|
||||||
|
|
||||||
|
clutter_actor_destroy (stage);
|
||||||
|
#endif /* defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 */
|
||||||
|
}
|
@ -45,6 +45,8 @@ test_conform_simple_fixture_setup (TestConformSimpleFixture *fixture,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
clutter_x11_enable_xinput ();
|
||||||
|
|
||||||
g_assert (clutter_init (shared_state->argc_addr, shared_state->argv_addr)
|
g_assert (clutter_init (shared_state->argc_addr, shared_state->argv_addr)
|
||||||
== CLUTTER_INIT_SUCCESS);
|
== CLUTTER_INIT_SUCCESS);
|
||||||
|
|
||||||
|
@ -116,6 +116,13 @@ clutter_test_init (gint *argc,
|
|||||||
shared_state->argv_addr = argv;
|
shared_state->argv_addr = argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
can_write_to_uinput ()
|
||||||
|
{
|
||||||
|
return g_access ("/dev/uinput", R_OK | W_OK) ||
|
||||||
|
g_access ("/dev/input/uinput", R_OK | W_OK);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -253,6 +260,8 @@ main (int argc, char **argv)
|
|||||||
TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_interleved);
|
TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_interleved);
|
||||||
TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_mutability);
|
TEST_CONFORM_SIMPLE ("/cogl/vertex-buffer", test_cogl_vertex_buffer_mutability);
|
||||||
|
|
||||||
|
TEST_CONFORM_SKIP (can_write_to_uinput (), "/events", events_touch);
|
||||||
|
|
||||||
/* left to the end because they aren't currently very orthogonal and tend to
|
/* left to the end because they aren't currently very orthogonal and tend to
|
||||||
* break subsequent tests! */
|
* break subsequent tests! */
|
||||||
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_viewport);
|
TEST_CONFORM_SIMPLE ("/cogl", test_cogl_viewport);
|
||||||
|
Loading…
Reference in New Issue
Block a user