[PATCH libinput] libinput: add orientation and size of touch point and pressure to the API

Peter Hutterer peter.hutterer at who-t.net
Mon Aug 31 23:30:07 PDT 2015


please add the version of the patch to the subject. makes it a lot
easier to find whichever the latest version is. and add a short changelog
compared to the last version below the --- so reviewers know what to look
for.

On Fri, Aug 21, 2015 at 04:29:44PM +0200, Andreas Pokorny wrote:
> This change adds four new properties to touch events:
> * major: diameter of the touch ellipse along the major axis
> * minor: diameter perpendicular to major axis
> * pressure: a pressure value mapped into the range [0, 1]
> * orientation: the angle between major and the x axis [0, 360]
> 
> Those values are optionally supported by multi-touch drivers, so default values
> are used if the information is missing. The existance of each of the properties
> can be querried at the event using another set of libinput_event_touch_has_*

typo: queried

but first up, I have to ask: how did you test this, do you have an
implementation higher up in the stack that makes use of this? The API looks
generally ok now, but once I started testing it it didn't turn out too well.

what is the actual range of the major/minor your touchpad devices give you?
my touchscreen here gives me a measly 7-10 device units, translating to less
than 1mm. The orientation works correctly (1 bit), I don't have pressure
here.
double-checking with a magic trackpad shows that the range there is
accurate, so now we need to figure out how commonplace the bogus major/minor
coordinates are.

also: it's a bit disappointing that I had to fix the tools myself to
actually print or display this data. this should be part of this patch and
again brings up the question on how you tested this.
adding printfs to the event-debug tool also revealed a bug with the
has_major/has_minor/has_... implementation (see later in this email)

> functions.
> 
> Explanation of those values was added to the touch screen page.
> 
> Signed-off-by: Andreas Pokorny <andreas.pokorny at canonical.com>
> ---
>  doc/Makefile.am                                |   2 +
>  doc/page-hierarchy.dox                         |   1 +
>  doc/svg/touchscreen-touch-event-properties.svg | 347 +++++++++++++++++++++++++
>  doc/touch-event-properties.dox                 |  42 +++
>  src/evdev.c                                    | 218 ++++++++++++++--
>  src/evdev.h                                    |  25 ++
>  src/libinput-private.h                         |  25 +-
>  src/libinput-util.h                            |   6 +
>  src/libinput.c                                 | 205 ++++++++++++++-
>  src/libinput.h                                 | 222 ++++++++++++++++
>  src/libinput.sym                               |  13 +
>  test/touch.c                                   | 239 +++++++++++++++++
>  12 files changed, 1313 insertions(+), 32 deletions(-)
>  create mode 100644 doc/svg/touchscreen-touch-event-properties.svg
>  create mode 100644 doc/touch-event-properties.dox
> 
> diff --git a/doc/Makefile.am b/doc/Makefile.am
> index a8d4182..da21283 100644
> --- a/doc/Makefile.am
> +++ b/doc/Makefile.am
> @@ -26,6 +26,7 @@ header_files = \
>  	$(srcdir)/tapping.dox \
>  	$(srcdir)/test-suite.dox \
>  	$(srcdir)/tools.dox \
> +	$(srcdir)/touch-event-properties.dox \
>  	$(srcdir)/touchpads.dox
>  
>  diagram_files = \
> @@ -49,6 +50,7 @@ diagram_files = \
>  	$(srcdir)/svg/thumb-detection.svg \
>  	$(srcdir)/svg/top-software-buttons.svg \
>  	$(srcdir)/svg/touchscreen-gestures.svg \
> +	$(srcdir)/svg/touchscreen-touch-event-properties.svg \
>  	$(srcdir)/svg/twofinger-scrolling.svg
>  
>  style_files = \
> diff --git a/doc/page-hierarchy.dox b/doc/page-hierarchy.dox
> index 3fdb1f7..72765e2 100644
> --- a/doc/page-hierarchy.dox
> +++ b/doc/page-hierarchy.dox
> @@ -11,6 +11,7 @@
>  @page touchscreens Touchscreens
>  
>  - @subpage absolute_axes
> +- @subpage touch_event_properties 
>  
>  @page pointers Mice, Trackballs, etc.
>  
> diff --git a/doc/svg/touchscreen-touch-event-properties.svg b/doc/svg/touchscreen-touch-event-properties.svg
> new file mode 100644
> index 0000000..b728f40
> --- /dev/null
> +++ b/doc/svg/touchscreen-touch-event-properties.svg
> @@ -0,0 +1,347 @@

[...]

thanks for the drawing, beats ascii-art by a mile :)

