diff options
Diffstat (limited to 'backend/libinput')
-rw-r--r-- | backend/libinput/backend.c | 204 | ||||
-rw-r--r-- | backend/libinput/events.c | 294 | ||||
-rw-r--r-- | backend/libinput/keyboard.c | 83 | ||||
-rw-r--r-- | backend/libinput/pointer.c | 136 | ||||
-rw-r--r-- | backend/libinput/switch.c | 55 | ||||
-rw-r--r-- | backend/libinput/tablet_pad.c | 183 | ||||
-rw-r--r-- | backend/libinput/tablet_tool.c | 371 | ||||
-rw-r--r-- | backend/libinput/touch.c | 97 |
8 files changed, 1423 insertions, 0 deletions
diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c new file mode 100644 index 00000000..8106af00 --- /dev/null +++ b/backend/libinput/backend.c @@ -0,0 +1,204 @@ +#include <assert.h> +#include <libinput.h> +#include <stdlib.h> +#include <wlr/backend/interface.h> +#include <wlr/backend/session.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" +#include "util/signal.h" + +static struct wlr_libinput_backend *get_libinput_backend_from_backend( + struct wlr_backend *wlr_backend) { + assert(wlr_backend_is_libinput(wlr_backend)); + return (struct wlr_libinput_backend *)wlr_backend; +} + +static int libinput_open_restricted(const char *path, + int flags, void *_backend) { + struct wlr_libinput_backend *backend = _backend; + return wlr_session_open_file(backend->session, path); +} + +static void libinput_close_restricted(int fd, void *_backend) { + struct wlr_libinput_backend *backend = _backend; + wlr_session_close_file(backend->session, fd); +} + +static const struct libinput_interface libinput_impl = { + .open_restricted = libinput_open_restricted, + .close_restricted = libinput_close_restricted +}; + +static int handle_libinput_readable(int fd, uint32_t mask, void *_backend) { + struct wlr_libinput_backend *backend = _backend; + if (libinput_dispatch(backend->libinput_context) != 0) { + wlr_log(WLR_ERROR, "Failed to dispatch libinput"); + // TODO: some kind of abort? + return 0; + } + struct libinput_event *event; + while ((event = libinput_get_event(backend->libinput_context))) { + handle_libinput_event(backend, event); + libinput_event_destroy(event); + } + return 0; +} + +static void log_libinput(struct libinput *libinput_context, + enum libinput_log_priority priority, const char *fmt, va_list args) { + _wlr_vlog(WLR_ERROR, fmt, args); +} + +static bool backend_start(struct wlr_backend *wlr_backend) { + struct wlr_libinput_backend *backend = + get_libinput_backend_from_backend(wlr_backend); + wlr_log(WLR_DEBUG, "Initializing libinput"); + + backend->libinput_context = libinput_udev_create_context(&libinput_impl, + backend, backend->session->udev); + if (!backend->libinput_context) { + wlr_log(WLR_ERROR, "Failed to create libinput context"); + return false; + } + + if (libinput_udev_assign_seat(backend->libinput_context, + backend->session->seat) != 0) { + wlr_log(WLR_ERROR, "Failed to assign libinput seat"); + return false; + } + + // TODO: More sophisticated logging + libinput_log_set_handler(backend->libinput_context, log_libinput); + libinput_log_set_priority(backend->libinput_context, LIBINPUT_LOG_PRIORITY_ERROR); + + int libinput_fd = libinput_get_fd(backend->libinput_context); + char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES"); + if (no_devs) { + if (strcmp(no_devs, "1") != 0) { + no_devs = NULL; + } + } + if (!no_devs && backend->wlr_device_lists.length == 0) { + handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend); + if (backend->wlr_device_lists.length == 0) { + wlr_log(WLR_ERROR, "libinput initialization failed, no input devices"); + wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check"); + return false; + } + } + + struct wl_event_loop *event_loop = + wl_display_get_event_loop(backend->display); + if (backend->input_event) { + wl_event_source_remove(backend->input_event); + } + backend->input_event = wl_event_loop_add_fd(event_loop, libinput_fd, + WL_EVENT_READABLE, handle_libinput_readable, backend); + if (!backend->input_event) { + wlr_log(WLR_ERROR, "Failed to create input event on event loop"); + return false; + } + wlr_log(WLR_DEBUG, "libinput successfully initialized"); + return true; +} + +static void backend_destroy(struct wlr_backend *wlr_backend) { + if (!wlr_backend) { + return; + } + struct wlr_libinput_backend *backend = + get_libinput_backend_from_backend(wlr_backend); + + for (size_t i = 0; i < backend->wlr_device_lists.length; i++) { + struct wl_list *wlr_devices = backend->wlr_device_lists.items[i]; + struct wlr_input_device *wlr_dev, *next; + wl_list_for_each_safe(wlr_dev, next, wlr_devices, link) { + wlr_input_device_destroy(wlr_dev); + } + free(wlr_devices); + } + + wlr_signal_emit_safe(&wlr_backend->events.destroy, wlr_backend); + + wl_list_remove(&backend->display_destroy.link); + wl_list_remove(&backend->session_signal.link); + + wlr_list_finish(&backend->wlr_device_lists); + if (backend->input_event) { + wl_event_source_remove(backend->input_event); + } + libinput_unref(backend->libinput_context); + free(backend); +} + +static const struct wlr_backend_impl backend_impl = { + .start = backend_start, + .destroy = backend_destroy, +}; + +bool wlr_backend_is_libinput(struct wlr_backend *b) { + return b->impl == &backend_impl; +} + +static void session_signal(struct wl_listener *listener, void *data) { + struct wlr_libinput_backend *backend = + wl_container_of(listener, backend, session_signal); + struct wlr_session *session = data; + + if (!backend->libinput_context) { + return; + } + + if (session->active) { + libinput_resume(backend->libinput_context); + } else { + libinput_suspend(backend->libinput_context); + } +} + +static void handle_display_destroy(struct wl_listener *listener, void *data) { + struct wlr_libinput_backend *backend = + wl_container_of(listener, backend, display_destroy); + backend_destroy(&backend->backend); +} + +struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, + struct wlr_session *session) { + struct wlr_libinput_backend *backend = + calloc(1, sizeof(struct wlr_libinput_backend)); + if (!backend) { + wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno)); + return NULL; + } + wlr_backend_init(&backend->backend, &backend_impl); + + if (!wlr_list_init(&backend->wlr_device_lists)) { + wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno)); + goto error_backend; + } + + backend->session = session; + backend->display = display; + + backend->session_signal.notify = session_signal; + wl_signal_add(&session->session_signal, &backend->session_signal); + + backend->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &backend->display_destroy); + + return &backend->backend; +error_backend: + free(backend); + return NULL; +} + +struct libinput_device *wlr_libinput_get_device_handle( + struct wlr_input_device *wlr_dev) { + struct wlr_libinput_input_device *dev = + (struct wlr_libinput_input_device *)wlr_dev; + return dev->handle; +} + +uint32_t usec_to_msec(uint64_t usec) { + return (uint32_t)(usec / 1000); +} diff --git a/backend/libinput/events.c b/backend/libinput/events.c new file mode 100644 index 00000000..a7a6c114 --- /dev/null +++ b/backend/libinput/events.c @@ -0,0 +1,294 @@ +#define _POSIX_C_SOURCE 200809L +#include <assert.h> +#include <libinput.h> +#include <stdlib.h> +#include <wayland-util.h> +#include <wlr/backend/session.h> +#include <wlr/interfaces/wlr_input_device.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" +#include "util/signal.h" + +struct wlr_libinput_input_device *get_libinput_device_from_device( + struct wlr_input_device *wlr_dev) { + assert(wlr_input_device_is_libinput(wlr_dev)); + return (struct wlr_libinput_input_device *)wlr_dev; +} + +struct wlr_input_device *get_appropriate_device( + enum wlr_input_device_type desired_type, + struct libinput_device *libinput_dev) { + struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev); + if (!wlr_devices) { + return NULL; + } + struct wlr_input_device *dev; + wl_list_for_each(dev, wlr_devices, link) { + if (dev->type == desired_type) { + return dev; + } + } + return NULL; +} + +static void input_device_destroy(struct wlr_input_device *wlr_dev) { + struct wlr_libinput_input_device *dev = + get_libinput_device_from_device(wlr_dev); + libinput_device_unref(dev->handle); + wl_list_remove(&dev->wlr_input_device.link); + free(dev); +} + +static const struct wlr_input_device_impl input_device_impl = { + .destroy = input_device_destroy, +}; + +static struct wlr_input_device *allocate_device( + struct wlr_libinput_backend *backend, + struct libinput_device *libinput_dev, struct wl_list *wlr_devices, + enum wlr_input_device_type type) { + int vendor = libinput_device_get_id_vendor(libinput_dev); + int product = libinput_device_get_id_product(libinput_dev); + const char *name = libinput_device_get_name(libinput_dev); + struct wlr_libinput_input_device *dev = + calloc(1, sizeof(struct wlr_libinput_input_device)); + if (dev == NULL) { + return NULL; + } + struct wlr_input_device *wlr_dev = &dev->wlr_input_device; + libinput_device_get_size(libinput_dev, + &wlr_dev->width_mm, &wlr_dev->height_mm); + const char *output_name = libinput_device_get_output_name(libinput_dev); + if (output_name != NULL) { + wlr_dev->output_name = strdup(output_name); + } + wl_list_insert(wlr_devices, &wlr_dev->link); + dev->handle = libinput_dev; + libinput_device_ref(libinput_dev); + wlr_input_device_init(wlr_dev, type, &input_device_impl, + name, vendor, product); + return wlr_dev; +} + +bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) { + return wlr_dev->impl == &input_device_impl; +} + +static void handle_device_added(struct wlr_libinput_backend *backend, + struct libinput_device *libinput_dev) { + /* + * Note: the wlr API exposes only devices with a single capability, because + * that meshes better with how Wayland does things and is a bit simpler. + * However, libinput devices often have multiple capabilities - in such + * cases we have to create several devices. + */ + int vendor = libinput_device_get_id_vendor(libinput_dev); + int product = libinput_device_get_id_product(libinput_dev); + const char *name = libinput_device_get_name(libinput_dev); + struct wl_list *wlr_devices = calloc(1, sizeof(struct wl_list)); + if (!wlr_devices) { + wlr_log(WLR_ERROR, "Allocation failed"); + return; + } + wl_list_init(wlr_devices); + wlr_log(WLR_DEBUG, "Added %s [%d:%d]", name, vendor, product); + + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) { + struct wlr_input_device *wlr_dev = allocate_device(backend, + libinput_dev, wlr_devices, WLR_INPUT_DEVICE_KEYBOARD); + if (!wlr_dev) { + goto fail; + } + wlr_dev->keyboard = create_libinput_keyboard(libinput_dev); + if (!wlr_dev->keyboard) { + free(wlr_dev); + goto fail; + } + wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + } + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_POINTER)) { + struct wlr_input_device *wlr_dev = allocate_device(backend, + libinput_dev, wlr_devices, WLR_INPUT_DEVICE_POINTER); + if (!wlr_dev) { + goto fail; + } + wlr_dev->pointer = create_libinput_pointer(libinput_dev); + if (!wlr_dev->pointer) { + free(wlr_dev); + goto fail; + } + wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + } + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) { + struct wlr_input_device *wlr_dev = allocate_device(backend, + libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TOUCH); + if (!wlr_dev) { + goto fail; + } + wlr_dev->touch = create_libinput_touch(libinput_dev); + if (!wlr_dev->touch) { + free(wlr_dev); + goto fail; + } + wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + } + if (libinput_device_has_capability(libinput_dev, + LIBINPUT_DEVICE_CAP_TABLET_TOOL)) { + struct wlr_input_device *wlr_dev = allocate_device(backend, + libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_TOOL); + if (!wlr_dev) { + goto fail; + } + wlr_dev->tablet = create_libinput_tablet(libinput_dev); + if (!wlr_dev->tablet) { + free(wlr_dev); + goto fail; + } + wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + } + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) { + struct wlr_input_device *wlr_dev = allocate_device(backend, + libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_PAD); + if (!wlr_dev) { + goto fail; + } + wlr_dev->tablet_pad = create_libinput_tablet_pad(libinput_dev); + if (!wlr_dev->tablet_pad) { + free(wlr_dev); + goto fail; + } + wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + } + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_GESTURE)) { + // TODO + } + if (libinput_device_has_capability( + libinput_dev, LIBINPUT_DEVICE_CAP_SWITCH)) { + struct wlr_input_device *wlr_dev = allocate_device(backend, + libinput_dev, wlr_devices, WLR_INPUT_DEVICE_SWITCH); + if (!wlr_dev) { + goto fail; + } + wlr_dev->lid_switch = create_libinput_switch(libinput_dev); + if (!wlr_dev->lid_switch) { + free(wlr_dev); + goto fail; + } + wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev); + } + + if (!wl_list_empty(wlr_devices)) { + libinput_device_set_user_data(libinput_dev, wlr_devices); + wlr_list_push(&backend->wlr_device_lists, wlr_devices); + } else { + free(wlr_devices); + } + return; + +fail: + wlr_log(WLR_ERROR, "Could not allocate new device"); + struct wlr_input_device *dev, *tmp_dev; + wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { + free(dev); + } + free(wlr_devices); +} + +static void handle_device_removed(struct wlr_libinput_backend *backend, + struct libinput_device *libinput_dev) { + struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev); + int vendor = libinput_device_get_id_vendor(libinput_dev); + int product = libinput_device_get_id_product(libinput_dev); + const char *name = libinput_device_get_name(libinput_dev); + wlr_log(WLR_DEBUG, "Removing %s [%d:%d]", name, vendor, product); + if (!wlr_devices) { + return; + } + struct wlr_input_device *dev, *tmp_dev; + wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { + wlr_input_device_destroy(dev); + } + for (size_t i = 0; i < backend->wlr_device_lists.length; i++) { + if (backend->wlr_device_lists.items[i] == wlr_devices) { + wlr_list_del(&backend->wlr_device_lists, i); + break; + } + } + free(wlr_devices); +} + +void handle_libinput_event(struct wlr_libinput_backend *backend, + struct libinput_event *event) { + struct libinput_device *libinput_dev = libinput_event_get_device(event); + enum libinput_event_type event_type = libinput_event_get_type(event); + switch (event_type) { + case LIBINPUT_EVENT_DEVICE_ADDED: + handle_device_added(backend, libinput_dev); + break; + case LIBINPUT_EVENT_DEVICE_REMOVED: + handle_device_removed(backend, libinput_dev); + break; + case LIBINPUT_EVENT_KEYBOARD_KEY: + handle_keyboard_key(event, libinput_dev); + break; + case LIBINPUT_EVENT_POINTER_MOTION: + handle_pointer_motion(event, libinput_dev); + break; + case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: + handle_pointer_motion_abs(event, libinput_dev); + break; + case LIBINPUT_EVENT_POINTER_BUTTON: + handle_pointer_button(event, libinput_dev); + break; + case LIBINPUT_EVENT_POINTER_AXIS: + handle_pointer_axis(event, libinput_dev); + break; + case LIBINPUT_EVENT_TOUCH_DOWN: + handle_touch_down(event, libinput_dev); + break; + case LIBINPUT_EVENT_TOUCH_UP: + handle_touch_up(event, libinput_dev); + break; + case LIBINPUT_EVENT_TOUCH_MOTION: + handle_touch_motion(event, libinput_dev); + break; + case LIBINPUT_EVENT_TOUCH_CANCEL: + handle_touch_cancel(event, libinput_dev); + break; + case LIBINPUT_EVENT_TOUCH_FRAME: + // no-op (at least for now) + break; + case LIBINPUT_EVENT_TABLET_TOOL_AXIS: + handle_tablet_tool_axis(event, libinput_dev); + break; + case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: + handle_tablet_tool_proximity(event, libinput_dev); + break; + case LIBINPUT_EVENT_TABLET_TOOL_TIP: + handle_tablet_tool_tip(event, libinput_dev); + break; + case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: + handle_tablet_tool_button(event, libinput_dev); + break; + case LIBINPUT_EVENT_TABLET_PAD_BUTTON: + handle_tablet_pad_button(event, libinput_dev); + break; + case LIBINPUT_EVENT_TABLET_PAD_RING: + handle_tablet_pad_ring(event, libinput_dev); + break; + case LIBINPUT_EVENT_TABLET_PAD_STRIP: + handle_tablet_pad_strip(event, libinput_dev); + break; + case LIBINPUT_EVENT_SWITCH_TOGGLE: + handle_switch_toggle(event, libinput_dev); + break; + default: + wlr_log(WLR_DEBUG, "Unknown libinput event %d", event_type); + break; + } +} diff --git a/backend/libinput/keyboard.c b/backend/libinput/keyboard.c new file mode 100644 index 00000000..93605e77 --- /dev/null +++ b/backend/libinput/keyboard.c @@ -0,0 +1,83 @@ +#include <assert.h> +#include <libinput.h> +#include <stdlib.h> +#include <wlr/backend/session.h> +#include <wlr/interfaces/wlr_keyboard.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" + +struct wlr_libinput_keyboard { + struct wlr_keyboard wlr_keyboard; + struct libinput_device *libinput_dev; +}; + +static const struct wlr_keyboard_impl impl; + +static struct wlr_libinput_keyboard *get_libinput_keyboard_from_keyboard( + struct wlr_keyboard *wlr_kb) { + assert(wlr_kb->impl == &impl); + return (struct wlr_libinput_keyboard *)wlr_kb; +} + +static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) { + struct wlr_libinput_keyboard *kb = + get_libinput_keyboard_from_keyboard(wlr_kb); + libinput_device_led_update(kb->libinput_dev, leds); +} + +static void keyboard_destroy(struct wlr_keyboard *wlr_kb) { + struct wlr_libinput_keyboard *kb = + get_libinput_keyboard_from_keyboard(wlr_kb); + libinput_device_unref(kb->libinput_dev); + free(kb); +} + +static const struct wlr_keyboard_impl impl = { + .destroy = keyboard_destroy, + .led_update = keyboard_set_leds +}; + +struct wlr_keyboard *create_libinput_keyboard( + struct libinput_device *libinput_dev) { + struct wlr_libinput_keyboard *kb = + calloc(1, sizeof(struct wlr_libinput_keyboard)); + if (kb == NULL) { + return NULL; + } + kb->libinput_dev = libinput_dev; + libinput_device_ref(libinput_dev); + libinput_device_led_update(libinput_dev, 0); + struct wlr_keyboard *wlr_kb = &kb->wlr_keyboard; + wlr_keyboard_init(wlr_kb, &impl); + return wlr_kb; +} + +void handle_keyboard_key(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_KEYBOARD, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a keyboard event for a device with no keyboards?"); + return; + } + struct libinput_event_keyboard *kbevent = + libinput_event_get_keyboard_event(event); + struct wlr_event_keyboard_key wlr_event = { 0 }; + wlr_event.time_msec = + usec_to_msec(libinput_event_keyboard_get_time_usec(kbevent)); + wlr_event.keycode = libinput_event_keyboard_get_key(kbevent); + enum libinput_key_state state = + libinput_event_keyboard_get_key_state(kbevent); + switch (state) { + case LIBINPUT_KEY_STATE_RELEASED: + wlr_event.state = WLR_KEY_RELEASED; + break; + case LIBINPUT_KEY_STATE_PRESSED: + wlr_event.state = WLR_KEY_PRESSED; + break; + } + wlr_event.update_state = true; + wlr_keyboard_notify_key(wlr_dev->keyboard, &wlr_event); +} diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c new file mode 100644 index 00000000..fb85cddd --- /dev/null +++ b/backend/libinput/pointer.c @@ -0,0 +1,136 @@ +#include <assert.h> +#include <libinput.h> +#include <stdlib.h> +#include <wlr/backend/session.h> +#include <wlr/interfaces/wlr_pointer.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" +#include "util/signal.h" + +struct wlr_pointer *create_libinput_pointer( + struct libinput_device *libinput_dev) { + assert(libinput_dev); + struct wlr_pointer *wlr_pointer = calloc(1, sizeof(struct wlr_pointer)); + if (!wlr_pointer) { + wlr_log(WLR_ERROR, "Unable to allocate wlr_pointer"); + return NULL; + } + wlr_pointer_init(wlr_pointer, NULL); + return wlr_pointer; +} + +void handle_pointer_motion(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); + return; + } + struct libinput_event_pointer *pevent = + libinput_event_get_pointer_event(event); + struct wlr_event_pointer_motion wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); + wlr_event.delta_x = libinput_event_pointer_get_dx(pevent); + wlr_event.delta_y = libinput_event_pointer_get_dy(pevent); + wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &wlr_event); +} + +void handle_pointer_motion_abs(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); + return; + } + struct libinput_event_pointer *pevent = + libinput_event_get_pointer_event(event); + struct wlr_event_pointer_motion_absolute wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); + wlr_event.x = libinput_event_pointer_get_absolute_x_transformed(pevent, 1); + wlr_event.y = libinput_event_pointer_get_absolute_y_transformed(pevent, 1); + wlr_signal_emit_safe(&wlr_dev->pointer->events.motion_absolute, &wlr_event); +} + +void handle_pointer_button(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); + return; + } + struct libinput_event_pointer *pevent = + libinput_event_get_pointer_event(event); + struct wlr_event_pointer_button wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); + wlr_event.button = libinput_event_pointer_get_button(pevent); + switch (libinput_event_pointer_get_button_state(pevent)) { + case LIBINPUT_BUTTON_STATE_PRESSED: + wlr_event.state = WLR_BUTTON_PRESSED; + break; + case LIBINPUT_BUTTON_STATE_RELEASED: + wlr_event.state = WLR_BUTTON_RELEASED; + break; + } + wlr_signal_emit_safe(&wlr_dev->pointer->events.button, &wlr_event); +} + +void handle_pointer_axis(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?"); + return; + } + struct libinput_event_pointer *pevent = + libinput_event_get_pointer_event(event); + struct wlr_event_pointer_axis wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); + switch (libinput_event_pointer_get_axis_source(pevent)) { + case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: + wlr_event.source = WLR_AXIS_SOURCE_WHEEL; + break; + case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: + wlr_event.source = WLR_AXIS_SOURCE_FINGER; + break; + case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: + wlr_event.source = WLR_AXIS_SOURCE_CONTINUOUS; + break; + case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: + wlr_event.source = WLR_AXIS_SOURCE_WHEEL_TILT; + break; + } + enum libinput_pointer_axis axies[] = { + LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, + LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, + }; + for (size_t i = 0; i < sizeof(axies) / sizeof(axies[0]); ++i) { + if (libinput_event_pointer_has_axis(pevent, axies[i])) { + switch (axies[i]) { + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL; + break; + } + wlr_event.delta = + libinput_event_pointer_get_axis_value(pevent, axies[i]); + wlr_event.delta_discrete = + libinput_event_pointer_get_axis_value_discrete(pevent, axies[i]); + wlr_signal_emit_safe(&wlr_dev->pointer->events.axis, &wlr_event); + } + } +} diff --git a/backend/libinput/switch.c b/backend/libinput/switch.c new file mode 100644 index 00000000..393460b0 --- /dev/null +++ b/backend/libinput/switch.c @@ -0,0 +1,55 @@ +#include <assert.h> +#include <libinput.h> +#include <stdlib.h> +#include <wlr/backend/session.h> +#include <wlr/interfaces/wlr_switch.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" +#include "util/signal.h" + +struct wlr_switch *create_libinput_switch( + struct libinput_device *libinput_dev) { + assert(libinput_dev); + struct wlr_switch *wlr_switch = calloc(1, sizeof(struct wlr_switch)); + if (!wlr_switch) { + wlr_log(WLR_ERROR, "Unable to allocate wlr_switch"); + return NULL; + } + wlr_switch_init(wlr_switch, NULL); + wlr_log(WLR_DEBUG, "Created switch for device %s", libinput_device_get_name(libinput_dev)); + return wlr_switch; +} + +void handle_switch_toggle(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_SWITCH, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a switch event for a device with no switch?"); + return; + } + struct libinput_event_switch *sevent = + libinput_event_get_switch_event (event); + struct wlr_event_switch_toggle wlr_event = { 0 }; + wlr_event.device = wlr_dev; + switch (libinput_event_switch_get_switch(sevent)) { + case LIBINPUT_SWITCH_LID: + wlr_event.switch_type = WLR_SWITCH_TYPE_LID; + break; + case LIBINPUT_SWITCH_TABLET_MODE: + wlr_event.switch_type = WLR_SWITCH_TYPE_TABLET_MODE; + break; + } + switch (libinput_event_switch_get_switch_state(sevent)) { + case LIBINPUT_SWITCH_STATE_OFF: + wlr_event.switch_state = WLR_SWITCH_STATE_OFF; + break; + case LIBINPUT_SWITCH_STATE_ON: + wlr_event.switch_state = WLR_SWITCH_STATE_ON; + break; + } + wlr_event.time_msec = + usec_to_msec(libinput_event_switch_get_time_usec(sevent)); + wlr_signal_emit_safe(&wlr_dev->lid_switch->events.toggle, &wlr_event); +} diff --git a/backend/libinput/tablet_pad.c b/backend/libinput/tablet_pad.c new file mode 100644 index 00000000..b053b9a0 --- /dev/null +++ b/backend/libinput/tablet_pad.c @@ -0,0 +1,183 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#include <assert.h> +#include <string.h> +#include <libinput.h> +#include <stdlib.h> +#include <wlr/backend/session.h> +#include <wlr/interfaces/wlr_tablet_pad.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" +#include "util/signal.h" + +// FIXME: Decide on how to alloc/count here +static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad, + struct libinput_device *device, unsigned int index) { + struct libinput_tablet_pad_mode_group *li_group = + libinput_device_tablet_pad_get_mode_group(device, index); + struct wlr_tablet_pad_group *group = + calloc(1, sizeof(struct wlr_tablet_pad_group)); + if (!group) { + return; + } + + for (size_t i = 0; i < pad->ring_count; ++i) { + if (libinput_tablet_pad_mode_group_has_ring(li_group, i)) { + ++group->ring_count; + } + } + group->rings = calloc(sizeof(unsigned int), group->ring_count); + size_t ring = 0; + for (size_t i = 0; i < pad->ring_count; ++i) { + if (libinput_tablet_pad_mode_group_has_ring(li_group, i)) { + group->rings[ring++] = i; + } + } + + for (size_t i = 0; i < pad->strip_count; ++i) { + if (libinput_tablet_pad_mode_group_has_strip(li_group, i)) { + ++group->strip_count; + } + } + group->strips = calloc(sizeof(unsigned int), group->strip_count); + size_t strip = 0; + for (size_t i = 0; i < pad->strip_count; ++i) { + if (libinput_tablet_pad_mode_group_has_strip(li_group, i)) { + group->strips[strip++] = i; + } + } + + for (size_t i = 0; i < pad->button_count; ++i) { + if (libinput_tablet_pad_mode_group_has_button(li_group, i)) { + ++group->button_count; + } + } + group->buttons = calloc(sizeof(unsigned int), group->button_count); + size_t button = 0; + for (size_t i = 0; i < pad->button_count; ++i) { + if (libinput_tablet_pad_mode_group_has_button(li_group, i)) { + group->buttons[button++] = i; + } + } + + group->mode_count = libinput_tablet_pad_mode_group_get_num_modes(li_group); + wl_list_insert(&pad->groups, &group->link); +} + +struct wlr_tablet_pad *create_libinput_tablet_pad( + struct libinput_device *libinput_dev) { + assert(libinput_dev); + struct wlr_tablet_pad *wlr_tablet_pad = + calloc(1, sizeof(struct wlr_tablet_pad)); + if (!wlr_tablet_pad) { + wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_pad"); + return NULL; + } + + wlr_tablet_pad->button_count = + libinput_device_tablet_pad_get_num_buttons(libinput_dev); + wlr_tablet_pad->ring_count = + libinput_device_tablet_pad_get_num_rings(libinput_dev); + wlr_tablet_pad->strip_count = + libinput_device_tablet_pad_get_num_strips(libinput_dev); + + wlr_list_init(&wlr_tablet_pad->paths); + struct udev_device *udev = libinput_device_get_udev_device(libinput_dev); + wlr_list_push(&wlr_tablet_pad->paths, strdup(udev_device_get_syspath(udev))); + + wl_list_init(&wlr_tablet_pad->groups); + int groups = libinput_device_tablet_pad_get_num_mode_groups(libinput_dev); + for (int i = 0; i < groups; ++i) { + add_pad_group_from_libinput(wlr_tablet_pad, libinput_dev, i); + } + + wlr_tablet_pad_init(wlr_tablet_pad, NULL); + return wlr_tablet_pad; +} + +void handle_tablet_pad_button(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a tablet pad event for a device with no tablet pad?"); + return; + } + struct libinput_event_tablet_pad *pevent = + libinput_event_get_tablet_pad_event(event); + struct wlr_event_tablet_pad_button wlr_event = { 0 }; + wlr_event.time_msec = + usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); + wlr_event.button = libinput_event_tablet_pad_get_button_number(pevent); + wlr_event.mode = libinput_event_tablet_pad_get_mode(pevent); + wlr_event.group = libinput_tablet_pad_mode_group_get_index( + libinput_event_tablet_pad_get_mode_group(pevent)); + switch (libinput_event_tablet_pad_get_button_state(pevent)) { + case LIBINPUT_BUTTON_STATE_PRESSED: + wlr_event.state = WLR_BUTTON_PRESSED; + break; + case LIBINPUT_BUTTON_STATE_RELEASED: + wlr_event.state = WLR_BUTTON_RELEASED; + break; + } + wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.button, &wlr_event); +} + +void handle_tablet_pad_ring(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a tablet pad event for a device with no tablet pad?"); + return; + } + struct libinput_event_tablet_pad *pevent = + libinput_event_get_tablet_pad_event(event); + struct wlr_event_tablet_pad_ring wlr_event = { 0 }; + wlr_event.time_msec = + usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); + wlr_event.ring = libinput_event_tablet_pad_get_ring_number(pevent); + wlr_event.position = libinput_event_tablet_pad_get_ring_position(pevent); + wlr_event.mode = libinput_event_tablet_pad_get_mode(pevent); + switch (libinput_event_tablet_pad_get_ring_source(pevent)) { + case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN: + wlr_event.source = WLR_TABLET_PAD_RING_SOURCE_UNKNOWN; + break; + case LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER: + wlr_event.source = WLR_TABLET_PAD_RING_SOURCE_FINGER; + break; + } + wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.ring, &wlr_event); +} + +void handle_tablet_pad_strip(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a tablet pad event for a device with no tablet pad?"); + return; + } + struct libinput_event_tablet_pad *pevent = + libinput_event_get_tablet_pad_event(event); + struct wlr_event_tablet_pad_strip wlr_event = { 0 }; + wlr_event.time_msec = + usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); + wlr_event.strip = libinput_event_tablet_pad_get_strip_number(pevent); + wlr_event.position = libinput_event_tablet_pad_get_strip_position(pevent); + wlr_event.mode = libinput_event_tablet_pad_get_mode(pevent); + switch (libinput_event_tablet_pad_get_strip_source(pevent)) { + case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN: + wlr_event.source = WLR_TABLET_PAD_STRIP_SOURCE_UNKNOWN; + break; + case LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER: + wlr_event.source = WLR_TABLET_PAD_STRIP_SOURCE_FINGER; + break; + } + wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.strip, &wlr_event); +} diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c new file mode 100644 index 00000000..4e87b700 --- /dev/null +++ b/backend/libinput/tablet_tool.c @@ -0,0 +1,371 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif +#include <string.h> +#include <assert.h> +#include <libinput.h> +#include <stdlib.h> +#include <wayland-util.h> +#include <wlr/backend/session.h> +#include <wlr/interfaces/wlr_tablet_tool.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" +#include "util/signal.h" + +static struct wlr_tablet_impl tablet_impl; + +static bool tablet_is_libinput(struct wlr_tablet *tablet) { + return tablet->impl == &tablet_impl; +} + +struct wlr_libinput_tablet_tool { + struct wlr_tablet_tool wlr_tool; + + struct libinput_tablet_tool *libinput_tool; + + bool unique; + // Refcount for destroy + release + size_t pad_refs; +}; + +// TODO: Maybe this should be a wlr_list? Do we keep it, or want to get rid of +// it? +struct tablet_tool_list_elem { + struct wl_list link; + + struct wlr_libinput_tablet_tool *tool; +}; + +struct wlr_libinput_tablet { + struct wlr_tablet wlr_tablet; + + struct wl_list tools; // tablet_tool_list_elem::link +}; + +static void destroy_tool(struct wlr_libinput_tablet_tool *tool) { + wlr_signal_emit_safe(&tool->wlr_tool.events.destroy, &tool->wlr_tool); + libinput_tablet_tool_ref(tool->libinput_tool); + libinput_tablet_tool_set_user_data(tool->libinput_tool, NULL); + free(tool); +} + + +static void destroy_tablet(struct wlr_tablet *wlr_tablet) { + assert(tablet_is_libinput(wlr_tablet)); + struct wlr_libinput_tablet *tablet = + wl_container_of(wlr_tablet, tablet, wlr_tablet); + + struct tablet_tool_list_elem *pos; + struct tablet_tool_list_elem *tmp; + wl_list_for_each_safe(pos, tmp, &tablet->tools, link) { + struct wlr_libinput_tablet_tool *tool = pos->tool; + wl_list_remove(&pos->link); + free(pos); + + if (--tool->pad_refs == 0) { + destroy_tool(tool); + } + } + + free(tablet); +} + +static struct wlr_tablet_impl tablet_impl = { + .destroy = destroy_tablet, +}; + +struct wlr_tablet *create_libinput_tablet( + struct libinput_device *libinput_dev) { + assert(libinput_dev); + struct wlr_libinput_tablet *libinput_tablet = + calloc(1, sizeof(struct wlr_libinput_tablet)); + if (!libinput_tablet) { + wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_tool"); + return NULL; + } + struct wlr_tablet *wlr_tablet = &libinput_tablet->wlr_tablet; + + wlr_list_init(&wlr_tablet->paths); + struct udev_device *udev = libinput_device_get_udev_device(libinput_dev); + wlr_list_push(&wlr_tablet->paths, strdup(udev_device_get_syspath(udev))); + wlr_tablet->name = strdup(libinput_device_get_name(libinput_dev)); + wl_list_init(&libinput_tablet->tools); + + wlr_tablet_init(wlr_tablet, &tablet_impl); + return wlr_tablet; +} + +static enum wlr_tablet_tool_type wlr_type_from_libinput_type( + enum libinput_tablet_tool_type value) { + switch (value) { + case LIBINPUT_TABLET_TOOL_TYPE_PEN: + return WLR_TABLET_TOOL_TYPE_PEN; + case LIBINPUT_TABLET_TOOL_TYPE_ERASER: + return WLR_TABLET_TOOL_TYPE_ERASER; + case LIBINPUT_TABLET_TOOL_TYPE_BRUSH: + return WLR_TABLET_TOOL_TYPE_BRUSH; + case LIBINPUT_TABLET_TOOL_TYPE_PENCIL: + return WLR_TABLET_TOOL_TYPE_PENCIL; + case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH: + return WLR_TABLET_TOOL_TYPE_AIRBRUSH; + case LIBINPUT_TABLET_TOOL_TYPE_MOUSE: + return WLR_TABLET_TOOL_TYPE_MOUSE; + case LIBINPUT_TABLET_TOOL_TYPE_LENS: + return WLR_TABLET_TOOL_TYPE_LENS; + } + + assert(false && "UNREACHABLE"); +} + +static struct wlr_libinput_tablet_tool *get_wlr_tablet_tool( + struct libinput_tablet_tool *tool) { + struct wlr_libinput_tablet_tool *ret = + libinput_tablet_tool_get_user_data(tool); + + if (ret) { + return ret; + } + + ret = calloc(1, sizeof(struct wlr_libinput_tablet_tool)); + if (!ret) { + return NULL; + } + + ret->libinput_tool = libinput_tablet_tool_ref(tool); + ret->wlr_tool.pressure = libinput_tablet_tool_has_pressure(tool); + ret->wlr_tool.distance = libinput_tablet_tool_has_distance(tool); + ret->wlr_tool.tilt = libinput_tablet_tool_has_tilt(tool); + ret->wlr_tool.rotation = libinput_tablet_tool_has_rotation(tool); + ret->wlr_tool.slider = libinput_tablet_tool_has_slider(tool); + ret->wlr_tool.wheel = libinput_tablet_tool_has_wheel(tool); + + ret->wlr_tool.hardware_serial = libinput_tablet_tool_get_serial(tool); + ret->wlr_tool.hardware_wacom = libinput_tablet_tool_get_tool_id(tool); + ret->wlr_tool.type = wlr_type_from_libinput_type( + libinput_tablet_tool_get_type(tool)); + + ret->unique = libinput_tablet_tool_is_unique(tool); + + wl_signal_init(&ret->wlr_tool.events.destroy); + + libinput_tablet_tool_set_user_data(tool, ret); + return ret; +} + +static void ensure_tool_reference(struct wlr_libinput_tablet_tool *tool, + struct wlr_tablet *wlr_dev) { + assert(tablet_is_libinput(wlr_dev)); + struct wlr_libinput_tablet *tablet = + wl_container_of(wlr_dev, tablet, wlr_tablet); + + struct tablet_tool_list_elem *pos; + wl_list_for_each(pos, &tablet->tools, link) { + if (pos->tool == tool) { // We already have a ref + // XXX: We *could* optimize the tool to the front of + // the list here, since we will probably get the next + // couple of events from the same tool. + // BUT the list should always be rather short (probably + // single digit amount of tools) so it might be more + // work than it saves + return; + } + } + + struct tablet_tool_list_elem *new = + calloc(1, sizeof(struct tablet_tool_list_elem)); + if (!new) { + wlr_log(WLR_ERROR, "Failed to allocate memory for tracking tablet tool"); + return; + } + + new->tool = tool; + wl_list_insert(&tablet->tools, &new->link); + ++tool->pad_refs; +} + +void handle_tablet_tool_axis(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a tablet tool event for a device with no tablet tools?"); + return; + } + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_event_tablet_tool_axis wlr_event = { 0 }; + struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( + libinput_event_tablet_tool_get_tool(tevent)); + ensure_tool_reference(tool, wlr_dev->tablet); + + wlr_event.device = wlr_dev; + wlr_event.tool = &tool->wlr_tool; + wlr_event.time_msec = + usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); + if (libinput_event_tablet_tool_x_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_X; + wlr_event.x = libinput_event_tablet_tool_get_x_transformed(tevent, 1); + wlr_event.dx = libinput_event_tablet_tool_get_dx(tevent); + } + if (libinput_event_tablet_tool_y_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_Y; + wlr_event.y = libinput_event_tablet_tool_get_y_transformed(tevent, 1); + wlr_event.dy = libinput_event_tablet_tool_get_dy(tevent); + } + if (libinput_event_tablet_tool_pressure_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_PRESSURE; + wlr_event.pressure = libinput_event_tablet_tool_get_pressure(tevent); + } + if (libinput_event_tablet_tool_distance_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_DISTANCE; + wlr_event.distance = libinput_event_tablet_tool_get_distance(tevent); + } + if (libinput_event_tablet_tool_tilt_x_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_X; + wlr_event.tilt_x = libinput_event_tablet_tool_get_tilt_x(tevent); + } + if (libinput_event_tablet_tool_tilt_y_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_Y; + wlr_event.tilt_y = libinput_event_tablet_tool_get_tilt_y(tevent); + } + if (libinput_event_tablet_tool_rotation_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_ROTATION; + wlr_event.rotation = libinput_event_tablet_tool_get_rotation(tevent); + } + if (libinput_event_tablet_tool_slider_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_SLIDER; + wlr_event.slider = libinput_event_tablet_tool_get_slider_position(tevent); + } + if (libinput_event_tablet_tool_wheel_has_changed(tevent)) { + wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL; + wlr_event.wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent); + } + wlr_signal_emit_safe(&wlr_dev->tablet->events.axis, &wlr_event); +} + +void handle_tablet_tool_proximity(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a tablet tool event for a device with no tablet tools?"); + return; + } + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_event_tablet_tool_proximity wlr_event = { 0 }; + struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( + libinput_event_tablet_tool_get_tool(tevent)); + ensure_tool_reference(tool, wlr_dev->tablet); + + wlr_event.tool = &tool->wlr_tool; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); + switch (libinput_event_tablet_tool_get_proximity_state(tevent)) { + case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT: + wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_OUT; + break; + case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN: + wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_IN; + break; + } + wlr_signal_emit_safe(&wlr_dev->tablet->events.proximity, &wlr_event); + + if (libinput_event_tablet_tool_get_proximity_state(tevent) == + LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) { + handle_tablet_tool_axis(event, libinput_dev); + } + + // If the tool is not unique, libinput will not find it again after the + // proximity out, so we should destroy it + if (!tool->unique && + libinput_event_tablet_tool_get_proximity_state(tevent) == + LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) { + // The tool isn't unique, it can't be on multiple tablets + assert(tool->pad_refs == 1); + assert(tablet_is_libinput(wlr_dev->tablet)); + struct wlr_libinput_tablet *tablet = + wl_container_of(wlr_dev->tablet, tablet, wlr_tablet); + struct tablet_tool_list_elem *pos; + struct tablet_tool_list_elem *tmp; + + wl_list_for_each_safe(pos, tmp, &tablet->tools, link) { + if (pos->tool == tool) { + wl_list_remove(&pos->link); + free(pos); + break; + } + } + + destroy_tool(tool); + } +} + +void handle_tablet_tool_tip(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a tablet tool event for a device with no tablet tools?"); + return; + } + handle_tablet_tool_axis(event, libinput_dev); + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_event_tablet_tool_tip wlr_event = { 0 }; + struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( + libinput_event_tablet_tool_get_tool(tevent)); + ensure_tool_reference(tool, wlr_dev->tablet); + + wlr_event.device = wlr_dev; + wlr_event.tool = &tool->wlr_tool; + wlr_event.time_msec = + usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); + switch (libinput_event_tablet_tool_get_tip_state(tevent)) { + case LIBINPUT_TABLET_TOOL_TIP_UP: + wlr_event.state = WLR_TABLET_TOOL_TIP_UP; + break; + case LIBINPUT_TABLET_TOOL_TIP_DOWN: + wlr_event.state = WLR_TABLET_TOOL_TIP_DOWN; + break; + } + wlr_signal_emit_safe(&wlr_dev->tablet->events.tip, &wlr_event); +} + +void handle_tablet_tool_button(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, + "Got a tablet tool event for a device with no tablet tools?"); + return; + } + handle_tablet_tool_axis(event, libinput_dev); + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_event_tablet_tool_button wlr_event = { 0 }; + struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( + libinput_event_tablet_tool_get_tool(tevent)); + ensure_tool_reference(tool, wlr_dev->tablet); + + wlr_event.device = wlr_dev; + wlr_event.tool = &tool->wlr_tool; + wlr_event.time_msec = + usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); + wlr_event.button = libinput_event_tablet_tool_get_button(tevent); + switch (libinput_event_tablet_tool_get_button_state(tevent)) { + case LIBINPUT_BUTTON_STATE_RELEASED: + wlr_event.state = WLR_BUTTON_RELEASED; + break; + case LIBINPUT_BUTTON_STATE_PRESSED: + wlr_event.state = WLR_BUTTON_PRESSED; + break; + } + wlr_signal_emit_safe(&wlr_dev->tablet->events.button, &wlr_event); +} diff --git a/backend/libinput/touch.c b/backend/libinput/touch.c new file mode 100644 index 00000000..cb9b0e36 --- /dev/null +++ b/backend/libinput/touch.c @@ -0,0 +1,97 @@ +#include <assert.h> +#include <libinput.h> +#include <stdlib.h> +#include <wlr/backend/session.h> +#include <wlr/interfaces/wlr_touch.h> +#include <wlr/types/wlr_input_device.h> +#include <wlr/util/log.h> +#include "backend/libinput.h" +#include "util/signal.h" + +struct wlr_touch *create_libinput_touch( + struct libinput_device *libinput_dev) { + assert(libinput_dev); + struct wlr_touch *wlr_touch = calloc(1, sizeof(struct wlr_touch)); + if (!wlr_touch) { + wlr_log(WLR_ERROR, "Unable to allocate wlr_touch"); + return NULL; + } + wlr_touch_init(wlr_touch, NULL); + return wlr_touch; +} + +void handle_touch_down(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); + return; + } + struct libinput_event_touch *tevent = + libinput_event_get_touch_event(event); + struct wlr_event_touch_down wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_touch_get_time_usec(tevent)); + wlr_event.touch_id = libinput_event_touch_get_slot(tevent); + wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1); + wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1); + wlr_signal_emit_safe(&wlr_dev->touch->events.down, &wlr_event); +} + +void handle_touch_up(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); + return; + } + struct libinput_event_touch *tevent = + libinput_event_get_touch_event(event); + struct wlr_event_touch_up wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_touch_get_time_usec(tevent)); + wlr_event.touch_id = libinput_event_touch_get_slot(tevent); + wlr_signal_emit_safe(&wlr_dev->touch->events.up, &wlr_event); +} + +void handle_touch_motion(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); + return; + } + struct libinput_event_touch *tevent = + libinput_event_get_touch_event(event); + struct wlr_event_touch_motion wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_touch_get_time_usec(tevent)); + wlr_event.touch_id = libinput_event_touch_get_slot(tevent); + wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1); + wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1); + wlr_signal_emit_safe(&wlr_dev->touch->events.motion, &wlr_event); +} + +void handle_touch_cancel(struct libinput_event *event, + struct libinput_device *libinput_dev) { + struct wlr_input_device *wlr_dev = + get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev); + if (!wlr_dev) { + wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?"); + return; + } + struct libinput_event_touch *tevent = + libinput_event_get_touch_event(event); + struct wlr_event_touch_cancel wlr_event = { 0 }; + wlr_event.device = wlr_dev; + wlr_event.time_msec = + usec_to_msec(libinput_event_touch_get_time_usec(tevent)); + wlr_event.touch_id = libinput_event_touch_get_slot(tevent); + wlr_signal_emit_safe(&wlr_dev->touch->events.cancel, &wlr_event); +} |