[PATCH libinput] Add an API for touchpad gesture events

Peter Hutterer peter.hutterer at who-t.net
Tue Feb 17 13:55:00 PST 2015


On Thu, Feb 12, 2015 at 12:27:49PM +0100, Hans de Goede wrote:
> 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 at redhat.com>

looks good to me, one minor change below:

> + * Gesture sequences always start with a LIBINPUT_EVENT_GESTURE_FOO_START
> + * event. All following gesture events will be of the
> + * LIBINPUT_EVENT_GESTURE_FOO type until a LIBINPUT_EVENT_GESTURE_FOO_END is

LIBINPUT_EVENT_GESTURE_FOO -> LIBINPUT_EVENT_GESTURE_FOO_UPDATE

one other comment: I think we should make gestures a capability. the API is
separate to pointer interface and it's not clear which device can send
gestures by just looking at the pointer interface. the simple change to make
this a capability resolves that issue.

Cheers,
   Peter



> ---
>  src/libinput-private.h |  10 ++++
>  src/libinput.c         | 129 +++++++++++++++++++++++++++++++++++++++++++
>  src/libinput.h         | 145 ++++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 283 insertions(+), 1 deletion(-)
> 
> diff --git a/src/libinput-private.h b/src/libinput-private.h
> index 23f66e4..d0bd7f0 100644
> --- a/src/libinput-private.h
> +++ b/src/libinput-private.h
> @@ -330,6 +330,16 @@ 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,
> +		     double dx,
> +		     double dy,
> +		     double dx_unaccel,
> +		     double dy_unaccel);
> +
> +void
>  touch_notify_frame(struct libinput_device *device,
>  		   uint64_t time);
>  
> diff --git a/src/libinput.c b/src/libinput.c
> index 81862d5..220bb1d 100644
> --- a/src/libinput.c
> +++ b/src/libinput.c
> @@ -79,6 +79,16 @@ struct libinput_event_touch {
>  	double y;
>  };
>  
> +struct libinput_event_gesture {
> +	struct libinput_event base;
> +	uint32_t time;
> +	int finger_count;
> +	double dx;
> +	double dy;
> +	double dx_unaccel;
> +	double dy_unaccel;
> +};
> +
>  static void
>  libinput_default_log_func(struct libinput *libinput,
>  			  enum libinput_log_priority priority,
> @@ -183,6 +193,10 @@ libinput_event_get_pointer_event(struct libinput_event *event)
>  	case LIBINPUT_EVENT_TOUCH_CANCEL:
>  	case LIBINPUT_EVENT_TOUCH_FRAME:
>  		break;
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_START:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
> +		break;
>  	}
>  
>  	return NULL;
> @@ -209,6 +223,10 @@ libinput_event_get_keyboard_event(struct libinput_event *event)
>  	case LIBINPUT_EVENT_TOUCH_CANCEL:
>  	case LIBINPUT_EVENT_TOUCH_FRAME:
>  		break;
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_START:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
> +		break;
>  	}
>  
>  	return NULL;
> @@ -234,6 +252,40 @@ libinput_event_get_touch_event(struct libinput_event *event)
>  	case LIBINPUT_EVENT_TOUCH_CANCEL:
>  	case LIBINPUT_EVENT_TOUCH_FRAME:
>  		return (struct libinput_event_touch *) event;
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_START:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
> +LIBINPUT_EXPORT struct libinput_event_gesture *
> +libinput_event_get_gesture_event(struct libinput_event *event)
> +{
> +	switch (event->type) {
> +	case LIBINPUT_EVENT_NONE:
> +		abort(); /* not used as actual event type */
> +	case LIBINPUT_EVENT_DEVICE_ADDED:
> +	case LIBINPUT_EVENT_DEVICE_REMOVED:
> +	case LIBINPUT_EVENT_KEYBOARD_KEY:
> +		break;
> +	case LIBINPUT_EVENT_POINTER_MOTION:
> +	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
> +	case LIBINPUT_EVENT_POINTER_BUTTON:
> +	case LIBINPUT_EVENT_POINTER_AXIS:
> +		break;
> +	case LIBINPUT_EVENT_TOUCH_DOWN:
> +	case LIBINPUT_EVENT_TOUCH_UP:
> +	case LIBINPUT_EVENT_TOUCH_MOTION:
> +	case LIBINPUT_EVENT_TOUCH_CANCEL:
> +	case LIBINPUT_EVENT_TOUCH_FRAME:
> +		break;
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_START:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
> +		return (struct libinput_event_gesture *) event;
>  	}
>  
>  	return NULL;
> @@ -259,6 +311,10 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
>  	case LIBINPUT_EVENT_TOUCH_CANCEL:
>  	case LIBINPUT_EVENT_TOUCH_FRAME:
>  		break;
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_START:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
> +	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
> +		break;
>  	}
>  
>  	return NULL;
> @@ -501,6 +557,44 @@ libinput_event_touch_get_y(struct libinput_event_touch *event)
>  	return evdev_convert_to_mm(device->abs.absinfo_y, event->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->dx;
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_gesture_get_dy(struct libinput_event_gesture *event)
> +{
> +	return event->dy;
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_gesture_get_dx_unaccelerated(
> +	struct libinput_event_gesture *event)
> +{
> +	return event->dx_unaccel;
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_gesture_get_dy_unaccelerated(
> +	struct libinput_event_gesture *event)
> +{
> +	return event->dy_unaccel;
> +}
> +
>  struct libinput_source *
>  libinput_add_fd(struct libinput *libinput,
>  		int fd,
> @@ -1162,6 +1256,35 @@ 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,
> +		     double dx,
> +		     double dy,
> +		     double dx_unaccel,
> +		     double dy_unaccel)
> +{
> +	struct libinput_event_gesture *gesture_event;
> +
> +	gesture_event = zalloc(sizeof *gesture_event);
> +	if (!gesture_event)
> +		return;
> +
> +	*gesture_event = (struct libinput_event_gesture) {
> +		.time = time,
> +		.finger_count = finger_count,
> +		.dx = dx,
> +		.dy = dy,
> +		.dx_unaccel = dx_unaccel,
> +		.dy_unaccel = dy_unaccel,
> +	};
> +
> +	post_device_event(device, time, type,
> +			  &gesture_event->base);
> +}
> +
>  static void
>  libinput_post_event(struct libinput *libinput,
>  		    struct libinput_event *event)
> @@ -1393,6 +1516,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 857b3fa..9104b94 100644
> --- a/src/libinput.h
> +++ b/src/libinput.h
> @@ -173,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 = 600,
> +	LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE,
> +	LIBINPUT_EVENT_GESTURE_SWIPE_END,
>  };
>  
>  /**
> @@ -360,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.
>   *
> @@ -894,6 +911,132 @@ 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_FOO type until a LIBINPUT_EVENT_GESTURE_FOO_END is

LIBINPUT_EVENT_GESTURE_FOO -> LIBINPUT_EVENT_GESTURE_FOO_UPDATE


> + * 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
>   */
>  
> -- 
> 2.1.0
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
> 


More information about the wayland-devel mailing list