2023-12-01 22:12:00 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <linux/input-event-codes.h>
|
|
|
|
|
#include <wlr/types/wlr_tablet_pad.h>
|
|
|
|
|
#include <wlr/types/wlr_tablet_tool.h>
|
|
|
|
|
#include <wlr/util/log.h>
|
|
|
|
|
#include "common/macros.h"
|
|
|
|
|
#include "common/mem.h"
|
|
|
|
|
#include "config/rcxml.h"
|
|
|
|
|
#include "input/cursor.h"
|
2023-12-29 10:10:41 +01:00
|
|
|
#include "input/tablet.h"
|
2023-12-01 22:12:00 +01:00
|
|
|
|
2024-05-07 19:35:44 +02:00
|
|
|
static bool
|
|
|
|
|
tool_supports_absolute_motion(struct wlr_tablet_tool *tool)
|
|
|
|
|
{
|
|
|
|
|
switch (tool->type) {
|
|
|
|
|
case WLR_TABLET_TOOL_TYPE_MOUSE:
|
|
|
|
|
case WLR_TABLET_TOOL_TYPE_LENS:
|
|
|
|
|
return false;
|
|
|
|
|
default:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-01 18:26:44 +01:00
|
|
|
static void
|
|
|
|
|
adjust_for_tablet_area(double tablet_width, double tablet_height,
|
|
|
|
|
struct wlr_fbox box, double *x, double *y)
|
|
|
|
|
{
|
|
|
|
|
if ((!box.x && !box.y && !box.width && !box.height)
|
|
|
|
|
|| !tablet_width || !tablet_height) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!box.width) {
|
|
|
|
|
box.width = tablet_width - box.x;
|
|
|
|
|
}
|
|
|
|
|
if (!box.height) {
|
|
|
|
|
box.height = tablet_height - box.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (box.x + box.width <= tablet_width) {
|
|
|
|
|
const double max_x = 1;
|
|
|
|
|
double width_offset = max_x * box.x / tablet_width;
|
|
|
|
|
*x = (*x - width_offset) * tablet_width / box.width;
|
|
|
|
|
}
|
|
|
|
|
if (box.y + box.height <= tablet_height) {
|
|
|
|
|
const double max_y = 1;
|
|
|
|
|
double height_offset = max_y * box.y / tablet_height;
|
|
|
|
|
*y = (*y - height_offset) * tablet_height / box.height;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-29 22:38:05 +01:00
|
|
|
static void
|
|
|
|
|
adjust_for_rotation(enum rotation rotation, double *x, double *y)
|
|
|
|
|
{
|
|
|
|
|
double tmp;
|
|
|
|
|
switch (rotation) {
|
|
|
|
|
case LAB_ROTATE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case LAB_ROTATE_90:
|
|
|
|
|
tmp = *x;
|
|
|
|
|
*x = 1.0 - *y;
|
|
|
|
|
*y = tmp;
|
|
|
|
|
break;
|
|
|
|
|
case LAB_ROTATE_180:
|
|
|
|
|
*x = 1.0 - *x;
|
|
|
|
|
*y = 1.0 - *y;
|
|
|
|
|
break;
|
|
|
|
|
case LAB_ROTATE_270:
|
|
|
|
|
tmp = *x;
|
|
|
|
|
*x = *y;
|
|
|
|
|
*y = 1.0 - tmp;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-07 19:35:44 +02:00
|
|
|
static void
|
|
|
|
|
handle_proximity(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_tablet_tool_proximity_event *ev = data;
|
|
|
|
|
|
|
|
|
|
if (!tool_supports_absolute_motion(ev->tool)) {
|
|
|
|
|
if (ev->state == WLR_TABLET_TOOL_PROXIMITY_IN) {
|
|
|
|
|
wlr_log(WLR_INFO, "ignoring not supporting tablet tool");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-01 22:12:00 +01:00
|
|
|
static void
|
|
|
|
|
handle_axis(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_tablet_tool_axis_event *ev = data;
|
|
|
|
|
struct drawing_tablet *tablet = ev->tablet->data;
|
2024-05-07 19:35:44 +02:00
|
|
|
|
|
|
|
|
if (!tool_supports_absolute_motion(ev->tool)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-01 22:12:00 +01:00
|
|
|
if (ev->updated_axes & (WLR_TABLET_TOOL_AXIS_X | WLR_TABLET_TOOL_AXIS_Y)) {
|
|
|
|
|
if (ev->updated_axes & WLR_TABLET_TOOL_AXIS_X) {
|
|
|
|
|
tablet->x = ev->x;
|
|
|
|
|
}
|
|
|
|
|
if (ev->updated_axes & WLR_TABLET_TOOL_AXIS_Y) {
|
|
|
|
|
tablet->y = ev->y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double x = tablet->x;
|
|
|
|
|
double y = tablet->y;
|
2024-01-01 18:26:44 +01:00
|
|
|
adjust_for_tablet_area(tablet->tablet->width_mm, tablet->tablet->height_mm,
|
|
|
|
|
rc.tablet.box, &x, &y);
|
2023-12-29 22:38:05 +01:00
|
|
|
adjust_for_rotation(rc.tablet.rotation, &x, &y);
|
2023-12-01 22:12:00 +01:00
|
|
|
cursor_emulate_move_absolute(tablet->seat, &ev->tablet->base, x, y, ev->time_msec);
|
|
|
|
|
}
|
|
|
|
|
// Ignore other events
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handle_tip(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_tablet_tool_tip_event *ev = data;
|
|
|
|
|
struct drawing_tablet *tablet = ev->tablet->data;
|
|
|
|
|
|
2024-01-02 18:26:25 +01:00
|
|
|
uint32_t button = tablet_get_mapped_button(BTN_TOOL_PEN);
|
2023-12-29 10:06:59 +01:00
|
|
|
if (!button) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-01 22:12:00 +01:00
|
|
|
cursor_emulate_button(tablet->seat,
|
2023-12-29 10:06:59 +01:00
|
|
|
button,
|
2023-12-01 22:12:00 +01:00
|
|
|
ev->state == WLR_TABLET_TOOL_TIP_DOWN
|
|
|
|
|
? WLR_BUTTON_PRESSED
|
|
|
|
|
: WLR_BUTTON_RELEASED,
|
|
|
|
|
ev->time_msec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handle_button(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct wlr_tablet_tool_button_event *ev = data;
|
|
|
|
|
struct drawing_tablet *tablet = ev->tablet->data;
|
|
|
|
|
|
2024-01-02 18:26:25 +01:00
|
|
|
uint32_t button = tablet_get_mapped_button(ev->button);
|
2023-12-29 10:06:59 +01:00
|
|
|
if (!button) {
|
2023-12-01 22:12:00 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cursor_emulate_button(tablet->seat, button, ev->state, ev->time_msec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
handle_destroy(struct wl_listener *listener, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct drawing_tablet *tablet =
|
|
|
|
|
wl_container_of(listener, tablet, handlers.destroy);
|
2024-04-11 23:47:10 +02:00
|
|
|
|
|
|
|
|
wl_list_remove(&tablet->handlers.tip.link);
|
|
|
|
|
wl_list_remove(&tablet->handlers.button.link);
|
2024-05-07 19:35:44 +02:00
|
|
|
wl_list_remove(&tablet->handlers.proximity.link);
|
2024-04-11 23:47:10 +02:00
|
|
|
wl_list_remove(&tablet->handlers.axis.link);
|
|
|
|
|
wl_list_remove(&tablet->handlers.destroy.link);
|
2023-12-01 22:12:00 +01:00
|
|
|
free(tablet);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-02 18:26:25 +01:00
|
|
|
void
|
|
|
|
|
tablet_init(struct seat *seat, struct wlr_input_device *wlr_device)
|
2023-12-01 22:12:00 +01:00
|
|
|
{
|
|
|
|
|
wlr_log(WLR_DEBUG, "setting up tablet");
|
|
|
|
|
struct drawing_tablet *tablet = znew(*tablet);
|
|
|
|
|
tablet->seat = seat;
|
|
|
|
|
tablet->tablet = wlr_tablet_from_input_device(wlr_device);
|
|
|
|
|
tablet->tablet->data = tablet;
|
|
|
|
|
tablet->x = 0.0;
|
|
|
|
|
tablet->y = 0.0;
|
2023-12-30 19:14:11 +01:00
|
|
|
wlr_log(WLR_INFO, "tablet dimensions: %.2fmm x %.2fmm",
|
|
|
|
|
tablet->tablet->width_mm, tablet->tablet->height_mm);
|
2023-12-01 22:12:00 +01:00
|
|
|
CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, axis);
|
2024-05-07 19:35:44 +02:00
|
|
|
CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, proximity);
|
2023-12-01 22:12:00 +01:00
|
|
|
CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, tip);
|
|
|
|
|
CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, button);
|
|
|
|
|
CONNECT_SIGNAL(wlr_device, &tablet->handlers, destroy);
|
|
|
|
|
}
|