summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2015-01-22 16:41:50 +0100
committerPeter Hutterer <peter.hutterer@who-t.net>2015-05-26 10:53:23 +1000
commit9035e4a767786652858e06b3c77dce333437f565 (patch)
treee39300679e6afc9caa596b35ede13f28bf7d6e70
parent0c8d76181d35f30014b78385256b3a99471ac93f (diff)
downloadlibinput-9035e4a767786652858e06b3c77dce333437f565.tar.gz
touchpad: Add an API for touchpad gesture events
For touchscreens we always send raw touch events to the compositor, and the compositor or application toolkits do gesture recognition. This makes sense because on a touchscreen which window / widget the touches are over is important context to know to interpret gestures. On touchpads however we never send raw events since a touchpad is an absolute device which primary function is to send pointer motion delta-s, so we always need to do processing (and a lot of it) on the raw events. Moreover there is nothing underneath the finger which influences how to interpret gestures, and there is a lot of touchpad and libinput configuration specific context necessary for gesture recognition. E.g. is this a clickpad, and if so are softbuttons or clickfinger used? What is the size of the softbuttons? Is this a true multi-touch touchpad or a semi multi-touch touchpad which only gives us a bounding box enclosing the fingers? Etc. So for touchpads it is better to do gesture processing in libinput, this commit adds an initial implementation of a Gesture event API which only supports swipe gestures, other gestures will be added later following the same model wrt, having clear start and stop events and the number of fingers involved being fixed once a gesture sequence starts. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Jason Gerecke <jason.gerecke@wacom.com> [add gesture events to event-gui] [add separate symbol block to libinput.sym]
-rw-r--r--src/evdev.c3
-rw-r--r--src/evdev.h3
-rw-r--r--src/libinput-private.h8
-rw-r--r--src/libinput.c96
-rw-r--r--src/libinput.h149
-rw-r--r--src/libinput.sym12
-rw-r--r--test/litest.c9
-rw-r--r--tools/event-debug.c46
-rw-r--r--tools/event-gui.c4
9 files changed, 327 insertions, 3 deletions
diff --git a/src/evdev.c b/src/evdev.c
index c6c8102b..cc5042ad 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1877,6 +1877,7 @@ evdev_configure_device(struct evdev_device *device)
if (udev_tags & EVDEV_UDEV_TAG_TOUCHPAD) {
device->dispatch = evdev_mt_touchpad_create(device);
+ device->seat_caps |= EVDEV_DEVICE_GESTURE;
log_info(libinput,
"input device '%s', %s is a touchpad\n",
device->devname, devnode);
@@ -2234,6 +2235,8 @@ evdev_device_has_capability(struct evdev_device *device,
return !!(device->seat_caps & EVDEV_DEVICE_KEYBOARD);
case LIBINPUT_DEVICE_CAP_TOUCH:
return !!(device->seat_caps & EVDEV_DEVICE_TOUCH);
+ case LIBINPUT_DEVICE_CAP_GESTURE:
+ return !!(device->seat_caps & EVDEV_DEVICE_GESTURE);
default:
return 0;
}
diff --git a/src/evdev.h b/src/evdev.h
index 22e6b019..e5411db0 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -60,7 +60,8 @@ enum evdev_event_type {
enum evdev_device_seat_capability {
EVDEV_DEVICE_POINTER = (1 << 0),
EVDEV_DEVICE_KEYBOARD = (1 << 1),
- EVDEV_DEVICE_TOUCH = (1 << 2)
+ EVDEV_DEVICE_TOUCH = (1 << 2),
+ EVDEV_DEVICE_GESTURE = (1 << 5),
};
enum evdev_device_tags {
diff --git a/src/libinput-private.h b/src/libinput-private.h
index cec529c8..20271111 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -359,6 +359,14 @@ touch_notify_touch_up(struct libinput_device *device,
int32_t seat_slot);
void
+gesture_notify_swipe(struct libinput_device *device,
+ uint64_t time,
+ enum libinput_event_type type,
+ int finger_count,
+ const struct normalized_coords *delta,
+ const struct normalized_coords *unaccel);
+
+void
touch_notify_frame(struct libinput_device *device,
uint64_t time);
diff --git a/src/libinput.c b/src/libinput.c
index 444e9ce9..28c7f392 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -112,6 +112,14 @@ struct libinput_event_touch {
struct device_coords point;
};
+struct libinput_event_gesture {
+ struct libinput_event base;
+ uint32_t time;
+ int finger_count;
+ struct normalized_coords delta;
+ struct normalized_coords delta_unaccel;
+};
+
static void
libinput_default_log_func(struct libinput *libinput,
enum libinput_log_priority priority,
@@ -235,6 +243,19 @@ libinput_event_get_touch_event(struct libinput_event *event)
return (struct libinput_event_touch *) event;
}
+LIBINPUT_EXPORT struct libinput_event_gesture *
+libinput_event_get_gesture_event(struct libinput_event *event)
+{
+ require_event_type(libinput_event_get_context(event),
+ event->type,
+ NULL,
+ LIBINPUT_EVENT_GESTURE_SWIPE_START,
+ LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
+ LIBINPUT_EVENT_GESTURE_SWIPE_END);
+
+ return (struct libinput_event_gesture *) event;
+}
+
LIBINPUT_EXPORT struct libinput_event_device_notify *
libinput_event_get_device_notify_event(struct libinput_event *event)
{
@@ -635,6 +656,44 @@ libinput_event_touch_get_y(struct libinput_event_touch *event)
return evdev_convert_to_mm(device->abs.absinfo_y, event->point.y);
}
+LIBINPUT_EXPORT uint32_t
+libinput_event_gesture_get_time(struct libinput_event_gesture *event)
+{
+ return event->time;
+}
+
+LIBINPUT_EXPORT int
+libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event)
+{
+ return event->finger_count;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_gesture_get_dx(struct libinput_event_gesture *event)
+{
+ return event->delta.x;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_gesture_get_dy(struct libinput_event_gesture *event)
+{
+ return event->delta.y;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_gesture_get_dx_unaccelerated(
+ struct libinput_event_gesture *event)
+{
+ return event->delta_unaccel.x;
+}
+
+LIBINPUT_EXPORT double
+libinput_event_gesture_get_dy_unaccelerated(
+ struct libinput_event_gesture *event)
+{
+ return event->delta_unaccel.y;
+}
+
struct libinput_source *
libinput_add_fd(struct libinput *libinput,
int fd,
@@ -1084,6 +1143,9 @@ device_has_cap(struct libinput_device *device,
case LIBINPUT_DEVICE_CAP_TOUCH:
capability = "CAP_TOUCH";
break;
+ case LIBINPUT_DEVICE_CAP_GESTURE:
+ capability = "CAP_GESTURE";
+ break;
}
log_bug_libinput(device->seat->libinput,
@@ -1340,6 +1402,34 @@ touch_notify_frame(struct libinput_device *device,
&touch_event->base);
}
+void
+gesture_notify_swipe(struct libinput_device *device,
+ uint64_t time,
+ enum libinput_event_type type,
+ int finger_count,
+ const struct normalized_coords *delta,
+ const struct normalized_coords *unaccel)
+{
+ struct libinput_event_gesture *gesture_event;
+
+ if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_GESTURE))
+ return;
+
+ gesture_event = zalloc(sizeof *gesture_event);
+ if (!gesture_event)
+ return;
+
+ *gesture_event = (struct libinput_event_gesture) {
+ .time = time,
+ .finger_count = finger_count,
+ .delta = *delta,
+ .delta_unaccel = *unaccel,
+ };
+
+ post_device_event(device, time, type,
+ &gesture_event->base);
+}
+
static void
libinput_post_event(struct libinput *libinput,
struct libinput_event *event)
@@ -1605,6 +1695,12 @@ libinput_event_touch_get_base_event(struct libinput_event_touch *event)
return &event->base;
}
+LIBINPUT_EXPORT struct libinput_event *
+libinput_event_gesture_get_base_event(struct libinput_event_gesture *event)
+{
+ return &event->base;
+}
+
LIBINPUT_EXPORT struct libinput_device_group *
libinput_device_group_ref(struct libinput_device_group *group)
{
diff --git a/src/libinput.h b/src/libinput.h
index 9ef8b8f4..c767d83d 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -53,7 +53,8 @@ enum libinput_log_priority {
enum libinput_device_capability {
LIBINPUT_DEVICE_CAP_KEYBOARD = 0,
LIBINPUT_DEVICE_CAP_POINTER = 1,
- LIBINPUT_DEVICE_CAP_TOUCH = 2
+ LIBINPUT_DEVICE_CAP_TOUCH = 2,
+ LIBINPUT_DEVICE_CAP_GESTURE = 5,
};
/**
@@ -172,7 +173,11 @@ enum libinput_event_type {
* Signals the end of a set of touchpoints at one device sample
* time. This event has no coordinate information attached.
*/
- LIBINPUT_EVENT_TOUCH_FRAME
+ LIBINPUT_EVENT_TOUCH_FRAME,
+
+ LIBINPUT_EVENT_GESTURE_SWIPE_START = 800,
+ LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
+ LIBINPUT_EVENT_GESTURE_SWIPE_END,
};
/**
@@ -359,6 +364,19 @@ libinput_event_get_touch_event(struct libinput_event *event);
/**
* @ingroup event
*
+ * Return the gesture event that is this input event. If the event type does
+ * not match the gesture event types, this function returns NULL.
+ *
+ * The inverse of this function is libinput_event_gesture_get_base_event().
+ *
+ * @return A gesture event, or NULL for other events
+ */
+struct libinput_event_gesture *
+libinput_event_get_gesture_event(struct libinput_event *event);
+
+/**
+ * @ingroup event
+ *
* Return the device event that is this input event. If the event type does
* not match the device event types, this function returns NULL.
*
@@ -919,6 +937,133 @@ struct libinput_event *
libinput_event_touch_get_base_event(struct libinput_event_touch *event);
/**
+ * @defgroup event_gesture Gesture events
+ *
+ * Gesture events are generated when a gesture is recognized on a touchpad.
+ *
+ * Gesture sequences always start with a LIBINPUT_EVENT_GESTURE_FOO_START
+ * event. All following gesture events will be of the
+ * LIBINPUT_EVENT_GESTURE_UPDATE_FOO type until a
+ * LIBINPUT_EVENT_GESTURE_FOO_END is generated which signals the end of the
+ * gesture.
+ */
+
+/**
+ * @ingroup event_gesture
+ *
+ * @return The event time for this event
+ */
+uint32_t
+libinput_event_gesture_get_time(struct libinput_event_gesture *event);
+
+/**
+ * @ingroup event_gesture
+ *
+ * @return The generic libinput_event of this event
+ */
+struct libinput_event *
+libinput_event_gesture_get_base_event(struct libinput_event_gesture *event);
+
+/**
+ * @ingroup event_gesture
+ *
+ * Return the number of fingers used for a gesture. This can be used e.g.
+ * to differentiate between 3 or 4 finger swipes.
+ *
+ * This function can be called on all gesture events including
+ * LIBINPUT_EVENT_GESTURE_FOO_START and the returned finger count value will
+ * not change during a sequence.
+ *
+ * @return the number of fingers used for a gesture
+ */
+int
+libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event);
+
+/**
+ * @ingroup event_gesture
+ *
+ * Return the delta between the last event and the current event. For gesture
+ * events that are not of type @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this
+ * function returns 0.
+ *
+ * If a device employs pointer acceleration, the delta returned by this
+ * function is the accelerated delta.
+ *
+ * Relative motion deltas are normalized to represent those of a device with
+ * 1000dpi resolution. See @ref motion_normalization for more details.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE.
+ *
+ * @return the relative x movement since the last event
+ */
+double
+libinput_event_gesture_get_dx(struct libinput_event_gesture *event);
+
+/**
+ * @ingroup event_gesture
+ *
+ * Return the delta between the last event and the current event. For gesture
+ * events that are not of type @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this
+ * function returns 0.
+ *
+ * If a device employs pointer acceleration, the delta returned by this
+ * function is the accelerated delta.
+ *
+ * Relative motion deltas are normalized to represent those of a device with
+ * 1000dpi resolution. See @ref motion_normalization for more details.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE.
+ *
+ * @return the relative y movement since the last event
+ */
+double
+libinput_event_gesture_get_dy(struct libinput_event_gesture *event);
+
+/**
+ * @ingroup event_gesture
+ *
+ * Return the relative delta of the unaccelerated motion vector of the
+ * current event. For gesture events that are not of type @ref
+ * LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this function returns 0.
+ *
+ * Relative unaccelerated motion deltas are normalized to represent those of a
+ * device with 1000dpi resolution. See @ref motion_normalization for more
+ * details. Note that unaccelerated events are not equivalent to 'raw' events
+ * as read from the device.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE.
+ *
+ * @return the unaccelerated relative x movement since the last event
+ */
+double
+libinput_event_gesture_get_dx_unaccelerated(
+ struct libinput_event_gesture *event);
+
+/**
+ * @ingroup event_gesture
+ *
+ * Return the relative delta of the unaccelerated motion vector of the
+ * current event. For gesture events that are not of type @ref
+ * LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, this function returns 0.
+ *
+ * Relative unaccelerated motion deltas are normalized to represent those of a
+ * device with 1000dpi resolution. See @ref motion_normalization for more
+ * details. Note that unaccelerated events are not equivalent to 'raw' events
+ * as read from the device.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE.
+ *
+ * @return the unaccelerated relative y movement since the last event
+ */
+double
+libinput_event_gesture_get_dy_unaccelerated(
+ struct libinput_event_gesture *event);
+
+/**
* @defgroup base Initialization and manipulation of libinput contexts
*/
diff --git a/src/libinput.sym b/src/libinput.sym
index 9c11174b..3891562a 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -140,3 +140,15 @@ LIBINPUT_0.15.0 {
global:
libinput_device_keyboard_has_key;
} LIBINPUT_0.14.0;
+
+
+TOUCHPAD_GESTURES {
+ libinput_event_gesture_get_base_event;
+ libinput_event_gesture_get_dx;
+ libinput_event_gesture_get_dx_unaccelerated;
+ libinput_event_gesture_get_dy;
+ libinput_event_gesture_get_dy_unaccelerated;
+ libinput_event_gesture_get_finger_count;
+ libinput_event_gesture_get_time;
+ libinput_event_get_gesture_event;
+} LIBINPUT_0.15.0;
diff --git a/test/litest.c b/test/litest.c
index 8221a7a2..19035b73 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -1546,6 +1546,15 @@ litest_event_type_str(struct libinput_event *event)
case LIBINPUT_EVENT_TOUCH_FRAME:
str = "TOUCH FRAME";
break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_START:
+ str = "GESTURE SWIPE START";
+ break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
+ str = "GESTURE SWIPE UPDATE";
+ break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_END:
+ str = "GESTURE SWIPE END";
+ break;
}
return str;
}
diff --git a/tools/event-debug.c b/tools/event-debug.c
index 3629e745..f994ea12 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -106,6 +106,15 @@ print_event_header(struct libinput_event *ev)
case LIBINPUT_EVENT_TOUCH_FRAME:
type = "TOUCH_FRAME";
break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_START:
+ type = "GESTURE_SWIPE_START";
+ break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
+ type = "GESTURE_SWIPE_UPDATE";
+ break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_END:
+ type = "GESTURE_SWIPE_END";
+ break;
}
printf("%-7s %s ", libinput_device_get_sysname(dev), type);
@@ -151,6 +160,9 @@ print_device_notify(struct libinput_event *ev)
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_TOUCH))
printf("t");
+ if (libinput_device_has_capability(dev,
+ LIBINPUT_DEVICE_CAP_GESTURE))
+ printf("g");
if (libinput_device_get_size(dev, &w, &h) == 0)
printf("\tsize %.2f/%.2fmm", w, h);
@@ -286,6 +298,31 @@ print_touch_event_with_coords(struct libinput_event *ev)
xmm, ymm);
}
+static void
+print_gesture_event_without_coords(struct libinput_event *ev)
+{
+ struct libinput_event_gesture *t = libinput_event_get_gesture_event(ev);
+
+ print_event_time(libinput_event_gesture_get_time(t));
+ printf("%d\n", libinput_event_gesture_get_finger_count(t));
+}
+
+static void
+print_gesture_event_with_coords(struct libinput_event *ev)
+{
+ struct libinput_event_gesture *t = libinput_event_get_gesture_event(ev);
+ double dx = libinput_event_gesture_get_dx(t);
+ double dy = libinput_event_gesture_get_dy(t);
+ double dx_unaccel = libinput_event_gesture_get_dx_unaccelerated(t);
+ double dy_unaccel = libinput_event_gesture_get_dy_unaccelerated(t);
+
+ print_event_time(libinput_event_gesture_get_time(t));
+
+ printf("%d %5.2f/%5.2f (%5.2f/%5.2f unaccelerated)\n",
+ libinput_event_gesture_get_finger_count(t),
+ dx, dy, dx_unaccel, dy_unaccel);
+}
+
static int
handle_and_print_events(struct libinput *li)
{
@@ -335,6 +372,15 @@ handle_and_print_events(struct libinput *li)
case LIBINPUT_EVENT_TOUCH_FRAME:
print_touch_event_without_coords(ev);
break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_START:
+ print_gesture_event_without_coords(ev);
+ break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
+ print_gesture_event_with_coords(ev);
+ break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_END:
+ print_gesture_event_without_coords(ev);
+ break;
}
libinput_event_destroy(ev);
diff --git a/tools/event-gui.c b/tools/event-gui.c
index 678e75bc..2f2dd756 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -469,6 +469,10 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
return FALSE;
}
break;
+ case LIBINPUT_EVENT_GESTURE_SWIPE_START:
+ case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
+ case LIBINPUT_EVENT_GESTURE_SWIPE_END:
+ break;
}
libinput_event_destroy(ev);