> diff --git a/doc/touch-event-properties.dox b/doc/touch-event-properties.dox
> new file mode 100644
> index 0000000..75fc072
> --- /dev/null
> +++ b/doc/touch-event-properties.dox
> @@ -0,0 +1,42 @@
> +/**
> + at page touch_event_properties Properties of a touch event
> +
> +This page gives some overview on touchscreen events. With libinput touchscreens
> +provide the event types @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref LIBINPUT_EVENT_TOUCH_UP,
> + at ref LIBINPUT_EVENT_TOUCH_MOTION and @ref LIBINPUT_EVENT_TOUCH_CANCEL. The
> +touchscreen events @ref LIBINPUT_EVENT_TOUCH_DOWN and
> + at ref LIBINPUT_EVENT_TOUCH_MOTION provide alongside the actual state change and
> +the absolute coordinates (@ref absolute_axes_handling) additional information
> +about the touch contact.

this is just a heads-up, the final version will need a couple of
rewordings. I'll do that when merging the final patch, that's a bit easier.
Especially the sentence above makes sense when I read it in german but not
so much in english :)

> +
> + at image html touchscreen-touch-event-properties.svg "Properties of a touch screen contact"
> +
> +Assuming the interaction of fingers with a touch screen, touch contacts are
> +approximated with an ellipse. The major axis of the ellipse describes the
> +pointing direction of the finger. The minor axis is the perpendicular
> +extent of the touching shape. The orientation angle is the clockwise rotation of
> +the pointing direction against the y-axis of the touchscreen.
> +
> +Additionally to the values shown in the drawing above, most touchscreens also
> +provide a pressure value to indicate the force applied with the contact point.
> +
> +The support for those contact properties varies between the different
> +available touchscreens. In the case of pressure libinput will return the
> +maximum pressure value, which is 1.0. If only the major axis but no minor axis
> +is present, libinput will assume a circular shape and return the major axis
> +value for convenience. If also no major axis value is known 0.0 is returned.
> +If the orientation is not available libinput will return 0.0 degrees.
> +
> +For querying the touch properties see:
> +- @ref libinput_event_touch_get_major_transformed
> +- @ref libinput_event_touch_get_minor_transformed
> +- @ref libinput_event_touch_get_orientation
> +- @ref libinput_event_touch_get_pressure
> +
> +For testing which of the touch properties are available see:
> +- @ref libinput_event_touch_has_major
> +- @ref libinput_event_touch_has_minor
> +- @ref libinput_event_touch_has_orientation
> +- @ref libinput_event_touch_has_pressure

append () to the function and you can drop the @ref, doxygen will
automatically resolve anything written as some_function()

> +
> +*/
> diff --git a/src/evdev.c b/src/evdev.c
> index 303e447..29303f8 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -45,6 +45,10 @@
>  
>  #define DEFAULT_WHEEL_CLICK_ANGLE 15
>  #define DEFAULT_MIDDLE_BUTTON_SCROLL_TIMEOUT ms2us(200)
> +#define DEFAULT_TOUCH_PRESSURE 1
> +#define DEFAULT_TOUCH_ORIENTATION 0
> +#define DEFAULT_TOUCH_MAJOR 0
> +#define DEFAULT_TOUCH_MINOR 0

make this 0.0 and 1.0 since we're dealing with doubles

