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
Those values are optionally supported by multi-touch drivers, so zero as a default value is used if the information is missing. This change also correctly bumps the ABI version to 0.20.0 and adds the new libinput symbols there. Signed-off-by: Andreas Pokorny <[email protected]> --- src/evdev.c | 192 +++++++++++++++++++++++++++++++++++++++++------- src/evdev.h | 24 ++++++ src/libinput-private.h | 10 ++- src/libinput.c | 137 +++++++++++++++++++++++++++++++++- src/libinput.h | 194 +++++++++++++++++++++++++++++++++++++++++++++++++ src/libinput.sym | 10 +++ test/touch.c | 162 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 697 insertions(+), 32 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index 346f11a..1dbfc61 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 200 +#define DEFAULT_TOUCH_PRESSURE 0 +#define DEFAULT_TOUCH_ORIENTATION 0 +#define DEFAULT_TOUCH_MAJOR 0 +#define DEFAULT_TOUCH_MINOR 0 enum evdev_key_type { EVDEV_KEY_TYPE_NONE, @@ -87,6 +91,12 @@ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = { { 0 }, }; +static inline double +deg2rad(double angle) +{ + return angle * M_PI/180.0; +} + static void hw_set_key_down(struct evdev_device *device, int code, int pressed) { @@ -245,6 +255,80 @@ evdev_device_transform_y(struct evdev_device *device, return scale_axis(device->abs.absinfo_y, y, height); } +double +evdev_device_transform_touch_point_to_mm(struct evdev_device *device, + int32_t axis_value, + 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 axis_value / x_res; + + if (device->abs.absinfo_orientation == NULL) + return axis_value * 2.0 / (x_res + y_res); + + return axis_value / (y_res*fabs(cos(deg2rad(axis_angle))) + + x_res*fabs(sin(deg2rad(axis_angle)))); +} + +double +evdev_device_transform_touch_point(struct evdev_device *device, + int32_t axis_value, + 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 axis_value * x_scale; + + if (device->abs.absinfo_orientation == NULL) + return axis_value * (x_scale + y_scale) / 2.0; + + return axis_value * (y_scale*fabs(cos(deg2rad(axis_angle))) + + x_scale*fabs(sin(deg2rad(axis_angle)))); +} + +double +evdev_device_transform_orientation(struct evdev_device *device, + int32_t orientation) +{ + const struct input_absinfo *orientation_info = + device->abs.absinfo_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) + return (90.0 * orientation) / orientation_info->maximum; + else + return DEFAULT_TOUCH_ORIENTATION; +} + +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 (double)(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 +366,14 @@ 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 device_coords default_touch = { + .x = DEFAULT_TOUCH_MAJOR, + .y = DEFAULT_TOUCH_MINOR + }; slot = device->mt.slot; + slot_data = &device->mt.slots[slot]; switch (device->pending_event) { case EVDEV_NONE: @@ -314,7 +404,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 +413,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->touch_point, + slot_data->orientation, + 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->touch_point, + slot_data->orientation, + 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 +490,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, + &default_touch, + DEFAULT_TOUCH_ORIENTATION, + DEFAULT_TOUCH_PRESSURE); break; case EVDEV_ABSOLUTE_MOTION: point = device->abs.point; @@ -398,8 +509,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, + &default_touch, + DEFAULT_TOUCH_ORIENTATION, + DEFAULT_TOUCH_PRESSURE); } else if (device->seat_caps & EVDEV_DEVICE_POINTER) { pointer_notify_motion_absolute(base, time, &point); } @@ -559,8 +676,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 %d)\n", @@ -571,8 +689,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 +697,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->touch_point.x = e->value; + break; + case ABS_MT_TOUCH_MINOR: + current_slot->touch_point.y = e->value; + break; + case ABS_MT_ORIENTATION: + current_slot->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; } } @@ -1921,6 +2055,8 @@ 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 (udev_tags & EVDEV_UDEV_TAG_TOUCHPAD) { device->dispatch = evdev_mt_touchpad_create(device); diff --git a/src/evdev.h b/src/evdev.h index aa548d2..746a3df 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -109,6 +109,9 @@ enum evdev_device_model { struct mt_slot { int32_t seat_slot; struct device_coords point; + struct device_coords touch_point; + int32_t orientation; + int32_t pressure; }; struct evdev_device { @@ -125,6 +128,7 @@ 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; @@ -344,6 +348,26 @@ double evdev_device_transform_y(struct evdev_device *device, double y, uint32_t height); +double +evdev_device_transform_touch_point_to_mm(struct evdev_device *device, + int32_t axis_value, + double axis_angle); + +double +evdev_device_transform_touch_point(struct evdev_device *device, + int32_t axis_value, + 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 d11f000..d960a82 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -350,14 +350,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, + const struct device_coords *touch_point, + int32_t orientation, + 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 device_coords *touch_point, + int32_t orientation, + int32_t pressure); void touch_notify_touch_up(struct libinput_device *device, diff --git a/src/libinput.c b/src/libinput.c index d164604..32ed817 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; + struct device_coords touch_point; + int32_t orientation; + int32_t pressure; }; static void @@ -637,6 +640,124 @@ 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 = evdev_device_transform_orientation(device, + event->orientation); + + 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_touch_point_to_mm(device, + event->touch_point.x, + 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 = evdev_device_transform_orientation(device, + event->orientation); + + 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_touch_point(device, + event->touch_point.x, + angle, + width, + height); +} + +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 = evdev_device_transform_orientation(device, + event->orientation); + + 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_touch_point_to_mm(device, + event->touch_point.y, + 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 = + evdev_device_transform_orientation(device, + event->orientation); + + 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_touch_point(device, + event->touch_point.y, + angle + 90.0, + width, + height); +} + +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->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); +} + struct libinput_source * libinput_add_fd(struct libinput *libinput, int fd, @@ -1243,7 +1364,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, + const struct device_coords *touch_point, + int32_t orientation, + int32_t pressure) { struct libinput_event_touch *touch_event; @@ -1259,6 +1383,9 @@ touch_notify_touch_down(struct libinput_device *device, .slot = slot, .seat_slot = seat_slot, .point = *point, + .touch_point = *touch_point, + .orientation = orientation, + .pressure = pressure, }; post_device_event(device, time, @@ -1271,7 +1398,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, + const struct device_coords *touch_point, + int32_t orientation, + int32_t pressure) { struct libinput_event_touch *touch_event; @@ -1287,6 +1417,9 @@ touch_notify_touch_motion(struct libinput_device *device, .slot = slot, .seat_slot = seat_slot, .point = *point, + .touch_point = *touch_point, + .orientation = orientation, + .pressure = pressure, }; post_device_event(device, time, diff --git a/src/libinput.h b/src/libinput.h index 5df7183..c705398 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -919,6 +919,200 @@ libinput_event_touch_get_y_transformed(struct libinput_event_touch *event, /** * @ingroup event_touch * + * @verbatim + * screen space + * major + * _______/\________ + * / \ + * +++++++ + * +++ +++ + * ++ ++ + * + touch + + * + ellipse + ---> finger pointing direction + * ++ ++ + * +++ +++ + * +++++++ + * @endverbatim + * + * 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 + * + * 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 + * @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref LIBINPUT_EVENT_TOUCH_MOTION. + * + * @param event The libinput touch event + * @return The current touch major value + */ +double +libinput_event_touch_get_major(struct libinput_event_touch *event); + +/** + * @ingroup event_touch + * + * @verbatim + * screen space + * major + * _______/\________ + * / \ + * +++++++ + * +++ +++ + * ++ ++ + * + touch + + * + ellipse + ---> finger pointing direction + * ++ ++ + * +++ +++ + * +++++++ + * @endverbatim + * + * 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. + * + * 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 + * @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 touch major value + */ +double +libinput_event_touch_get_major_transformed(struct libinput_event_touch *event, + uint32_t width, + uint32_t height); + +/** + * @ingroup event_touch + * + * @verbatim + * screen space + * + * +++++++ - + * +++ +++ \ + * ++ ++ | + * + touch + =- minor + * + ellipse + | ---> finger pointing direction + * ++ ++ | + * +++ +++ / + * +++++++ - + * + * @endverbatim + * + * 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. + * + * 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 + * @ref LIBINPUT_EVENT_TOUCH_DOWN or @ref LIBINPUT_EVENT_TOUCH_MOTION. + * + * @param event The libinput touch event + * @return The current touch minor value + */ +double +libinput_event_touch_get_minor(struct libinput_event_touch *event); + +/** + * @ingroup event_touch + * + * @verbatim + * screen space + * + * +++++++ - + * +++ +++ \ + * ++ ++ | + * + touch + =- minor + * + ellipse + | ---> finger pointing direction + * ++ ++ | + * +++ +++ / + * +++++++ - + * + * @endverbatim + * + * 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. + * + * 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 + * @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 touch minor value + */ +double +libinput_event_touch_get_minor_transformed(struct libinput_event_touch *event, + uint32_t width, + uint32_t height); + +/** + * @ingroup event_touch + * + * Return the current pressure value touch point normalized to the range + * [0,1]. If this value is not provided by the device, it is always 0.0. + * + * 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 + * @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 + * @verbatim + * + * major ∧ y + * axis \ | + * \++ | + * + \ ++ + * + \ |+ + * + \| + + * + 0--+---------------> x + * + + + * ++ + + * +++ + * + * @endverbatim + * + * Return the major axis rotation in degrees, clock wise from the logical north + * of the touch screen. In the example drawn above the value would be 315". + * This orientation might not be measured by the device, or only measured + * in coarse steps (e.g only indicating alignment with either of the axes). + * + * 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 + * @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 The generic libinput_event of this event */ struct libinput_event * diff --git a/src/libinput.sym b/src/libinput.sym index 773a7a4..60e4ebd 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -147,3 +147,13 @@ global: libinput_device_config_tap_get_drag_lock_enabled; libinput_device_config_tap_get_default_drag_lock_enabled; } LIBINPUT_0.15.0; + +LIBINPUT_0.20.0 { +global: + libinput_event_touch_get_minor; + libinput_event_touch_get_major; + libinput_event_touch_get_minor_transformed; + libinput_event_touch_get_major_transformed; + libinput_event_touch_get_orientation; + libinput_event_touch_get_pressure; +} LIBINPUT_0.19.0; diff --git a/test/touch.c b/test/touch.c index b519613..1e47289 100644 --- a/test/touch.c +++ b/test/touch.c @@ -33,6 +33,13 @@ #include "libinput-util.h" #include "litest.h" +static inline void +fix_resolution(struct input_absinfo *info) +{ + if (info->resolution == 0) + info->resolution = 1; +} + START_TEST(touch_frame_events) { struct litest_device *dev = litest_current_device(); @@ -652,6 +659,157 @@ START_TEST(touch_initial_state) } END_TEST +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; + struct axis_replacement down_values[] = { + {ABS_MT_PRESSURE, 128}, + {ABS_MT_ORIENTATION, 64}, + {ABS_MT_TOUCH_MAJOR, 14}, + {ABS_MT_TOUCH_MINOR, 8}}; + struct axis_replacement move_values[] = { + {ABS_MT_ORIENTATION, 128}, + {ABS_MT_TOUCH_MAJOR, 30}}; + struct input_absinfo const *orientation_info = + libevdev_get_abs_info(dev->evdev, ABS_MT_ORIENTATION); + struct input_absinfo const *pressure_info = + libevdev_get_abs_info(dev->evdev, ABS_MT_PRESSURE); + struct input_absinfo const *x_info = + libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X); + struct input_absinfo const *y_info = + libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_Y); + double x_res, y_res, touch_minor_scale, touch_major_scale; + double expected_orientation; + + if (!orientation_info || !pressure_info || !x_info || !y_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; + + fix_resolution(x_info); + fix_resolution(y_info); + + expected_orientation = 90.0*64.0/orientation_info->maximum; + x_res = x_info->resolution; + y_res = y_info->resolution; + + touch_major_scale = (x_res == y_res) + ? x_res + : (y_res*fabs(cos(M_PI * expected_orientation / 180.0)) + + x_res*fabs(sin(M_PI * expected_orientation / 180.0))); + touch_minor_scale = (x_res == y_res) + ? x_res + : (y_res*fabs(sin(M_PI * expected_orientation / 180.0)) + + x_res*fabs(cos(M_PI * expected_orientation / 180.0))); + + litest_drain_events(li); + + litest_touch_down_extended(dev, 0, 5, 95, down_values); + + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1); + + ev = libinput_get_event(li); + tev = litest_is_touch_event(ev, 0); + + ck_assert_double_eq(libinput_event_touch_get_pressure(tev), 128.0/ + (pressure_info->maximum - pressure_info->minimum)); + ck_assert_double_eq(libinput_event_touch_get_orientation(tev), + expected_orientation); + ck_assert_double_eq(libinput_event_touch_get_major(tev), 14.0/touch_major_scale); + ck_assert_double_eq(libinput_event_touch_get_minor(tev), 8.0/touch_minor_scale); + + libinput_event_destroy(ev); + + litest_touch_move_extended(dev, 0, 5, 95, move_values); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1); + + + expected_orientation = 90.0*128.0/orientation_info->maximum; + touch_major_scale = (x_res == y_res) + ? x_res + : (y_res*fabs(cos(M_PI * expected_orientation / 180.0)) + + x_res*fabs(sin(M_PI * expected_orientation / 180.0))); + touch_minor_scale = (x_res == y_res) + ? x_res + : (y_res*fabs(sin(M_PI * expected_orientation / 180.0)) + + x_res*fabs(cos(M_PI * expected_orientation / 180.0))); + + ev = libinput_get_event(li); + tev = litest_is_touch_event(ev, 0); + + ck_assert_double_eq(libinput_event_touch_get_pressure(tev), 128.0/ + (pressure_info->maximum - pressure_info->minimum)); + ck_assert_double_eq(libinput_event_touch_get_orientation(tev), + expected_orientation); + ck_assert_double_eq(libinput_event_touch_get_major(tev), 30.0/touch_major_scale); + ck_assert_double_eq(libinput_event_touch_get_minor(tev), 8.0/touch_minor_scale); + + libinput_event_destroy(ev); +} +END_TEST + +START_TEST(touch_point_no_minor_or_orienation) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *ev; + struct libinput_event_touch *tev; + struct axis_replacement down_values[] = { + {ABS_MT_PRESSURE, 43}, + {ABS_MT_TOUCH_MAJOR, 23}}; + struct axis_replacement move_values[] = { + {ABS_MT_TOUCH_MAJOR, 30}}; + + struct input_absinfo const *orientation_info = + libevdev_get_abs_info(dev->evdev, ABS_MT_ORIENTATION); + struct input_absinfo const *pressure_info = + libevdev_get_abs_info(dev->evdev, ABS_MT_PRESSURE); + struct input_absinfo const *x_info = + libevdev_get_abs_info(dev->evdev, ABS_MT_POSITION_X); + double x_res; + + if (orientation_info || !pressure_info || !x_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; + + fix_resolution(x_info); + + x_res = x_info->resolution; + + litest_drain_events(li); + + litest_touch_down_extended(dev, 0, 5, 95, down_values); + + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1); + + ev = libinput_get_event(li); + tev = litest_is_touch_event(ev, 0); + + ck_assert_double_eq(libinput_event_touch_get_orientation(tev), 0.0); + ck_assert_double_eq(libinput_event_touch_get_pressure(tev), 43.0 / + (pressure_info->maximum - pressure_info->minimum)); + ck_assert_double_eq(libinput_event_touch_get_major(tev), 23.0/x_res); + ck_assert_double_eq(libinput_event_touch_get_minor(tev), 0.0); + + libinput_event_destroy(ev); + + litest_touch_move_extended(dev, 0, 5, 95, move_values); + litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1); + + ev = libinput_get_event(li); + tev = litest_is_touch_event(ev, 0); + + ck_assert_double_eq(libinput_event_touch_get_major(tev), 30.0/x_res); + ck_assert_double_eq(libinput_event_touch_get_minor(tev), 0.0); + + libinput_event_destroy(ev); +} +END_TEST + void litest_setup_tests(void) { @@ -676,6 +834,10 @@ 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:propertiees", 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 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
