From 17d792445edd689edc5b83608dbca51a1ab9e6fa Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 13 Sep 2018 13:26:22 +1000 Subject: [PATCH] tablet: add a the Totem tool type to the tablet interface This is the public API only, not the internal bits, so nothing will work just yet. This interface addition is for the Dell Canvas Totem tool, so let's go with the same name because options like "Rotary" are too ambiguous. The totem is a knob that can be placed on the surface, it provides us with location and rotation data. The touch major/minor fields are filled in by the current totem, but they're always the same size. The totem exports BTN_0 as well, so let's add that to the debug-events output. Signed-off-by: Peter Hutterer --- src/evdev-tablet.h | 6 +++ src/libinput-private.h | 11 +++- src/libinput.c | 69 ++++++++++++++++++++++++- src/libinput.h | 96 +++++++++++++++++++++++++++++++++++ src/libinput.sym | 8 +++ tools/libinput-debug-events.c | 16 ++++++ tools/libinput-debug-gui.c | 28 ++++++++++ 7 files changed, 232 insertions(+), 2 deletions(-) diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h index e19b62ca..86ed5ed3 100644 --- a/src/evdev-tablet.h +++ b/src/evdev-tablet.h @@ -200,6 +200,12 @@ axis_to_evcode(const enum libinput_tablet_tool_axis axis) case LIBINPUT_TABLET_TOOL_AXIS_SLIDER: evcode = ABS_WHEEL; break; + case LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR: + evcode = ABS_MT_TOUCH_MAJOR; + break; + case LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR: + evcode = ABS_MT_TOUCH_MINOR; + break; default: abort(); } diff --git a/src/libinput-private.h b/src/libinput-private.h index 13a36b49..56e37a4a 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -111,6 +111,12 @@ struct device_coord_rect { int w, h; }; +/* A pair of major/minor in mm */ +struct phys_ellipsis { + double major; + double minor; +}; + /* A pair of tilt flags */ struct wheel_tilt_flags { bool vertical, horizontal; @@ -349,9 +355,11 @@ enum libinput_tablet_tool_axis { LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z = 7, LIBINPUT_TABLET_TOOL_AXIS_SLIDER = 8, LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL = 9, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR = 10, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR = 11, }; -#define LIBINPUT_TABLET_TOOL_AXIS_MAX LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL +#define LIBINPUT_TABLET_TOOL_AXIS_MAX LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR struct tablet_axes { struct device_coords point; @@ -363,6 +371,7 @@ struct tablet_axes { double slider; double wheel; int wheel_discrete; + struct phys_ellipsis size; }; struct libinput_tablet_tool { diff --git a/src/libinput.c b/src/libinput.c index 4891736d..896fde7e 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1,6 +1,6 @@ /* * Copyright © 2013 Jonas Ådahl - * Copyright © 2013-2015 Red Hat, Inc. + * Copyright © 2013-2018 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -1153,6 +1153,38 @@ libinput_event_tablet_tool_slider_has_changed( LIBINPUT_TABLET_TOOL_AXIS_SLIDER); } +LIBINPUT_EXPORT int +libinput_event_tablet_tool_size_major_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_size_minor_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR); +} + LIBINPUT_EXPORT int libinput_event_tablet_tool_wheel_has_changed( struct libinput_event_tablet_tool *event) @@ -1315,6 +1347,34 @@ libinput_event_tablet_tool_get_slider_position(struct libinput_event_tablet_tool return event->axes.slider; } +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_size_major(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.size.major; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_size_minor(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.size.minor; +} + LIBINPUT_EXPORT double libinput_event_tablet_tool_get_wheel_delta(struct libinput_event_tablet_tool *event) { @@ -1551,6 +1611,13 @@ libinput_tablet_tool_has_wheel(struct libinput_tablet_tool *tool) LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL); } +LIBINPUT_EXPORT int +libinput_tablet_tool_has_size(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR); +} + LIBINPUT_EXPORT int libinput_tablet_tool_has_button(struct libinput_tablet_tool *tool, uint32_t code) diff --git a/src/libinput.h b/src/libinput.h index 859d3d4c..bde76f83 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -341,6 +341,9 @@ enum libinput_tablet_tool_type { LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH, /**< An airbrush-like tool */ LIBINPUT_TABLET_TOOL_TYPE_MOUSE, /**< A mouse bound to the tablet */ LIBINPUT_TABLET_TOOL_TYPE_LENS, /**< A mouse tool with a lens */ + LIBINPUT_TABLET_TOOL_TYPE_TOTEM, /**< A rotary device with + positional and rotation + data */ }; /** @@ -2082,6 +2085,49 @@ libinput_event_tablet_tool_rotation_has_changed( int libinput_event_tablet_tool_slider_has_changed( struct libinput_event_tablet_tool *event); + +/** + * @ingroup event_tablet + * + * Check if the size major axis was updated in this event. + * For events that are not of type @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, + * @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or + * @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0. + * + * @note It is an application bug to call this function for events other + * than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref + * LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref + * LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref + * LIBINPUT_EVENT_TABLET_TOOL_BUTTON. + * + * @param event The libinput tablet tool event + * @return 1 if the axis was updated or 0 otherwise + */ +int +libinput_event_tablet_tool_size_major_has_changed( + struct libinput_event_tablet_tool *event); + +/** + * @ingroup event_tablet + * + * Check if the size minor axis was updated in this event. + * For events that are not of type @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, + * @ref LIBINPUT_EVENT_TABLET_TOOL_TIP, or + * @ref LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, this function returns 0. + * + * @note It is an application bug to call this function for events other + * than @ref LIBINPUT_EVENT_TABLET_TOOL_AXIS, @ref + * LIBINPUT_EVENT_TABLET_TOOL_TIP, or @ref + * LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, or @ref + * LIBINPUT_EVENT_TABLET_TOOL_BUTTON. + * + * @param event The libinput tablet tool event + * @return 1 if the axis was updated or 0 otherwise + */ +int +libinput_event_tablet_tool_size_minor_has_changed( + struct libinput_event_tablet_tool *event); + /** * @ingroup event_tablet * @@ -2293,6 +2339,42 @@ libinput_event_tablet_tool_get_rotation(struct libinput_event_tablet_tool *event double libinput_event_tablet_tool_get_slider_position(struct libinput_event_tablet_tool *event); +/** + * @ingroup event_tablet + * + * Returns the current size in mm along the major axis of the touching + * ellipse. This axis is not necessarily aligned with either x or y, the + * rotation must be taken into account. + * + * Where no rotation is available on a tool, or where rotation is zero, the + * major axis aligns with the y axis and the minor axis with the x axis. + * + * If this axis does not exist on the current tool, this function returns 0. + * + * @param event The libinput tablet tool event + * @return The current value of the axis major in mm + */ +double +libinput_event_tablet_tool_get_size_major(struct libinput_event_tablet_tool *event); + +/** + * @ingroup event_tablet + * + * Returns the current size in mm along the minor axis of the touching + * ellipse. This axis is not necessarily aligned with either x or y, the + * rotation must be taken into account. + * + * Where no rotation is available on a tool, or where rotation is zero, the + * minor axis aligns with the y axis and the minor axis with the x axis. + * + * If this axis does not exist on the current tool, this function returns 0. + * + * @param event The libinput tablet tool event + * @return The current value of the axis minor in mm + */ +double +libinput_event_tablet_tool_get_size_minor(struct libinput_event_tablet_tool *event); + /** * @ingroup event_tablet * @@ -2664,6 +2746,20 @@ libinput_tablet_tool_has_rotation(struct libinput_tablet_tool *tool); int libinput_tablet_tool_has_slider(struct libinput_tablet_tool *tool); +/** + * @ingroup event_tablet + * + * Return whether the tablet tool has a ellipsis major and minor. + * Where the underlying hardware only supports one of either major or minor, + * libinput emulates the other axis as a circular contact, i.e. major == + * minor for all values of major. + * + * @param tool The tool to check the axis capabilities of + * @return Nonzero if the axis is available, zero otherwise. + */ +int +libinput_tablet_tool_has_size(struct libinput_tablet_tool *tool); + /** * @ingroup event_tablet * diff --git a/src/libinput.sym b/src/libinput.sym index aa2794e9..ef9d9178 100644 --- a/src/libinput.sym +++ b/src/libinput.sym @@ -297,3 +297,11 @@ LIBINPUT_1.9 { LIBINPUT_1.11 { libinput_device_touch_get_touch_count; } LIBINPUT_1.9; + +LIBINPUT_1.14 { + libinput_tablet_tool_has_size; + libinput_event_tablet_tool_get_size_major; + libinput_event_tablet_tool_get_size_minor; + libinput_event_tablet_tool_size_major_has_changed; + libinput_event_tablet_tool_size_minor_has_changed; +} LIBINPUT_1.11; diff --git a/tools/libinput-debug-events.c b/tools/libinput-debug-events.c index c989733e..23926af1 100644 --- a/tools/libinput-debug-events.c +++ b/tools/libinput-debug-events.c @@ -366,6 +366,7 @@ print_tablet_axes(struct libinput_event_tablet_tool *t) double dist, pressure; double rotation, slider, wheel; double delta; + double major, minor; #define changed_sym(ev, ax) \ (libinput_event_tablet_tool_##ax##_has_changed(ev) ? "*" : "") @@ -415,6 +416,14 @@ print_tablet_axes(struct libinput_event_tablet_tool *t) wheel, changed_sym(t, wheel), (int)delta); } + + if (libinput_tablet_tool_has_size(tool)) { + major = libinput_event_tablet_tool_get_size_major(t); + minor = libinput_event_tablet_tool_get_size_minor(t); + printq("\tsize: %.2f%s/%.2f%s", + major, changed_sym(t, size_major), + minor, changed_sym(t, size_minor)); + } } static void @@ -548,6 +557,9 @@ print_proximity_event(struct libinput_event *ev) case LIBINPUT_TABLET_TOOL_TYPE_LENS: tool_str = "lens"; break; + case LIBINPUT_TABLET_TOOL_TYPE_TOTEM: + tool_str = "totem"; + break; default: abort(); } @@ -586,6 +598,8 @@ print_proximity_event(struct libinput_event *ev) printq("s"); if (libinput_tablet_tool_has_wheel(tool)) printq("w"); + if (libinput_tablet_tool_has_size(tool)) + printq("S"); printq("\tbtn:"); if (libinput_tablet_tool_has_button(tool, BTN_TOUCH)) @@ -604,6 +618,8 @@ print_proximity_event(struct libinput_event *ev) printq("Sd"); if (libinput_tablet_tool_has_button(tool, BTN_EXTRA)) printq("Ex"); + if (libinput_tablet_tool_has_button(tool, BTN_0)) + printq("0"); } printq("\n"); diff --git a/tools/libinput-debug-gui.c b/tools/libinput-debug-gui.c index 3a8bc195..3a1c99f7 100644 --- a/tools/libinput-debug-gui.c +++ b/tools/libinput-debug-gui.c @@ -134,6 +134,8 @@ struct window { double pressure; double distance; double tilt_x, tilt_y; + double rotation; + double size_major, size_minor; /* these are for the delta coordinates, but they're not * deltas, they are converted into abs positions */ @@ -473,13 +475,36 @@ draw_tablet(struct window *w, cairo_t *cr) cairo_set_source_rgb(cr, .2, .8, .8); cairo_translate(cr, w->tool.x, w->tool.y); + /* scale of 2.5 is large enough to make the marker visible around the + physical totem */ + cairo_scale(cr, + 1.0 + w->tool.size_major * 2.5, + 1.0 + w->tool.size_minor * 2.5); cairo_scale(cr, 1.0 + w->tool.tilt_x/30.0, 1.0 + w->tool.tilt_y/30.0); + if (w->tool.rotation) + cairo_rotate(cr, w->tool.rotation * M_PI/180.0); + if (w->tool.pressure) + cairo_set_source_rgb(cr, .8, .8, .2); cairo_arc(cr, 0, 0, 1 + 10 * max(w->tool.pressure, w->tool.distance), 0, 2 * M_PI); cairo_fill(cr); cairo_restore(cr); + /* The line to indicate the origin */ + if (w->tool.size_major) { + cairo_save(cr); + cairo_scale(cr, 1.0, 1.0); + cairo_translate(cr, w->tool.x, w->tool.y); + if (w->tool.rotation) + cairo_rotate(cr, w->tool.rotation * M_PI/180.0); + cairo_set_source_rgb(cr, .0, .0, .0); + cairo_move_to(cr, 0, 0); + cairo_rel_line_to(cr, 0, -w->tool.size_major * 2.5); + cairo_stroke(cr); + cairo_restore(cr); + } + /* tablet deltas */ mask = ARRAY_LENGTH(w->tool.deltas); first = max(w->tool.ndeltas + 1, mask) - mask; @@ -1207,6 +1232,9 @@ handle_event_tablet(struct libinput_event *ev, struct window *w) w->tool.distance = libinput_event_tablet_tool_get_distance(t); w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t); w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t); + w->tool.rotation = libinput_event_tablet_tool_get_rotation(t); + w->tool.size_major = libinput_event_tablet_tool_get_size_major(t); + w->tool.size_minor = libinput_event_tablet_tool_get_size_minor(t); /* Add the delta to the last position and store them as abs * coordinates */