>  enum evdev_key_type {
>  	EVDEV_KEY_TYPE_NONE,
> @@ -245,6 +249,100 @@ evdev_device_transform_y(struct evdev_device *device,
>  	return scale_axis(device->abs.absinfo_y, y, height);
>  }
>  
> +double
> +evdev_device_transform_ellipse_diameter_to_mm(struct evdev_device *device,
> +					      int diameter,
> +					      double axis_angle)
> +{
> +	double x_res = device->abs.absinfo_x->resolution;
> +	double y_res = device->abs.absinfo_y->resolution;
> +
> +	if (x_res == y_res)
> +		return diameter / x_res;
> +
> +	/* resolution differs but no orientation available
> +	 * -> estimate resolution using the average */
> +	if (device->abs.absinfo_orientation == NULL) {
> +		return diameter * 2.0 / (x_res + y_res);
> +	} else {
> +		/* Why scale x using sine of angle?
> +		 * axis_angle = 0 indicates that the given diameter
> +		 * is aligned with the y-axis. */
> +		double x_scaling_ratio = fabs(sin(deg2rad(axis_angle)));
> +		double y_scaling_ratio = fabs(cos(deg2rad(axis_angle)));
> +
> +		return diameter / (y_res * y_scaling_ratio +
> +				   x_res * x_scaling_ratio);
> +	}
> +}
> +
> +double
> +evdev_device_transform_ellipse_diameter(struct evdev_device *device,
> +					int diameter,
> +					double axis_angle,
> +					uint32_t width,
> +					uint32_t height)
> +{
> +	double x_res = device->abs.absinfo_x->resolution;
> +	double y_res = device->abs.absinfo_y->resolution;
> +	double x_scale = width / (device->abs.dimensions.x + 1.0);
> +	double y_scale = height / (device->abs.dimensions.y + 1.0);
> +
> +	if (x_res == y_res)
> +		return diameter * x_scale;
> +
> +	/* no orientation available -> estimate resolution using the
> +	 * average */
> +	if (device->abs.absinfo_orientation == NULL) {
> +		return diameter * (x_scale + y_scale) / 2.0;
> +	} else {
> +		/* Why scale x using sine of angle?
> +		 * axis_angle = 0 indicates that the given diameter
> +		 * is aligned with the y-axis. */
> +		double x_scaling_ratio = fabs(sin(deg2rad(axis_angle)));
> +		double y_scaling_ratio = fabs(cos(deg2rad(axis_angle)));
> +
> +		return diameter * (y_scale * y_scaling_ratio +
> +				   x_scale * x_scaling_ratio);
> +	}
> +}
> +
> +double
> +evdev_device_transform_orientation(struct evdev_device *device,
> +				   int32_t orientation)
> +{
> +	const struct input_absinfo *orientation_info =
> +					device->abs.absinfo_orientation;
> +
> +	double angle = DEFAULT_TOUCH_ORIENTATION;
> +
> +	/* ABS_MT_ORIENTATION is defined as a clockwise rotation - zero
> +	 * (instead of minimum) is mapped to the y-axis, and maximum is
> +	 * mapped to the x-axis. So minimum is likely to be negative but
> +	 * plays no role in scaling the value to degrees.*/
> +	if (orientation_info)
> +		angle = (90.0 * orientation) / orientation_info->maximum;
> +
> +	return fmod(360.0 + angle, 360.0);
> +}
> +
> +double
> +evdev_device_transform_pressure(struct evdev_device *device,
> +				int32_t pressure)
> +{
> +	const struct input_absinfo *pressure_info =
> +					device->abs.absinfo_pressure;
> +
> +	if (pressure_info) {
> +		double max_pressure = pressure_info->maximum;
> +		double min_pressure = pressure_info->minimum;
> +		return (pressure - min_pressure) /
> +					(max_pressure - min_pressure);
> +	} else {
> +		return DEFAULT_TOUCH_PRESSURE;
> +	}
> +}
> +
>  static inline void
>  normalize_delta(struct evdev_device *device,
>  		const struct device_coords *delta,
> @@ -282,8 +380,15 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
>  	struct normalized_coords accel, unaccel;
>  	struct device_coords point;
>  	struct device_float_coords raw;
> +	struct mt_slot *slot_data;
> +	struct ellipse default_touch = {
> +		.major = DEFAULT_TOUCH_MAJOR,
> +		.minor = DEFAULT_TOUCH_MINOR,
> +		.orientation = DEFAULT_TOUCH_ORIENTATION
> +	};
>  
>  	slot = device->mt.slot;
> +	slot_data = &device->mt.slots[slot];
>  
>  	switch (device->pending_event) {
>  	case EVDEV_NONE:
> @@ -314,7 +419,7 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
>  		if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
>  			break;
>  
> -		if (device->mt.slots[slot].seat_slot != -1) {
> +		if (slot_data->seat_slot != -1) {
>  			log_bug_kernel(libinput,
>  				       "%s: Driver sent multiple touch down for the "
>  				       "same slot",
> @@ -323,38 +428,52 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
>  		}
>  
>  		seat_slot = ffs(~seat->slot_map) - 1;
> -		device->mt.slots[slot].seat_slot = seat_slot;
> +		slot_data->seat_slot = seat_slot;
>  
>  		if (seat_slot == -1)
>  			break;
>  
>  		seat->slot_map |= 1 << seat_slot;
> -		point = device->mt.slots[slot].point;
> +		point = slot_data->point;
>  		transform_absolute(device, &point);
>  
> -		touch_notify_touch_down(base, time, slot, seat_slot,
> -					&point);
> +		touch_notify_touch_down(base,
> +					time,
> +					slot,
> +					seat_slot,
> +					&point,
> +					slot_data->available_data,
> +					&slot_data->area,
> +					slot_data->pressure);
>  		break;
>  	case EVDEV_ABSOLUTE_MT_MOTION:
>  		if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
>  			break;
>  
> -		seat_slot = device->mt.slots[slot].seat_slot;
> -		point = device->mt.slots[slot].point;
> +		seat_slot = slot_data->seat_slot;
> +
> +		point = slot_data->point;
>  
>  		if (seat_slot == -1)
>  			break;
>  
>  		transform_absolute(device, &point);
> -		touch_notify_touch_motion(base, time, slot, seat_slot,
> -					  &point);
> +
> +		touch_notify_touch_motion(base,
> +					  time,
> +					  slot,
> +					  seat_slot,
> +					  &point,
> +					  slot_data->available_data,
> +					  &slot_data->area,
> +					  slot_data->pressure);
>  		break;
>  	case EVDEV_ABSOLUTE_MT_UP:
>  		if (!(device->seat_caps & EVDEV_DEVICE_TOUCH))
>  			break;
>  
> -		seat_slot = device->mt.slots[slot].seat_slot;
> -		device->mt.slots[slot].seat_slot = -1;
> +		seat_slot = slot_data->seat_slot;
> +		slot_data->seat_slot = -1;
>  
>  		if (seat_slot == -1)
>  			break;
> @@ -386,7 +505,14 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
>  		point = device->abs.point;
>  		transform_absolute(device, &point);
>  
> -		touch_notify_touch_down(base, time, -1, seat_slot, &point);
> +		touch_notify_touch_down(base,
> +					time,
> +					-1,
> +					seat_slot,
> +					&point,
> +					TOUCH_SLOT_DATA_NONE,
> +					&default_touch,
> +					DEFAULT_TOUCH_PRESSURE);
>  		break;
>  	case EVDEV_ABSOLUTE_MOTION:
>  		point = device->abs.point;
> @@ -398,8 +524,14 @@ evdev_flush_pending_event(struct evdev_device *device, uint64_t time)
>  			if (seat_slot == -1)
>  				break;
>  
> -			touch_notify_touch_motion(base, time, -1, seat_slot,
> -						  &point);
> +			touch_notify_touch_motion(base,
> +						  time,
> +						  -1,
> +						  seat_slot,
> +						  &point,
> +						  TOUCH_SLOT_DATA_NONE,
> +						  &default_touch,
> +						  DEFAULT_TOUCH_PRESSURE);
>  		} else if (device->seat_caps & EVDEV_DEVICE_POINTER) {
>  			pointer_notify_motion_absolute(base, time, &point);
>  		}
> @@ -559,8 +691,9 @@ evdev_process_touch(struct evdev_device *device,
>  		    struct input_event *e,
>  		    uint64_t time)
>  {
> -	switch (e->code) {
> -	case ABS_MT_SLOT:
> +	struct mt_slot *current_slot = &device->mt.slots[device->mt.slot];
> +
> +	if (e->code == ABS_MT_SLOT) {
>  		if ((size_t)e->value >= device->mt.slots_len) {
>  			log_bug_libinput(device->base.seat->libinput,
>  					 "%s exceeds slots (%d of %zd)\n",
> @@ -571,8 +704,7 @@ evdev_process_touch(struct evdev_device *device,
>  		}
>  		evdev_flush_pending_event(device, time);
>  		device->mt.slot = e->value;
> -		break;
> -	case ABS_MT_TRACKING_ID:
> +	} else if(e->code == ABS_MT_TRACKING_ID) {
>  		if (device->pending_event != EVDEV_NONE &&
>  		    device->pending_event != EVDEV_ABSOLUTE_MT_MOTION)
>  			evdev_flush_pending_event(device, time);
> @@ -580,17 +712,40 @@ evdev_process_touch(struct evdev_device *device,
>  			device->pending_event = EVDEV_ABSOLUTE_MT_DOWN;
>  		else
>  			device->pending_event = EVDEV_ABSOLUTE_MT_UP;
> -		break;
> -	case ABS_MT_POSITION_X:
> -		device->mt.slots[device->mt.slot].point.x = e->value;
> -		if (device->pending_event == EVDEV_NONE)
> -			device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;
> -		break;
> -	case ABS_MT_POSITION_Y:
> -		device->mt.slots[device->mt.slot].point.y = e->value;
> -		if (device->pending_event == EVDEV_NONE)
> +	} else {
> +		bool needs_wake = true;
> +
> +		switch(e->code) {
> +		case ABS_MT_POSITION_X:
> +			current_slot->point.x = e->value;
> +			break;
> +		case ABS_MT_POSITION_Y:
> +			current_slot->point.y = e->value;
> +			break;
> +		case ABS_MT_TOUCH_MAJOR:
> +			current_slot->available_data |= TOUCH_SLOT_DATA_MAJOR;
> +			current_slot->area.major = e->value;

the handling of the has_major/minor/orientation isn't correct. if a device
has the axis, you can get the current per-slot value on device startup.
the value remains valid until overwritten by a new value on the device. so
libinput_event_touch_has_major() doesn't tell us whether a specific event
has a major axis, but rather whether a device do the axis at all, i.e. it's
either always true or always false.

the API could be libinput_device_has_... but I think the per-event API is
better. the current implementation is broken though, just add a printf to
event-debug and you'll see how we don't know major/minor until we get an
event for each.

orientation is the same: there's no orientation value for the first touch
point, though after that it keeps being printed (which ironically means that
available_data is never reset).

> +			break;
> +		case ABS_MT_TOUCH_MINOR:
> +			current_slot->available_data |= TOUCH_SLOT_DATA_MINOR;
> +			current_slot->area.minor = e->value;
> +			break;
> +		case ABS_MT_ORIENTATION:
> +			current_slot->available_data |=
> +						TOUCH_SLOT_DATA_ORIENTATION;
> +			current_slot->area.orientation = e->value;
> +			break;
> +		case ABS_MT_PRESSURE:
> +			current_slot->available_data |=
> +						TOUCH_SLOT_DATA_PRESSURE;
> +			current_slot->pressure = e->value;
> +			break;
> +		default:
> +			needs_wake = false;
> +			break;
> +		}
> +		if (needs_wake && device->pending_event == EVDEV_NONE)
>  			device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;
> -		break;
>  	}
>  }
>  
> @@ -1941,6 +2096,13 @@ evdev_configure_device(struct evdev_device *device)
>  		return -1;
>  	}
>  
> +	device->abs.absinfo_orientation =
> +		libevdev_get_abs_info(evdev,
> +				      ABS_MT_ORIENTATION);
> +	device->abs.absinfo_pressure =
> +		libevdev_get_abs_info(evdev,
> +				      ABS_MT_PRESSURE);
> +
>  	if (!evdev_is_fake_mt_device(device))
>  		evdev_fix_android_mt(device);
>  
> diff --git a/src/evdev.h b/src/evdev.h
> index e44a65d..383e682 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -112,6 +112,9 @@ enum evdev_device_model {
>  struct mt_slot {
>  	int32_t seat_slot;
>  	struct device_coords point;
> +	enum touch_slot_data available_data;
> +	struct ellipse area;
> +	int32_t pressure;
>  };
>  
>  struct evdev_device {
> @@ -128,6 +131,8 @@ struct evdev_device {
>  	int fd;
>  	struct {
>  		const struct input_absinfo *absinfo_x, *absinfo_y;
> +		const struct input_absinfo *absinfo_pressure,
> +					   *absinfo_orientation;
>  		int fake_resolution;
>  
>  		struct device_coords point;
> @@ -349,6 +354,26 @@ double
>  evdev_device_transform_y(struct evdev_device *device,
>  			 double y,
>  			 uint32_t height);
> +double
> +evdev_device_transform_ellipse_diameter_to_mm(struct evdev_device *device,
> +					      int32_t diameter,
> +					      double axis_angle);
> +
> +double
> +evdev_device_transform_ellipse_diameter(struct evdev_device *device,
> +					int32_t diameter,
> +					double axis_angle,
> +					uint32_t width,
> +					uint32_t height);
> +
> +double
> +evdev_device_transform_orientation(struct evdev_device *device,
> +				   int32_t orientation);
> +
> +double
> +evdev_device_transform_pressure(struct evdev_device *device,
> +				int32_t pressure);
> +
>  int
>  evdev_device_suspend(struct evdev_device *device);
>  
> diff --git a/src/libinput-private.h b/src/libinput-private.h
> index 8b161cc..0060030 100644
> --- a/src/libinput-private.h
> +++ b/src/libinput-private.h
> @@ -40,6 +40,11 @@ struct device_coords {
>  	int x, y;
>  };
>  
> +/* Ellipse parameters in device coordinates */
> +struct ellipse {
> +	int major, minor, orientation;
> +};
> +
>  /*
>   * A coordinate pair in device coordinates, capable of holding non discrete
>   * values, this is necessary e.g. when device coordinates get averaged.
> @@ -58,6 +63,16 @@ struct discrete_coords {
>  	int x, y;
>  };
>  
> +enum touch_slot_data {
> +	TOUCH_SLOT_DATA_NONE = 0,
> +	TOUCH_SLOT_DATA_MAJOR = (1 << 1),
> +	TOUCH_SLOT_DATA_MINOR = (1 << 2),
> +	TOUCH_SLOT_DATA_ORIENTATION = (1 << 3),
> +	TOUCH_SLOT_DATA_PRESSURE = (1 << 4),
> +};
> +
> +
> +

no duplicate empty lines please.

I recommend git config filter.trimWhitespace.clean git-stripspace

>  struct libinput_interface_backend {
>  	int (*resume)(struct libinput *libinput);
>  	void (*suspend)(struct libinput *libinput);
> @@ -381,14 +396,20 @@ touch_notify_touch_down(struct libinput_device *device,
>  			uint64_t time,
>  			int32_t slot,
>  			int32_t seat_slot,
> -			const struct device_coords *point);
> +			const struct device_coords *point,
> +			enum touch_slot_data available_data,
> +			const struct ellipse *area,
> +			int32_t pressure);
>  
>  void
>  touch_notify_touch_motion(struct libinput_device *device,
>  			  uint64_t time,
>  			  int32_t slot,
>  			  int32_t seat_slot,
> -			  const struct device_coords *point);
> +			  const struct device_coords *point,
> +			  enum touch_slot_data available_data,
> +			  const struct ellipse *area,
> +			  int32_t pressure);
>  
>  void
>  touch_notify_touch_up(struct libinput_device *device,
> diff --git a/src/libinput-util.h b/src/libinput-util.h
> index ba253b5..9495fa6 100644
> --- a/src/libinput-util.h
> +++ b/src/libinput-util.h
> @@ -118,6 +118,12 @@ msleep(unsigned int ms)
>  	usleep(ms * 1000);
>  }
>  
> +static inline double
> +deg2rad(double angle)
> +{
> +	return angle * M_PI/180.0;
> +}
> +
>  static inline int
>  long_bit_is_set(const unsigned long *array, int bit)
>  {
> diff --git a/src/libinput.c b/src/libinput.c
> index e564571..237a35f 100644
> --- a/src/libinput.c
> +++ b/src/libinput.c
> @@ -112,6 +112,9 @@ struct libinput_event_touch {
>  	int32_t slot;
>  	int32_t seat_slot;
>  	struct device_coords point;
> +	enum touch_slot_data available_data;
> +	struct ellipse area;
> +	int32_t pressure;
>  };
>  
>  struct libinput_event_gesture {
> @@ -729,6 +732,192 @@ libinput_event_touch_get_y(struct libinput_event_touch *event)
>  	return evdev_convert_to_mm(device->abs.absinfo_y, event->point.y);
>  }
>  
> +LIBINPUT_EXPORT double
> +libinput_event_touch_get_major(struct libinput_event_touch *event)
> +{
> +	struct evdev_device *device =
> +		(struct evdev_device *) event->base.device;
> +	double angle;
> +
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	angle = evdev_device_transform_orientation(device,
> +						   event->area.orientation);
> +
> +	return evdev_device_transform_ellipse_diameter_to_mm(device,
> +							     event->area.major,
> +							     angle);
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_touch_get_major_transformed(struct libinput_event_touch *event,
> +					   uint32_t width,
> +					   uint32_t height)
> +{
> +	struct evdev_device *device =
> +		(struct evdev_device *) event->base.device;
> +	double angle;
> +
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	angle = evdev_device_transform_orientation(device,
> +						   event->area.orientation);
> +
> +	return evdev_device_transform_ellipse_diameter(device,
> +						       event->area.major,
> +						       angle,
> +						       width,
> +						       height);
> +}
> +
> +LIBINPUT_EXPORT int
> +libinput_event_touch_has_major(struct libinput_event_touch *event)
> +{
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	return event->available_data & TOUCH_SLOT_DATA_MAJOR;
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_touch_get_minor(struct libinput_event_touch *event)
> +{
> +	struct evdev_device *device =
> +		(struct evdev_device *) event->base.device;
> +	double angle;
> +
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	angle = evdev_device_transform_orientation(device,
> +						   event->area.orientation);
> +
> +	/* angle + 90 since the minor diameter is perpendicular to the
> +	 * major axis */
> +	return evdev_device_transform_ellipse_diameter_to_mm(device,
> +							     event->area.minor,
> +							     angle + 90.0);
> +
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_touch_get_minor_transformed(struct libinput_event_touch *event,
> +					   uint32_t width,
> +					   uint32_t height)
> +{
> +	struct evdev_device *device =
> +		(struct evdev_device *) event->base.device;
> +	double angle;
> +	int diameter;
> +
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	angle = evdev_device_transform_orientation(device,
> +						   event->area.orientation);
> +
> +	/* use major diameter if minor is not available, but if it is
> +	 * add 90 since the minor diameter is perpendicular to the
> +	 * major axis */
> +	if( event->available_data & TOUCH_SLOT_DATA_MINOR) {
> +		diameter = event->area.minor,
> +		angle += 90.0;
> +	} else {
> +		diameter = event->area.major;
> +	}
> +
> +	return evdev_device_transform_ellipse_diameter(device,
> +						       diameter,
> +						       angle,
> +						       width,
> +						       height);
> +}
> +
> +LIBINPUT_EXPORT int
> +libinput_event_touch_has_minor(struct libinput_event_touch *event)
> +{
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	return event->available_data & TOUCH_SLOT_DATA_MINOR;
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_touch_get_orientation(struct libinput_event_touch *event)
> +{
> +	struct evdev_device *device =
> +		(struct evdev_device *) event->base.device;
> +
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	return evdev_device_transform_orientation(device,
> +						  event->area.orientation);
> +}
> +
> +LIBINPUT_EXPORT int
> +libinput_event_touch_has_orientation(struct libinput_event_touch *event)
> +{
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	return event->available_data & TOUCH_SLOT_DATA_ORIENTATION;
> +}
> +
> +LIBINPUT_EXPORT double
> +libinput_event_touch_get_pressure(struct libinput_event_touch *event)
> +{
> +	struct evdev_device *device =
> +		(struct evdev_device *) event->base.device;
> +
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	return evdev_device_transform_pressure(device,
> +					       event->pressure);
> +}
> +
> +LIBINPUT_EXPORT int
> +libinput_event_touch_has_pressure(struct libinput_event_touch *event)
> +{
> +	require_event_type(libinput_event_get_context(&event->base),
> +			   event->base.type,
> +			   0,
> +			   LIBINPUT_EVENT_TOUCH_DOWN,
> +			   LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	return event->available_data & TOUCH_SLOT_DATA_PRESSURE;
> +}
> +
>  LIBINPUT_EXPORT uint32_t
>  libinput_event_gesture_get_time(struct libinput_event_gesture *event)
>  {
> @@ -1500,7 +1689,10 @@ touch_notify_touch_down(struct libinput_device *device,
>  			uint64_t time,
>  			int32_t slot,
>  			int32_t seat_slot,
> -			const struct device_coords *point)
> +			const struct device_coords *point,
> +			enum touch_slot_data available_data,
> +			const struct ellipse *area,
> +			int32_t pressure)
>  {
>  	struct libinput_event_touch *touch_event;
>  
> @@ -1516,6 +1708,9 @@ touch_notify_touch_down(struct libinput_device *device,
>  		.slot = slot,
>  		.seat_slot = seat_slot,
>  		.point = *point,
> +		.available_data = available_data,
> +		.area = *area,
> +		.pressure = pressure,
>  	};
>  
>  	post_device_event(device, time,
> @@ -1528,7 +1723,10 @@ touch_notify_touch_motion(struct libinput_device *device,
>  			  uint64_t time,
>  			  int32_t slot,
>  			  int32_t seat_slot,
> -			  const struct device_coords *point)
> +			  const struct device_coords *point,
> +			  enum touch_slot_data available_data,
> +			  const struct ellipse *area,
> +			  int32_t pressure)
>  {
>  	struct libinput_event_touch *touch_event;
>  
> @@ -1544,6 +1742,9 @@ touch_notify_touch_motion(struct libinput_device *device,
>  		.slot = slot,
>  		.seat_slot = seat_slot,
>  		.point = *point,
> +		.available_data = available_data,
> +		.area = *area,
> +		.pressure = pressure,
>  	};
>  
>  	post_device_event(device, time,
> diff --git a/src/libinput.h b/src/libinput.h
> index 88b3c05..34ef518 100644
> --- a/src/libinput.h
> +++ b/src/libinput.h
> @@ -968,6 +968,228 @@ libinput_event_touch_get_y_transformed(struct libinput_event_touch *event,
>  /**
>   * @ingroup event_touch
>   *
> + * Return the diameter of the major axis of the touch ellipse in mm.
> + * This value might not be provided by the device, in that case the value
> + * 0.0 is returned.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return The current major axis diameter
> + */
> +double
> +libinput_event_touch_get_major(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return the diameter of the major axis of the touch ellipse in screen
> + * space. This value might not be provided by the device, in that case the
> + * value 0.0 is returned.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @param width The current output screen width
> + * @param height The current output screen height
> + * @return The current major axis diameter
> + */
> +double
> +libinput_event_touch_get_major_transformed(struct libinput_event_touch *event,
> +					   uint32_t width,
> +					   uint32_t height);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return if the event contains a major axis value of the touch ellipse.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return Whether a major diameter is available

the other functions use something like "non-zero when the axis is available
or zero otherwise", please stick to the same wording.

> + */
> +int
> +libinput_event_touch_has_major(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return the diameter of the minor axis of the touch ellipse in mm.
> + * This value might not be provided by the device, in this case the value
> + * 0.0 is returned.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return The current minor diameter
> + */
> +double
> +libinput_event_touch_get_minor(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return the diameter of the minor axis of the touch ellipse in screen
> + * space. This value might not be provided by the device, in this case
> + * the value 0.0 is returned.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @param width The current output screen width
> + * @param height The current output screen height
> + * @return The current minor diameter
> + */
> +double
> +libinput_event_touch_get_minor_transformed(struct libinput_event_touch *event,
> +					   uint32_t width,
> +					   uint32_t height);
> +/**
> + * @ingroup event_touch
> + *
> + * Return if the event contains a minor axis value of the touch ellipse.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return Whether a minor diameter is available
> + */
> +int
> +libinput_event_touch_has_minor(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return the pressure value applied to the touch contact normalized to the
> + * range [0, 1]. If this value is not available the function returns the maximum
> + * value 1.0.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return The current pressure value
> + */
> +double
> +libinput_event_touch_get_pressure(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return if the event contains a pressure value for the touch contact.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return Whether a pressure value is available
> + */
> +int
> +libinput_event_touch_has_pressure(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return the major axis rotation in degrees, clockwise from the logical north
> + * of the touch screen.
> + *
> + * @note Even when the orientation is measured by the device, it might be only
> + * available in coarse steps (e.g only indicating alignment with either of the
> + * axes).
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return The current orientation value
> + */
> +double
> +libinput_event_touch_get_orientation(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
> + * Return if the event contains a orientation value for the touch contact.
> + *
> + * A more detailed explanation can be found in @ref touch_event_properties.
> + *
> + * For events not of type @ref LIBINPUT_EVENT_TOUCH_DOWN, @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION, this function returns 0.
> + *
> + * @note It is an application bug to call this function for events of type
> + * other than @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref
> + * LIBINPUT_EVENT_TOUCH_MOTION.
> + *
> + * @param event The libinput touch event
> + * @return Whether a orientation value is available
> + */
> +int
> +libinput_event_touch_has_orientation(struct libinput_event_touch *event);
> +
> +/**
> + * @ingroup event_touch
> + *
>   * @return The generic libinput_event of this event
>   */
>  struct libinput_event *
> diff --git a/src/libinput.sym b/src/libinput.sym
> index 7e0ef1c..12edd15 100644
> --- a/src/libinput.sym
> +++ b/src/libinput.sym
> @@ -172,3 +172,16 @@ LIBINPUT_0.21.0 {
>  	libinput_event_pointer_get_time_usec;
>  	libinput_event_touch_get_time_usec;
>  } LIBINPUT_0.20.0;
> +
> +LIBINPUT_0.22.0 {
> +	libinput_event_touch_get_major;
> +	libinput_event_touch_get_major_transformed;
> +	libinput_event_touch_get_minor;
> +	libinput_event_touch_get_minor_transformed;
> +	libinput_event_touch_get_orientation;
> +	libinput_event_touch_get_pressure;
> +	libinput_event_touch_has_major;
> +	libinput_event_touch_has_minor;
> +	libinput_event_touch_has_orientation;
> +	libinput_event_touch_has_pressure;
> +} LIBINPUT_0.21.0;
> diff --git a/test/touch.c b/test/touch.c
> index eae8007..066eee4 100644
> --- a/test/touch.c
> +++ b/test/touch.c
> @@ -673,6 +673,243 @@ START_TEST(touch_time_usec)
>  }
>  END_TEST
>  
> +static inline double calc_diameter_scale(double x_res,
> +					 double y_res,
> +					 double orientation)
> +{
> +	double orientation_rad = deg2rad(orientation);

empty line after the declarations.

> +	if (x_res == y_res)
> +		return x_res;
> +
> +	return y_res * fabs(cos(orientation_rad)) +
> +		x_res * fabs(sin(orientation_rad));
> +}
> +
> +static inline bool exceeds_range(const struct input_absinfo *info,
> +				 int value)
> +{
> +	return !info || (info->minimum > value) || (info->maximum < value);
> +}
> +
> +START_TEST(touch_point_properties)
> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +	struct libinput_event *ev;
> +	struct libinput_event_touch *tev;
> +
> +	const int touch_x = 50;
> +	const int touch_y = 90;
> +	const int input_orientation = 64;
> +	const int input_pressure = 128;
> +	const int input_major = 14;
> +	const int input_minor= 8;
> +
> +	const int input_orientation_2 = 128;
> +	const int input_major_2 = 30;
> +
> +	struct axis_replacement down_values[] = {
> +		{ABS_MT_PRESSURE, input_pressure},
> +		{ABS_MT_ORIENTATION, input_orientation},
> +		{ABS_MT_TOUCH_MAJOR, input_major},
> +		{ABS_MT_TOUCH_MINOR, input_minor},
> +		{-1, -1}};
> +	struct axis_replacement move_values[] = {
> +		{ABS_MT_ORIENTATION, input_orientation_2},
> +		{ABS_MT_TOUCH_MAJOR, input_major_2},
> +		{-1, -1}};
> +	const struct input_absinfo *orientation_info;
> +	const struct input_absinfo *pressure_info;
> +	const struct input_absinfo *major_info;
> +	const struct input_absinfo *minor_info;
> +	const struct input_absinfo *x_info, *y_info;
> +
> +	double x_res, y_res, touch_minor_scale, touch_major_scale;
> +
> +	double expected_major;
> +	double expected_minor;
> +	double expected_orientation;
> +	double expected_pressure;
> +
> +	pressure_info = libevdev_get_abs_info(dev->evdev, ABS_MT_PRESSURE);
> +	orientation_info = libevdev_get_abs_info(dev->evdev, ABS_MT_ORIENTATION);
> +	major_info = libevdev_get_abs_info(dev->evdev, ABS_MT_TOUCH_MAJOR);
> +	minor_info = libevdev_get_abs_info(dev->evdev, ABS_MT_TOUCH_MINOR);
> +	x_info = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X);
> +	y_info = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_Y);
> +
> +	if (!orientation_info || !pressure_info || !major_info || !minor_info)
> +		return;
> +
> +	if (exceeds_range(pressure_info, input_pressure) ||
> +	    exceeds_range(major_info, input_major) ||
> +	    exceeds_range(major_info, input_major_2) ||
> +	    exceeds_range(minor_info, input_minor) ||
> +	    exceeds_range(orientation_info, input_orientation) ||
> +	    exceeds_range(orientation_info, input_orientation_2)) {
> +		fprintf(stderr, "%s does not support the required value ranges",
> +			libinput_device_get_name(dev->libinput_device));

use ck_abort_msg() here, when this happens it's a test bug and needs to be fixed.

> +		return;
> +        }
> +
> +	x_res = x_info->resolution ? x_info->resolution : 1;
> +	y_res = y_info->resolution ? y_info->resolution : 1;
> +
> +	expected_orientation = 90.0 * input_orientation /
> +				orientation_info->maximum;
> +	touch_major_scale = calc_diameter_scale(x_res,
> +						y_res,
> +						expected_orientation);
> +	touch_minor_scale = calc_diameter_scale(x_res,
> +						y_res,
> +						expected_orientation + 90.0);
> +	expected_major = input_major / touch_major_scale;
> +	expected_minor = input_minor / touch_minor_scale;
> +	expected_pressure = (double)input_pressure / (pressure_info->maximum -
> +						      pressure_info->minimum);
> +
> +	litest_drain_events(li);
> +
> +	litest_touch_down_extended(dev, 0, touch_x, touch_y, down_values);
> +
> +	litest_wait_for_event(li);
> +	ev = libinput_get_event(li);
> +	tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_DOWN);
> +
> +	ck_assert_double_eq(libinput_event_touch_get_pressure(tev),
> +			    expected_pressure);
> +	ck_assert_double_eq(libinput_event_touch_get_orientation(tev),
> +			    expected_orientation);
> +	ck_assert_double_eq(libinput_event_touch_get_major(tev),
> +			    expected_major);
> +	ck_assert_double_eq(libinput_event_touch_get_minor(tev),
> +			    expected_minor);
> +
> +	libinput_event_destroy(ev);
> +
> +	litest_touch_move_extended(dev, 0, touch_x, touch_y, move_values);
> +
> +	do {
> +		litest_wait_for_event(li);
> +		ev = libinput_get_event(li);
> +	} while (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_FRAME);

empty line needed after the while, and this fails make check's valgrind run,
you're not freeing the frame event. please do run make check before sending
out patches.

> +	tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	expected_orientation = 90.0 * input_orientation_2 /
> +				orientation_info->maximum;
> +	touch_major_scale = calc_diameter_scale(x_res,
> +						y_res,
> +						expected_orientation);
> +	expected_major = input_major_2 / touch_major_scale;
> +
> +	ck_assert_double_eq(libinput_event_touch_get_pressure(tev),
> +			    expected_pressure);
> +	ck_assert_double_eq(libinput_event_touch_get_orientation(tev),
> +			    expected_orientation);
> +	ck_assert_double_eq(libinput_event_touch_get_major(tev),
> +			    expected_major);
> +	ck_assert_double_eq(libinput_event_touch_get_minor(tev),
> +			    expected_minor);
> +
> +	libinput_event_destroy(ev);
> +}
> +END_TEST
> +
> +START_TEST(touch_point_no_minor_or_orienation)

typo

> +{
> +	struct litest_device *dev = litest_current_device();
> +	struct libinput *li = dev->libinput;
> +	struct libinput_event *ev;
> +	struct libinput_event_touch *tev;
> +	const int touch_x = 50;
> +	const int touch_y = 90;
> +	const int input_pressure = 43;
> +	const int input_major = 23;
> +	const int input_major_2 = 30;
> +
> +	struct axis_replacement down_values[] = {
> +		{ABS_MT_PRESSURE, input_pressure},
> +		{ABS_MT_TOUCH_MAJOR, input_major},
> +		{-1, -1}};
> +	struct axis_replacement move_values[] = {
> +		{ABS_MT_TOUCH_MAJOR, input_major_2},
> +		{-1, -1}};
> +
> +	const struct input_absinfo *orientation_info;
> +	const struct input_absinfo *pressure_info;
> +	const struct input_absinfo *x_info;
> +	const struct input_absinfo *major_info;
> +	double touch_major_scale;
> +
> +	double expected_major;
> +	double expected_minor;
> +	double expected_orientation = 0.0;
> +	double expected_pressure;
> +
> +	x_info = libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X);
> +	pressure_info = libevdev_get_abs_info(dev->evdev, ABS_MT_PRESSURE);
> +	major_info = libevdev_get_abs_info(dev->evdev, ABS_MT_TOUCH_MAJOR);
> +	orientation_info = libevdev_get_abs_info(dev->evdev,
> +						 ABS_MT_ORIENTATION);
> +
> +	if (orientation_info || !pressure_info || !x_info || !major_info ||

do we have a touch screen that doesn't have x_info?
I had to look through the test devices here to make sure we have something
that actually runs the test - I wonder if there's some litest addition we
can do to make sure a test runs fully at least once. we've had the problem
once or twice in the past where a test returned early and the actual test
bits didn't get triggered by any device in the list.

> +	    !libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_TOUCH_MAJOR) ||
> +	    libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_TOUCH_MINOR))
> +		return;
> +
> +	if (exceeds_range(pressure_info, input_pressure) ||
> +	    exceeds_range(major_info, input_major) ||
> +	    exceeds_range(major_info, input_major_2)) {
> +		fprintf(stderr, "%s does not support the required value ranges",
> +			libinput_device_get_name(dev->libinput_device));

    ck_abort_msg()

> +		return;
> +        }
> +
> +	expected_pressure = (double) input_pressure /
> +			(pressure_info->maximum - pressure_info->minimum);
> +	touch_major_scale = x_info->resolution ? x_info->resolution : 1;
> +	expected_major = input_major / touch_major_scale;
> +	expected_minor = expected_major;
> +
> +	litest_drain_events(li);
> +
> +	litest_touch_down_extended(dev, 0, touch_x, touch_y, down_values);
> +
> +	litest_wait_for_event(li);
> +	ev = libinput_get_event(li);
> +	tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_DOWN);
> +
> +	ck_assert_double_eq(libinput_event_touch_get_orientation(tev),
> +			    expected_orientation);
> +	ck_assert_double_eq(libinput_event_touch_get_pressure(tev),
> +			    expected_pressure);
> +	ck_assert_double_eq(libinput_event_touch_get_major(tev),
> +			    expected_major);
> +	ck_assert_double_eq(libinput_event_touch_get_minor(tev),
> +			    expected_minor);
> +
> +	libinput_event_destroy(ev);
> +
> +	expected_major = input_major_2 / touch_major_scale;
> +	expected_minor = expected_major;
> +
> +	litest_touch_move_extended(dev, 0, touch_x, touch_y, move_values);
> +
> +	do {
> +		litest_wait_for_event(li);
> +		ev = libinput_get_event(li);
> +	} while (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_FRAME);

same as in the other test

Cheers,
   Peter

> +	tev = litest_is_touch_event(ev, LIBINPUT_EVENT_TOUCH_MOTION);
> +
> +	ck_assert_double_eq(libinput_event_touch_get_major(tev),
> +			    expected_major);
> +	ck_assert_double_eq(libinput_event_touch_get_minor(tev),
> +			    expected_minor);
> +
> +	libinput_event_destroy(ev);
> +}
> +END_TEST
> +
>  void
>  litest_setup_tests(void)
>  {
> @@ -697,6 +934,8 @@ litest_setup_tests(void)
>  	litest_add("touch:protocol a", touch_protocol_a_init, LITEST_PROTOCOL_A, LITEST_ANY);
>  	litest_add("touch:protocol a", touch_protocol_a_touch, LITEST_PROTOCOL_A, LITEST_ANY);
>  	litest_add("touch:protocol a", touch_protocol_a_2fg_touch, LITEST_PROTOCOL_A, LITEST_ANY);
> +	litest_add("touch:properties", touch_point_properties, LITEST_TOUCH|LITEST_ELLIPSE, LITEST_ANY);
> +	litest_add("touch:properties", touch_point_no_minor_or_orienation, LITEST_TOUCH|LITEST_ELLIPSE, LITEST_ANY);
>  
>  	litest_add_ranged("touch:state", touch_initial_state, LITEST_TOUCH, LITEST_PROTOCOL_A, &axes);
>  
> -- 
> 2.1.4
> 


More information about the wayland-devel mailing list