[Bf-blender-cvs] [97f894881ca] master: GHOST/Wayland add tablet support

Campbell Barton noreply at git.blender.org
Tue Jun 14 06:54:14 CEST 2022


Commit: 97f894881cab339eacbf69738ea7c5f687c5179d
Author: Campbell Barton
Date:   Tue Jun 14 14:51:26 2022 +1000
Branches: master
https://developer.blender.org/rB97f894881cab339eacbf69738ea7c5f687c5179d

GHOST/Wayland add tablet support

Add support for tablet pressure, tilt and type detection
(eraser, pen.. etc).

There is currently an inconsistency where the tablets cursor is scaled
larger than the mouse cursor (when the UI is scaled). Although there
doesn't seem to be a way to control this from the client.

===================================================================

M	intern/ghost/CMakeLists.txt
M	intern/ghost/intern/GHOST_SystemWayland.cpp

===================================================================

diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index dceb9ced803..0a6e19f006c 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -344,6 +344,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
       relative-pointer
       "${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
     )
+    # Tablet.
+    generate_protocol_bindings(
+      tablet
+      "${WAYLAND_PROTOCOLS_DIR}/unstable/tablet/tablet-unstable-v2.xml"
+    )
 
     add_definitions(-DWITH_GHOST_WAYLAND)
   endif()
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index c3300c82b55..75e06abdc87 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -29,6 +29,7 @@
 #include "GHOST_WaylandCursorSettings.h"
 #include <pointer-constraints-client-protocol.h>
 #include <relative-pointer-client-protocol.h>
+#include <tablet-client-protocol.h>
 #include <wayland-cursor.h>
 #include <xkbcommon/xkbcommon.h>
 
@@ -60,6 +61,14 @@ static GHOST_IWindow *get_window(struct wl_surface *surface);
 #define BTN_BACK 0x116
 // #define BTN_TASK 0x117 /* UNUSED. */
 
