test: add a couple of basic gesture tests
authorPeter Hutterer <peter.hutterer@who-t.net>
Tue, 7 Jul 2015 01:52:05 +0000 (11:52 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Wed, 15 Jul 2015 04:48:52 +0000 (14:48 +1000)
3finger swipe, pinch and spread. While we expect the pinch/spread to have a
zero angle, the discrete coordinates we use cause some angle, but below 1
degree.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
test/Makefile.am
test/gestures.c [new file with mode: 0644]
test/litest.c
test/litest.h
test/misc.c

index 49b3b02..1393ac3 100644 (file)
@@ -56,6 +56,7 @@ run_tests = \
        test-touchpad \
        test-touchpad-tap \
        test-device \
+       test-gestures \
        test-pointer \
        test-touch \
        test-trackpoint \
@@ -122,6 +123,10 @@ test_device_SOURCES = device.c
 test_device_LDADD = $(TEST_LIBS)
 test_device_LDFLAGS = -no-install
 
+test_gestures_SOURCES = gestures.c
+test_gestures_LDADD = $(TEST_LIBS)
+test_gestures_LDFLAGS = -no-install
+
 test_litest_selftest_SOURCES = litest-selftest.c litest.c litest-int.h litest.h
 test_litest_selftest_CFLAGS = -DLITEST_DISABLE_BACKTRACE_LOGGING -DLITEST_NO_MAIN $(liblitest_la_CFLAGS)
 test_litest_selftest_LDADD = $(TEST_LIBS)
diff --git a/test/gestures.c b/test/gestures.c
new file mode 100644 (file)
index 0000000..3d20bf2
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright © 2015 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
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <config.h>
+
+#include <check.h>
+#include <libinput.h>
+
+#include "libinput-util.h"
+#include "litest.h"
+
+START_TEST(gestures_cap)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput_device *device = dev->libinput_device;
+
+       ck_assert(libinput_device_has_capability(device,
+                                                LIBINPUT_DEVICE_CAP_GESTURE));
+}
+END_TEST
+
+START_TEST(gestures_nocap)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput_device *device = dev->libinput_device;
+
+       ck_assert(!libinput_device_has_capability(device,
+                                                 LIBINPUT_DEVICE_CAP_GESTURE));
+}
+END_TEST
+
+START_TEST(gestures_swipe_3fg)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct libinput_event *event;
+       struct libinput_event_gesture *gevent;
+       double dx, dy;
+       int cardinal = _i; /* ranged test */
+       double dir_x, dir_y;
+       int cardinals[8][2] = {
+               { 0, 30 },
+               { 30, 30 },
+               { 30, 0 },
+               { 30, -30 },
+               { 0, -30 },
+               { -30, -30 },
+               { -30, 0 },
+               { -30, 30 },
+       };
+
+       if (libevdev_get_num_slots(dev->evdev) < 3)
+               return;
+
+       dir_x = cardinals[cardinal][0];
+       dir_y = cardinals[cardinal][1];
+
+       litest_drain_events(li);
+
+       litest_touch_down(dev, 0, 40, 40);
+       litest_touch_down(dev, 1, 40, 50);
+       litest_touch_down(dev, 2, 40, 60);
+       libinput_dispatch(li);
+       litest_touch_move_three_touches(dev,
+                                       40, 40,
+                                       40, 50,
+                                       40, 60,
+                                       dir_x, dir_y,
+                                       10, 2);
+       libinput_dispatch(li);
+
+       event = libinput_get_event(li);
+       gevent = litest_is_gesture_event(event,
+                                        LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN,
+                                        3);
+       dx = libinput_event_gesture_get_dx(gevent);
+       dy = libinput_event_gesture_get_dy(gevent);
+       ck_assert(dx == 0.0);
+       ck_assert(dy == 0.0);
+       libinput_event_destroy(event);
+
+       while ((event = libinput_get_event(li)) != NULL) {
+               gevent = litest_is_gesture_event(event,
+                                                LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
+                                                3);
+
+               dx = libinput_event_gesture_get_dx(gevent);
+               dy = libinput_event_gesture_get_dy(gevent);
+               debug_trace("delta: %.2f/%.2f\n", dx, dy);
+               if (dir_x == 0.0)
+                       ck_assert(dx == 0.0);
+               else if (dir_x < 0.0)
+                       ck_assert(dx < 0.0);
+               else if (dir_x > 0.0)
+                       ck_assert(dx > 0.0);
+
+               if (dir_y == 0.0)
+                       ck_assert(dy == 0.0);
+               else if (dir_y < 0.0)
+                       ck_assert(dy < 0.0);
+               else if (dir_y > 0.0)
+                       ck_assert(dy > 0.0);
+
+               dx = libinput_event_gesture_get_dx_unaccelerated(gevent);
+               dy = libinput_event_gesture_get_dy_unaccelerated(gevent);
+               if (dir_x == 0.0)
+                       ck_assert(dx == 0.0);
+               else if (dir_x < 0.0)
+                       ck_assert(dx < 0.0);
+               else if (dir_x > 0.0)
+                       ck_assert(dx > 0.0);
+
+               if (dir_y == 0.0)
+                       ck_assert(dy == 0.0);
+               else if (dir_y < 0.0)
+                       ck_assert(dy < 0.0);
+               else if (dir_y > 0.0)
+                       ck_assert(dy > 0.0);
+
+               libinput_event_destroy(event);
+       }
+
+       litest_touch_up(dev, 0);
+       litest_touch_up(dev, 1);
+       litest_touch_up(dev, 2);
+       libinput_dispatch(li);
+       event = libinput_get_event(li);
+       gevent = litest_is_gesture_event(event,
+                                        LIBINPUT_EVENT_GESTURE_SWIPE_END,
+                                        3);
+       ck_assert(!libinput_event_gesture_get_cancelled(gevent));
+       libinput_event_destroy(event);
+}
+END_TEST
+
+START_TEST(gestures_pinch)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct libinput_event *event;
+       struct libinput_event_gesture *gevent;
+       double dx, dy;
+       int cardinal = _i; /* ranged test */
+       double dir_x, dir_y;
+       int i;
+       double scale, oldscale;
+       double angle;
+       int cardinals[8][2] = {
+               { 0, 30 },
+               { 30, 30 },
+               { 30, 0 },
+               { 30, -30 },
+               { 0, -30 },
+               { -30, -30 },
+               { -30, 0 },
+               { -30, 30 },
+       };
+
+       if (libevdev_get_num_slots(dev->evdev) < 3)
+               return;
+
+       dir_x = cardinals[cardinal][0];
+       dir_y = cardinals[cardinal][1];
+
+       litest_drain_events(li);
+
+       litest_touch_down(dev, 0, 50 + dir_x, 50 + dir_y);
+       litest_touch_down(dev, 1, 50 - dir_x, 50 - dir_y);
+       libinput_dispatch(li);
+
+       for (i = 0; i < 8; i++) {
+               litest_push_event_frame(dev);
+               if (dir_x > 0.0)
+                       dir_x -= 3;
+               else if (dir_x < 0.0)
+                       dir_x += 3;
+               if (dir_y > 0.0)
+                       dir_y -= 3;
+               else if (dir_y < 0.0)
+                       dir_y += 3;
+               litest_touch_move(dev,
+                                 0,
+                                 50 + dir_x,
+                                 50 + dir_y);
+               litest_touch_move(dev,
+                                 1,
+                                 50 - dir_x,
+                                 50 - dir_y);
+               litest_pop_event_frame(dev);
+               libinput_dispatch(li);
+       }
+
+       event = libinput_get_event(li);
+       gevent = litest_is_gesture_event(event,
+                                        LIBINPUT_EVENT_GESTURE_PINCH_BEGIN,
+                                        2);
+       dx = libinput_event_gesture_get_dx(gevent);
+       dy = libinput_event_gesture_get_dy(gevent);
+       scale = libinput_event_gesture_get_scale(gevent);
+       ck_assert(dx == 0.0);
+       ck_assert(dy == 0.0);
+       ck_assert(scale == 1.0);
+
+       libinput_event_destroy(event);
+
+       dir_x = cardinals[cardinal][0];
+       dir_y = cardinals[cardinal][1];
+       while ((event = libinput_get_event(li)) != NULL) {
+               gevent = litest_is_gesture_event(event,
+                                                LIBINPUT_EVENT_GESTURE_PINCH_UPDATE,
+                                                2);
+
+               oldscale = scale;
+               scale = libinput_event_gesture_get_scale(gevent);
+
+               ck_assert(scale < oldscale);
+
+               angle = libinput_event_gesture_get_angle_delta(gevent);
+               ck_assert_double_le(fabs(angle), 1.0);
+
+               libinput_event_destroy(event);
+               libinput_dispatch(li);
+       }
+
+       litest_touch_up(dev, 0);
+       litest_touch_up(dev, 1);
+       libinput_dispatch(li);
+       event = libinput_get_event(li);
+       gevent = litest_is_gesture_event(event,
+                                        LIBINPUT_EVENT_GESTURE_PINCH_END,
+                                        2);
+       ck_assert(!libinput_event_gesture_get_cancelled(gevent));
+       libinput_event_destroy(event);
+}
+END_TEST
+
+START_TEST(gestures_spread)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct libinput_event *event;
+       struct libinput_event_gesture *gevent;
+       double dx, dy;
+       int cardinal = _i; /* ranged test */
+       double dir_x, dir_y;
+       int i;
+       double scale, oldscale;
+       double angle;
+       int cardinals[8][2] = {
+               { 0, 1 },
+               { 1, 1 },
+               { 1, 0 },
+               { 1, -1 },
+               { 0, -1 },
+               { -1, -1 },
+               { -1, 0 },
+               { -1, 1 },
+       };
+
+       if (libevdev_get_num_slots(dev->evdev) < 3)
+               return;
+
+       dir_x = cardinals[cardinal][0];
+       dir_y = cardinals[cardinal][1];
+
+       litest_drain_events(li);
+
+       litest_touch_down(dev, 0, 50 + dir_x, 50 + dir_y);
+       litest_touch_down(dev, 1, 50 - dir_x, 50 - dir_y);
+       libinput_dispatch(li);
+
+       for (i = 0; i < 8; i++) {
+               litest_push_event_frame(dev);
+               if (dir_x > 0.0)
+                       dir_x += 3;
+               else if (dir_x < 0.0)
+                       dir_x -= 3;
+               if (dir_y > 0.0)
+                       dir_y += 3;
+               else if (dir_y < 0.0)
+                       dir_y -= 3;
+               litest_touch_move(dev,
+                                 0,
+                                 50 + dir_x,
+                                 50 + dir_y);
+               litest_touch_move(dev,
+                                 1,
+                                 50 - dir_x,
+                                 50 - dir_y);
+               litest_pop_event_frame(dev);
+               libinput_dispatch(li);
+       }
+
+       event = libinput_get_event(li);
+       gevent = litest_is_gesture_event(event,
+                                        LIBINPUT_EVENT_GESTURE_PINCH_BEGIN,
+                                        2);
+       dx = libinput_event_gesture_get_dx(gevent);
+       dy = libinput_event_gesture_get_dy(gevent);
+       scale = libinput_event_gesture_get_scale(gevent);
+       ck_assert(dx == 0.0);
+       ck_assert(dy == 0.0);
+       ck_assert(scale == 1.0);
+
+       libinput_event_destroy(event);
+
+       dir_x = cardinals[cardinal][0];
+       dir_y = cardinals[cardinal][1];
+       while ((event = libinput_get_event(li)) != NULL) {
+               gevent = litest_is_gesture_event(event,
+                                                LIBINPUT_EVENT_GESTURE_PINCH_UPDATE,
+                                                2);
+               oldscale = scale;
+               scale = libinput_event_gesture_get_scale(gevent);
+               ck_assert(scale > oldscale);
+
+               angle = libinput_event_gesture_get_angle_delta(gevent);
+               ck_assert_double_le(fabs(angle), 1.0);
+
+               libinput_event_destroy(event);
+               libinput_dispatch(li);
+       }
+
+       litest_touch_up(dev, 0);
+       litest_touch_up(dev, 1);
+       libinput_dispatch(li);
+       event = libinput_get_event(li);
+       gevent = litest_is_gesture_event(event,
+                                        LIBINPUT_EVENT_GESTURE_PINCH_END,
+                                        2);
+       ck_assert(!libinput_event_gesture_get_cancelled(gevent));
+       libinput_event_destroy(event);
+}
+END_TEST
+
+void
+litest_setup_tests(void)
+{
+       /* N, NE, ... */
+       struct range cardinals = { 0, 8 };
+
+       litest_add("gestures:cap", gestures_cap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+       litest_add("gestures:cap", gestures_nocap, LITEST_ANY, LITEST_TOUCHPAD);
+
+       litest_add_ranged("gestures:swipe", gestures_swipe_3fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
+       litest_add_ranged("gestures:pinch", gestures_pinch, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
+       litest_add_ranged("gestures:pinch", gestures_spread, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &cardinals);
+}
index 2d3f47c..1fa8f23 100644 (file)
@@ -1472,6 +1472,32 @@ litest_touch_move_two_touches(struct litest_device *d,
 }
 
 void
+litest_touch_move_three_touches(struct litest_device *d,
+                               double x0, double y0,
+                               double x1, double y1,
+                               double x2, double y2,
+                               double dx, double dy,
+                               int steps, int sleep_ms)
+{
+       for (int i = 0; i < steps - 1; i++) {
+               litest_touch_move(d, 0, x0 + dx / steps * i,
+                                       y0 + dy / steps * i);
+               litest_touch_move(d, 1, x1 + dx / steps * i,
+                                       y1 + dy / steps * i);
+               litest_touch_move(d, 2, x2 + dx / steps * i,
+                                       y2 + dy / steps * i);
+               if (sleep_ms) {
+                       libinput_dispatch(d->libinput);
+                       msleep(sleep_ms);
+                       libinput_dispatch(d->libinput);
+               }
+       }
+       litest_touch_move(d, 0, x0 + dx, y0 + dy);
+       litest_touch_move(d, 1, x1 + dx, y1 + dy);
+       litest_touch_move(d, 2, x2 + dx, y2 + dy);
+}
+
+void
 litest_hover_start(struct litest_device *d,
                   unsigned int slot,
                   double x,
@@ -2142,6 +2168,25 @@ litest_is_keyboard_event(struct libinput_event *event,
        return kevent;
 }
 
+struct libinput_event_gesture *
+litest_is_gesture_event(struct libinput_event *event,
+                       enum libinput_event_type type,
+                       int nfingers)
+{
+       struct libinput_event_gesture *gevent;
+
+       litest_assert(event != NULL);
+       litest_assert_int_eq(libinput_event_get_type(event), type);
+
+       gevent = libinput_event_get_gesture_event(event);
+       litest_assert(gevent != NULL);
+
+       if (nfingers != -1)
+               litest_assert_int_eq(libinput_event_gesture_get_finger_count(gevent),
+                                    nfingers);
+       return gevent;
+}
+
 void
 litest_assert_scroll(struct libinput *li,
                     enum libinput_pointer_axis axis,
@@ -2255,6 +2300,12 @@ litest_timeout_dwt_long(void)
 }
 
 void
+litest_timeout_gesture(void)
+{
+       msleep(120);
+}
+
+void
 litest_push_event_frame(struct litest_device *dev)
 {
        assert(!dev->skip_ev_syn);
index d557b5d..b5d0f49 100644 (file)
@@ -326,6 +326,12 @@ void litest_touch_move_two_touches(struct litest_device *d,
                                   double x1, double y1,
                                   double dx, double dy,
                                   int steps, int sleep_ms);
+void litest_touch_move_three_touches(struct litest_device *d,
+                                    double x0, double y0,
+                                    double x1, double y1,
+                                    double x2, double y2,
+                                    double dx, double dy,
+                                    int steps, int sleep_ms);
 void litest_hover_start(struct litest_device *d,
                        unsigned int slot,
                        double x,
@@ -375,6 +381,11 @@ struct libinput_event_keyboard * litest_is_keyboard_event(
                       struct libinput_event *event,
                       unsigned int key,
                       enum libinput_key_state state);
+struct libinput_event_gesture * litest_is_gesture_event(
+                      struct libinput_event *event,
+                      enum libinput_event_type type,
+                      int nfingers);
+
 void litest_assert_button_event(struct libinput *li,
                                unsigned int button,
                                enum libinput_button_state state);
@@ -401,6 +412,7 @@ void litest_timeout_finger_switch(void);
 void litest_timeout_middlebutton(void);
 void litest_timeout_dwt_short(void);
 void litest_timeout_dwt_long(void);
+void litest_timeout_gesture(void);
 
 void litest_push_event_frame(struct litest_device *dev);
 void litest_pop_event_frame(struct litest_device *dev);
index 2a2a63a..6412b3b 100644 (file)
@@ -131,6 +131,7 @@ START_TEST(event_conversion_device_notify)
                        ck_assert(libinput_event_get_pointer_event(event) == NULL);
                        ck_assert(libinput_event_get_keyboard_event(event) == NULL);
                        ck_assert(libinput_event_get_touch_event(event) == NULL);
+                       ck_assert(libinput_event_get_gesture_event(event) == NULL);
                        litest_restore_log_handler(li);
                }
 
@@ -185,6 +186,7 @@ START_TEST(event_conversion_pointer)
                        ck_assert(libinput_event_get_device_notify_event(event) == NULL);
                        ck_assert(libinput_event_get_keyboard_event(event) == NULL);
                        ck_assert(libinput_event_get_touch_event(event) == NULL);
+                       ck_assert(libinput_event_get_gesture_event(event) == NULL);
                        litest_restore_log_handler(li);
                }
                libinput_event_destroy(event);
@@ -233,6 +235,7 @@ START_TEST(event_conversion_pointer_abs)
                        ck_assert(libinput_event_get_device_notify_event(event) == NULL);
                        ck_assert(libinput_event_get_keyboard_event(event) == NULL);
                        ck_assert(libinput_event_get_touch_event(event) == NULL);
+                       ck_assert(libinput_event_get_gesture_event(event) == NULL);
                        litest_restore_log_handler(li);
                }
                libinput_event_destroy(event);
@@ -274,6 +277,7 @@ START_TEST(event_conversion_key)
                        ck_assert(libinput_event_get_device_notify_event(event) == NULL);
                        ck_assert(libinput_event_get_pointer_event(event) == NULL);
                        ck_assert(libinput_event_get_touch_event(event) == NULL);
+                       ck_assert(libinput_event_get_gesture_event(event) == NULL);
                        litest_restore_log_handler(li);
                }
                libinput_event_destroy(event);
@@ -322,6 +326,7 @@ START_TEST(event_conversion_touch)
                        ck_assert(libinput_event_get_device_notify_event(event) == NULL);
                        ck_assert(libinput_event_get_pointer_event(event) == NULL);
                        ck_assert(libinput_event_get_keyboard_event(event) == NULL);
+                       ck_assert(libinput_event_get_gesture_event(event) == NULL);
                        litest_restore_log_handler(li);
                }
                libinput_event_destroy(event);
@@ -331,6 +336,54 @@ START_TEST(event_conversion_touch)
 }
 END_TEST
 
