[PATCH libinput] Add pointer axis sources to the API

Hans de Goede hdegoede at redhat.com
Mon Nov 10 00:52:50 PST 2014


Hi,

On 11/06/2014 06:02 AM, Peter Hutterer wrote:
> For a caller to implement/provide kinetic scrolling (intertial scrolling,
> fling scrolling), it needs to know how the scrolling motion was implemented,
> and what to expect in the future. Add this information to the pointer axis
> event.
> 
> The three scroll sources we have are:
> * wheels: scrolling is in discreet steps, you don't know when it ends, the
>   wheel will just stop sending events
> * fingers: scrolling is continuous coordinate space, we know when it stops and
>   we can tell the caller
> * continuous: scrolling is in continuous coordinate space but we may or may not
>   know when it stops. if scroll lock is used, the device may never technically
>   get out of scroll mode even if it doesn't send events at any given moment
>   Use case: trackpoint/trackball scroll emulation on button press
> 
> The stop event is now codified in the API documentation, so callers can use
> that for kinetic scrolling. libinput does not implement kinetic scrolling
> itself.
> 
> Not covered by this patch:
> * The wheel event is currently defined as "typical mouse wheel step", this is
>   different to Qt where the step value is 1/8 of a degree. Some better
>   definition here may help.
> * It is unclear how an absolute device would map into relative motion if the
>   device itself is not controlling absolute motion.
> * For diagonal scrolling, the vertical/horizontal terminator events would come
>   in separately. The caller would have to deal with that somehow.
> 
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>

Looks good:

Reviewed-by: Hans de Goede <hdegoede at redhat.com>

Regards,

Hans

