diff --git a/src/Makefile.am b/src/Makefile.am index 39c22c21..48e704a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,7 @@ libinput_la_SOURCES = \ evdev-tablet.h \ evdev-tablet-pad.c \ evdev-tablet-pad.h \ + evdev-tablet-pad-leds.c \ filter.c \ filter.h \ filter-private.h \ diff --git a/src/evdev-tablet-pad-leds.c b/src/evdev-tablet-pad-leds.c new file mode 100644 index 00000000..8b162a61 --- /dev/null +++ b/src/evdev-tablet-pad-leds.c @@ -0,0 +1,177 @@ +/* + * Copyright © 2016 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "evdev-tablet-pad.h" + +struct pad_led_group { + struct libinput_tablet_pad_mode_group base; +}; + +static void +pad_led_group_destroy(struct libinput_tablet_pad_mode_group *g) +{ + struct pad_led_group *group = (struct pad_led_group *)g; + + free(group); +} + +static struct pad_led_group * +pad_group_new_basic(struct pad_dispatch *pad, + unsigned int group_index, + int nleds) +{ + struct pad_led_group *group; + + group = zalloc(sizeof *group); + if (!group) + return NULL; + + group->base.device = &pad->device->base; + group->base.refcount = 1; + group->base.index = group_index; + group->base.current_mode = 0; + group->base.num_modes = nleds; + group->base.destroy = pad_led_group_destroy; + + return group; +} + +static inline struct libinput_tablet_pad_mode_group * +pad_get_mode_group(struct pad_dispatch *pad, unsigned int index) +{ + struct libinput_tablet_pad_mode_group *group; + + list_for_each(group, &pad->modes.mode_group_list, link) { + if (group->index == index) + return group; + } + + return NULL; +} + +static int +pad_init_fallback_group(struct pad_dispatch *pad) +{ + struct pad_led_group *group; + + group = pad_group_new_basic(pad, 0, 1); + if (!group) + return 1; + + /* If we only have one group, all buttons/strips/rings are part of + * that group. We rely on the other layers to filter out invalid + * indices */ + group->base.button_mask = -1; + group->base.strip_mask = -1; + group->base.ring_mask = -1; + group->base.toggle_button_mask = 0; + + list_insert(&pad->modes.mode_group_list, &group->base.link); + + return 0; +} + +int +pad_init_leds(struct pad_dispatch *pad, + struct evdev_device *device) +{ + int rc = 1; + + list_init(&pad->modes.mode_group_list); + + if (pad->nbuttons > 32) { + log_bug_libinput(device->base.seat->libinput, + "Too many pad buttons for modes %d\n", + pad->nbuttons); + return rc; + } + + /* Eventually we slot the libwacom-based led detection in here. That + * requires getting the kernel ready first. For now we just init the + * fallback single-mode group. + */ + rc = pad_init_fallback_group(pad); + + return rc; +} + +void +pad_destroy_leds(struct pad_dispatch *pad) +{ + struct libinput_tablet_pad_mode_group *group, *tmpgrp; + + list_for_each_safe(group, tmpgrp, &pad->modes.mode_group_list, link) + libinput_tablet_pad_mode_group_unref(group); +} + +void +pad_button_update_mode(struct libinput_tablet_pad_mode_group *g, + unsigned int button_index, + enum libinput_button_state state) +{ + struct pad_led_group *group = (struct pad_led_group*)g; + + if (state != LIBINPUT_BUTTON_STATE_PRESSED) + return; + + if (!libinput_tablet_pad_mode_group_button_is_toggle(g, button_index)) + return; + + log_bug_libinput(group->base.device->seat->libinput, + "Button %d should not be a toggle button", + button_index); +} + +int +evdev_device_tablet_pad_get_num_mode_groups(struct evdev_device *device) +{ + struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch; + struct libinput_tablet_pad_mode_group *group; + int num_groups = 0; + + if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD)) + return -1; + + list_for_each(group, &pad->modes.mode_group_list, link) + num_groups++; + + return num_groups; +} + +struct libinput_tablet_pad_mode_group * +evdev_device_tablet_pad_get_mode_group(struct evdev_device *device, + unsigned int index) +{ + struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch; + + if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD)) + return NULL; + + return pad_get_mode_group(pad, index); +} diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c index b7a2950e..0e95408c 100644 --- a/src/evdev-tablet-pad.c +++ b/src/evdev-tablet-pad.c @@ -209,12 +209,45 @@ pad_handle_strip(struct pad_dispatch *pad, return pos; } +static inline struct libinput_tablet_pad_mode_group * +pad_ring_get_mode_group(struct pad_dispatch *pad, + unsigned int ring) +{ + struct libinput_tablet_pad_mode_group *group; + + list_for_each(group, &pad->modes.mode_group_list, link) { + if (libinput_tablet_pad_mode_group_has_ring(group, ring)) + return group; + } + + assert(!"Unable to find ring mode group"); + + return NULL; +} + +static inline struct libinput_tablet_pad_mode_group * +pad_strip_get_mode_group(struct pad_dispatch *pad, + unsigned int strip) +{ + struct libinput_tablet_pad_mode_group *group; + + list_for_each(group, &pad->modes.mode_group_list, link) { + if (libinput_tablet_pad_mode_group_has_strip(group, strip)) + return group; + } + + assert(!"Unable to find strip mode group"); + + return NULL; +} + static void pad_check_notify_axes(struct pad_dispatch *pad, struct evdev_device *device, uint64_t time) { struct libinput_device *base = &device->base; + struct libinput_tablet_pad_mode_group *group; double value; bool send_finger_up = false; @@ -229,11 +262,13 @@ pad_check_notify_axes(struct pad_dispatch *pad, if (send_finger_up) value = -1.0; + group = pad_ring_get_mode_group(pad, 0); tablet_pad_notify_ring(base, time, 0, value, - LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER); + LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER, + group); } if (pad->changed_axes & PAD_AXIS_RING2) { @@ -241,11 +276,13 @@ pad_check_notify_axes(struct pad_dispatch *pad, if (send_finger_up) value = -1.0; + group = pad_ring_get_mode_group(pad, 1); tablet_pad_notify_ring(base, time, 1, value, - LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER); + LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER, + group); } if (pad->changed_axes & PAD_AXIS_STRIP1) { @@ -253,11 +290,13 @@ pad_check_notify_axes(struct pad_dispatch *pad, if (send_finger_up) value = -1.0; + group = pad_strip_get_mode_group(pad, 0); tablet_pad_notify_strip(base, time, 0, value, - LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER); + LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER, + group); } if (pad->changed_axes & PAD_AXIS_STRIP2) { @@ -265,11 +304,13 @@ pad_check_notify_axes(struct pad_dispatch *pad, if (send_finger_up) value = -1.0; + group = pad_strip_get_mode_group(pad, 1); tablet_pad_notify_strip(base, time, 1, value, - LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER); + LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER, + group); } pad->changed_axes = PAD_AXIS_NONE; @@ -288,6 +329,22 @@ pad_process_key(struct pad_dispatch *pad, pad_button_set_down(pad, button, is_press); } +static inline struct libinput_tablet_pad_mode_group * +pad_button_get_mode_group(struct pad_dispatch *pad, + unsigned int button) +{ + struct libinput_tablet_pad_mode_group *group; + + list_for_each(group, &pad->modes.mode_group_list, link) { + if (libinput_tablet_pad_mode_group_has_button(group, button)) + return group; + } + + assert(!"Unable to find button mode group\n"); + + return NULL; +} + static void pad_notify_button_mask(struct pad_dispatch *pad, struct evdev_device *device, @@ -296,6 +353,7 @@ pad_notify_button_mask(struct pad_dispatch *pad, enum libinput_button_state state) { struct libinput_device *base = &device->base; + struct libinput_tablet_pad_mode_group *group; int32_t code; unsigned int i; @@ -315,8 +373,11 @@ pad_notify_button_mask(struct pad_dispatch *pad, continue; map = pad->button_map[code - 1]; - if (map != -1) - tablet_pad_notify_button(base, time, map, state); + if (map != -1) { + group = pad_button_get_mode_group(pad, map); + pad_button_update_mode(group, map, state); + tablet_pad_notify_button(base, time, map, state, group); + } } } } @@ -437,6 +498,7 @@ pad_destroy(struct evdev_dispatch *dispatch) { struct pad_dispatch *pad = (struct pad_dispatch*)dispatch; + pad_destroy_leds(pad); free(pad); } @@ -500,6 +562,8 @@ pad_init(struct pad_dispatch *pad, struct evdev_device *device) pad_init_buttons(pad, device); pad_init_left_handed(device); + if (pad_init_leds(pad, device) != 0) + return 1; return 0; } diff --git a/src/evdev-tablet-pad.h b/src/evdev-tablet-pad.h index 84324bcb..9002fca9 100644 --- a/src/evdev-tablet-pad.h +++ b/src/evdev-tablet-pad.h @@ -64,6 +64,10 @@ struct pad_dispatch { struct libinput_device_config_send_events config; enum libinput_config_send_events_mode current_mode; } sendevents; + + struct { + struct list mode_group_list; + } modes; }; static inline struct libinput * @@ -72,4 +76,12 @@ pad_libinput_context(const struct pad_dispatch *pad) return evdev_libinput_context(pad->device); } +int +pad_init_leds(struct pad_dispatch *pad, struct evdev_device *device); +void +pad_destroy_leds(struct pad_dispatch *pad); +void +pad_button_update_mode(struct libinput_tablet_pad_mode_group *g, + unsigned int pressed_button, + enum libinput_button_state state); #endif diff --git a/src/evdev.h b/src/evdev.h index ca133181..d5e23231 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -392,6 +392,22 @@ evdev_device_tablet_pad_get_num_rings(struct evdev_device *device); int evdev_device_tablet_pad_get_num_strips(struct evdev_device *device); +int +evdev_device_tablet_pad_get_num_mode_groups(struct evdev_device *device); + +struct libinput_tablet_pad_mode_group * +evdev_device_tablet_pad_get_mode_group(struct evdev_device *device, + unsigned int index); + +unsigned int +evdev_device_tablet_pad_mode_group_get_button_target( + struct libinput_tablet_pad_mode_group *g, + unsigned int button_index); + +struct libinput_tablet_pad_led * +evdev_device_tablet_pad_get_led(struct evdev_device *device, + unsigned int led); + double evdev_device_transform_x(struct evdev_device *device, double x, diff --git a/src/libinput-private.h b/src/libinput-private.h index 98cb419f..b3257073 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -330,9 +330,22 @@ struct libinput_tablet_tool { }; struct libinput_tablet_pad_mode_group { + struct libinput_device *device; struct list link; int refcount; void *user_data; + + unsigned int index; + unsigned int num_modes; + unsigned int current_mode; + + uint32_t button_mask; + uint32_t ring_mask; + uint32_t strip_mask; + + uint32_t toggle_button_mask; + + void (*destroy)(struct libinput_tablet_pad_mode_group *group); }; struct libinput_event { @@ -572,19 +585,22 @@ void tablet_pad_notify_button(struct libinput_device *device, uint64_t time, int32_t button, - enum libinput_button_state state); + enum libinput_button_state state, + struct libinput_tablet_pad_mode_group *group); void tablet_pad_notify_ring(struct libinput_device *device, uint64_t time, unsigned int number, double value, - enum libinput_tablet_pad_ring_axis_source source); + enum libinput_tablet_pad_ring_axis_source source, + struct libinput_tablet_pad_mode_group *group); void tablet_pad_notify_strip(struct libinput_device *device, uint64_t time, unsigned int number, double value, - enum libinput_tablet_pad_strip_axis_source source); + enum libinput_tablet_pad_strip_axis_source source, + struct libinput_tablet_pad_mode_group *group); static inline uint64_t libinput_now(struct libinput *libinput) diff --git a/src/libinput-util.h b/src/libinput-util.h index 051d08f2..a7ebc308 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -87,6 +87,7 @@ int list_empty(const struct list *list); pos = tmp, \ tmp = container_of(pos->member.next, tmp, member)) +#define NBITS(b) (b * 8) #define LONG_BITS (sizeof(long) * 8) #define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) diff --git a/src/libinput.c b/src/libinput.c index a7892e14..cf0ed5bf 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -1668,6 +1668,12 @@ libinput_event_tablet_tool_destroy(struct libinput_event_tablet_tool *event) libinput_tablet_tool_unref(event->tool); } +static void +libinput_event_tablet_pad_destroy(struct libinput_event_tablet_pad *event) +{ + libinput_tablet_pad_mode_group_unref(event->mode_group); +} + LIBINPUT_EXPORT void libinput_event_destroy(struct libinput_event *event) { @@ -1682,6 +1688,13 @@ libinput_event_destroy(struct libinput_event *event) libinput_event_tablet_tool_destroy( libinput_event_get_tablet_tool_event(event)); break; + case LIBINPUT_EVENT_TABLET_PAD_RING: + case LIBINPUT_EVENT_TABLET_PAD_STRIP: + case LIBINPUT_EVENT_TABLET_PAD_BUTTON: + case LIBINPUT_EVENT_TABLET_PAD_MODE: + libinput_event_tablet_pad_destroy( + libinput_event_get_tablet_pad_event(event)); + break; default: break; } @@ -2402,18 +2415,24 @@ void tablet_pad_notify_button(struct libinput_device *device, uint64_t time, int32_t button, - enum libinput_button_state state) + enum libinput_button_state state, + struct libinput_tablet_pad_mode_group *group) { struct libinput_event_tablet_pad *button_event; + unsigned int mode; button_event = zalloc(sizeof *button_event); if (!button_event) return; + mode = libinput_tablet_pad_mode_group_get_mode(group); + *button_event = (struct libinput_event_tablet_pad) { .time = time, .button.number = button, .button.state = state, + .mode_group = libinput_tablet_pad_mode_group_ref(group), + .mode = mode, }; post_device_event(device, @@ -2427,19 +2446,25 @@ tablet_pad_notify_ring(struct libinput_device *device, uint64_t time, unsigned int number, double value, - enum libinput_tablet_pad_ring_axis_source source) + enum libinput_tablet_pad_ring_axis_source source, + struct libinput_tablet_pad_mode_group *group) { struct libinput_event_tablet_pad *ring_event; + unsigned int mode; ring_event = zalloc(sizeof *ring_event); if (!ring_event) return; + mode = libinput_tablet_pad_mode_group_get_mode(group); + *ring_event = (struct libinput_event_tablet_pad) { .time = time, .ring.number = number, .ring.position = value, .ring.source = source, + .mode_group = libinput_tablet_pad_mode_group_ref(group), + .mode = mode, }; post_device_event(device, @@ -2453,19 +2478,25 @@ tablet_pad_notify_strip(struct libinput_device *device, uint64_t time, unsigned int number, double value, - enum libinput_tablet_pad_strip_axis_source source) + enum libinput_tablet_pad_strip_axis_source source, + struct libinput_tablet_pad_mode_group *group) { struct libinput_event_tablet_pad *strip_event; + unsigned int mode; strip_event = zalloc(sizeof *strip_event); if (!strip_event) return; + mode = libinput_tablet_pad_mode_group_get_mode(group); + *strip_event = (struct libinput_event_tablet_pad) { .time = time, .strip.number = number, .strip.position = value, .strip.source = source, + .mode_group = libinput_tablet_pad_mode_group_ref(group), + .mode = mode, }; post_device_event(device, @@ -2835,61 +2866,78 @@ libinput_device_tablet_pad_get_num_strips(struct libinput_device *device) LIBINPUT_EXPORT int libinput_device_tablet_pad_get_num_mode_groups(struct libinput_device *device) { - return 0; + return evdev_device_tablet_pad_get_num_mode_groups((struct evdev_device *)device); } LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group* libinput_device_tablet_pad_get_mode_group(struct libinput_device *device, unsigned int index) { - return NULL; + return evdev_device_tablet_pad_get_mode_group((struct evdev_device *)device, + index); } LIBINPUT_EXPORT unsigned int libinput_tablet_pad_mode_group_get_num_modes( struct libinput_tablet_pad_mode_group *group) { - return 1; + return group->num_modes; } LIBINPUT_EXPORT unsigned int libinput_tablet_pad_mode_group_get_mode(struct libinput_tablet_pad_mode_group *group) { - return 0; + return group->current_mode; } LIBINPUT_EXPORT unsigned int libinput_tablet_pad_mode_group_get_index(struct libinput_tablet_pad_mode_group *group) { - return 0; + return group->index; } LIBINPUT_EXPORT int libinput_tablet_pad_mode_group_has_button(struct libinput_tablet_pad_mode_group *group, unsigned int button) { - return 1; + if ((int)button >= + libinput_device_tablet_pad_get_num_buttons(group->device)) + return 0; + + return !!(group->button_mask & (1 << button)); } LIBINPUT_EXPORT int libinput_tablet_pad_mode_group_has_ring(struct libinput_tablet_pad_mode_group *group, unsigned int ring) { - return 1; + if ((int)ring >= + libinput_device_tablet_pad_get_num_rings(group->device)) + return 0; + + return !!(group->ring_mask & (1 << ring)); } LIBINPUT_EXPORT int libinput_tablet_pad_mode_group_has_strip(struct libinput_tablet_pad_mode_group *group, unsigned int strip) { - return 1; + if ((int)strip >= + libinput_device_tablet_pad_get_num_strips(group->device)) + return 0; + + return !!(group->strip_mask & (1 << strip)); } LIBINPUT_EXPORT int libinput_tablet_pad_mode_group_button_is_toggle(struct libinput_tablet_pad_mode_group *group, unsigned int button) { - return 0; + if ((int)button >= + libinput_device_tablet_pad_get_num_buttons(group->device)) + return 0; + + return !!(group->toggle_button_mask & (1 << button)); } LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group * @@ -2911,7 +2959,7 @@ libinput_tablet_pad_mode_group_unref( return group; list_remove(&group->link); - free(group); + group->destroy(group); return NULL; }