From 92a67a3a9425fec1fb6a388de65eb91f537df462 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 18 Jun 2014 14:22:24 +0200 Subject: [PATCH 1/5] touchpad: tp_current_touch: Fix off by one error Signed-off-by: Hans de Goede Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- src/evdev-mt-touchpad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 0294eb2b..92e0651a 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -139,7 +139,7 @@ tp_motion_history_reset(struct tp_touch *t) static inline struct tp_touch * tp_current_touch(struct tp_dispatch *tp) { - return &tp->touches[min(tp->slot, tp->ntouches)]; + return &tp->touches[min(tp->slot, tp->ntouches - 1)]; } static inline struct tp_touch * From df212db2a3335466648496d34d1ece4b2bdd1c5d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 19 Jun 2014 11:11:36 +1000 Subject: [PATCH 2/5] evdev: keep the absinfo struct around instead of min/max We'll need that later for conversion to mm. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev-mt-touchpad-buttons.c | 20 +++++++++++++------- src/evdev-mt-touchpad.c | 6 ++++-- src/evdev.c | 25 +++++++++++++------------ src/evdev.h | 2 +- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c index ce48ed0b..45d5d703 100644 --- a/src/evdev-mt-touchpad-buttons.c +++ b/src/evdev-mt-touchpad-buttons.c @@ -565,6 +565,7 @@ tp_init_buttons(struct tp_dispatch *tp, struct tp_touch *t; int width, height; double diagonal; + const struct input_absinfo *absinfo_x, *absinfo_y; tp->buttons.is_clickpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD); @@ -580,8 +581,11 @@ tp_init_buttons(struct tp_dispatch *tp, log_bug_kernel("non clickpad without right button?\n"); } - width = abs(device->abs.max_x - device->abs.min_x); - height = abs(device->abs.max_y - device->abs.min_y); + absinfo_x = device->abs.absinfo_x; + absinfo_y = device->abs.absinfo_y; + + width = abs(absinfo_x->maximum - absinfo_x->minimum); + height = abs(absinfo_y->maximum - absinfo_y->minimum); diagonal = sqrt(width*width + height*height); tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD; @@ -590,13 +594,15 @@ tp_init_buttons(struct tp_dispatch *tp, tp->buttons.use_clickfinger = true; if (tp->buttons.is_clickpad && !tp->buttons.use_clickfinger) { - tp->buttons.bottom_area.top_edge = height * .8 + device->abs.min_y; - tp->buttons.bottom_area.rightbutton_left_edge = width/2 + device->abs.min_x; + int xoffset = absinfo_x->minimum, + yoffset = absinfo_y->minimum; + tp->buttons.bottom_area.top_edge = height * .8 + yoffset; + tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset; if (tp->buttons.has_topbuttons) { - tp->buttons.top_area.bottom_edge = height * .08 + device->abs.min_y; - tp->buttons.top_area.rightbutton_left_edge = width * .58 + device->abs.min_x; - tp->buttons.top_area.leftbutton_right_edge = width * .42 + device->abs.min_x; + tp->buttons.top_area.bottom_edge = height * .08 + yoffset; + tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset; + tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset; } else { tp->buttons.top_area.bottom_edge = INT_MIN; } diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c index 92e0651a..787afa4c 100644 --- a/src/evdev-mt-touchpad.c +++ b/src/evdev-mt-touchpad.c @@ -750,8 +750,10 @@ tp_init(struct tp_dispatch *tp, if (tp_init_slots(tp, device) != 0) return -1; - width = abs(device->abs.max_x - device->abs.min_x); - height = abs(device->abs.max_y - device->abs.min_y); + width = abs(device->abs.absinfo_x->maximum - + device->abs.absinfo_x->minimum); + height = abs(device->abs.absinfo_y->maximum - + device->abs.absinfo_y->minimum); diagonal = sqrt(width*width + height*height); tp->hysteresis.margin_x = diff --git a/src/evdev.c b/src/evdev.c index 51ad5e31..907d18e5 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -89,13 +89,19 @@ transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y) } } +static inline double +scale_axis(const struct input_absinfo *absinfo, double val, double to_range) +{ + return (val - absinfo->minimum) * to_range / + (absinfo->maximum - absinfo->minimum + 1); +} + double evdev_device_transform_x(struct evdev_device *device, double x, uint32_t width) { - return (x - device->abs.min_x) * width / - (device->abs.max_x - device->abs.min_x + 1); + return scale_axis(device->abs.absinfo_x, x, width); } double @@ -103,8 +109,7 @@ evdev_device_transform_y(struct evdev_device *device, double y, uint32_t height) { - return (y - device->abs.min_y) * height / - (device->abs.max_y - device->abs.min_y + 1); + return scale_axis(device->abs.absinfo_y, y, height); } static void @@ -606,13 +611,11 @@ evdev_configure_device(struct evdev_device *device) if (libevdev_has_event_type(evdev, EV_ABS)) { if ((absinfo = libevdev_get_abs_info(evdev, ABS_X))) { - device->abs.min_x = absinfo->minimum; - device->abs.max_x = absinfo->maximum; + device->abs.absinfo_x = absinfo; has_abs = 1; } if ((absinfo = libevdev_get_abs_info(evdev, ABS_Y))) { - device->abs.min_y = absinfo->minimum; - device->abs.max_y = absinfo->maximum; + device->abs.absinfo_y = absinfo; has_abs = 1; } /* We only handle the slotted Protocol B in weston. @@ -621,11 +624,9 @@ evdev_configure_device(struct evdev_device *device) if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) && libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y)) { absinfo = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X); - device->abs.min_x = absinfo->minimum; - device->abs.max_x = absinfo->maximum; + device->abs.absinfo_x = absinfo; absinfo = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y); - device->abs.min_y = absinfo->minimum; - device->abs.max_y = absinfo->maximum; + device->abs.absinfo_y = absinfo; device->is_mt = 1; has_touch = 1; has_mt = 1; diff --git a/src/evdev.h b/src/evdev.h index d057010b..03b67429 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -66,7 +66,7 @@ struct evdev_device { const char *devname; int fd; struct { - int min_x, max_x, min_y, max_y; + const struct input_absinfo *absinfo_x, *absinfo_y; int32_t x, y; int32_t seat_slot; From 3a812385d1c21747508ca51634a48ebf2970b84c Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 19 Jun 2014 11:17:10 +1000 Subject: [PATCH 3/5] evdev: force a resolution of 1 where no resolution is set Avoids nasty surprises later when we divide by 0. This matters particularly when testing a device through uinput, which can't set the resolution. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/evdev.c b/src/evdev.c index 907d18e5..2b2725cf 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -593,6 +593,7 @@ evdev_configure_device(struct evdev_device *device) { struct libevdev *evdev = device->evdev; const struct input_absinfo *absinfo; + struct input_absinfo fixed; int has_abs, has_rel, has_mt; int has_button, has_keyboard, has_touch; struct mt_slot *slots; @@ -611,10 +612,20 @@ evdev_configure_device(struct evdev_device *device) if (libevdev_has_event_type(evdev, EV_ABS)) { if ((absinfo = libevdev_get_abs_info(evdev, ABS_X))) { + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, ABS_X, &fixed); + } device->abs.absinfo_x = absinfo; has_abs = 1; } if ((absinfo = libevdev_get_abs_info(evdev, ABS_Y))) { + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, ABS_Y, &fixed); + } device->abs.absinfo_y = absinfo; has_abs = 1; } @@ -624,8 +635,22 @@ evdev_configure_device(struct evdev_device *device) if (libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X) && libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y)) { absinfo = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X); + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, + ABS_MT_POSITION_X, + &fixed); + } device->abs.absinfo_x = absinfo; absinfo = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y); + if (absinfo->resolution == 0) { + fixed = *absinfo; + fixed.resolution = 1; + libevdev_set_abs_info(evdev, + ABS_MT_POSITION_Y, + &fixed); + } device->abs.absinfo_y = absinfo; device->is_mt = 1; has_touch = 1; From 21cf84a5801dc63932857574b81e5e79db10aed1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 19 Jun 2014 11:30:21 +1000 Subject: [PATCH 4/5] Change absolute and touch events to use mm as default unit Instead of device-specific coordinates that the caller can't interpret without knowing the range anyway, return mm as the default value. Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev.h | 7 +++++++ src/libinput.c | 20 ++++++++++++++++---- src/libinput.h | 32 ++++++++++++-------------------- tools/event-debug.c | 7 +++++-- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/evdev.h b/src/evdev.h index 03b67429..eebfab19 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -164,4 +164,11 @@ evdev_device_remove(struct evdev_device *device); void evdev_device_destroy(struct evdev_device *device); +static inline double +evdev_convert_to_mm(const struct input_absinfo *absinfo, double v) +{ + double value = v - absinfo->minimum; + return value/absinfo->resolution; +} + #endif /* EVDEV_H */ diff --git a/src/libinput.c b/src/libinput.c index 5b10a10a..f384f439 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -319,13 +319,19 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event) LIBINPUT_EXPORT double libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event) { - return event->x; + struct evdev_device *device = + (struct evdev_device *) event->base.device; + + return evdev_convert_to_mm(device->abs.absinfo_x, event->x); } LIBINPUT_EXPORT double libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event) { - return event->y; + struct evdev_device *device = + (struct evdev_device *) event->base.device; + + return evdev_convert_to_mm(device->abs.absinfo_y, event->y); } LIBINPUT_EXPORT double @@ -402,7 +408,10 @@ libinput_event_touch_get_seat_slot(struct libinput_event_touch *event) LIBINPUT_EXPORT double libinput_event_touch_get_x(struct libinput_event_touch *event) { - return event->x; + struct evdev_device *device = + (struct evdev_device *) event->base.device; + + return evdev_convert_to_mm(device->abs.absinfo_x, event->x); } LIBINPUT_EXPORT double @@ -428,7 +437,10 @@ libinput_event_touch_get_y_transformed(struct libinput_event_touch *event, LIBINPUT_EXPORT double libinput_event_touch_get_y(struct libinput_event_touch *event) { - return event->y; + struct evdev_device *device = + (struct evdev_device *) event->base.device; + + return evdev_convert_to_mm(device->abs.absinfo_y, event->y); } struct libinput_source * diff --git a/src/libinput.h b/src/libinput.h index 54c96e58..c19460b0 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -452,11 +452,9 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event); /** * @ingroup event_pointer * - * Return the current absolute x coordinate of the pointer event. - * - * The coordinate is in a device specific coordinate space; to get the - * corresponding output screen coordinate, use - * libinput_event_pointer_get_x_transformed(). + * Return the current absolute x coordinate of the pointer event, in mm from + * the top left corner of the device. To get the corresponding output screen + * coordinate, use libinput_event_pointer_get_x_transformed(). * * For pointer events that are not of type * LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, this function returns 0. @@ -472,11 +470,9 @@ libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event); /** * @ingroup event_pointer * - * Return the current absolute y coordinate of the pointer event. - * - * The coordinate is in a device specific coordinate space; to get the - * corresponding output screen coordinate, use - * libinput_event_pointer_get_y_transformed(). + * Return the current absolute y coordinate of the pointer event, in mm from + * the top left corner of the device. To get the corresponding output screen + * coordinate, use libinput_event_pointer_get_x_transformed(). * * For pointer events that are not of type * LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, this function returns 0. @@ -677,11 +673,9 @@ libinput_event_touch_get_seat_slot(struct libinput_event_touch *event); /** * @ingroup event_touch * - * Return the current absolute x coordinate of the touch event. - * - * The coordinate is in a device specific coordinate space; to get the - * corresponding output screen coordinate, use - * libinput_event_touch_get_x_transformed(). + * Return the current absolute x coordinate of the touch event, in mm from + * the top left corner of the device. To get the corresponding output screen + * coordinate, use libinput_event_touch_get_x_transformed(). * * @note this function should only be called for LIBINPUT_EVENT_TOUCH_DOWN and * LIBINPUT_EVENT_TOUCH_MOTION. @@ -695,11 +689,9 @@ libinput_event_touch_get_x(struct libinput_event_touch *event); /** * @ingroup event_touch * - * Return the current absolute y coordinate of the touch event. - * - * The coordinate is in a device specific coordinate space; to get the - * corresponding output screen coordinate, use - * libinput_event_touch_get_y_transformed(). + * Return the current absolute y coordinate of the touch event, in mm from + * the top left corner of the device. To get the corresponding output screen + * coordinate, use libinput_event_touch_get_y_transformed(). * * For LIBINPUT_EVENT_TOUCH_UP 0 is returned. * diff --git a/tools/event-debug.c b/tools/event-debug.c index 864f77ed..ffb45249 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -329,13 +329,16 @@ print_touch_event_with_coords(struct libinput_event *ev) struct libinput_event_touch *t = libinput_event_get_touch_event(ev); double x = libinput_event_touch_get_x_transformed(t, screen_width); double y = libinput_event_touch_get_y_transformed(t, screen_height); + double xmm = libinput_event_touch_get_x(t); + double ymm = libinput_event_touch_get_y(t); print_event_time(libinput_event_touch_get_time(t)); - printf("%d (%d) %5.2f/%5.2f\n", + printf("%d (%d) %5.2f/%5.2f (%5.2f/%5.2fmm)\n", libinput_event_touch_get_slot(t), libinput_event_touch_get_seat_slot(t), - x, y); + x, y, + xmm, ymm); } static int From 41f9176c0ad24a97c4e01976ed44df3ca300e99d Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 17 Jun 2014 15:45:07 +1000 Subject: [PATCH 5/5] Add a function to get the size of a device Signed-off-by: Peter Hutterer Reviewed-by: Hans de Goede --- src/evdev.c | 19 +++++++++++++++++++ src/evdev.h | 5 +++++ src/libinput.c | 10 ++++++++++ src/libinput.h | 19 +++++++++++++++++++ tools/event-debug.c | 8 +++++++- 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/evdev.c b/src/evdev.c index 2b2725cf..70c232ce 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -871,6 +871,25 @@ evdev_device_has_capability(struct evdev_device *device, } } +int +evdev_device_get_size(struct evdev_device *device, + double *width, + double *height) +{ + const struct input_absinfo *x, *y; + + x = libevdev_get_abs_info(device->evdev, ABS_X); + y = libevdev_get_abs_info(device->evdev, ABS_Y); + + if (!x || !y || !x->resolution || !y->resolution) + return -1; + + *width = evdev_convert_to_mm(x, x->maximum); + *height = evdev_convert_to_mm(y, y->maximum); + + return 0; +} + void evdev_device_remove(struct evdev_device *device) { diff --git a/src/evdev.h b/src/evdev.h index eebfab19..4a83a78a 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -148,6 +148,11 @@ int evdev_device_has_capability(struct evdev_device *device, enum libinput_device_capability capability); +int +evdev_device_get_size(struct evdev_device *device, + double *w, + double *h); + double evdev_device_transform_x(struct evdev_device *device, double x, diff --git a/src/libinput.c b/src/libinput.c index f384f439..c4f7fe12 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1185,6 +1185,16 @@ libinput_device_has_capability(struct libinput_device *device, capability); } +LIBINPUT_EXPORT int +libinput_device_get_size(struct libinput_device *device, + double *width, + double *height) +{ + return evdev_device_get_size((struct evdev_device *)device, + width, + height); +} + LIBINPUT_EXPORT struct libinput_event * libinput_event_device_notify_get_base_event(struct libinput_event_device_notify *event) { diff --git a/src/libinput.h b/src/libinput.h index c19460b0..fe75f87d 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1303,6 +1303,25 @@ int libinput_device_has_capability(struct libinput_device *device, enum libinput_device_capability capability); +/** + * @ingroup device + * + * Get the physical size of a device in mm, where meaningful. This function + * only succeeds on devices with the required data, i.e. tablets, touchpads + * and touchscreens. + * + * If this function returns nonzero, width and height are unmodified. + * + * @param device The device + * @param width Set to the width of the device + * @param height Set to the height of the device + * @return 0 on success, or nonzero otherwise + */ +int +libinput_device_get_size(struct libinput_device *device, + double *width, + double *height); + #ifdef __cplusplus } #endif diff --git a/tools/event-debug.c b/tools/event-debug.c index ffb45249..0f0d0339 100644 --- a/tools/event-debug.c +++ b/tools/event-debug.c @@ -231,10 +231,16 @@ print_device_notify(struct libinput_event *ev) { struct libinput_device *dev = libinput_event_get_device(ev); struct libinput_seat *seat = libinput_device_get_seat(dev); + double w, h; - printf("%s %s\n", + printf("%s %s", libinput_seat_get_physical_name(seat), libinput_seat_get_logical_name(seat)); + + if (libinput_device_get_size(dev, &w, &h) == 0) + printf("\tsize %.2f/%.2fmm", w, h); + + printf("\n"); } static void