+/**
+ * Tablet events, also from `linux/input-event-codes.h`.
+ */
+#define BTN_STYLUS 0x14b  /* Use as right-mouse. */
+#define BTN_STYLUS2 0x14c /* Use as middle-mouse. */
+/* NOTE(@campbellbarton): Map to an additional button (not sure which hardware uses this). */
+#define BTN_STYLUS3 0x149
+
 struct buffer_t {
   void *data;
   size_t size;
@@ -79,6 +88,18 @@ struct cursor_t {
   int scale = 1;
 };
 
+/**
+ * A single tablet can have multiple tools (pen, eraser, brush... etc).
+ * WAYLAND exposes tools via #zwp_tablet_tool_v2.
+ * Since are no API's to access properties of the tool, store the values here.
+ */
+struct tablet_tool_input_t {
+  struct input_t *input;
+  struct wl_surface *cursor_surface;
+
+  GHOST_TabletData data;
+};
+
 struct data_offer_t {
   std::unordered_set<std::string> types;
   uint32_t source_actions;
@@ -109,8 +130,13 @@ struct input_t {
   struct wl_seat *seat;
   struct wl_pointer *pointer = nullptr;
   struct wl_keyboard *keyboard = nullptr;
+  struct zwp_tablet_seat_v2 *tablet_seat = nullptr;
+
+  /** All currently active tablet tools (needed for changing the cursor). */
+  std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools;
 
   uint32_t pointer_serial;
+  uint32_t tablet_serial;
   int x, y;
   GHOST_Buttons buttons;
   struct cursor_t cursor;
@@ -130,6 +156,7 @@ struct input_t {
     GHOST_ITimerTask *timer = nullptr;
   } key_repeat;
 
+  struct wl_surface *focus_tablet = nullptr;
   struct wl_surface *focus_pointer = nullptr;
   struct wl_surface *focus_keyboard = nullptr;
   struct wl_surface *focus_dnd = nullptr;
@@ -165,6 +192,7 @@ struct display_t {
     int size;
   } cursor;
   struct wl_data_device_manager *data_device_manager = nullptr;
+  struct zwp_tablet_manager_v2 *tablet_manager = nullptr;
   struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
   struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
 
@@ -206,6 +234,10 @@ static void display_destroy(display_t *d)
     wl_data_device_manager_destroy(d->data_device_manager);
   }
 
+  if (d->tablet_manager) {
+    zwp_tablet_manager_v2_destroy(d->tablet_manager);
+  }
+
   for (output_t *output : d->outputs) {
     wl_output_destroy(output->output);
     delete output;
@@ -403,6 +435,27 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
   return gkey;
 }
 
+static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_tablet_tool_type)
+{
+  switch (wl_tablet_tool_type) {
+    case ZWP_TABLET_TOOL_V2_TYPE_ERASER: {
+      return GHOST_kTabletModeEraser;
+    }
+    case ZWP_TABLET_TOOL_V2_TYPE_PEN:
+    case ZWP_TABLET_TOOL_V2_TYPE_BRUSH:
+    case ZWP_TABLET_TOOL_V2_TYPE_PENCIL:
+    case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH:
+    case ZWP_TABLET_TOOL_V2_TYPE_FINGER:
+    case ZWP_TABLET_TOOL_V2_TYPE_MOUSE:
+    case ZWP_TABLET_TOOL_V2_TYPE_LENS: {
+      return GHOST_kTabletModeStylus;
+    }
+  }
+
+  GHOST_PRINT("unknown tablet tool: " << wl_tablet_tool_type << std::endl);
+  return GHOST_kTabletModeStylus;
+}
+
 static const int default_cursor_size = 24;
 
 static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
@@ -1141,6 +1194,343 @@ static const struct wl_pointer_listener pointer_listener = {
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Listener (Tablet Tool), #zwp_tablet_tool_v2_listener
+ * \{ */
+
+static void tablet_tool_type(void *data,
+                             struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+                             uint32_t tool_type)
+{
+  tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+
+  tool_input->data.Active = tablet_tool_map_type((enum zwp_tablet_tool_v2_type)tool_type);
+}
+
+static void tablet_tool_hardware_serial(void * /*data*/,
+                                        struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+                                        uint32_t /*hardware_serial_hi*/,
+                                        uint32_t /*hardware_serial_lo*/)
+{
+}
+
+static void tablet_tool_hardware_id_wacom(void * /*data*/,
+                                          struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+                                          uint32_t /*hardware_id_hi*/,
+                                          uint32_t /*hardware_id_lo*/)
+{
+}
+
+static void tablet_tool_capability(void * /*data*/,
+                                   struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+                                   uint32_t /*capability*/)
+{
+}
+
+static void tablet_tool_done(void * /*data*/, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+}
+static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2)
+{
+  tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+  input_t *input = tool_input->input;
+
+  if (tool_input->cursor_surface) {
+    wl_surface_destroy(tool_input->cursor_surface);
+  }
+  input->tablet_tools.erase(zwp_tablet_tool_v2);
+
+  delete tool_input;
+}
+static void tablet_tool_proximity_in(void *data,
+                                     struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+                                     uint32_t serial,
+                                     struct zwp_tablet_v2 * /*tablet*/,
+                                     struct wl_surface *surface)
+{
+  tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+  input_t *input = tool_input->input;
+
+  input->focus_tablet = surface;
+  input->tablet_serial = serial;
+  input->data_source_serial = serial;
+
+  /* Update #GHOST_TabletData. */
+  GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+  if (!win) {
+    return;
+  }
+
+  win->activate();
+
+  GHOST_TabletData &td = tool_input->data;
+  /* Reset, to avoid using stale tilt/pressure. */
+  td.Xtilt = 0.0f;
+  td.Ytilt = 0.0f;
+  /* In case pressure isn't supported. */
+  td.Pressure = 1.0f;
+
+  win->setCursorShape(win->getCursorShape());
+}
+static void tablet_tool_proximity_out(void *data,
+                                      struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+  tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+  input_t *input = tool_input->input;
+  GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+
+  input->focus_tablet = nullptr;
+
+  win->setCursorShape(win->getCursorShape());
+}
+
+static void tablet_tool_down(void *data,
+                             struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+                             uint32_t serial)
+{
+  tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+  input_t *input = tool_input->input;
+
+  GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+  if (!win) {
+    return;
+  }
+
+  const GHOST_TEventType etype = GHOST_kEventButtonDown;
+  const GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+  input->data_source_serial = serial;
+  input->buttons.set(ebutton, true);
+  input->system->pushEvent(new GHOST_EventButton(
+      input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+}
+
+static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+  tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+  input_t *input = tool_input->input;
+
+  GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+  if (!win) {
+    return;
+  }
+  const GHOST_TEventType etype = GHOST_kEventButtonUp;
+  const GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+  input->buttons.set(ebutton, false);
+  input->system->pushEvent(new GHOST_EventButton(
+      input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+}
+
+static void tablet_tool_motion(void *data,
+                               struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+                               wl_fixed_t x,
+                               wl_fixed_t y)
+{
+  tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+  input_t *input = tool_input->input;
+
+  GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_tablet));
+  if (!win) {
+    return;
+  }
+
+  input->x = win->scale() * wl_fixed_to_int(x);
+  input->y = win->scale() * wl_fixed_to_int(y);
+
+  input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+                                                 GHOST_kEventCursorMove,
+                                                 win,
+                                                 input->x,
+                                                 input->y,
+                                                 tool_input->data));
+}
+
+static void tablet_tool_pressure(void *data,
+                                 struct zwp_table

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list