+START_TEST(event_conversion_gesture)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct libinput_event *event;
+       int gestures = 0;
+       int i;
+
+       libinput_dispatch(li);
+
+       litest_touch_down(dev, 0, 70, 30);
+       litest_touch_down(dev, 1, 30, 70);
+       for (i = 0; i < 8; i++) {
+               litest_push_event_frame(dev);
+               litest_touch_move(dev, 0, 70 - i * 5, 30 + i * 5);
+               litest_touch_move(dev, 1, 30 + i * 5, 70 - i * 5);
+               litest_pop_event_frame(dev);
+               libinput_dispatch(li);
+       }
+
+       while ((event = libinput_get_event(li))) {
+               enum libinput_event_type type;
+               type = libinput_event_get_type(event);
+
+               if (type >= LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN &&
+                   type <= LIBINPUT_EVENT_GESTURE_PINCH_END) {
+                       struct libinput_event_gesture *g;
+                       struct libinput_event *base;
+                       g = libinput_event_get_gesture_event(event);
+                       base = libinput_event_gesture_get_base_event(g);
+                       ck_assert(event == base);
+
+                       gestures++;
+
+                       litest_disable_log_handler(li);
+                       ck_assert(libinput_event_get_device_notify_event(event) == NULL);
+                       ck_assert(libinput_event_get_pointer_event(event) == NULL);
+                       ck_assert(libinput_event_get_keyboard_event(event) == NULL);
+                       ck_assert(libinput_event_get_touch_event(event) == NULL);
+                       litest_restore_log_handler(li);
+               }
+               libinput_event_destroy(event);
+       }
+
+       ck_assert_int_gt(gestures, 0);
+}
+END_TEST
+
 START_TEST(context_ref_counting)
 {
        struct libinput *li;
@@ -639,6 +692,7 @@ litest_setup_tests(void)
        litest_add_for_device("events:conversion", event_conversion_pointer_abs, LITEST_XEN_VIRTUAL_POINTER);
        litest_add_for_device("events:conversion", event_conversion_key, LITEST_KEYBOARD);
        litest_add_for_device("events:conversion", event_conversion_touch, LITEST_WACOM_TOUCH);
+       litest_add_for_device("events:conversion", event_conversion_gesture, LITEST_BCM5974);
 
        litest_add_no_device("context:refcount", context_ref_counting);
        litest_add_no_device("config:status string", config_status_string);