aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/devices
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/IHID.hpp3
-rw-r--r--src/devices/Tablet.cpp326
-rw-r--r--src/devices/Tablet.hpp228
3 files changed, 557 insertions, 0 deletions
diff --git a/src/devices/IHID.hpp b/src/devices/IHID.hpp
index 2830864b..cac25112 100644
--- a/src/devices/IHID.hpp
+++ b/src/devices/IHID.hpp
@@ -8,6 +8,7 @@ enum eHIDCapabilityType : uint32_t {
HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0),
HID_INPUT_CAPABILITY_POINTER = (1 << 1),
HID_INPUT_CAPABILITY_TOUCH = (1 << 2),
+ HID_INPUT_CAPABILITY_TABLET = (1 << 3),
};
enum eHIDType {
@@ -16,6 +17,8 @@ enum eHIDType {
HID_TYPE_KEYBOARD,
HID_TYPE_TOUCH,
HID_TYPE_TABLET,
+ HID_TYPE_TABLET_TOOL,
+ HID_TYPE_TABLET_PAD,
};
/*
diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp
new file mode 100644
index 00000000..f5b610a9
--- /dev/null
+++ b/src/devices/Tablet.cpp
@@ -0,0 +1,326 @@
+#include "Tablet.hpp"
+#include "../defines.hpp"
+#include "../protocols/Tablet.hpp"
+
+SP<CTablet> CTablet::create(wlr_tablet* tablet) {
+ SP<CTablet> pTab = SP<CTablet>(new CTablet(tablet));
+
+ pTab->self = pTab;
+
+ PROTO::tablet->registerDevice(pTab);
+
+ return pTab;
+}
+
+SP<CTabletTool> CTabletTool::create(wlr_tablet_tool* tablet) {
+ SP<CTabletTool> pTab = SP<CTabletTool>(new CTabletTool(tablet));
+
+ pTab->self = pTab;
+
+ PROTO::tablet->registerDevice(pTab);
+
+ return pTab;
+}
+
+SP<CTabletPad> CTabletPad::create(wlr_tablet_pad* tablet) {
+ SP<CTabletPad> pTab = SP<CTabletPad>(new CTabletPad(tablet));
+
+ pTab->self = pTab;
+
+ PROTO::tablet->registerDevice(pTab);
+
+ return pTab;
+}
+
+SP<CTabletTool> CTabletTool::fromWlr(wlr_tablet_tool* tool) {
+ return ((CTabletTool*)tool->data)->self.lock();
+}
+
+SP<CTablet> CTablet::fromWlr(wlr_tablet* tablet) {
+ return ((CTablet*)tablet->data)->self.lock();
+}
+
+static uint32_t wlrUpdateToHl(uint32_t wlr) {
+ uint32_t result = 0;
+ if (wlr & WLR_TABLET_TOOL_AXIS_X)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X;
+ if (wlr & WLR_TABLET_TOOL_AXIS_Y)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y;
+ if (wlr & WLR_TABLET_TOOL_AXIS_DISTANCE)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE;
+ if (wlr & WLR_TABLET_TOOL_AXIS_PRESSURE)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE;
+ if (wlr & WLR_TABLET_TOOL_AXIS_TILT_X)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X;
+ if (wlr & WLR_TABLET_TOOL_AXIS_TILT_Y)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y;
+ if (wlr & WLR_TABLET_TOOL_AXIS_ROTATION)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION;
+ if (wlr & WLR_TABLET_TOOL_AXIS_SLIDER)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER;
+ if (wlr & WLR_TABLET_TOOL_AXIS_WHEEL)
+ result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL;
+ return result;
+}
+
+uint32_t CTablet::getCapabilities() {
+ return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
+}
+
+wlr_tablet* CTablet::wlr() {
+ return tablet;
+}
+
+CTablet::CTablet(wlr_tablet* tablet_) : tablet(tablet_) {
+ if (!tablet)
+ return;
+
+ tablet->data = this;
+
+ // clang-format off
+ hyprListener_destroy.initCallback(&tablet->base.events.destroy, [this] (void* owner, void* data) {
+ tablet = nullptr;
+ disconnectCallbacks();
+ events.destroy.emit();
+ }, this, "CTablet");
+
+ hyprListener_axis.initCallback(&tablet->events.axis, [this] (void* owner, void* data) {
+ auto E = (wlr_tablet_tool_axis_event*)data;
+
+ tabletEvents.axis.emit(SAxisEvent{
+ .tool = E->tool,
+ .tablet = self.lock(),
+ .timeMs = E->time_msec,
+ .updatedAxes = wlrUpdateToHl(E->updated_axes),
+ .axis = {E->x, E->y},
+ .axisDelta = {E->dx, E->dy},
+ .tilt = {E->tilt_x, E->tilt_y},
+ .pressure = E->pressure,
+ .distance = E->distance,
+ .rotation = E->rotation,
+ .slider = E->slider,
+ .wheelDelta = E->wheel_delta,
+ });
+ }, this, "CTablet");
+
+ hyprListener_proximity.initCallback(&tablet->events.proximity, [this] (void* owner, void* data) {
+ auto E = (wlr_tablet_tool_proximity_event*)data;
+
+ tabletEvents.proximity.emit(SProximityEvent{
+ .tool = E->tool,
+ .tablet = self.lock(),
+ .timeMs = E->time_msec,
+ .proximity = {E->x, E->y},
+ .in = E->state == WLR_TABLET_TOOL_PROXIMITY_IN,
+ });
+ }, this, "CTablet");
+
+ hyprListener_tip.initCallback(&tablet->events.tip, [this] (void* owner, void* data) {
+ auto E = (wlr_tablet_tool_tip_event*)data;
+
+ tabletEvents.tip.emit(STipEvent{
+ .tool = E->tool,
+ .tablet = self.lock(),
+ .timeMs = E->time_msec,
+ .tip = {E->x, E->y},
+ .in = E->state == WLR_TABLET_TOOL_TIP_DOWN,
+ });
+ }, this, "CTablet");
+
+ hyprListener_button.initCallback(&tablet->events.button, [this] (void* owner, void* data) {
+ auto E = (wlr_tablet_tool_button_event*)data;
+
+ tabletEvents.button.emit(SButtonEvent{
+ .tool = E->tool,
+ .tablet = self.lock(),
+ .timeMs = E->time_msec,
+ .button = E->button,
+ .down = E->state == WLR_BUTTON_PRESSED,
+ });
+ }, this, "CTablet");
+ // clang-format on
+
+ deviceName = tablet->base.name ? tablet->base.name : "UNKNOWN";
+}
+
+CTablet::~CTablet() {
+ if (tablet)
+ tablet->data = nullptr;
+
+ PROTO::tablet->recheckRegisteredDevices();
+}
+
+void CTablet::disconnectCallbacks() {
+ hyprListener_axis.removeCallback();
+ hyprListener_button.removeCallback();
+ hyprListener_destroy.removeCallback();
+ hyprListener_proximity.removeCallback();
+ hyprListener_tip.removeCallback();
+}
+
+eHIDType CTablet::getType() {
+ return HID_TYPE_TABLET;
+}
+
+uint32_t CTabletPad::getCapabilities() {
+ return HID_INPUT_CAPABILITY_TABLET;
+}
+
+wlr_tablet_pad* CTabletPad::wlr() {
+ return pad;
+}
+
+eHIDType CTabletPad::getType() {
+ return HID_TYPE_TABLET_PAD;
+}
+
+CTabletPad::CTabletPad(wlr_tablet_pad* pad_) : pad(pad_) {
+ if (!pad)
+ return;
+
+ // clang-format off
+ hyprListener_destroy.initCallback(&pad->base.events.destroy, [this] (void* owner, void* data) {
+ pad = nullptr;
+ disconnectCallbacks();
+ events.destroy.emit();
+ }, this, "CTabletPad");
+
+ hyprListener_button.initCallback(&pad->events.button, [this] (void* owner, void* data) {
+ auto E = (wlr_tablet_pad_button_event*)data;
+
+ padEvents.button.emit(SButtonEvent{
+ .timeMs = E->time_msec,
+ .button = E->button,
+ .down = E->state == WLR_BUTTON_PRESSED,
+ .mode = E->mode,
+ .group = E->group,
+ });
+ }, this, "CTabletPad");
+
+ hyprListener_ring.initCallback(&pad->events.ring, [this] (void* owner, void* data) {
+ auto E = (wlr_tablet_pad_ring_event*)data;
+
+ padEvents.ring.emit(SRingEvent{
+ .timeMs = E->time_msec,
+ .finger = E->source == WLR_TABLET_PAD_RING_SOURCE_FINGER,
+ .ring = E->ring,
+ .position = E->position,
+ .mode = E->mode,
+ });
+ }, this, "CTabletPad");
+
+ hyprListener_strip.initCallback(&pad->events.strip, [this] (void* owner, void* data) {
+ auto E = (wlr_tablet_pad_strip_event*)data;
+
+ padEvents.strip.emit(SStripEvent{
+ .timeMs = E->time_msec,
+ .finger = E->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER,
+ .strip = E->strip,
+ .position = E->position,
+ .mode = E->mode,
+ });
+ }, this, "CTabletPad");
+
+ hyprListener_attach.initCallback(&pad->events.attach_tablet, [this] (void* owner, void* data) {
+ if (!data)
+ return;
+
+ padEvents.attach.emit(CTabletTool::fromWlr((wlr_tablet_tool*)data));
+ }, this, "CTabletPad");
+ // clang-format on
+
+ deviceName = pad->base.name ? pad->base.name : "UNKNOWN";
+}
+
+CTabletPad::~CTabletPad() {
+ PROTO::tablet->recheckRegisteredDevices();
+}
+
+void CTabletPad::disconnectCallbacks() {
+ hyprListener_ring.removeCallback();
+ hyprListener_button.removeCallback();
+ hyprListener_destroy.removeCallback();
+ hyprListener_strip.removeCallback();
+ hyprListener_attach.removeCallback();
+}
+
+uint32_t CTabletTool::getCapabilities() {
+ return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET;
+}
+
+wlr_tablet_tool* CTabletTool::wlr() {
+ return tool;
+}
+
+eHIDType CTabletTool::getType() {
+ return HID_TYPE_TABLET_TOOL;
+}
+
+CTabletTool::CTabletTool(wlr_tablet_tool* tool_) : tool(tool_) {
+ if (!tool)
+ return;
+
+ // clang-format off
+ hyprListener_destroy.initCallback(&tool->events.destroy, [this] (void* owner, void* data) {
+ tool = nullptr;
+ disconnectCallbacks();
+ events.destroy.emit();
+ }, this, "CTabletTool");
+ // clang-format on
+
+ if (tool->tilt)
+ toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT;
+ if (tool->pressure)
+ toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE;
+ if (tool->distance)
+ toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE;
+ if (tool->rotation)
+ toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION;
+ if (tool->slider)
+ toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER;
+ if (tool->wheel)
+ toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL;
+
+ tool->data = this;
+
+ deviceName = std::to_string(tool->hardware_serial) + std::to_string(tool->hardware_wacom);
+}
+
+CTabletTool::~CTabletTool() {
+ if (tool)
+ tool->data = nullptr;
+
+ PROTO::tablet->recheckRegisteredDevices();
+}
+
+void CTabletTool::disconnectCallbacks() {
+ hyprListener_destroy.removeCallback();
+ hyprListener_destroySurface.removeCallback();
+}
+
+wlr_surface* CTabletTool::getSurface() {
+ return pSurface;
+}
+
+void CTabletTool::setSurface(wlr_surface* surf) {
+ if (surf == pSurface)
+ return;
+
+ if (pSurface) {
+ hyprListener_destroySurface.removeCallback();
+ pSurface = nullptr;
+ }
+
+ pSurface = surf;
+
+ if (surf) {
+ hyprListener_destroySurface.initCallback(
+ &surf->events.destroy,
+ [this](void* owner, void* data) {
+ PROTO::tablet->proximityOut(self.lock());
+ pSurface = nullptr;
+ hyprListener_destroySurface.removeCallback();
+ },
+ this, "CTabletTool");
+ }
+}
diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp
new file mode 100644
index 00000000..f2444972
--- /dev/null
+++ b/src/devices/Tablet.hpp
@@ -0,0 +1,228 @@
+#pragma once
+
+#include "IHID.hpp"
+#include "../helpers/WLListener.hpp"
+#include "../macros.hpp"
+#include "../helpers/Vector2D.hpp"
+#include "../helpers/Box.hpp"
+
+struct wlr_tablet;
+struct wlr_tablet_tool;
+struct wlr_tablet_pad;
+
+class CTabletTool;
+class CTabletPad;
+
+/*
+ A tablet device
+ Tablets don't have an interface for now,
+ if there will be a need it's trivial to do.
+*/
+class CTablet : public IHID {
+ public:
+ static SP<CTablet> create(wlr_tablet* tablet);
+ static SP<CTablet> fromWlr(wlr_tablet* tablet);
+ ~CTablet();
+
+ virtual uint32_t getCapabilities();
+ virtual eHIDType getType();
+ wlr_tablet* wlr();
+
+ enum eTabletToolAxes {
+ HID_TABLET_TOOL_AXIS_X = (1 << 0),
+ HID_TABLET_TOOL_AXIS_Y = (1 << 1),
+ HID_TABLET_TOOL_AXIS_TILT_X = (1 << 2),
+ HID_TABLET_TOOL_AXIS_TILT_Y = (1 << 3),
+ HID_TABLET_TOOL_AXIS_DISTANCE = (1 << 4),
+ HID_TABLET_TOOL_AXIS_PRESSURE = (1 << 5),
+ HID_TABLET_TOOL_AXIS_ROTATION = (1 << 6),
+ HID_TABLET_TOOL_AXIS_SLIDER = (1 << 7),
+ HID_TABLET_TOOL_AXIS_WHEEL = (1 << 8),
+ };
+
+ struct SAxisEvent {
+ wlr_tablet_tool* tool;
+ SP<CTablet> tablet;
+
+ uint32_t timeMs = 0;
+ uint32_t updatedAxes = 0; // eTabletToolAxes
+ Vector2D axis;
+ Vector2D axisDelta;
+ Vector2D tilt;
+ double pressure = 0;
+ double distance = 0;
+ double rotation = 0;
+ double slider = 0;
+ double wheelDelta = 0;
+ };
+
+ struct SProximityEvent {
+ wlr_tablet_tool* tool;
+ SP<CTablet> tablet;
+
+ uint32_t timeMs = 0;
+ Vector2D proximity;
+ bool in = false;
+ };
+
+ struct STipEvent {
+ wlr_tablet_tool* tool;
+ SP<CTablet> tablet;
+
+ uint32_t timeMs = 0;
+ Vector2D tip;
+ bool in = false;
+ };
+
+ struct SButtonEvent {
+ wlr_tablet_tool* tool;
+ SP<CTablet> tablet;
+
+ uint32_t timeMs = 0;
+ uint32_t button;
+ bool down = false;
+ };
+
+ struct {
+ CSignal axis;
+ CSignal proximity;
+ CSignal tip;
+ CSignal button;
+ } tabletEvents;
+
+ WP<CTablet> self;
+
+ bool relativeInput = false;
+ std::string hlName = "";
+ std::string boundOutput = "";
+ CBox activeArea;
+ CBox boundBox; // output-local
+
+ private:
+ CTablet(wlr_tablet* tablet);
+
+ void disconnectCallbacks();
+
+ wlr_tablet* tablet = nullptr;
+
+ DYNLISTENER(destroy);
+ DYNLISTENER(axis);
+ DYNLISTENER(proximity);
+ DYNLISTENER(tip);
+ DYNLISTENER(button);
+};
+
+class CTabletPad : public IHID {
+ public:
+ static SP<CTabletPad> create(wlr_tablet_pad* pad);
+ ~CTabletPad();
+
+ virtual uint32_t getCapabilities();
+ virtual eHIDType getType();
+ wlr_tablet_pad* wlr();
+
+ struct SButtonEvent {
+ uint32_t timeMs = 0;
+ uint32_t button = 0;
+ bool down = false;
+ uint32_t mode = 0;
+ uint32_t group = 0;
+ };
+
+ struct SRingEvent {
+ uint32_t timeMs = 0;
+ bool finger = false;
+ uint32_t ring = 0;
+ double position = 0;
+ uint32_t mode = 0;
+ };
+
+ struct SStripEvent {
+ uint32_t timeMs = 0;
+ bool finger = false;
+ uint32_t strip = 0;
+ double position = 0;
+ uint32_t mode = 0;
+ };
+
+ struct {
+ CSignal button;
+ CSignal ring;
+ CSignal strip;
+ CSignal attach;
+ } padEvents;
+
+ WP<CTabletPad> self;
+ WP<CTabletTool> parent;
+
+ std::string hlName;
+
+ private:
+ CTabletPad(wlr_tablet_pad* pad);
+
+ void disconnectCallbacks();
+
+ wlr_tablet_pad* pad = nullptr;
+
+ DYNLISTENER(destroy);
+ DYNLISTENER(ring);
+ DYNLISTENER(strip);
+ DYNLISTENER(button);
+ DYNLISTENER(attach);
+};
+
+class CTabletTool : public IHID {
+ public:
+ static SP<CTabletTool> create(wlr_tablet_tool* tool);
+ static SP<CTabletTool> fromWlr(wlr_tablet_tool* tool);
+ ~CTabletTool();
+
+ enum eTabletToolType {
+ HID_TABLET_TOOL_TYPE_PEN = 1,
+ HID_TABLET_TOOL_TYPE_ERASER,
+ HID_TABLET_TOOL_TYPE_BRUSH,
+ HID_TABLET_TOOL_TYPE_PENCIL,
+ HID_TABLET_TOOL_TYPE_AIRBRUSH,
+ HID_TABLET_TOOL_TYPE_MOUSE,
+ HID_TABLET_TOOL_TYPE_LENS,
+ HID_TABLET_TOOL_TYPE_TOTEM,
+ };
+
+ enum eTabletToolCapabilities {
+ HID_TABLET_TOOL_CAPABILITY_TILT = (1 << 0),
+ HID_TABLET_TOOL_CAPABILITY_PRESSURE = (1 << 1),
+ HID_TABLET_TOOL_CAPABILITY_DISTANCE = (1 << 2),
+ HID_TABLET_TOOL_CAPABILITY_ROTATION = (1 << 3),
+ HID_TABLET_TOOL_CAPABILITY_SLIDER = (1 << 4),
+ HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5),
+ };
+
+ virtual uint32_t getCapabilities();
+ wlr_tablet_tool* wlr();
+ virtual eHIDType getType();
+ wlr_surface* getSurface();
+ void setSurface(wlr_surface*);
+
+ WP<CTabletTool> self;
+ Vector2D tilt;
+ bool active = false; // true if in proximity
+ uint32_t toolCapabilities = 0;
+
+ bool isDown = false;
+ std::vector<uint32_t> buttonsDown;
+ Vector2D absolutePos; // last known absolute position.
+
+ std::string hlName;
+
+ private:
+ CTabletTool(wlr_tablet_tool* tool);
+
+ void disconnectCallbacks();
+
+ wlr_surface* pSurface = nullptr;
+
+ wlr_tablet_tool* tool = nullptr;
+
+ DYNLISTENER(destroy);
+ DYNLISTENER(destroySurface);
+}; \ No newline at end of file