1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
|
#include <string.h>
#include <assert.h>
#include <libinput.h>
#include <linux/input.h>
#include <stdlib.h>
#include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "config.h"
struct tablet_tool {
struct wlr_tablet_tool wlr_tool;
struct libinput_tablet_tool *handle;
struct wl_list link; // wlr_libinput_input_device.tablet_tools
};
const struct wlr_tablet_impl libinput_tablet_impl = {
.name = "libinput-tablet-tool",
};
void init_device_tablet(struct wlr_libinput_input_device *dev) {
const char *name = get_libinput_device_name(dev->handle);
struct wlr_tablet *wlr_tablet = &dev->tablet;
wlr_tablet_init(wlr_tablet, &libinput_tablet_impl, name);
#if HAVE_LIBINPUT_BUSTYPE
if (libinput_device_get_id_bustype(dev->handle) == BUS_USB)
#endif
{
wlr_tablet->usb_vendor_id = libinput_device_get_id_vendor(dev->handle);
wlr_tablet->usb_product_id = libinput_device_get_id_product(dev->handle);
}
libinput_device_get_size(dev->handle, &wlr_tablet->width_mm,
&wlr_tablet->height_mm);
struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev));
udev_device_unref(udev);
wl_list_init(&dev->tablet_tools);
}
static void tool_destroy(struct tablet_tool *tool) {
wl_signal_emit_mutable(&tool->wlr_tool.events.destroy, &tool->wlr_tool);
libinput_tablet_tool_unref(tool->handle);
libinput_tablet_tool_set_user_data(tool->handle, NULL);
wl_list_remove(&tool->link);
free(tool);
}
void finish_device_tablet(struct wlr_libinput_input_device *dev) {
struct tablet_tool *tool, *tmp;
wl_list_for_each_safe(tool, tmp, &dev->tablet_tools, link) {
tool_destroy(tool);
}
wlr_tablet_finish(&dev->tablet);
}
struct wlr_libinput_input_device *device_from_tablet(
struct wlr_tablet *wlr_tablet) {
assert(wlr_tablet->impl == &libinput_tablet_impl);
struct wlr_libinput_input_device *dev =
wl_container_of(wlr_tablet, dev, tablet);
return dev;
}
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;
case LIBINPUT_TABLET_TOOL_TYPE_TOTEM:
return WLR_TABLET_TOOL_TYPE_TOTEM;
}
abort(); // unreachable
}
static struct tablet_tool *get_tablet_tool(
struct wlr_libinput_input_device *dev,
struct libinput_tablet_tool *libinput_tool) {
struct tablet_tool *tool =
libinput_tablet_tool_get_user_data(libinput_tool);
if (tool) {
return tool;
}
tool = calloc(1, sizeof(*tool));
if (tool == NULL) {
wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_tablet_tool");
return NULL;
}
tool->wlr_tool.type = wlr_type_from_libinput_type(
libinput_tablet_tool_get_type(libinput_tool));
tool->wlr_tool.hardware_serial =
libinput_tablet_tool_get_serial(libinput_tool);
tool->wlr_tool.hardware_wacom =
libinput_tablet_tool_get_tool_id(libinput_tool);
tool->wlr_tool.pressure = libinput_tablet_tool_has_pressure(libinput_tool);
tool->wlr_tool.distance = libinput_tablet_tool_has_distance(libinput_tool);
tool->wlr_tool.tilt = libinput_tablet_tool_has_tilt(libinput_tool);
tool->wlr_tool.rotation = libinput_tablet_tool_has_rotation(libinput_tool);
tool->wlr_tool.slider = libinput_tablet_tool_has_slider(libinput_tool);
tool->wlr_tool.wheel = libinput_tablet_tool_has_wheel(libinput_tool);
wl_signal_init(&tool->wlr_tool.events.destroy);
tool->handle = libinput_tablet_tool_ref(libinput_tool);
libinput_tablet_tool_set_user_data(libinput_tool, tool);
wl_list_insert(&dev->tablet_tools, &tool->link);
return tool;
}
void handle_tablet_tool_axis(struct libinput_event *event,
struct wlr_tablet *wlr_tablet) {
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
struct wlr_tablet_tool_axis_event wlr_event = {
.tablet = wlr_tablet,
.tool = &tool->wlr_tool,
.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);
}
wl_signal_emit_mutable(&wlr_tablet->events.axis, &wlr_event);
}
void handle_tablet_tool_proximity(struct libinput_event *event,
struct wlr_tablet *wlr_tablet) {
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
struct wlr_tablet_tool_proximity_event wlr_event = {
.tablet = wlr_tablet,
.tool = &tool->wlr_tool,
.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)),
.x = libinput_event_tablet_tool_get_x_transformed(tevent, 1),
.y = libinput_event_tablet_tool_get_y_transformed(tevent, 1),
};
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;
}
wl_signal_emit_mutable(&wlr_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, wlr_tablet);
}
// If the tool is not unique, libinput will not find it again after the
// proximity out, so we should destroy it
if (!libinput_tablet_tool_is_unique(tool->handle)
&& 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
tool_destroy(tool);
}
}
void handle_tablet_tool_tip(struct libinput_event *event,
struct wlr_tablet *wlr_tablet) {
handle_tablet_tool_axis(event, wlr_tablet);
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
struct wlr_tablet_tool_tip_event wlr_event = {
.tablet = wlr_tablet,
.tool = &tool->wlr_tool,
.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)),
.x = libinput_event_tablet_tool_get_x_transformed(tevent, 1),
.y = libinput_event_tablet_tool_get_y_transformed(tevent, 1),
};
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;
}
wl_signal_emit_mutable(&wlr_tablet->events.tip, &wlr_event);
}
void handle_tablet_tool_button(struct libinput_event *event,
struct wlr_tablet *wlr_tablet) {
handle_tablet_tool_axis(event, wlr_tablet);
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
struct wlr_tablet_tool_button_event wlr_event = {
.tablet = wlr_tablet,
.tool = &tool->wlr_tool,
.time_msec = usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)),
.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;
}
wl_signal_emit_mutable(&wlr_tablet->events.button, &wlr_event);
}
|