> ---
>  src/evdev-mt-touchpad.c | 16 +++++++++---
>  src/evdev.c             | 15 ++++++++++--
>  src/evdev.h             |  5 +++-
>  src/libinput-private.h  |  1 +
>  src/libinput.c          |  9 +++++++
>  src/libinput.h          | 65 ++++++++++++++++++++++++++++++++++++++++++++++---
>  test/pointer.c          |  2 ++
>  test/touchpad.c         | 23 +++++++++++++++++
>  test/trackpoint.c       | 23 +++++++++++++++++
>  9 files changed, 149 insertions(+), 10 deletions(-)
> 
> diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
> index b7a559f..1b1ff84 100644
> --- a/src/evdev-mt-touchpad.c
> +++ b/src/evdev-mt-touchpad.c
> @@ -499,7 +499,9 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
>  		dy = -dy;
>  	}
>  
> -	evdev_post_scroll(tp->device, time, dx, dy);
> +	evdev_post_scroll(tp->device, time,
> +			  LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
> +			  dx, dy);
>  }
>  
>  static int
> @@ -515,7 +517,9 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
>  	}
>  
>  	if (nfingers_down != 2) {
> -		evdev_stop_scroll(tp->device, time);
> +		evdev_stop_scroll(tp->device,
> +				  time,
> +				  LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
>  		return 0;
>  	}
>  
> @@ -540,7 +544,9 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
>  	filter_motion |= tp_post_button_events(tp, time);
>  
>  	if (filter_motion || tp->sendevents.trackpoint_active) {
> -		evdev_stop_scroll(tp->device, time);
> +		evdev_stop_scroll(tp->device,
> +				  time,
> +				  LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
>  		return;
>  	}
>  
> @@ -703,7 +709,9 @@ tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data)
>  		return;
>  
>  	if (!tp->sendevents.trackpoint_active) {
> -		evdev_stop_scroll(tp->device, time);
> +		evdev_stop_scroll(tp->device,
> +				  time,
> +				  LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
>  		tp_tap_suspend(tp, time);
>  		tp->sendevents.trackpoint_active = true;
>  	}
> diff --git a/src/evdev.c b/src/evdev.c
> index 3aa87a7..d04da88 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -217,6 +217,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
>  		    hw_is_key_down(device, BTN_MIDDLE)) {
>  			if (device->scroll.middle_button_scroll_active)
>  				evdev_post_scroll(device, time,
> +						  LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
>  						  motion.dx, motion.dy);
>  			break;
>  		}
> @@ -381,7 +382,8 @@ evdev_middle_button_scroll_button(struct evdev_device *device,
>  	} else {
>  		libinput_timer_cancel(&device->scroll.timer);
>  		if (device->scroll.middle_button_scroll_active) {
> -			evdev_stop_scroll(device, time);
> +			evdev_stop_scroll(device, time,
> +					  LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
>  			device->scroll.middle_button_scroll_active = false;
>  		} else {
>  			/* If the button is released quickly enough emit the
> @@ -545,6 +547,7 @@ evdev_process_relative(struct evdev_device *device,
>  			base,
>  			time,
>  			LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
> +			LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
>  			-1 * e->value * DEFAULT_AXIS_STEP_DISTANCE);
>  		break;
>  	case REL_HWHEEL:
> @@ -558,6 +561,7 @@ evdev_process_relative(struct evdev_device *device,
>  				base,
>  				time,
>  				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
> +				LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
>  				e->value * DEFAULT_AXIS_STEP_DISTANCE);
>  			break;
>  		default:
> @@ -1483,6 +1487,7 @@ evdev_device_get_size(struct evdev_device *device,
>  void
>  evdev_post_scroll(struct evdev_device *device,
>  		  uint64_t time,
> +		  enum libinput_pointer_axis_source source,
>  		  double dx,
>  		  double dy)
>  {
> @@ -1497,6 +1502,7 @@ evdev_post_scroll(struct evdev_device *device,
>  		pointer_notify_axis(&device->base,
>  				    time,
>  				    LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
> +				    source,
>  				    dy);
>  	}
>  
> @@ -1505,23 +1511,28 @@ evdev_post_scroll(struct evdev_device *device,
>  		pointer_notify_axis(&device->base,
>  				    time,
>  				    LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
> +				    source,
>  				    dx);
>  	}
>  }
>  
>  void
> -evdev_stop_scroll(struct evdev_device *device, uint64_t time)
> +evdev_stop_scroll(struct evdev_device *device,
> +		  uint64_t time,
> +		  enum libinput_pointer_axis_source source)
>  {
>  	/* terminate scrolling with a zero scroll event */
>  	if (device->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
>  		pointer_notify_axis(&device->base,
>  				    time,
>  				    LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
> +				    source,
>  				    0);
>  	if (device->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
>  		pointer_notify_axis(&device->base,
>  				    time,
>  				    LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
> +				    source,
>  				    0);
>  
>  	device->scroll.direction = 0;
> diff --git a/src/evdev.h b/src/evdev.h
> index 666c8dc..19f6137 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -275,12 +275,15 @@ evdev_pointer_notify_button(struct evdev_device *device,
>  void
>  evdev_post_scroll(struct evdev_device *device,
>  		  uint64_t time,
> +		  enum libinput_pointer_axis_source source,
>  		  double dx,
>  		  double dy);
>  
>  
>  void
> -evdev_stop_scroll(struct evdev_device *device, uint64_t time);
> +evdev_stop_scroll(struct evdev_device *device,
> +		  uint64_t time,
> +		  enum libinput_pointer_axis_source source);
>  
>  void
>  evdev_device_remove(struct evdev_device *device);
> diff --git a/src/libinput-private.h b/src/libinput-private.h
> index 92bd96b..7b71da2 100644
> --- a/src/libinput-private.h
> +++ b/src/libinput-private.h
> @@ -263,6 +263,7 @@ void
>  pointer_notify_axis(struct libinput_device *device,
>  		    uint64_t time,
>  		    enum libinput_pointer_axis axis,
> +		    enum libinput_pointer_axis_source source,
>  		    double value);
>  
>  void
> diff --git a/src/libinput.c b/src/libinput.c
> index 35262dd..b97117b 100644
> --- a/src/libinput.c
> +++ b/src/libinput.c
> @@ -63,6 +63,7 @@ struct libinput_event_pointer {
>  	uint32_t seat_button_count;
>  	enum libinput_button_state state;
>  	enum libinput_pointer_axis axis;
> +	enum libinput_pointer_axis_source source;
>  	double value;
>  };
>  
> @@ -374,6 +375,12 @@ libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event)
>  	return event->value;
>  }
>  
> +LIBINPUT_EXPORT enum libinput_pointer_axis_source
> +libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event)
> +{
> +	return event->source;
> +}
> +
>  LIBINPUT_EXPORT uint32_t
>  libinput_event_touch_get_time(struct libinput_event_touch *event)
>  {
> @@ -960,6 +967,7 @@ void
>  pointer_notify_axis(struct libinput_device *device,
>  		    uint64_t time,
>  		    enum libinput_pointer_axis axis,
> +		    enum libinput_pointer_axis_source source,
>  		    double value)
>  {
>  	struct libinput_event_pointer *axis_event;
> @@ -972,6 +980,7 @@ pointer_notify_axis(struct libinput_device *device,
>  		.time = time,
>  		.axis = axis,
>  		.value = value,
> +		.source = source,
>  	};
>  
>  	post_device_event(device, time,
> diff --git a/src/libinput.h b/src/libinput.h
> index 5623bff..932e65d 100644
> --- a/src/libinput.h
> +++ b/src/libinput.h
> @@ -202,6 +202,28 @@ enum libinput_pointer_axis {
>  };
>  
>  /**
> + * @ingroup device
> + *
> + * The source for a libinput_pointer_axis event. See
> + * libinput_event_pointer_get_axis_source() for details.
> + */
> +enum libinput_pointer_axis_source {
> +	/**
> +	 * The event is caused by the rotation of a wheel.
> +	 */
> +	LIBINPUT_POINTER_AXIS_SOURCE_WHEEL = 1,
> +	/**
> +	 * The event is caused by the movement of one or more fingers on a
> +	 * device.
> +	 */
> +	LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
> +	/**
> +	 * The event is caused by the motion of some device.
> +	 */
> +	LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
> +};
> +
> +/**
>   * @ingroup base
>   *
>   * Event type for events returned by libinput_get_event().
> @@ -637,9 +659,8 @@ libinput_event_pointer_get_axis(struct libinput_event_pointer *event);
>   * LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL and
>   * LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, the value of the event is in
>   * relative scroll units, with the positive direction being down or right,
> - * respectively. The dimension of a scroll unit is equal to one unit of
> - * motion in the respective axis, where applicable (e.g. touchpad two-finger
> - * scrolling).
> + * respectively. For the interpretation of the value, see
> + * libinput_event_pointer_get_axis_source().
>   *
>   * For pointer events that are not of type LIBINPUT_EVENT_POINTER_AXIS,
>   * this function returns 0.
> @@ -655,6 +676,44 @@ libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event);
>  /**
>   * @ingroup event_pointer
>   *
> + * Return the source for a given axis event. Axis events (scroll events) can
> + * be caused by a hardware item such as a scroll wheel or emulated from
> + * other input sources, such as two-finger or edge scrolling on a
> + * touchpad.
> + *
> + * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_FINGER, libinput
> + * guarantees that a scroll sequence is terminated with a scroll value of 0.
> + * A caller may use this information to decide on whether kinetic scrolling
> + * should be triggered on this scroll sequence.
> + * The coordinate system is identical to the cursor movement, i.e. a
> + * scroll value of 1 represents the equivalent relative motion of 1.
> + *
> + * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, no terminating
> + * event is guaranteed (though it may happen).
> + * Scrolling is in discreet steps, a value of 10 representing one click
> + * of a typical mouse wheel. Some mice may have differently grained wheels,
> + * libinput will adjust the value accordingly. It is up to the caller how to
> + * interpret such different step sizes.
> + *
> + * If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, no
> + * terminating event is guaranteed (though it may happen).
> + * The coordinate system is identical to the cursor movement, i.e. a
> + * scroll value of 1 represents the equivalent relative motion of 1.
> + *
> + * For pointer events that are not of type LIBINPUT_EVENT_POINTER_AXIS,
> + * this function returns 0.
> + *
> + * @note It is an application bug to call this function for events other than
> + * LIBINPUT_EVENT_POINTER_AXIS.
> + *
> + * @return the source for this axis event
> + */
> +enum libinput_pointer_axis_source
> +libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event);
> +
> +/**
> + * @ingroup event_pointer
> + *
>   * @return The generic libinput_event of this event
>   */
>  struct libinput_event *
> diff --git a/test/pointer.c b/test/pointer.c
> index 56b6709..b82f2b8 100644
> --- a/test/pointer.c
> +++ b/test/pointer.c
> @@ -262,6 +262,8 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
>  				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL :
>  				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
>  	ck_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev), expected);
> +	ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
> +			 LIBINPUT_POINTER_AXIS_SOURCE_WHEEL);
>  	libinput_event_destroy(event);
>  }
>  
> diff --git a/test/touchpad.c b/test/touchpad.c
> index 8cd838e..70de791 100644
> --- a/test/touchpad.c
> +++ b/test/touchpad.c
> @@ -1368,6 +1368,28 @@ START_TEST(touchpad_2fg_scroll)
>  }
>  END_TEST
>  
> +START_TEST(touchpad_2fg_scroll_source)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +	struct libinput_event *event;
> +	struct libinput_event_pointer *ptrev;
> +
> +	litest_drain_events(li);
> +
> +	test_2fg_scroll(dev, 0.1, 40, 0);
> +	litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);
> +
> +	event = libinput_get_event(li);
> +	ptrev = libinput_event_get_pointer_event(event);
> +
> +	ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
> +			 LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
> +
> +	libinput_event_destroy(event);
> +}
> +END_TEST
> +
>  START_TEST(touchpad_scroll_natural_defaults)
>  {
>  	struct litest_device *dev = litest_current_device();
> @@ -1984,6 +2006,7 @@ int main(int argc, char **argv) {
>  	litest_add("touchpad:topsoftbuttons", clickpad_topsoftbuttons_move_out_ignore, LITEST_TOPBUTTONPAD, LITEST_ANY);
>  
>  	litest_add("touchpad:scroll", touchpad_2fg_scroll, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
> +	litest_add("touchpad:scroll", touchpad_2fg_scroll_source, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
>  	litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY);
>  	litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY);
>  	litest_add("touchpad:scroll", touchpad_scroll_natural, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
> diff --git a/test/trackpoint.c b/test/trackpoint.c
> index d4dfe41..729062a 100644
> --- a/test/trackpoint.c
> +++ b/test/trackpoint.c
> @@ -94,10 +94,33 @@ START_TEST(trackpoint_scroll)
>  }
>  END_TEST
>  
> +START_TEST(trackpoint_scroll_source)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +	struct libinput_event *event;
> +	struct libinput_event_pointer *ptrev;
> +
> +	litest_drain_events(li);
> +
> +	test_2fg_scroll(dev, 1, 6);
> +	litest_wait_for_event_of_type(li, LIBINPUT_EVENT_POINTER_AXIS, -1);
> +
> +	event = libinput_get_event(li);
> +	ptrev = libinput_event_get_pointer_event(event);
> +
> +	ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
> +			 LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS);
> +
> +	litest_assert_empty_queue(li);
> +}
> +END_TEST
> +
>  int main(int argc, char **argv) {
>  
>  	litest_add("trackpoint:middlebutton", trackpoint_middlebutton, LITEST_POINTINGSTICK, LITEST_ANY);
>  	litest_add("trackpoint:scroll", trackpoint_scroll, LITEST_POINTINGSTICK, LITEST_ANY);
> +	litest_add("trackpoint:scroll", trackpoint_scroll_source, LITEST_POINTINGSTICK, LITEST_ANY);
>  
>  	return litest_run(argc, argv);
>  }
> 


More information about the wayland-devel mailing list