[RFC libinput] Add dial input device support
Peter Hutterer
peter.hutterer at who-t.net
Thu Feb 18 00:29:05 UTC 2016
Hi PrasannaKumar
On Mon, Feb 15, 2016 at 04:21:23PM +0530, PrasannaKumar Muralidharan wrote:
> From: PrasannaKumar Muralidharan <prasannatsmkumar at gmail.com>
>
> I am implementing dial input device support and would like to get feedback
> on the code that I have implemented so far. Did not implement test cases
> as of now, any pointers on how the test framework works will be helpful.
>
> Smartwatch can use dial input, Car can use steering wheel rotation as
> input for maps may be. But I would like to know if dial input device
> support is useful before proceeding further?
>
> Appreciate positive and negative comments.
First: yes, implementing support for dial interfaces is within the scope of
libinput, I think it makes sense to add this. But not quite in this form,
the various CAP flags are libinput interfaces that denote a specific
functionality. We should not add one per event group.
A while ago we started work on the so-called buttonset interface which is
a generic interface to support a bunch of devices like yours:
https://lists.freedesktop.org/archives/wayland-devel/2016-January/026670.html
Since that patchset we've split out the wacom-specific parts so you can
ignore any strip/ring handling. There is no dial axis atm, but there
could be.
Have a look at that patchset, the documentation should explain what the
interface is for, etc. I think adding dial to buttonset and then getting
that interface ready for merging is the best approach here.
One comment on the API (to save you from scrolling down):
libinput_event_dial_get_rotation_count() should simply be
libinput_event_dial_get_rotation() and return the value in degrees. This is
more flexible than the current one which reads like it's multiples of 360
degrees?
Cheers,
Peter
> ---
> src/Makefile.am | 2 ++
> src/evdev-dial.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++
> src/evdev-dial.h | 6 ++++
> src/evdev.c | 12 ++++++++
> src/evdev.h | 6 ++++
> src/libinput-private.h | 5 ++++
> src/libinput.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++
> src/libinput.h | 46 +++++++++++++++++++++++++++++
> src/libinput.sym | 5 ++++
> tools/event-debug.c | 23 +++++++++++++++
> 10 files changed, 259 insertions(+)
> create mode 100644 src/evdev-dial.c
> create mode 100644 src/evdev-dial.h
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 343e75c..20a32a5 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -11,6 +11,8 @@ libinput_la_SOURCES = \
> libinput-private.h \
> evdev.c \
> evdev.h \
> + evdev-dial.c \
> + evdev-dial.h \
> evdev-middle-button.c \
> evdev-mt-touchpad.c \
> evdev-mt-touchpad.h \
> diff --git a/src/evdev-dial.c b/src/evdev-dial.c
> new file mode 100644
> index 0000000..2427724
> --- /dev/null
> +++ b/src/evdev-dial.c
> @@ -0,0 +1,80 @@
> +#include "config.h"
> +
> +#include <assert.h>
> +#include <math.h>
> +#include <stdbool.h>
> +#include <limits.h>
> +
> +#include "evdev-dial.h"
> +
> +static void
> +dial_process(struct evdev_dispatch *dispatch,
> + struct evdev_device *device,
> + struct input_event *event,
> + uint64_t time)
> +{
> + struct libinput_device *base = &device->base;
> + dial_notify(base, time, (int16_t)event->value);
> +}
> +
> +/*
> +static void
> +dial_suspend(struct evdev_dispatch *dispatch,
> + struct evdev_device *device)
> +{
> +
> +}
> +
> +static void
> +dial_remove(struct evdev_dispatch *dispatch)
> +{
> +
> +}
> +*/
> +
> +static void
> +dial_destroy(struct evdev_dispatch *dispatch)
> +{
> + free(dispatch);
> +}
> +
> +/*
> +static void
> +dial_device_added(struct evdev_device *device,
> + struct evdev_device *added_device)
> +{
> +
> +}
> +
> +static void
> +dial_device_removed(struct evdev_device *device,
> + struct evdev_device *removed_device)
> +{
> +
> +}
> +*/
> +
> +/* TODO: Check whether other callbacks have to be implemented? */
> +static struct evdev_dispatch_interface dial_interface = {
> + dial_process,
> + NULL, /* device suspend */
> + NULL, /* device remove */
> + dial_destroy,
> + NULL, /* device added */
> + NULL, /* device removed */
> + NULL, /* device suspended */
> + NULL, /* device resumed */
> + NULL, /* device post added */
> +};
> +
> +struct evdev_dispatch *
> +evdev_dial_create(struct evdev_device *device)
> +{
> + struct evdev_dispatch *dispatch = zalloc(sizeof(struct evdev_dispatch));
> + if (!dispatch)
> + return NULL;
> +
> + dispatch->interface = &dial_interface;
> +
> + return dispatch;
> +}
> diff --git a/src/evdev-dial.h b/src/evdev-dial.h
> new file mode 100644
> index 0000000..0e191e7
> --- /dev/null
> +++ b/src/evdev-dial.h
> @@ -0,0 +1,6 @@
> +#ifndef EVDEV_DIAL_H
> +#define EVDEV_DIAL_H
> +
> +#include "evdev.h"
> +
> +#endif /* EVDEV_DIAL_H */
> diff --git a/src/evdev.c b/src/evdev.c
> index 66673a8..1e044fb 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -63,6 +63,7 @@ enum evdev_device_udev_tags {
> EVDEV_UDEV_TAG_ACCELEROMETER = (1 << 7),
> EVDEV_UDEV_TAG_BUTTONSET = (1 << 8),
> EVDEV_UDEV_TAG_POINTINGSTICK = (1 << 9),
> + EVDEV_UDEV_TAG_DIAL = (1 << 10),
> };
>
> struct evdev_udev_tag_match {
> @@ -82,6 +83,7 @@ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = {
> {"ID_INPUT_JOYSTICK", EVDEV_UDEV_TAG_JOYSTICK},
> {"ID_INPUT_ACCELEROMETER", EVDEV_UDEV_TAG_ACCELEROMETER},
> {"ID_INPUT_POINTINGSTICK", EVDEV_UDEV_TAG_POINTINGSTICK},
> + {"ID_INPUT_DIAL", EVDEV_UDEV_TAG_DIAL},
>
> /* sentinel value */
> { 0 },
> @@ -779,6 +781,7 @@ evdev_need_touch_frame(struct evdev_device *device)
> switch (device->pending_event) {
> case EVDEV_NONE:
> case EVDEV_RELATIVE_MOTION:
> + case EVDEV_RELATIVE_DIAL:
> break;
> case EVDEV_ABSOLUTE_MT_DOWN:
> case EVDEV_ABSOLUTE_MT_MOTION:
> @@ -2157,6 +2160,15 @@ evdev_configure_device(struct evdev_device *device)
> return -1;
> }
>
> + if (udev_tags & EVDEV_UDEV_TAG_DIAL) {
> + device->dispatch = evdev_dial_create(device);
> + device->seat_caps |= EVDEV_DEVICE_DIAL;
> + log_info(libinput, "input device '%s', '%s' is a rotatory dial\n",
> + device->devname, devnode);
> +
> + return device->dispatch == NULL ? -1 : 0;
> + }
> +
> return 0;
> }
>
> diff --git a/src/evdev.h b/src/evdev.h
> index 8b567a8..b26ae10 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -54,6 +54,7 @@ enum evdev_event_type {
> EVDEV_ABSOLUTE_MT_MOTION,
> EVDEV_ABSOLUTE_MT_UP,
> EVDEV_RELATIVE_MOTION,
> + EVDEV_RELATIVE_DIAL,
> };
>
> enum evdev_device_seat_capability {
> @@ -62,6 +63,7 @@ enum evdev_device_seat_capability {
> EVDEV_DEVICE_TOUCH = (1 << 2),
> EVDEV_DEVICE_TABLET = (1 << 3),
> EVDEV_DEVICE_GESTURE = (1 << 5),
> + EVDEV_DEVICE_DIAL = (1 << 9),
> };
>
> enum evdev_device_tags {
> @@ -69,6 +71,7 @@ enum evdev_device_tags {
> EVDEV_TAG_INTERNAL_TOUCHPAD = (1 << 1),
> EVDEV_TAG_TRACKPOINT = (1 << 2),
> EVDEV_TAG_KEYBOARD = (1 << 3),
> + EVDEV_TAG_DIAL = (1 << 4),
> };
>
> enum evdev_middlebutton_state {
> @@ -309,6 +312,9 @@ struct evdev_dispatch *
> evdev_touchpad_create(struct evdev_device *device);
>
> struct evdev_dispatch *
> +evdev_dial_create(struct evdev_device *device);
> +
> +struct evdev_dispatch *
> evdev_mt_touchpad_create(struct evdev_device *device);
>
> struct evdev_dispatch *
> diff --git a/src/libinput-private.h b/src/libinput-private.h
> index bc7000d..eabed47 100644
> --- a/src/libinput-private.h
> +++ b/src/libinput-private.h
> @@ -503,6 +503,11 @@ gesture_notify_pinch_end(struct libinput_device *device,
> int cancelled);
>
> void
> +dial_notify(struct libinput_device *device,
> + uint64_t time,
> + int16_t value);
> +
> +void
> touch_notify_frame(struct libinput_device *device,
> uint64_t time);
>
> diff --git a/src/libinput.c b/src/libinput.c
> index 2bcd416..8fc6ed8 100644
> --- a/src/libinput.c
> +++ b/src/libinput.c
> @@ -125,6 +125,12 @@ struct libinput_event_gesture {
> double angle;
> };
>
> +struct libinput_event_dial {
> + struct libinput_event base;
> + uint64_t time;
> + int16_t count;
> +};
> +
> struct libinput_event_tablet_tool {
> struct libinput_event base;
> uint32_t button;
> @@ -318,6 +324,15 @@ libinput_event_get_tablet_tool_event(struct libinput_event *event)
> return (struct libinput_event_tablet_tool *) event;
> }
>
> +LIBINPUT_EXPORT struct libinput_event_dial *
> +libinput_event_get_dial_event(struct libinput_event *event)
> +{
> + require_event_type(libinput_event_get_context(event), event->type, NULL,
> + LIBINPUT_EVENT_DIAL);
> +
> + return (struct libinput_event_dial *) event;
> +}
> +
> LIBINPUT_EXPORT struct libinput_event_device_notify *
> libinput_event_get_device_notify_event(struct libinput_event *event)
> {
> @@ -1473,6 +1488,39 @@ libinput_tablet_tool_unref(struct libinput_tablet_tool *tool)
> return NULL;
> }
>
> +LIBINPUT_EXPORT uint32_t
> +libinput_event_dial_get_time(struct libinput_event_dial *event)
> +{
> + require_event_type(libinput_event_get_context(&event->base),
> + event->base.type,
> + 0,
> + LIBINPUT_EVENT_DIAL);
> +
> + return us2ms(event->time);
> +}
> +
> +LIBINPUT_EXPORT uint64_t
> +libinput_event_dial_get_time_usec(struct libinput_event_dial *event)
> +{
> + require_event_type(libinput_event_get_context(&event->base),
> + event->base.type,
> + 0,
> + LIBINPUT_EVENT_DIAL);
> +
> + return event->time;
> +}
> +
> +LIBINPUT_EXPORT int16_t
> +libinput_event_dial_get_rotation_count(struct libinput_event_dial *event)
> +{
> + require_event_type(libinput_event_get_context(&event->base),
> + event->base.type,
> + 0,
> + LIBINPUT_EVENT_DIAL);
> +
> + return event->count;
> +}
> +
> struct libinput_source *
> libinput_add_fd(struct libinput *libinput,
> int fd,
> @@ -1953,6 +2001,9 @@ device_has_cap(struct libinput_device *device,
> case LIBINPUT_DEVICE_CAP_TABLET_TOOL:
> capability = "CAP_TABLET";
> break;
> + case LIBINPUT_DEVICE_CAP_DIAL:
> + capability = "CAP_DIAL";
> + break;
> }
>
> log_bug_libinput(device->seat->libinput,
> @@ -2451,6 +2502,7 @@ event_type_to_str(enum libinput_event_type type)
> CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_BEGIN);
> CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_UPDATE);
> CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END);
> + CASE_RETURN_STRING(LIBINPUT_EVENT_DIAL);
> case LIBINPUT_EVENT_NONE:
> abort();
> }
> @@ -2458,6 +2510,28 @@ event_type_to_str(enum libinput_event_type type)
> return NULL;
> }
>
> +void
> +dial_notify(struct libinput_device *device,
> + uint64_t time,
> + int16_t value)
> +{
> + struct libinput_event_dial *dial_event;
> +
> + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_DIAL))
> + return;
> +
> + dial_event = zalloc(sizeof *dial_event);
> + if (!dial_event)
> + return;
> +
> + *dial_event = (struct libinput_event_dial) {
> + .time = time,
> + .count = value,
> + };
> +
> + post_device_event(device, time, LIBINPUT_EVENT_DIAL, &dial_event->base);
> +}
> +
> static void
> libinput_post_event(struct libinput *libinput,
> struct libinput_event *event)
> diff --git a/src/libinput.h b/src/libinput.h
> index 8ed5632..fdba4f2 100644
> --- a/src/libinput.h
> +++ b/src/libinput.h
> @@ -60,6 +60,7 @@ enum libinput_device_capability {
> LIBINPUT_DEVICE_CAP_TOUCH = 2,
> LIBINPUT_DEVICE_CAP_TABLET_TOOL = 3,
> LIBINPUT_DEVICE_CAP_GESTURE = 5,
> + LIBINPUT_DEVICE_CAP_DIAL = 8,
> };
>
> /**
> @@ -345,6 +346,8 @@ enum libinput_event_type {
> LIBINPUT_EVENT_GESTURE_PINCH_BEGIN,
> LIBINPUT_EVENT_GESTURE_PINCH_UPDATE,
> LIBINPUT_EVENT_GESTURE_PINCH_END,
> +
> + LIBINPUT_EVENT_DIAL = 900,
> };
>
> /**
> @@ -552,6 +555,20 @@ libinput_event_get_gesture_event(struct libinput_event *event);
> /**
> * @ingroup event
> *
> + * Return the dial event that is this input event. If the event type does
> + * not match the device event types, this function returns NULL.
> + *
> + * The inverse of this function is
> + * libinput_event_device_notify_get_base_event().
> + *
> + * @return A device event, or NULL for other events
> + */
> +struct libinput_event_dial *
> +libinput_event_get_dial_event(struct libinput_event *event);
> +
> +/**
> ++ * @ingroup event
> ++ *
> * Return the tablet event that is this input event. If the event type does not
> * match the tablet event types, this function returns NULL.
> *
> @@ -2082,6 +2099,35 @@ libinput_tablet_tool_set_user_data(struct libinput_tablet_tool *tool,
> void *user_data);
>
> /**
> + * @ingroup event_dial
> + *
> + * @return The event time for this event
> + */
> +uint32_t
> +libinput_event_dial_get_time(struct libinput_event_dial *event);
> +
> +/**
> + * @ingroup event_dial
> + *
> + * @return The event time for this event in microseconds
> + */
> +uint64_t
> +libinput_event_dial_get_time_usec(struct libinput_event_dial *event);
> +
> +/**
> + * @ingroup event_dial
> + *
> + * Return the number of rotation made in the dial.
> + *
> + * Positive value indicates clockwise dial rotation, negavtive value indicates
> + * anticlockwise dial rotation.
> + *
> + * @return the number of dial rotation
> + */
> +int16_t
> +libinput_event_dial_get_rotation_count(struct libinput_event_dial *event);
> +
> +/**
> * @defgroup base Initialization and manipulation of libinput contexts
> */
>
> diff --git a/src/libinput.sym b/src/libinput.sym
> index a211388..ce0d859 100644
> --- a/src/libinput.sym
> +++ b/src/libinput.sym
> @@ -233,4 +233,9 @@ LIBINPUT_1.2 {
> libinput_tablet_tool_ref;
> libinput_tablet_tool_set_user_data;
> libinput_tablet_tool_unref;
> +
> + libinput_event_get_dial_event;
> + libinput_event_dial_get_time;
> + libinput_event_dial_get_time_usec;
> + libinput_event_dial_get_rotation_count;
> } LIBINPUT_1.1;
> diff --git a/tools/event-debug.c b/tools/event-debug.c
> index 648111e..039c64d 100644
> --- a/tools/event-debug.c
> +++ b/tools/event-debug.c
> @@ -121,6 +121,9 @@ print_event_header(struct libinput_event *ev)
> case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
> type = "TABLET_BUTTON";
> break;
> + case LIBINPUT_EVENT_DIAL:
> + type = "DIAL_ROTATE";
> + break;
> }
>
> printf("%-7s %-16s ", libinput_device_get_sysname(dev), type);
> @@ -543,6 +546,23 @@ print_gesture_event_without_coords(struct libinput_event *ev)
> }
>
> static void
> +print_dial_event(struct libinput_event *ev)
> +{
> + struct libinput_event_dial *t = libinput_event_get_dial_event(ev);
> + enum libinput_event_type type;
> + int16_t count = 0;
> +
> + type = libinput_event_get_type(ev);
> +
> + print_event_time(libinput_event_dial_get_time(t));
> + count = libinput_event_dial_get_rotation_count(t);
> + if (count > 0)
> + printf("Dial rotated clockwise %d times\n", count);
> + else
> + printf("Dial rotated anti-clockwise %d times\n", count);
> +}
> +
> +static void
> print_gesture_event_with_coords(struct libinput_event *ev)
> {
> struct libinput_event_gesture *t = libinput_event_get_gesture_event(ev);
> @@ -647,6 +667,9 @@ handle_and_print_events(struct libinput *li)
> case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
> print_tablet_button_event(ev);
> break;
> + case LIBINPUT_EVENT_DIAL:
> + print_dial_event(ev);
> + break;
> }
>
> libinput_event_destroy(ev);
> --
> 2.5.0
More information about the wayland-devel
mailing list