[PATCH libinput v9 1/2] libinput: add orientation and size of touch point and pressure to the API
Peter Hutterer
peter.hutterer at who-t.net
Sun Nov 22 20:08:19 PST 2015
On Fri, Nov 13, 2015 at 08:46:43AM +0100, 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 queried at the event using another set of libinput_event_touch_has_*
> functions.
>
> Explanation of those values was added to the touch screen page.
>
> Signed-off-by: Andreas Pokorny <andreas.pokorny at canonical.com>
merged locally, with a couple of minor whitespace changes, thanks.
this will probably find its way into 1.2, once I do a bit more testing on
it.
Cheers,
Peter
> ---
> doc/Makefile.am | 2 +
> doc/page-hierarchy.dox | 1 +
> doc/svg/touchscreen-touch-event-properties.svg | 347 +++++++++++++++++++++++++
> doc/touch-event-properties.dox | 66 +++++
> src/evdev.c | 224 ++++++++++++++--
> src/evdev.h | 24 ++
> src/libinput-private.h | 13 +-
> src/libinput-util.h | 6 +
> src/libinput.c | 212 ++++++++++++++-
> src/libinput.h | 222 ++++++++++++++++
> src/libinput.sym | 13 +
> test/touch.c | 241 +++++++++++++++++
> 12 files changed, 1339 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 fe70f6a..c0b4f73 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 = \
> @@ -50,6 +51,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..aadc87f 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
[...]
> diff --git a/doc/touch-event-properties.dox b/doc/touch-event-properties.dox
> new file mode 100644
> index 0000000..c3fe03a
> --- /dev/null
> +++ b/doc/touch-event-properties.dox
> @@ -0,0 +1,66 @@
> +/**
> + at page touch_event_properties Properties of a touch event
> +
> +This page gives some overview on touchscreen events. libinput requires all
> +supported touchscreen to provide positional information and per-finger
> +tracking. Positional information is provided for the events
> + at ref LIBINPUT_EVENT_TOUCH_DOWN and @ref LIBINPUT_EVENT_TOUCH_MOTION with the
> +functions libinput_event_touch_get_x() and libinput_event_touch_get_y(), as
> +well as libinput_event_touch_get_x_transformed() and
> +libinput_event_touch_get_y_transformed(). See also @ref absolute_axes.
> +
> +Some touchscreen provide additional information, specifically @ref
> +touch_major_minor, @ref touch_orientation, and @ref touch_pressure.
> +
> + at image html touchscreen-touch-event-properties.svg "Properties of a touch screen contact"
> +
> +Note that the events @ref LIBINPUT_EVENT_TOUCH_UP and @ref
> +LIBINPUT_EVENT_TOUCH_CANCEL do not provide any positional information or
> +extended properties.
> +
> + at section touch_major_minor Major and minor axes
> +
> +A finger contact on a touch screen provides an approximately elliptical
> +contact area. The major axis of this ellipse is along the pointing
> +direction of the finger, the minor axis is perpendicular to the major axis.
> +
> +libinput provides both major and minor axes as a physical dimension. See
> +- libinput_event_touch_get_major()
> +- libinput_event_touch_get_minor()
> +- libinput_event_touch_get_major_transformed()
> +- libinput_event_touch_get_minor_transformed()
> +
> +Note that the granularity of the ellipse is device-specific and usually
> +less accurate than the positional information.
> +
> +Not all touch screens support touch ellipse detection. Where unavailable,
> +libinput returns zero as value for the major and minor axes. Where only
> +a major axis is available, libinput assumes a circular contact, the minor
> +axis is then always equivalent to the major axis.
> +Use libinput_event_touch_has_major() and libinput_event_touch_has_minor()
> +to determine if the values are available.
> +
> + at section touch_orientation Touch point orientation
> +
> +The orientation of a touch is the angle (clockwise) between the major
> +axis and the y-axis of the touchscreen. The granularity of the orientation
> +value is device-specific, some devices may only detect alignment of the
> +ellipse with the y or x axis (i.e. 0 or 90 degrees rotation).
> +
> +Use libinput_event_touch_has_orientation() to determine if the value is
> +available and libinput_event_touch_get_orientation() to get the value. If
> +the device does not support orientation, the orientation is always 0.
> +
> + at section touch_pressure Touch point pressure
> +
> +The pressure of a touch is the force applied to each contact point. Note
> +that as touch pressure increases, the finger flattens and the contact
> +surface area usually increases as well.
> +
> +Use libinput_event_touch_get_pressure() to get the pressure value. This
> +value is normalized to the range [0.0, 1.0]. Use
> +libinput_event_touch_has_pressure() to determine if the value is available.
> +A device that does not support pressure always returns a pressure value of
> +1.0.
> +
> +*/
> diff --git a/src/evdev.c b/src/evdev.c
> index ec3abc6..ea6be05 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.0
> +#define DEFAULT_TOUCH_ORIENTATION 0.0
> +#define DEFAULT_TOUCH_MAJOR 0.0
> +#define DEFAULT_TOUCH_MINOR 0.0
>
> 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 / hypotf(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:
> @@ -324,7 +429,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",
> @@ -333,38 +438,50 @@ 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->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->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;
> @@ -396,7 +513,13 @@ 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,
> + &default_touch,
> + DEFAULT_TOUCH_PRESSURE);
> break;
> case EVDEV_ABSOLUTE_MOTION:
> point = device->abs.point;
> @@ -408,8 +531,13 @@ 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,
> + &default_touch,
> + DEFAULT_TOUCH_PRESSURE);
> } else if (device->seat_caps & EVDEV_DEVICE_POINTER) {
> pointer_notify_motion_absolute(base, time, &point);
> }
> @@ -569,8 +697,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",
> @@ -581,8 +710,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);
> @@ -590,17 +718,34 @@ 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->area.major = e->value;
> + break;
> + case ABS_MT_TOUCH_MINOR:
> + current_slot->area.minor = e->value;
> + break;
> + case ABS_MT_ORIENTATION:
> + current_slot->area.orientation = e->value;
> + break;
> + case ABS_MT_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;
> }
> }
>
> @@ -1954,6 +2099,20 @@ evdev_configure_mt_device(struct evdev_device *device)
> slots[slot].point.y = libevdev_get_slot_value(evdev,
> slot,
> ABS_MT_POSITION_Y);
> + slots[slot].area.major =
> + libevdev_get_slot_value(evdev,
> + slot,
> + ABS_MT_TOUCH_MAJOR);
> + slots[slot].area.minor =
> + libevdev_get_slot_value(evdev,
> + slot,
> + ABS_MT_TOUCH_MINOR);
> + slots[slot].area.orientation =
> + libevdev_get_slot_value(evdev,
> + slot,
> + ABS_MT_ORIENTATION);
> + slots[slot].pressure =
> + libevdev_get_slot_value(evdev, slot, ABS_MT_PRESSURE);
> }
> device->mt.slots = slots;
> device->mt.slots_len = num_slots;
> @@ -2024,6 +2183,15 @@ 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);
> + device->abs.absinfo_major =
> + libevdev_get_abs_info(evdev, ABS_MT_TOUCH_MAJOR);
> + device->abs.absinfo_minor =
> + libevdev_get_abs_info(evdev, ABS_MT_TOUCH_MINOR);
> +
> if (!evdev_is_fake_mt_device(device))
> evdev_fix_android_mt(device);
>
> diff --git a/src/evdev.h b/src/evdev.h
> index e44a65d..7b8d0e6 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -112,6 +112,8 @@ enum evdev_device_model {
> struct mt_slot {
> int32_t seat_slot;
> struct device_coords point;
> + struct ellipse area;
> + int32_t pressure;
> };
>
> struct evdev_device {
> @@ -128,6 +130,8 @@ struct evdev_device {
> int fd;
> struct {
> const struct input_absinfo *absinfo_x, *absinfo_y;
> + const struct input_absinfo *absinfo_major, *absinfo_minor,
> + *absinfo_pressure, *absinfo_orientation;
split that up into a
const struct absinfo *blah,
*blah,
*blah,
...
> int fake_resolution;
>
> struct device_coords point;
> @@ -349,6 +353,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 e146c26..b90c21d 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.
> @@ -396,14 +401,18 @@ 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,
> + 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,
> + 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 24f2b69..bdd3d41 100644
> --- a/src/libinput.c
> +++ b/src/libinput.c
> @@ -112,6 +112,8 @@ struct libinput_event_touch {
> int32_t slot;
> int32_t seat_slot;
> struct device_coords point;
> + struct ellipse area;
> + int32_t pressure;
> };
>
> struct libinput_event_gesture {
> @@ -732,6 +734,204 @@ 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)
> +{
> + 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 device->abs.absinfo_major != 0;
> +}
> +
> +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 (device->abs.absinfo_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)
> +{
> + 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 device->abs.absinfo_minor != 0;
> +}
> +
> +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)
> +{
> + 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 device->abs.absinfo_orientation != 0;
> +}
> +
> +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)
> +{
> + 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 device->abs.absinfo_pressure != 0;
> +}
> +
> LIBINPUT_EXPORT uint32_t
> libinput_event_gesture_get_time(struct libinput_event_gesture *event)
> {
> @@ -1512,7 +1712,9 @@ 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,
> + const struct ellipse *area,
> + int32_t pressure)
> {
> struct libinput_event_touch *touch_event;
>
> @@ -1528,6 +1730,8 @@ touch_notify_touch_down(struct libinput_device *device,
> .slot = slot,
> .seat_slot = seat_slot,
> .point = *point,
> + .area = *area,
> + .pressure = pressure,
> };
>
> post_device_event(device, time,
> @@ -1540,7 +1744,9 @@ 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,
> + const struct ellipse *area,
> + int32_t pressure)
> {
> struct libinput_event_touch *touch_event;
>
> @@ -1556,6 +1762,8 @@ touch_notify_touch_motion(struct libinput_device *device,
> .slot = slot,
> .seat_slot = seat_slot,
> .point = *point,
> + .area = *area,
> + .pressure = pressure,
> };
>
> post_device_event(device, time,
> diff --git a/src/libinput.h b/src/libinput.h
> index 9057446..d349c1d 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 whether 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 Non-zero when a major diameter is available
> + */
> +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 whether 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 Non-zero when 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 whether 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 Non-zero when 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 whether 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 Non-zero when an 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 15203c8..23d7975 100644
> --- a/src/libinput.sym
> +++ b/src/libinput.sym
> @@ -179,3 +179,16 @@ LIBINPUT_1.1 {
> libinput_device_config_accel_get_default_profile;
> libinput_device_config_accel_set_profile;
> } LIBINPUT_0.21.0;
> +
> +LIBINPUT_1.1_unreleased {
> + 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_1.1;
> diff --git a/test/touch.c b/test/touch.c
> index eae8007..ab30914 100644
> --- a/test/touch.c
> +++ b/test/touch.c
> @@ -673,6 +673,245 @@ START_TEST(touch_time_usec)
> }
> END_TEST
>
> +static inline double calc_diameter_scale(double x_res,
> + double y_res,
> + double orientation)
newline before function names, i.e.
static inline double
calc_...
> +{
> + double orientation_rad = deg2rad(orientation);
> + if (x_res == y_res)
> + return x_res;
> +
> + return hypotf(y_res * fabs(cos(orientation_rad)),
> + x_res * fabs(sin(orientation_rad)));
> +}
> +
> +static inline bool exceeds_range(const struct input_absinfo *info,
> + int value)
same here
> +{
> + 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\n",
> + libinput_device_get_name(dev->libinput_device));
> + 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);
> +
> + litest_touch_move_extended(dev, 0, touch_x, touch_y, move_values);
> +
> + do {
> + libinput_event_destroy(ev);
> + litest_wait_for_event(li);
> + ev = libinput_get_event(li);
> + } while (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_FRAME);
> +
> + 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_orientation)
> +{
> + 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 ||
> + !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\n",
> + libinput_device_get_name(dev->libinput_device));
> + 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);
> +
> + 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 {
> + libinput_event_destroy(ev);
> + litest_wait_for_event(li);
> + ev = libinput_get_event(li);
> + } while (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_FRAME);
> +
> + 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 +936,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_orientation, LITEST_TOUCH|LITEST_ELLIPSE, LITEST_ANY);
>
> litest_add_ranged("touch:state", touch_initial_state, LITEST_TOUCH, LITEST_PROTOCOL_A, &axes);
>
> --
> 2.5.0
>
More information about the wayland-devel
mailing list