diff options
Diffstat (limited to 'src/devices')
-rw-r--r-- | src/devices/IHID.hpp | 3 | ||||
-rw-r--r-- | src/devices/Tablet.cpp | 326 | ||||
-rw-r--r-- | src/devices/Tablet.hpp | 228 |
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 |