mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 05:45:59 +01:00
Tablet: move to new impl
Ring and strip are not implemented. Will I implement this? God fucking knows. Nobody seems to have that anyways.
This commit is contained in:
parent
ed411f53bd
commit
84e8d1810d
21 changed files with 1926 additions and 1606 deletions
|
@ -251,7 +251,6 @@ target_link_libraries(Hyprland
|
|||
uuid
|
||||
)
|
||||
|
||||
protocol("protocols/tablet-unstable-v2.xml" "tablet-unstable-v2" true)
|
||||
protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true)
|
||||
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
|
||||
protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
|
||||
|
@ -285,6 +284,7 @@ protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "
|
|||
protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false)
|
||||
protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false)
|
||||
protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false)
|
||||
protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false)
|
||||
|
||||
# tools
|
||||
add_subdirectory(hyprctl)
|
||||
|
|
|
@ -29,7 +29,6 @@ protocols = [
|
|||
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
|
||||
['wlr-layer-shell-unstable-v1.xml'],
|
||||
['wlr-screencopy-unstable-v1.xml'],
|
||||
['tablet-unstable-v2.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
|
||||
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
|
||||
]
|
||||
|
@ -60,6 +59,7 @@ new_protocols = [
|
|||
[wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'],
|
||||
[wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'],
|
||||
[wl_protocol_dir, 'stable/tablet/tablet-v2.xml'],
|
||||
]
|
||||
|
||||
wl_protos_src = []
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -242,8 +242,6 @@ void CCompositor::initServer() {
|
|||
Debug::log(INFO, "VR will not be available");
|
||||
}
|
||||
|
||||
// m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay);
|
||||
|
||||
wlr_xdg_foreign_v1_create(m_sWLDisplay, m_sWLRForeignRegistry);
|
||||
|
|
|
@ -56,7 +56,6 @@ class CCompositor {
|
|||
wlr_presentation* m_sWLRPresentation;
|
||||
wlr_egl* m_sWLREGL;
|
||||
int m_iDRMFD;
|
||||
wlr_tablet_manager_v2* m_sWLRTabletManager;
|
||||
wlr_xdg_foreign_registry* m_sWLRForeignRegistry;
|
||||
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
|
||||
wlr_backend* m_sWLRHeadlessBackend;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "../devices/IPointer.hpp"
|
||||
#include "../devices/IKeyboard.hpp"
|
||||
#include "../devices/ITouch.hpp"
|
||||
#include "../devices/Tablet.hpp"
|
||||
|
||||
static void trimTrailingComma(std::string& str) {
|
||||
if (!str.empty() && str.back() == ',')
|
||||
|
@ -557,7 +558,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
|
||||
result += "\"tablets\": [\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletPads) {
|
||||
for (auto& d : g_pInputManager->m_vTabletPads) {
|
||||
result += std::format(
|
||||
R"#( {{
|
||||
"address": "0x{:x}",
|
||||
|
@ -567,26 +568,26 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
"name": "{}"
|
||||
}}
|
||||
}},)#",
|
||||
(uintptr_t)&d, (uintptr_t)d.pTabletParent, escapeJSONStrings(d.pTabletParent ? d.pTabletParent->name : ""));
|
||||
(uintptr_t)d.get(), (uintptr_t)d->parent.get(), escapeJSONStrings(d->parent ? d->parent->hlName : ""));
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTablets) {
|
||||
for (auto& d : g_pInputManager->m_vTablets) {
|
||||
result += std::format(
|
||||
R"#( {{
|
||||
"address": "0x{:x}",
|
||||
"name": "{}"
|
||||
}},)#",
|
||||
(uintptr_t)&d, escapeJSONStrings(d.name));
|
||||
(uintptr_t)d.get(), escapeJSONStrings(d->hlName));
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletTools) {
|
||||
for (auto& d : g_pInputManager->m_vTabletTools) {
|
||||
result += std::format(
|
||||
R"#( {{
|
||||
"address": "0x{:x}",
|
||||
"type": "tabletTool",
|
||||
"belongsTo": "0x{:x}"
|
||||
}},)#",
|
||||
(uintptr_t)&d, d.wlrTabletTool ? (uintptr_t)d.wlrTabletTool->data : 0);
|
||||
(uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0);
|
||||
}
|
||||
|
||||
trimTrailingComma(result);
|
||||
|
@ -643,16 +644,16 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
|
||||
result += "\n\nTablets:\n";
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletPads) {
|
||||
result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)&d, (uintptr_t)d.pTabletParent, d.pTabletParent ? d.pTabletParent->name : "");
|
||||
for (auto& d : g_pInputManager->m_vTabletPads) {
|
||||
result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)d.get(), (uintptr_t)d->parent.get(), d->parent ? d->parent->hlName : "");
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTablets) {
|
||||
result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)&d, d.name, d.wlrTablet->width_mm, d.wlrTablet->height_mm);
|
||||
for (auto& d : g_pInputManager->m_vTablets) {
|
||||
result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->wlr()->width_mm, d->wlr()->height_mm);
|
||||
}
|
||||
|
||||
for (auto& d : g_pInputManager->m_lTabletTools) {
|
||||
result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)&d, d.wlrTabletTool ? (uintptr_t)d.wlrTabletTool->data : 0);
|
||||
for (auto& d : g_pInputManager->m_vTabletTools) {
|
||||
result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0);
|
||||
}
|
||||
|
||||
result += "\n\nTouch:\n";
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
326
src/devices/Tablet.cpp
Normal file
326
src/devices/Tablet.cpp
Normal file
|
@ -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");
|
||||
}
|
||||
}
|
228
src/devices/Tablet.hpp
Normal file
228
src/devices/Tablet.hpp
Normal file
|
@ -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);
|
||||
};
|
|
@ -38,8 +38,8 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
|
|||
g_pInputManager->newTouchDevice(DEVICE);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET:
|
||||
Debug::log(LOG, "Attached a tablet tool with name {}", DEVICE->name);
|
||||
g_pInputManager->newTabletTool(DEVICE);
|
||||
Debug::log(LOG, "Attached a tablet with name {}", DEVICE->name);
|
||||
g_pInputManager->newTablet(DEVICE);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TABLET_PAD:
|
||||
Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name);
|
||||
|
|
|
@ -146,20 +146,6 @@ void CMonitor::onConnect(bool noRule) {
|
|||
if (!noRule)
|
||||
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
||||
|
||||
for (const auto& PTOUCHDEV : g_pInputManager->m_vTouches) {
|
||||
if (matchesStaticSelector(PTOUCHDEV->boundOutput)) {
|
||||
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, szName);
|
||||
// wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& PTABLET : g_pInputManager->m_lTablets) {
|
||||
if (matchesStaticSelector(PTABLET.boundOutput)) {
|
||||
Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName);
|
||||
// wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
|
||||
}
|
||||
}
|
||||
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
|
||||
|
||||
|
|
|
@ -85,72 +85,6 @@ struct SDrag {
|
|||
DYNLISTENER(commitIcon);
|
||||
};
|
||||
|
||||
struct STablet {
|
||||
DYNLISTENER(Tip);
|
||||
DYNLISTENER(Axis);
|
||||
DYNLISTENER(Button);
|
||||
DYNLISTENER(Proximity);
|
||||
DYNLISTENER(Destroy);
|
||||
|
||||
wlr_tablet* wlrTablet = nullptr;
|
||||
wlr_tablet_v2_tablet* wlrTabletV2 = nullptr;
|
||||
wlr_input_device* wlrDevice = nullptr;
|
||||
|
||||
bool relativeInput = false;
|
||||
|
||||
std::string name = "";
|
||||
|
||||
std::string boundOutput = "";
|
||||
|
||||
CBox activeArea;
|
||||
|
||||
//
|
||||
bool operator==(const STablet& b) const {
|
||||
return wlrDevice == b.wlrDevice;
|
||||
}
|
||||
};
|
||||
|
||||
struct STabletTool {
|
||||
wlr_tablet_tool* wlrTabletTool = nullptr;
|
||||
wlr_tablet_v2_tablet_tool* wlrTabletToolV2 = nullptr;
|
||||
|
||||
wlr_tablet_v2_tablet* wlrTabletOwnerV2 = nullptr;
|
||||
|
||||
wlr_surface* pSurface = nullptr;
|
||||
|
||||
double tiltX = 0;
|
||||
double tiltY = 0;
|
||||
|
||||
bool active = true;
|
||||
|
||||
std::string name = "";
|
||||
|
||||
DYNLISTENER(TabletToolDestroy);
|
||||
DYNLISTENER(TabletToolSetCursor);
|
||||
|
||||
bool operator==(const STabletTool& b) const {
|
||||
return wlrTabletTool == b.wlrTabletTool;
|
||||
}
|
||||
};
|
||||
|
||||
struct STabletPad {
|
||||
wlr_tablet_v2_tablet_pad* wlrTabletPadV2 = nullptr;
|
||||
STablet* pTabletParent = nullptr;
|
||||
wlr_input_device* pWlrDevice = nullptr;
|
||||
|
||||
std::string name = "";
|
||||
|
||||
DYNLISTENER(Attach);
|
||||
DYNLISTENER(Button);
|
||||
DYNLISTENER(Strip);
|
||||
DYNLISTENER(Ring);
|
||||
DYNLISTENER(Destroy);
|
||||
|
||||
bool operator==(const STabletPad& b) const {
|
||||
return wlrTabletPadV2 == b.wlrTabletPadV2;
|
||||
}
|
||||
};
|
||||
|
||||
struct SSwipeGesture {
|
||||
PHLWORKSPACE pWorkspaceBegin = nullptr;
|
||||
|
||||
|
|
|
@ -69,7 +69,6 @@ extern "C" {
|
|||
#include <wlr/util/edges.h>
|
||||
#include <wlr/types/wlr_tablet_pad.h>
|
||||
#include <wlr/types/wlr_tablet_tool.h>
|
||||
#include <wlr/types/wlr_tablet_v2.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <wlr/render/egl.h>
|
||||
#include <wlr/render/gles2.h>
|
||||
|
|
|
@ -635,37 +635,60 @@ void CPointerManager::warpTo(const Vector2D& logical) {
|
|||
|
||||
void CPointerManager::move(const Vector2D& deltaLogical) {
|
||||
const auto oldPos = pointerPos;
|
||||
auto newPos = oldPos + deltaLogical;
|
||||
auto newPos = oldPos + Vector2D{std::isnan(deltaLogical.x) ? 0.0 : deltaLogical.x, std::isnan(deltaLogical.y) ? 0.0 : deltaLogical.y};
|
||||
|
||||
warpTo(newPos);
|
||||
}
|
||||
|
||||
void CPointerManager::warpAbsolute(const Vector2D& abs, SP<IHID> dev) {
|
||||
void CPointerManager::warpAbsolute(Vector2D abs, SP<IHID> dev) {
|
||||
|
||||
SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock();
|
||||
if (!currentMonitor)
|
||||
return;
|
||||
|
||||
if (!std::isnan(abs.x))
|
||||
abs.x = std::clamp(abs.x, 0.0, 1.0);
|
||||
if (!std::isnan(abs.y))
|
||||
abs.y = std::clamp(abs.y, 0.0, 1.0);
|
||||
|
||||
// in logical global
|
||||
CBox mappedArea = currentMonitor->logicalBox();
|
||||
|
||||
switch (dev->getType()) {
|
||||
case HID_TYPE_TABLET:
|
||||
//TODO:
|
||||
break;
|
||||
case HID_TYPE_TOUCH: {
|
||||
auto TOUCH = SP<ITouch>(dev);
|
||||
if (!TOUCH->boundOutput.empty()) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput);
|
||||
if (PMONITOR)
|
||||
case HID_TYPE_TABLET: {
|
||||
CTablet* TAB = reinterpret_cast<CTablet*>(dev.get());
|
||||
if (!TAB->boundOutput.empty()) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromString(TAB->boundOutput); PMONITOR) {
|
||||
currentMonitor = PMONITOR->self.lock();
|
||||
mappedArea = currentMonitor->logicalBox();
|
||||
}
|
||||
}
|
||||
|
||||
if (!TAB->boundBox.empty())
|
||||
mappedArea = TAB->boundBox.translate(currentMonitor->vecPosition);
|
||||
break;
|
||||
}
|
||||
case HID_TYPE_TOUCH: {
|
||||
ITouch* TOUCH = reinterpret_cast<ITouch*>(dev.get());
|
||||
if (!TOUCH->boundOutput.empty()) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput); PMONITOR) {
|
||||
currentMonitor = PMONITOR->self.lock();
|
||||
mappedArea = currentMonitor->logicalBox();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (!currentMonitor)
|
||||
return;
|
||||
|
||||
damageIfSoftware();
|
||||
|
||||
pointerPos = currentMonitor->vecPosition + currentMonitor->vecSize * abs;
|
||||
if (std::isnan(abs.x) || std::isnan(abs.y)) {
|
||||
pointerPos.x = std::isnan(abs.x) ? pointerPos.x : mappedArea.x + mappedArea.w * abs.x;
|
||||
pointerPos.y = std::isnan(abs.y) ? pointerPos.y : mappedArea.y + mappedArea.h * abs.y;
|
||||
} else
|
||||
pointerPos = mappedArea.pos() + mappedArea.size() * abs;
|
||||
|
||||
onCursorMoved();
|
||||
recheckEnteredOutputs();
|
||||
|
||||
|
@ -839,6 +862,47 @@ void CPointerManager::attachTouch(SP<ITouch> touch) {
|
|||
Debug::log(LOG, "Attached touch {} to global", touch->hlName);
|
||||
}
|
||||
|
||||
void CPointerManager::attachTablet(SP<CTablet> tablet) {
|
||||
if (!tablet)
|
||||
return;
|
||||
|
||||
auto listener = tabletListeners.emplace_back(makeShared<STabletListener>());
|
||||
|
||||
listener->tablet = tablet;
|
||||
|
||||
// clang-format off
|
||||
listener->destroy = tablet->events.destroy.registerListener([this] (std::any d) {
|
||||
detachTablet(nullptr);
|
||||
});
|
||||
|
||||
listener->axis = tablet->tabletEvents.axis.registerListener([this] (std::any e) {
|
||||
auto E = std::any_cast<CTablet::SAxisEvent>(e);
|
||||
|
||||
g_pInputManager->onTabletAxis(E);
|
||||
});
|
||||
|
||||
listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) {
|
||||
auto E = std::any_cast<CTablet::SProximityEvent>(e);
|
||||
|
||||
g_pInputManager->onTabletProximity(E);
|
||||
});
|
||||
|
||||
listener->tip = tablet->tabletEvents.tip.registerListener([this] (std::any e) {
|
||||
auto E = std::any_cast<CTablet::STipEvent>(e);
|
||||
|
||||
g_pInputManager->onTabletTip(E);
|
||||
});
|
||||
|
||||
listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) {
|
||||
auto E = std::any_cast<CTablet::SButtonEvent>(e);
|
||||
|
||||
g_pInputManager->onTabletButton(E);
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
Debug::log(LOG, "Attached tablet {} to global", tablet->hlName);
|
||||
}
|
||||
|
||||
void CPointerManager::detachPointer(SP<IPointer> pointer) {
|
||||
std::erase_if(pointerListeners, [pointer](const auto& e) { return e->pointer.expired() || e->pointer == pointer; });
|
||||
}
|
||||
|
@ -847,6 +911,10 @@ void CPointerManager::detachTouch(SP<ITouch> touch) {
|
|||
std::erase_if(touchListeners, [touch](const auto& e) { return e->touch.expired() || e->touch == touch; });
|
||||
}
|
||||
|
||||
void CPointerManager::detachTablet(SP<CTablet> tablet) {
|
||||
std::erase_if(tabletListeners, [tablet](const auto& e) { return e->tablet.expired() || e->tablet == tablet; });
|
||||
}
|
||||
|
||||
void CPointerManager::damageCursor(SP<CMonitor> pMonitor) {
|
||||
for (auto& mw : monitorStates) {
|
||||
if (mw->monitor != pMonitor)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../devices/IPointer.hpp"
|
||||
#include "../devices/ITouch.hpp"
|
||||
#include "../devices/Tablet.hpp"
|
||||
#include "../helpers/Box.hpp"
|
||||
#include "../helpers/Region.hpp"
|
||||
#include "../desktop/WLSurface.hpp"
|
||||
|
@ -22,18 +23,18 @@ class CPointerManager {
|
|||
public:
|
||||
CPointerManager();
|
||||
|
||||
// pointers will move the cursor on their respective events
|
||||
void attachPointer(SP<IPointer> pointer);
|
||||
// touch inputs won't move the cursor, it needs to be done manually
|
||||
void attachTouch(SP<ITouch> touch);
|
||||
void attachTablet(SP<CTablet> tablet);
|
||||
|
||||
void detachPointer(SP<IPointer> pointer);
|
||||
void detachTouch(SP<ITouch> touch);
|
||||
void detachTablet(SP<CTablet> tablet);
|
||||
|
||||
// only clamps to the layout.
|
||||
void warpTo(const Vector2D& logical);
|
||||
void move(const Vector2D& deltaLogical);
|
||||
void warpAbsolute(const Vector2D& abs, SP<IHID> dev);
|
||||
void warpAbsolute(Vector2D abs, SP<IHID> dev);
|
||||
|
||||
void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale);
|
||||
void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot);
|
||||
|
@ -111,6 +112,17 @@ class CPointerManager {
|
|||
};
|
||||
std::vector<SP<STouchListener>> touchListeners;
|
||||
|
||||
struct STabletListener {
|
||||
CHyprSignalListener destroy;
|
||||
CHyprSignalListener axis;
|
||||
CHyprSignalListener proximity;
|
||||
CHyprSignalListener tip;
|
||||
CHyprSignalListener button;
|
||||
|
||||
WP<CTablet> tablet;
|
||||
};
|
||||
std::vector<SP<STabletListener>> tabletListeners;
|
||||
|
||||
struct {
|
||||
std::vector<CBox> monitorBoxes;
|
||||
} currentMonitorLayout;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "../protocols/OutputManagement.hpp"
|
||||
#include "../protocols/ServerDecorationKDE.hpp"
|
||||
#include "../protocols/FocusGrab.hpp"
|
||||
#include "../protocols/Tablet.hpp"
|
||||
|
||||
CProtocolManager::CProtocolManager() {
|
||||
|
||||
|
@ -53,6 +54,7 @@ CProtocolManager::CProtocolManager() {
|
|||
PROTO::outputManagement = std::make_unique<COutputManagementProtocol>(&zwlr_output_manager_v1_interface, 4, "OutputManagement");
|
||||
PROTO::serverDecorationKDE = std::make_unique<CServerDecorationKDEProtocol>(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE");
|
||||
PROTO::focusGrab = std::make_unique<CFocusGrabProtocol>(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab");
|
||||
PROTO::tablet = std::make_unique<CTabletV2Protocol>(&zwp_tablet_manager_v2_interface, 1, "TabletV2");
|
||||
|
||||
// Old protocol implementations.
|
||||
// TODO: rewrite them to use hyprwayland-scanner.
|
||||
|
|
|
@ -58,9 +58,9 @@ CInputManager::~CInputManager() {
|
|||
m_vKeyboards.clear();
|
||||
m_vPointers.clear();
|
||||
m_vTouches.clear();
|
||||
m_lTablets.clear();
|
||||
m_lTabletTools.clear();
|
||||
m_lTabletPads.clear();
|
||||
m_vTablets.clear();
|
||||
m_vTabletTools.clear();
|
||||
m_vTabletPads.clear();
|
||||
m_vIdleInhibitors.clear();
|
||||
m_lSwitches.clear();
|
||||
}
|
||||
|
@ -777,6 +777,8 @@ void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard)
|
|||
}
|
||||
|
||||
void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
|
||||
m_vHIDs.push_back(keeb);
|
||||
|
||||
try {
|
||||
keeb->hlName = getNameForNewDevice(keeb->wlr()->base.name);
|
||||
} catch (std::exception& e) {
|
||||
|
@ -977,6 +979,8 @@ void CInputManager::newMouse(wlr_input_device* mouse) {
|
|||
}
|
||||
|
||||
void CInputManager::setupMouse(SP<IPointer> mauz) {
|
||||
m_vHIDs.push_back(mauz);
|
||||
|
||||
try {
|
||||
mauz->hlName = getNameForNewDevice(mauz->wlr()->base.name);
|
||||
} catch (std::exception& e) {
|
||||
|
@ -1165,6 +1169,11 @@ void CInputManager::setPointerConfigs() {
|
|||
}
|
||||
}
|
||||
|
||||
static void removeFromHIDs(WP<IHID> hid) {
|
||||
std::erase_if(g_pInputManager->m_vHIDs, [hid](const auto& e) { return e.expired() || e == hid; });
|
||||
g_pInputManager->updateCapabilities();
|
||||
}
|
||||
|
||||
void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
|
||||
if (pKeyboard->xkbTranslationState)
|
||||
xkb_state_unref(pKeyboard->xkbTranslationState);
|
||||
|
@ -1180,6 +1189,8 @@ void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
|
|||
g_pCompositor->m_sSeat.keyboard.reset();
|
||||
wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, nullptr);
|
||||
}
|
||||
|
||||
removeFromHIDs(pKeyboard);
|
||||
}
|
||||
|
||||
void CInputManager::destroyPointer(SP<IPointer> mouse) {
|
||||
|
@ -1189,12 +1200,40 @@ void CInputManager::destroyPointer(SP<IPointer> mouse) {
|
|||
|
||||
if (!g_pCompositor->m_sSeat.mouse.expired())
|
||||
unconstrainMouse();
|
||||
|
||||
removeFromHIDs(mouse);
|
||||
}
|
||||
|
||||
void CInputManager::destroyTouchDevice(SP<ITouch> touch) {
|
||||
Debug::log(LOG, "Touch device at {:x} removed", (uintptr_t)touch.get());
|
||||
|
||||
std::erase_if(m_vTouches, [touch](const auto& other) { return other == touch; });
|
||||
|
||||
removeFromHIDs(touch);
|
||||
}
|
||||
|
||||
void CInputManager::destroyTablet(SP<CTablet> tablet) {
|
||||
Debug::log(LOG, "Tablet device at {:x} removed", (uintptr_t)tablet.get());
|
||||
|
||||
std::erase_if(m_vTablets, [tablet](const auto& other) { return other == tablet; });
|
||||
|
||||
removeFromHIDs(tablet);
|
||||
}
|
||||
|
||||
void CInputManager::destroyTabletTool(SP<CTabletTool> tool) {
|
||||
Debug::log(LOG, "Tablet tool at {:x} removed", (uintptr_t)tool.get());
|
||||
|
||||
std::erase_if(m_vTabletTools, [tool](const auto& other) { return other == tool; });
|
||||
|
||||
removeFromHIDs(tool);
|
||||
}
|
||||
|
||||
void CInputManager::destroyTabletPad(SP<CTabletPad> pad) {
|
||||
Debug::log(LOG, "Tablet pad at {:x} removed", (uintptr_t)pad.get());
|
||||
|
||||
std::erase_if(m_vTabletPads, [pad](const auto& other) { return other == pad; });
|
||||
|
||||
removeFromHIDs(pad);
|
||||
}
|
||||
|
||||
void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {
|
||||
|
@ -1338,14 +1377,19 @@ bool CInputManager::isConstrained() {
|
|||
void CInputManager::updateCapabilities() {
|
||||
uint32_t caps = 0;
|
||||
|
||||
if (!m_vKeyboards.empty())
|
||||
for (auto& h : m_vHIDs) {
|
||||
if (h.expired())
|
||||
continue;
|
||||
|
||||
auto cap = h->getCapabilities();
|
||||
|
||||
if (cap & HID_INPUT_CAPABILITY_KEYBOARD)
|
||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
if (!m_vPointers.empty())
|
||||
if (cap & HID_INPUT_CAPABILITY_POINTER)
|
||||
caps |= WL_SEAT_CAPABILITY_POINTER;
|
||||
if (!m_vTouches.empty())
|
||||
if (cap & HID_INPUT_CAPABILITY_TOUCH)
|
||||
caps |= WL_SEAT_CAPABILITY_TOUCH;
|
||||
if (!m_lTabletTools.empty())
|
||||
caps |= WL_SEAT_CAPABILITY_POINTER;
|
||||
}
|
||||
|
||||
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, caps);
|
||||
m_uiCapabilities = caps;
|
||||
|
@ -1380,6 +1424,7 @@ void CInputManager::disableAllKeyboards(bool virt) {
|
|||
|
||||
void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
|
||||
const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(wlr_touch_from_input_device(pDevice)));
|
||||
m_vHIDs.push_back(PNEWDEV);
|
||||
|
||||
try {
|
||||
PNEWDEV->hlName = getNameForNewDevice(pDevice->name);
|
||||
|
@ -1450,43 +1495,39 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
|
|||
}
|
||||
|
||||
void CInputManager::setTabletConfigs() {
|
||||
for (auto& t : m_lTablets) {
|
||||
if (wlr_input_device_is_libinput(t.wlrDevice)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(t.wlrDevice);
|
||||
for (auto& t : m_vTablets) {
|
||||
if (wlr_input_device_is_libinput(&t->wlr()->base)) {
|
||||
const auto NAME = t->hlName;
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&t->wlr()->base);
|
||||
|
||||
const auto RELINPUT = g_pConfigManager->getDeviceInt(t.name, "relative_input", "input:tablet:relative_input");
|
||||
t.relativeInput = RELINPUT;
|
||||
const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input");
|
||||
t->relativeInput = RELINPUT;
|
||||
|
||||
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(t.name, "transform", "input:tablet:transform"), 0, 7);
|
||||
Debug::log(LOG, "Setting calibration matrix for device {}", t.name);
|
||||
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(NAME, "transform", "input:tablet:transform"), 0, 7);
|
||||
Debug::log(LOG, "Setting calibration matrix for device {}", NAME);
|
||||
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
|
||||
|
||||
if (g_pConfigManager->getDeviceInt(t.name, "left_handed", "input:tablet:left_handed") == 0)
|
||||
if (g_pConfigManager->getDeviceInt(NAME, "left_handed", "input:tablet:left_handed") == 0)
|
||||
libinput_device_config_left_handed_set(LIBINPUTDEV, 0);
|
||||
else
|
||||
libinput_device_config_left_handed_set(LIBINPUTDEV, 1);
|
||||
|
||||
const auto OUTPUT = g_pConfigManager->getDeviceString(t.name, "output", "input:tablet:output");
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT);
|
||||
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) {
|
||||
Debug::log(LOG, "Binding tablet {} to output {}", t.name, PMONITOR->szName);
|
||||
// wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output);
|
||||
// wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr);
|
||||
t.boundOutput = OUTPUT;
|
||||
} else if (!PMONITOR)
|
||||
Debug::log(ERR, "Failed to bind tablet {} to output '{}': monitor not found", t.name, OUTPUT);
|
||||
const auto OUTPUT = g_pConfigManager->getDeviceString(NAME, "output", "input:tablet:output");
|
||||
if (OUTPUT != STRVAL_EMPTY) {
|
||||
Debug::log(LOG, "Binding tablet {} to output {}", NAME, OUTPUT);
|
||||
t->boundOutput = OUTPUT;
|
||||
} else
|
||||
t->boundOutput = "";
|
||||
|
||||
const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position");
|
||||
const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size");
|
||||
//auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y};
|
||||
// if (!regionBox.empty())
|
||||
// wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr());
|
||||
const auto REGION_POS = g_pConfigManager->getDeviceVec(NAME, "region_position", "input:tablet:region_position");
|
||||
const auto REGION_SIZE = g_pConfigManager->getDeviceVec(NAME, "region_size", "input:tablet:region_size");
|
||||
t->boundBox = {REGION_POS, REGION_SIZE};
|
||||
|
||||
const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(t.name, "active_area_size", "input:tablet:active_area_size");
|
||||
const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(t.name, "active_area_position", "input:tablet:active_area_position");
|
||||
const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(NAME, "active_area_size", "input:tablet:active_area_size");
|
||||
const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position");
|
||||
if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) {
|
||||
t.activeArea = CBox{ACTIVE_AREA_POS.x / t.wlrTablet->width_mm, ACTIVE_AREA_POS.y / t.wlrTablet->height_mm,
|
||||
(ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t.wlrTablet->width_mm, (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t.wlrTablet->height_mm};
|
||||
t->activeArea = CBox{ACTIVE_AREA_POS.x / t->wlr()->width_mm, ACTIVE_AREA_POS.y / t->wlr()->height_mm, (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->wlr()->width_mm,
|
||||
(ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->wlr()->height_mm};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1575,16 +1616,16 @@ std::string CInputManager::getNameForNewDevice(std::string internalName) {
|
|||
[&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTouches.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTabletPads.begin(), m_lTabletPads.end(),
|
||||
[&](const STabletPad& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletPads.end())
|
||||
while (std::find_if(m_vTabletPads.begin(), m_vTabletPads.end(),
|
||||
[&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTabletPads.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTablets.begin(), m_lTablets.end(),
|
||||
[&](const STablet& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTablets.end())
|
||||
while (std::find_if(m_vTablets.begin(), m_vTablets.end(),
|
||||
[&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTablets.end())
|
||||
dupeno++;
|
||||
|
||||
while (std::find_if(m_lTabletTools.begin(), m_lTabletTools.end(),
|
||||
[&](const STabletTool& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletTools.end())
|
||||
while (std::find_if(m_vTabletTools.begin(), m_vTabletTools.end(),
|
||||
[&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTabletTools.end())
|
||||
dupeno++;
|
||||
|
||||
return proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno)));
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "../../helpers/signal/Listener.hpp"
|
||||
#include "../../devices/IPointer.hpp"
|
||||
#include "../../devices/ITouch.hpp"
|
||||
#include "../../devices/Tablet.hpp"
|
||||
|
||||
class CPointerConstraint;
|
||||
class CWindow;
|
||||
|
@ -87,9 +88,15 @@ class CInputManager {
|
|||
void newVirtualMouse(SP<CVirtualPointerV1Resource>);
|
||||
void newTouchDevice(wlr_input_device*);
|
||||
void newSwitch(wlr_input_device*);
|
||||
void newTabletTool(wlr_tablet_tool*);
|
||||
void newTabletPad(wlr_input_device*);
|
||||
void newTablet(wlr_input_device*);
|
||||
void destroyTouchDevice(SP<ITouch>);
|
||||
void destroyKeyboard(SP<IKeyboard>);
|
||||
void destroyPointer(SP<IPointer>);
|
||||
void destroyTablet(SP<CTablet>);
|
||||
void destroyTabletTool(SP<CTabletTool>);
|
||||
void destroyTabletPad(SP<CTabletPad>);
|
||||
void destroySwitch(SSwitchDevice*);
|
||||
|
||||
void unconstrainMouse();
|
||||
|
@ -116,6 +123,15 @@ class CInputManager {
|
|||
void onTouchUp(ITouch::SUpEvent);
|
||||
void onTouchMove(ITouch::SMotionEvent);
|
||||
|
||||
void onSwipeBegin(IPointer::SSwipeBeginEvent);
|
||||
void onSwipeEnd(IPointer::SSwipeEndEvent);
|
||||
void onSwipeUpdate(IPointer::SSwipeUpdateEvent);
|
||||
|
||||
void onTabletAxis(CTablet::SAxisEvent);
|
||||
void onTabletProximity(CTablet::SProximityEvent);
|
||||
void onTabletTip(CTablet::STipEvent);
|
||||
void onTabletButton(CTablet::SButtonEvent);
|
||||
|
||||
STouchData m_sTouchData;
|
||||
|
||||
// for dragging floating windows
|
||||
|
@ -131,11 +147,10 @@ class CInputManager {
|
|||
std::vector<SP<IKeyboard>> m_vKeyboards;
|
||||
std::vector<SP<IPointer>> m_vPointers;
|
||||
std::vector<SP<ITouch>> m_vTouches;
|
||||
|
||||
// tablets
|
||||
std::list<STablet> m_lTablets;
|
||||
std::list<STabletTool> m_lTabletTools;
|
||||
std::list<STabletPad> m_lTabletPads;
|
||||
std::vector<SP<CTablet>> m_vTablets;
|
||||
std::vector<SP<CTabletTool>> m_vTabletTools;
|
||||
std::vector<SP<CTabletPad>> m_vTabletPads;
|
||||
std::vector<WP<IHID>> m_vHIDs; // general container for all HID devices connected to the input manager.
|
||||
|
||||
// Switches
|
||||
std::list<SSwitchDevice> m_lSwitches;
|
||||
|
@ -147,16 +162,9 @@ class CInputManager {
|
|||
std::vector<WP<CPointerConstraint>> m_vConstraints;
|
||||
|
||||
//
|
||||
void newTabletTool(wlr_input_device*);
|
||||
void newTabletPad(wlr_input_device*);
|
||||
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
|
||||
void newIdleInhibitor(std::any);
|
||||
void recheckIdleInhibitorStatus();
|
||||
|
||||
void onSwipeBegin(IPointer::SSwipeBeginEvent);
|
||||
void onSwipeEnd(IPointer::SSwipeEndEvent);
|
||||
void onSwipeUpdate(IPointer::SSwipeUpdateEvent);
|
||||
|
||||
SSwipeGesture m_sActiveSwipe;
|
||||
|
||||
CTimer m_tmrLastCursorMovement;
|
||||
|
@ -223,7 +231,7 @@ class CInputManager {
|
|||
|
||||
void mouseMoveUnified(uint32_t, bool refocus = false);
|
||||
|
||||
STabletTool* ensureTabletToolPresent(wlr_tablet_tool*);
|
||||
SP<CTabletTool> ensureTabletToolPresent(wlr_tablet_tool*);
|
||||
|
||||
void applyConfigToKeyboard(SP<IKeyboard>);
|
||||
|
||||
|
|
|
@ -1,290 +1,291 @@
|
|||
#include "InputManager.hpp"
|
||||
#include "../../Compositor.hpp"
|
||||
#include "../../protocols/IdleNotify.hpp"
|
||||
#include "../../protocols/Tablet.hpp"
|
||||
#include "../../devices/Tablet.hpp"
|
||||
#include "../../managers/PointerManager.hpp"
|
||||
#include "../../protocols/PointerConstraints.hpp"
|
||||
|
||||
void CInputManager::newTabletTool(wlr_input_device* pDevice) {
|
||||
const auto PNEWTABLET = &m_lTablets.emplace_back();
|
||||
static void unfocusTool(SP<CTabletTool> tool) {
|
||||
if (!tool->getSurface())
|
||||
return;
|
||||
|
||||
tool->setSurface(nullptr);
|
||||
if (tool->isDown)
|
||||
PROTO::tablet->up(tool);
|
||||
for (auto& b : tool->buttonsDown) {
|
||||
PROTO::tablet->buttonTool(tool, b, false);
|
||||
}
|
||||
PROTO::tablet->proximityOut(tool);
|
||||
}
|
||||
|
||||
static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf) {
|
||||
if (tool->getSurface() == surf || !surf)
|
||||
return;
|
||||
|
||||
if (tool->getSurface() && tool->getSurface() != surf)
|
||||
unfocusTool(tool);
|
||||
|
||||
tool->setSurface(surf);
|
||||
PROTO::tablet->proximityIn(tool, tablet, surf);
|
||||
if (tool->isDown)
|
||||
PROTO::tablet->down(tool);
|
||||
for (auto& b : tool->buttonsDown) {
|
||||
PROTO::tablet->buttonTool(tool, b, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = false) {
|
||||
const auto LASTHLSURFACE = CWLSurface::surfaceFromWlr(g_pInputManager->m_pLastMouseSurface);
|
||||
|
||||
if (!LASTHLSURFACE || !tool->active) {
|
||||
if (tool->getSurface())
|
||||
unfocusTool(tool);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto BOX = LASTHLSURFACE->getSurfaceBoxGlobal();
|
||||
|
||||
if (!BOX.has_value()) {
|
||||
if (tool->getSurface())
|
||||
unfocusTool(tool);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
focusTool(tool, tab, g_pInputManager->m_pLastMouseSurface);
|
||||
|
||||
if (!motion)
|
||||
return;
|
||||
|
||||
if (LASTHLSURFACE->constraint() && tool->wlr()->type != WLR_TABLET_TOOL_TYPE_MOUSE) {
|
||||
// cursor logic will completely break here as the cursor will be locked.
|
||||
// let's just "map" the desired position to the constraint area.
|
||||
|
||||
Vector2D local;
|
||||
|
||||
// yes, this technically ignores any regions set by the app. Too bad!
|
||||
if (LASTHLSURFACE->getWindow())
|
||||
local = tool->absolutePos * LASTHLSURFACE->getWindow()->m_vRealSize.goal();
|
||||
else
|
||||
local = tool->absolutePos * BOX->size();
|
||||
|
||||
if (LASTHLSURFACE->getWindow() && LASTHLSURFACE->getWindow()->m_bIsX11)
|
||||
local = local * LASTHLSURFACE->getWindow()->m_fX11SurfaceScaledBy;
|
||||
|
||||
PROTO::tablet->motion(tool, local);
|
||||
return;
|
||||
}
|
||||
|
||||
auto local = CURSORPOS - BOX->pos();
|
||||
|
||||
if (LASTHLSURFACE->getWindow() && LASTHLSURFACE->getWindow()->m_bIsX11)
|
||||
local = local * LASTHLSURFACE->getWindow()->m_fX11SurfaceScaledBy;
|
||||
|
||||
PROTO::tablet->motion(tool, local);
|
||||
}
|
||||
|
||||
void CInputManager::onTabletAxis(CTablet::SAxisEvent e) {
|
||||
const auto PTAB = e.tablet;
|
||||
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
||||
|
||||
if (PTOOL->active && (e.updatedAxes & (CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X | CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y))) {
|
||||
double x = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X) ? e.axis.x : NAN;
|
||||
double dx = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X) ? e.axisDelta.x : NAN;
|
||||
double y = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y) ? e.axis.y : NAN;
|
||||
double dy = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y) ? e.axisDelta.y : NAN;
|
||||
|
||||
Vector2D delta = {std::isnan(dx) ? 0.0 : dx, std::isnan(dy) ? 0.0 : dy};
|
||||
|
||||
switch (e.tool->type) {
|
||||
case WLR_TABLET_TOOL_TYPE_MOUSE: {
|
||||
g_pPointerManager->move(delta);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (!std::isnan(x))
|
||||
PTOOL->absolutePos.x = x;
|
||||
if (!std::isnan(y))
|
||||
PTOOL->absolutePos.y = y;
|
||||
|
||||
if (PTAB->relativeInput)
|
||||
g_pPointerManager->move(delta);
|
||||
else {
|
||||
//Calculate transformations if active area is set
|
||||
if (!PTAB->activeArea.empty()) {
|
||||
if (!std::isnan(x))
|
||||
x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x);
|
||||
if (!std::isnan(y))
|
||||
y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y);
|
||||
}
|
||||
g_pPointerManager->warpAbsolute({x, y}, PTAB);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
refocusTablet(PTAB, PTOOL, true);
|
||||
m_tmrLastCursorMovement.reset();
|
||||
}
|
||||
|
||||
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE)
|
||||
PROTO::tablet->pressure(PTOOL, e.pressure);
|
||||
|
||||
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE)
|
||||
PROTO::tablet->distance(PTOOL, e.distance);
|
||||
|
||||
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION)
|
||||
PROTO::tablet->rotation(PTOOL, e.rotation);
|
||||
|
||||
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER)
|
||||
PROTO::tablet->slider(PTOOL, e.slider);
|
||||
|
||||
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL)
|
||||
PROTO::tablet->wheel(PTOOL, e.wheelDelta);
|
||||
|
||||
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X)
|
||||
PTOOL->tilt.x = e.tilt.x;
|
||||
|
||||
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y)
|
||||
PTOOL->tilt.y = e.tilt.y;
|
||||
|
||||
if (e.updatedAxes & (CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X | CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y))
|
||||
PROTO::tablet->tilt(PTOOL, PTOOL->tilt);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
}
|
||||
|
||||
void CInputManager::onTabletTip(CTablet::STipEvent e) {
|
||||
const auto PTAB = e.tablet;
|
||||
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
||||
|
||||
if (e.in) {
|
||||
simulateMouseMovement();
|
||||
refocusTablet(PTAB, PTOOL);
|
||||
PROTO::tablet->down(PTOOL);
|
||||
} else
|
||||
PROTO::tablet->up(PTOOL);
|
||||
|
||||
PTOOL->isDown = e.in;
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
}
|
||||
|
||||
void CInputManager::onTabletButton(CTablet::SButtonEvent e) {
|
||||
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
||||
|
||||
PROTO::tablet->buttonTool(PTOOL, e.button, e.down);
|
||||
|
||||
if (e.down)
|
||||
PTOOL->buttonsDown.push_back(e.button);
|
||||
else
|
||||
std::erase(PTOOL->buttonsDown, e.button);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
}
|
||||
|
||||
void CInputManager::onTabletProximity(CTablet::SProximityEvent e) {
|
||||
const auto PTAB = e.tablet;
|
||||
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
||||
|
||||
PTOOL->active = e.in;
|
||||
|
||||
if (!e.in) {
|
||||
if (PTOOL->getSurface())
|
||||
unfocusTool(PTOOL);
|
||||
} else {
|
||||
simulateMouseMovement();
|
||||
refocusTablet(PTAB, PTOOL);
|
||||
}
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
}
|
||||
|
||||
void CInputManager::newTablet(wlr_input_device* pDevice) {
|
||||
const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(wlr_tablet_from_input_device(pDevice)));
|
||||
m_vHIDs.push_back(PNEWTABLET);
|
||||
|
||||
try {
|
||||
PNEWTABLET->name = deviceNameToInternalString(pDevice->name);
|
||||
PNEWTABLET->hlName = deviceNameToInternalString(pDevice->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Tablet had no name???"); // logic error
|
||||
}
|
||||
|
||||
PNEWTABLET->wlrTablet = wlr_tablet_from_input_device(pDevice);
|
||||
PNEWTABLET->wlrDevice = pDevice;
|
||||
PNEWTABLET->wlrTabletV2 = wlr_tablet_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice);
|
||||
PNEWTABLET->wlrTablet->data = PNEWTABLET;
|
||||
g_pPointerManager->attachTablet(PNEWTABLET);
|
||||
|
||||
Debug::log(LOG, "Attaching tablet to cursor!");
|
||||
|
||||
// wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice);
|
||||
|
||||
PNEWTABLET->hyprListener_Destroy.initCallback(
|
||||
&pDevice->events.destroy,
|
||||
[](void* owner, void* data) {
|
||||
const auto PTAB = (STablet*)owner;
|
||||
|
||||
g_pInputManager->m_lTablets.remove(*PTAB);
|
||||
|
||||
Debug::log(LOG, "Removed a tablet");
|
||||
PNEWTABLET->events.destroy.registerStaticListener(
|
||||
[this](void* owner, std::any d) {
|
||||
auto TABLET = ((CTablet*)owner)->self;
|
||||
destroyTablet(TABLET.lock());
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
PNEWTABLET->hyprListener_Axis.initCallback(
|
||||
&wlr_tablet_from_input_device(pDevice)->events.axis,
|
||||
[](void* owner, void* data) {
|
||||
const auto EVENT = (wlr_tablet_tool_axis_event*)data;
|
||||
const auto PTAB = (STablet*)owner;
|
||||
|
||||
switch (EVENT->tool->type) {
|
||||
case WLR_TABLET_TOOL_TYPE_MOUSE:
|
||||
// wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy);
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
|
||||
g_pInputManager->m_tmrLastCursorMovement.reset();
|
||||
break;
|
||||
default:
|
||||
double x = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->x : NAN;
|
||||
double dx = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->dx : NAN;
|
||||
double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN;
|
||||
double dy = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->dy : NAN;
|
||||
|
||||
// if (PTAB->relativeInput)
|
||||
// wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy);
|
||||
// else {
|
||||
// Calculate transformations if active area is set
|
||||
// if (!PTAB->activeArea.empty()) {
|
||||
// x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x);
|
||||
// y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y);
|
||||
// }
|
||||
// wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
|
||||
// }
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
|
||||
g_pInputManager->m_tmrLastCursorMovement.reset();
|
||||
break;
|
||||
}
|
||||
|
||||
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
|
||||
|
||||
// TODO: this might be wrong
|
||||
if (PTOOL->active) {
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
|
||||
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
|
||||
}
|
||||
|
||||
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)
|
||||
wlr_tablet_v2_tablet_tool_notify_pressure(PTOOL->wlrTabletToolV2, EVENT->pressure);
|
||||
|
||||
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)
|
||||
wlr_tablet_v2_tablet_tool_notify_distance(PTOOL->wlrTabletToolV2, EVENT->distance);
|
||||
|
||||
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION)
|
||||
wlr_tablet_v2_tablet_tool_notify_rotation(PTOOL->wlrTabletToolV2, EVENT->rotation);
|
||||
|
||||
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER)
|
||||
wlr_tablet_v2_tablet_tool_notify_slider(PTOOL->wlrTabletToolV2, EVENT->slider);
|
||||
|
||||
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL)
|
||||
wlr_tablet_v2_tablet_tool_notify_wheel(PTOOL->wlrTabletToolV2, EVENT->wheel_delta, 0);
|
||||
|
||||
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X)
|
||||
PTOOL->tiltX = EVENT->tilt_x;
|
||||
|
||||
if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y)
|
||||
PTOOL->tiltY = EVENT->tilt_y;
|
||||
|
||||
if (EVENT->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
|
||||
wlr_tablet_v2_tablet_tool_notify_tilt(PTOOL->wlrTabletToolV2, PTOOL->tiltX, PTOOL->tiltY);
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
PNEWTABLET->hyprListener_Tip.initCallback(
|
||||
&wlr_tablet_from_input_device(pDevice)->events.tip,
|
||||
[](void* owner, void* data) {
|
||||
const auto EVENT = (wlr_tablet_tool_tip_event*)data;
|
||||
const auto PTAB = (STablet*)owner;
|
||||
|
||||
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
|
||||
|
||||
// TODO: this might be wrong
|
||||
if (EVENT->state == WLR_TABLET_TOOL_TIP_DOWN) {
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->focusTablet(PTAB, EVENT->tool);
|
||||
wlr_send_tablet_v2_tablet_tool_down(PTOOL->wlrTabletToolV2);
|
||||
} else {
|
||||
wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2);
|
||||
}
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
PNEWTABLET->hyprListener_Button.initCallback(
|
||||
&wlr_tablet_from_input_device(pDevice)->events.button,
|
||||
[](void* owner, void* data) {
|
||||
const auto EVENT = (wlr_tablet_tool_button_event*)data;
|
||||
|
||||
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
|
||||
|
||||
wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state);
|
||||
PROTO::idle->onActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
|
||||
PNEWTABLET->hyprListener_Proximity.initCallback(
|
||||
&wlr_tablet_from_input_device(pDevice)->events.proximity,
|
||||
[](void* owner, void* data) {
|
||||
const auto EVENT = (wlr_tablet_tool_proximity_event*)data;
|
||||
const auto PTAB = (STablet*)owner;
|
||||
|
||||
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
|
||||
|
||||
if (EVENT->state == WLR_TABLET_TOOL_PROXIMITY_OUT) {
|
||||
PTOOL->active = false;
|
||||
|
||||
if (PTOOL->pSurface) {
|
||||
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
|
||||
PTOOL->pSurface = nullptr;
|
||||
}
|
||||
|
||||
} else {
|
||||
PTOOL->active = true;
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
g_pInputManager->focusTablet(PTAB, EVENT->tool);
|
||||
}
|
||||
|
||||
PROTO::idle->onActivity();
|
||||
},
|
||||
PNEWTABLET, "Tablet");
|
||||
PNEWTABLET.get());
|
||||
|
||||
setTabletConfigs();
|
||||
}
|
||||
|
||||
STabletTool* CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) {
|
||||
SP<CTabletTool> CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) {
|
||||
if (pTool->data == nullptr) {
|
||||
const auto PTOOL = &m_lTabletTools.emplace_back();
|
||||
const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool));
|
||||
m_vHIDs.push_back(PTOOL);
|
||||
|
||||
Debug::log(LOG, "Creating tablet tool v2 for {:x}", (uintptr_t)pTool);
|
||||
|
||||
PTOOL->wlrTabletTool = pTool;
|
||||
pTool->data = PTOOL;
|
||||
|
||||
PTOOL->wlrTabletToolV2 = wlr_tablet_tool_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pTool);
|
||||
|
||||
PTOOL->hyprListener_TabletToolDestroy.initCallback(
|
||||
&pTool->events.destroy,
|
||||
[](void* owner, void* data) {
|
||||
const auto PTOOL = (STabletTool*)owner;
|
||||
|
||||
PTOOL->wlrTabletTool->data = nullptr;
|
||||
g_pInputManager->m_lTabletTools.remove(*PTOOL);
|
||||
PTOOL->events.destroy.registerStaticListener(
|
||||
[this](void* owner, std::any d) {
|
||||
auto TOOL = ((CTabletTool*)owner)->self;
|
||||
destroyTabletTool(TOOL.lock());
|
||||
},
|
||||
PTOOL, "Tablet Tool V1");
|
||||
|
||||
//TODO: set cursor request
|
||||
PTOOL.get());
|
||||
}
|
||||
|
||||
return (STabletTool*)pTool->data;
|
||||
return CTabletTool::fromWlr(pTool);
|
||||
}
|
||||
|
||||
void CInputManager::newTabletPad(wlr_input_device* pDevice) {
|
||||
const auto PNEWPAD = &m_lTabletPads.emplace_back();
|
||||
const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(wlr_tablet_pad_from_input_device(pDevice)));
|
||||
m_vHIDs.push_back(PNEWPAD);
|
||||
|
||||
try {
|
||||
PNEWPAD->name = deviceNameToInternalString(pDevice->name);
|
||||
PNEWPAD->hlName = deviceNameToInternalString(pDevice->name);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Pad had no name???"); // logic error
|
||||
}
|
||||
|
||||
PNEWPAD->wlrTabletPadV2 = wlr_tablet_pad_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice);
|
||||
PNEWPAD->pWlrDevice = pDevice;
|
||||
// clang-format off
|
||||
PNEWPAD->events.destroy.registerStaticListener([this](void* owner, std::any d) {
|
||||
auto PAD = ((CTabletPad*)owner)->self;
|
||||
destroyTabletPad(PAD.lock());
|
||||
}, PNEWPAD.get());
|
||||
|
||||
PNEWPAD->hyprListener_Button.initCallback(
|
||||
&wlr_tablet_pad_from_input_device(pDevice)->events.button,
|
||||
[](void* owner, void* data) {
|
||||
const auto EVENT = (wlr_tablet_pad_button_event*)data;
|
||||
const auto PPAD = (STabletPad*)owner;
|
||||
PNEWPAD->padEvents.button.registerStaticListener([this](void* owner, std::any e) {
|
||||
const auto E = std::any_cast<CTabletPad::SButtonEvent>(e);
|
||||
const auto PPAD = ((CTabletPad*)owner)->self.lock();
|
||||
|
||||
wlr_tablet_v2_tablet_pad_notify_mode(PPAD->wlrTabletPadV2, EVENT->group, EVENT->mode, EVENT->time_msec);
|
||||
wlr_tablet_v2_tablet_pad_notify_button(PPAD->wlrTabletPadV2, EVENT->button, EVENT->time_msec, (zwp_tablet_pad_v2_button_state)EVENT->state);
|
||||
},
|
||||
PNEWPAD, "Tablet Pad");
|
||||
PROTO::tablet->mode(PPAD, 0, E.mode, E.timeMs);
|
||||
PROTO::tablet->buttonPad(PPAD, E.button, E.timeMs, E.down);
|
||||
}, PNEWPAD.get());
|
||||
|
||||
PNEWPAD->hyprListener_Strip.initCallback(
|
||||
&wlr_tablet_pad_from_input_device(pDevice)->events.strip,
|
||||
[](void* owner, void* data) {
|
||||
const auto EVENT = (wlr_tablet_pad_strip_event*)data;
|
||||
const auto PPAD = (STabletPad*)owner;
|
||||
PNEWPAD->padEvents.strip.registerStaticListener([this](void* owner, std::any e) {
|
||||
const auto E = std::any_cast<CTabletPad::SStripEvent>(e);
|
||||
const auto PPAD = ((CTabletPad*)owner)->self.lock();
|
||||
|
||||
wlr_tablet_v2_tablet_pad_notify_strip(PPAD->wlrTabletPadV2, EVENT->strip, EVENT->position, EVENT->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, EVENT->time_msec);
|
||||
},
|
||||
PNEWPAD, "Tablet Pad");
|
||||
PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs);
|
||||
}, PNEWPAD.get());
|
||||
|
||||
PNEWPAD->hyprListener_Ring.initCallback(
|
||||
&wlr_tablet_pad_from_input_device(pDevice)->events.strip,
|
||||
[](void* owner, void* data) {
|
||||
const auto EVENT = (wlr_tablet_pad_ring_event*)data;
|
||||
const auto PPAD = (STabletPad*)owner;
|
||||
PNEWPAD->padEvents.ring.registerStaticListener([this](void* owner, std::any e) {
|
||||
const auto E = std::any_cast<CTabletPad::SRingEvent>(e);
|
||||
const auto PPAD = ((CTabletPad*)owner)->self.lock();
|
||||
|
||||
wlr_tablet_v2_tablet_pad_notify_ring(PPAD->wlrTabletPadV2, EVENT->ring, EVENT->position, EVENT->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, EVENT->time_msec);
|
||||
},
|
||||
PNEWPAD, "Tablet Pad");
|
||||
PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs);
|
||||
}, PNEWPAD.get());
|
||||
|
||||
PNEWPAD->hyprListener_Attach.initCallback(
|
||||
&wlr_tablet_pad_from_input_device(pDevice)->events.strip,
|
||||
[](void* owner, void* data) {
|
||||
const auto TABLET = (wlr_tablet_tool*)data;
|
||||
const auto PPAD = (STabletPad*)owner;
|
||||
PNEWPAD->padEvents.attach.registerStaticListener([this](void* owner, std::any e) {
|
||||
const auto PPAD = ((CTabletPad*)owner)->self.lock();
|
||||
const auto TOOL = std::any_cast<SP<CTabletTool>>(e);
|
||||
|
||||
PPAD->pTabletParent = (STablet*)TABLET->data;
|
||||
PPAD->parent = TOOL;
|
||||
}, PNEWPAD.get());
|
||||
|
||||
if (!PPAD->pTabletParent)
|
||||
Debug::log(ERR, "tabletpad got attached to a nullptr tablet!! this might be bad.");
|
||||
},
|
||||
PNEWPAD, "Tablet Pad");
|
||||
|
||||
PNEWPAD->hyprListener_Destroy.initCallback(
|
||||
&pDevice->events.destroy,
|
||||
[](void* owner, void* data) {
|
||||
const auto PPAD = (STabletPad*)owner;
|
||||
|
||||
g_pInputManager->m_lTabletPads.remove(*PPAD);
|
||||
|
||||
Debug::log(LOG, "Removed a tablet pad");
|
||||
},
|
||||
PNEWPAD, "Tablet Pad");
|
||||
}
|
||||
|
||||
void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool motion) {
|
||||
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(pTool);
|
||||
|
||||
if (const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); PWINDOW) {
|
||||
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal();
|
||||
|
||||
if (PTOOL->pSurface != g_pInputManager->m_pLastMouseSurface)
|
||||
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
|
||||
|
||||
if (g_pInputManager->m_pLastMouseSurface) {
|
||||
PTOOL->pSurface = g_pCompositor->m_pLastFocus;
|
||||
wlr_tablet_v2_tablet_tool_notify_proximity_in(PTOOL->wlrTabletToolV2, pTab->wlrTabletV2, g_pInputManager->m_pLastMouseSurface);
|
||||
}
|
||||
|
||||
if (motion) {
|
||||
auto local = CURSORPOS - PWINDOW->m_vRealPosition.goal();
|
||||
|
||||
if (PWINDOW->m_bIsX11)
|
||||
local = local * PWINDOW->m_fX11SurfaceScaledBy;
|
||||
|
||||
wlr_tablet_v2_tablet_tool_notify_motion(PTOOL->wlrTabletToolV2, local.x, local.y);
|
||||
}
|
||||
} else {
|
||||
if (PTOOL->pSurface)
|
||||
wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2);
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
|
656
src/protocols/Tablet.cpp
Normal file
656
src/protocols/Tablet.cpp
Normal file
|
@ -0,0 +1,656 @@
|
|||
#include "Tablet.hpp"
|
||||
#include "../devices/Tablet.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
#define LOGM PROTO::tablet->protoLog
|
||||
|
||||
CTabletPadStripV2Resource::CTabletPadStripV2Resource(SP<CZwpTabletPadStripV2> resource_, uint32_t id_) : id(id_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CZwpTabletPadStripV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CZwpTabletPadStripV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
}
|
||||
|
||||
bool CTabletPadStripV2Resource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
CTabletPadRingV2Resource::CTabletPadRingV2Resource(SP<CZwpTabletPadRingV2> resource_, uint32_t id_) : id(id_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CZwpTabletPadRingV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CZwpTabletPadRingV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
}
|
||||
|
||||
bool CTabletPadRingV2Resource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
CTabletPadGroupV2Resource::CTabletPadGroupV2Resource(SP<CZwpTabletPadGroupV2> resource_, size_t idx_) : idx(idx_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CZwpTabletPadGroupV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CZwpTabletPadGroupV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
}
|
||||
|
||||
bool CTabletPadGroupV2Resource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CTabletPadGroupV2Resource::sendData(SP<CTabletPad> pad, wlr_tablet_pad_group* group) {
|
||||
resource->sendModes(group->mode_count);
|
||||
|
||||
wl_array buttonArr;
|
||||
wl_array_init(&buttonArr);
|
||||
wl_array_add(&buttonArr, group->button_count * sizeof(int));
|
||||
memcpy(buttonArr.data, group->buttons, group->button_count * sizeof(int));
|
||||
resource->sendButtons(&buttonArr);
|
||||
wl_array_release(&buttonArr);
|
||||
|
||||
for (size_t i = 0; i < group->strip_count; ++i) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vStrips.emplace_back(makeShared<CTabletPadStripV2Resource>(makeShared<CZwpTabletPadStripV2>(resource->client(), resource->version(), 0), i));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
PROTO::tablet->m_vStrips.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
resource->sendStrip(RESOURCE->resource.get());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < group->ring_count; ++i) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vRings.emplace_back(makeShared<CTabletPadRingV2Resource>(makeShared<CZwpTabletPadRingV2>(resource->client(), resource->version(), 0), i));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
PROTO::tablet->m_vRings.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
resource->sendRing(RESOURCE->resource.get());
|
||||
}
|
||||
|
||||
resource->sendDone();
|
||||
}
|
||||
|
||||
CTabletPadV2Resource::CTabletPadV2Resource(SP<CZwpTabletPadV2> resource_, SP<CTabletPad> pad_, SP<CTabletSeat> seat_) : pad(pad_), seat(seat_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CZwpTabletPadV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CZwpTabletPadV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
}
|
||||
|
||||
bool CTabletPadV2Resource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CTabletPadV2Resource::sendData() {
|
||||
// this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts
|
||||
const char** path_ptr;
|
||||
for (path_ptr = (const char**)(&pad->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&pad->wlr()->paths)->data + (&pad->wlr()->paths)->size); (path_ptr)++) {
|
||||
resource->sendPath(*path_ptr);
|
||||
}
|
||||
|
||||
resource->sendButtons(pad->wlr()->button_count);
|
||||
|
||||
wlr_tablet_pad_group* group;
|
||||
size_t i = 0;
|
||||
wl_list_for_each(group, &pad->wlr()->groups, link) {
|
||||
createGroup(group, i++);
|
||||
}
|
||||
|
||||
resource->sendDone();
|
||||
}
|
||||
|
||||
void CTabletPadV2Resource::createGroup(wlr_tablet_pad_group* group, size_t idx) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vGroups.emplace_back(makeShared<CTabletPadGroupV2Resource>(makeShared<CZwpTabletPadGroupV2>(resource->client(), resource->version(), 0), idx));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
PROTO::tablet->m_vGroups.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
resource->sendGroup(RESOURCE->resource.get());
|
||||
|
||||
RESOURCE->sendData(pad.lock(), group);
|
||||
}
|
||||
|
||||
CTabletV2Resource::CTabletV2Resource(SP<CZwpTabletV2> resource_, SP<CTablet> tablet_, SP<CTabletSeat> seat_) : tablet(tablet_), seat(seat_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CZwpTabletV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CZwpTabletV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
}
|
||||
|
||||
bool CTabletV2Resource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CTabletV2Resource::sendData() {
|
||||
resource->sendName(tablet->deviceName.c_str());
|
||||
resource->sendId(tablet->wlr()->usb_vendor_id, tablet->wlr()->usb_product_id);
|
||||
|
||||
// this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts
|
||||
const char** path_ptr;
|
||||
for (path_ptr = (const char**)(&tablet->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&tablet->wlr()->paths)->data + (&tablet->wlr()->paths)->size);
|
||||
(path_ptr)++) {
|
||||
resource->sendPath(*path_ptr);
|
||||
}
|
||||
|
||||
resource->sendDone();
|
||||
}
|
||||
|
||||
CTabletToolV2Resource::CTabletToolV2Resource(SP<CZwpTabletToolV2> resource_, SP<CTabletTool> tool_, SP<CTabletSeat> seat_) : tool(tool_), seat(seat_), resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
|
||||
resource->setSetCursor([this](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) {
|
||||
wlr_seat_pointer_request_set_cursor_event e;
|
||||
e.hotspot_x = hot_x;
|
||||
e.hotspot_y = hot_y;
|
||||
e.surface = surf ? wlr_surface_from_resource(surf) : nullptr;
|
||||
e.serial = serial;
|
||||
g_pInputManager->processMouseRequest(&e);
|
||||
});
|
||||
}
|
||||
|
||||
CTabletToolV2Resource::~CTabletToolV2Resource() {
|
||||
if (frameSource)
|
||||
wl_event_source_remove(frameSource);
|
||||
}
|
||||
|
||||
bool CTabletToolV2Resource::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CTabletToolV2Resource::sendData() {
|
||||
static auto WLR_TYPE_TO_PROTO = [](uint32_t wlr) -> zwpTabletToolV2Type {
|
||||
switch (wlr) {
|
||||
case WLR_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN;
|
||||
case WLR_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER;
|
||||
case WLR_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH;
|
||||
case WLR_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL;
|
||||
case WLR_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH;
|
||||
case WLR_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE;
|
||||
case WLR_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS;
|
||||
default: ASSERT(false);
|
||||
}
|
||||
UNREACHABLE();
|
||||
};
|
||||
|
||||
resource->sendType(WLR_TYPE_TO_PROTO(tool->wlr()->type));
|
||||
resource->sendHardwareSerial(tool->wlr()->hardware_serial >> 32, tool->wlr()->hardware_serial & 0xFFFFFFFF);
|
||||
resource->sendHardwareIdWacom(tool->wlr()->hardware_wacom >> 32, tool->wlr()->hardware_wacom & 0xFFFFFFFF);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_DISTANCE)
|
||||
resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_PRESSURE)
|
||||
resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_ROTATION)
|
||||
resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_SLIDER)
|
||||
resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_TILT)
|
||||
resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_TILT);
|
||||
if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_WHEEL)
|
||||
resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL);
|
||||
resource->sendDone();
|
||||
}
|
||||
|
||||
void CTabletToolV2Resource::queueFrame() {
|
||||
if (frameSource)
|
||||
return;
|
||||
|
||||
frameSource = wl_event_loop_add_idle(
|
||||
g_pCompositor->m_sWLEventLoop, [](void* data) { ((CTabletToolV2Resource*)data)->sendFrame(false); }, this);
|
||||
}
|
||||
|
||||
void CTabletToolV2Resource::sendFrame(bool removeSource) {
|
||||
if (frameSource) {
|
||||
if (removeSource)
|
||||
wl_event_source_remove(frameSource);
|
||||
frameSource = nullptr;
|
||||
}
|
||||
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
resource->sendFrame(now.tv_sec * 1000 + now.tv_nsec / 1000000);
|
||||
}
|
||||
|
||||
CTabletSeat::CTabletSeat(SP<CZwpTabletSeatV2> resource_) : resource(resource_) {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
resource->setDestroy([this](CZwpTabletSeatV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CZwpTabletSeatV2* r) { PROTO::tablet->destroyResource(this); });
|
||||
}
|
||||
|
||||
bool CTabletSeat::good() {
|
||||
return resource->resource();
|
||||
}
|
||||
|
||||
void CTabletSeat::sendTool(SP<CTabletTool> tool) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vTools.emplace_back(makeShared<CTabletToolV2Resource>(makeShared<CZwpTabletToolV2>(resource->client(), resource->version(), 0), tool, self.lock()));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
PROTO::tablet->m_vTools.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
resource->sendToolAdded(RESOURCE->resource.get());
|
||||
|
||||
RESOURCE->sendData();
|
||||
tools.push_back(RESOURCE);
|
||||
}
|
||||
|
||||
void CTabletSeat::sendPad(SP<CTabletPad> pad) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vPads.emplace_back(makeShared<CTabletPadV2Resource>(makeShared<CZwpTabletPadV2>(resource->client(), resource->version(), 0), pad, self.lock()));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
PROTO::tablet->m_vPads.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
resource->sendPadAdded(RESOURCE->resource.get());
|
||||
|
||||
RESOURCE->sendData();
|
||||
pads.push_back(RESOURCE);
|
||||
}
|
||||
|
||||
void CTabletSeat::sendTablet(SP<CTablet> tablet) {
|
||||
const auto RESOURCE =
|
||||
PROTO::tablet->m_vTablets.emplace_back(makeShared<CTabletV2Resource>(makeShared<CZwpTabletV2>(resource->client(), resource->version(), 0), tablet, self.lock()));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
resource->noMemory();
|
||||
PROTO::tablet->m_vTablets.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
resource->sendTabletAdded(RESOURCE->resource.get());
|
||||
|
||||
RESOURCE->sendData();
|
||||
tablets.push_back(RESOURCE);
|
||||
}
|
||||
|
||||
void CTabletSeat::sendData() {
|
||||
for (auto& tw : PROTO::tablet->tablets) {
|
||||
if (tw.expired())
|
||||
continue;
|
||||
|
||||
sendTablet(tw.lock());
|
||||
}
|
||||
|
||||
for (auto& tw : PROTO::tablet->tools) {
|
||||
if (tw.expired())
|
||||
continue;
|
||||
|
||||
sendTool(tw.lock());
|
||||
}
|
||||
|
||||
for (auto& tw : PROTO::tablet->pads) {
|
||||
if (tw.expired())
|
||||
continue;
|
||||
|
||||
sendPad(tw.lock());
|
||||
}
|
||||
}
|
||||
|
||||
CTabletV2Protocol::CTabletV2Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
|
||||
;
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||
const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CZwpTabletManagerV2>(client, ver, id)).get();
|
||||
RESOURCE->setOnDestroy([this](CZwpTabletManagerV2* p) { this->onManagerResourceDestroy(p->resource()); });
|
||||
|
||||
RESOURCE->setDestroy([this](CZwpTabletManagerV2* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
|
||||
RESOURCE->setGetTabletSeat([this](CZwpTabletManagerV2* pMgr, uint32_t id, wl_resource* seat) { this->onGetSeat(pMgr, id, seat); });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::onManagerResourceDestroy(wl_resource* res) {
|
||||
std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::destroyResource(CTabletSeat* resource) {
|
||||
std::erase_if(m_vSeats, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::destroyResource(CTabletToolV2Resource* resource) {
|
||||
std::erase_if(m_vTools, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::destroyResource(CTabletV2Resource* resource) {
|
||||
std::erase_if(m_vTablets, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::destroyResource(CTabletPadV2Resource* resource) {
|
||||
std::erase_if(m_vPads, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::destroyResource(CTabletPadGroupV2Resource* resource) {
|
||||
std::erase_if(m_vGroups, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::destroyResource(CTabletPadRingV2Resource* resource) {
|
||||
std::erase_if(m_vRings, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::destroyResource(CTabletPadStripV2Resource* resource) {
|
||||
std::erase_if(m_vStrips, [&](const auto& other) { return other.get() == resource; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::onGetSeat(CZwpTabletManagerV2* pMgr, uint32_t id, wl_resource* seat) {
|
||||
const auto RESOURCE = m_vSeats.emplace_back(makeShared<CTabletSeat>(makeShared<CZwpTabletSeatV2>(pMgr->client(), pMgr->version(), id)));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
pMgr->noMemory();
|
||||
m_vSeats.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
RESOURCE->self = RESOURCE;
|
||||
RESOURCE->sendData();
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::registerDevice(SP<CTablet> tablet) {
|
||||
for (auto& s : m_vSeats) {
|
||||
s->sendTablet(tablet);
|
||||
}
|
||||
|
||||
tablets.push_back(tablet);
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::registerDevice(SP<CTabletTool> tool) {
|
||||
for (auto& s : m_vSeats) {
|
||||
s->sendTool(tool);
|
||||
}
|
||||
|
||||
tools.push_back(tool);
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::registerDevice(SP<CTabletPad> pad) {
|
||||
for (auto& s : m_vSeats) {
|
||||
s->sendPad(pad);
|
||||
}
|
||||
|
||||
pads.push_back(pad);
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::unregisterDevice(SP<CTablet> tablet) {
|
||||
for (auto& t : m_vTablets) {
|
||||
if (t->tablet == tablet) {
|
||||
t->resource->sendRemoved();
|
||||
t->inert = true;
|
||||
}
|
||||
}
|
||||
std::erase_if(tablets, [tablet](const auto& e) { return e.expired() || e == tablet; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::unregisterDevice(SP<CTabletTool> tool) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool == tool) {
|
||||
t->resource->sendRemoved();
|
||||
t->inert = true;
|
||||
}
|
||||
}
|
||||
std::erase_if(tools, [tool](const auto& e) { return e.expired() || e == tool; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::unregisterDevice(SP<CTabletPad> pad) {
|
||||
for (auto& t : m_vPads) {
|
||||
if (t->pad == pad) {
|
||||
t->resource->sendRemoved();
|
||||
t->inert = true;
|
||||
}
|
||||
}
|
||||
std::erase_if(pads, [pad](const auto& e) { return e.expired() || e == pad; });
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::recheckRegisteredDevices() {
|
||||
std::erase_if(tablets, [](const auto& e) { return e.expired(); });
|
||||
std::erase_if(tools, [](const auto& e) { return e.expired(); });
|
||||
std::erase_if(pads, [](const auto& e) { return e.expired(); });
|
||||
|
||||
// now we need to send removed events
|
||||
for (auto& t : m_vTablets) {
|
||||
if (!t->tablet.expired() || t->inert)
|
||||
continue;
|
||||
|
||||
t->resource->sendRemoved();
|
||||
t->inert = true;
|
||||
}
|
||||
|
||||
for (auto& t : m_vTools) {
|
||||
if (!t->tool.expired() || t->inert)
|
||||
continue;
|
||||
|
||||
if (t->current) {
|
||||
t->resource->sendProximityOut();
|
||||
t->sendFrame();
|
||||
t->lastSurf = nullptr;
|
||||
}
|
||||
|
||||
t->resource->sendRemoved();
|
||||
t->inert = true;
|
||||
}
|
||||
|
||||
for (auto& t : m_vPads) {
|
||||
if (!t->pad.expired() || t->inert)
|
||||
continue;
|
||||
|
||||
t->resource->sendRemoved();
|
||||
t->inert = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::pressure(SP<CTabletTool> tool, double value) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendPressure(std::clamp(value * 65535, 0.0, 65535.0));
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::distance(SP<CTabletTool> tool, double value) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendDistance(std::clamp(value * 65535, 0.0, 65535.0));
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::rotation(SP<CTabletTool> tool, double value) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendRotation(wl_fixed_from_double(value));
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::slider(SP<CTabletTool> tool, double value) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendSlider(std::clamp(value * 65535, -65535.0, 65535.0));
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::wheel(SP<CTabletTool> tool, double value) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendWheel(wl_fixed_from_double(value), 0);
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::tilt(SP<CTabletTool> tool, const Vector2D& value) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendTilt(wl_fixed_from_double(value.x), wl_fixed_from_double(value.y));
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::up(SP<CTabletTool> tool) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendUp();
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::down(SP<CTabletTool> tool) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client()));
|
||||
t->resource->sendDown(serial);
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf) {
|
||||
proximityOut(tool);
|
||||
const auto CLIENT = wl_resource_get_client(surf->resource);
|
||||
|
||||
SP<CTabletToolV2Resource> toolResource;
|
||||
SP<CTabletV2Resource> tabletResource;
|
||||
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || t->resource->client() != CLIENT)
|
||||
continue;
|
||||
|
||||
if (t->seat.expired()) {
|
||||
LOGM(ERR, "proximityIn on a tool without a seat parent");
|
||||
return;
|
||||
}
|
||||
|
||||
if (t->lastSurf == surf)
|
||||
return;
|
||||
|
||||
toolResource = t;
|
||||
|
||||
for (auto& tab : m_vTablets) {
|
||||
if (tab->tablet != tablet)
|
||||
continue;
|
||||
|
||||
if (tab->seat != t->seat || !tab->seat)
|
||||
continue;
|
||||
|
||||
tabletResource = tab;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tabletResource || !toolResource) {
|
||||
LOGM(ERR, "proximityIn on a tool and tablet without valid resource(s)??");
|
||||
return;
|
||||
}
|
||||
|
||||
toolResource->current = true;
|
||||
toolResource->lastSurf = surf;
|
||||
|
||||
auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, toolResource->resource->client()));
|
||||
toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->resource);
|
||||
toolResource->queueFrame();
|
||||
|
||||
LOGM(ERR, "proximityIn: found no resource to send enter");
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::proximityOut(SP<CTabletTool> tool) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->current = false;
|
||||
t->lastSurf = nullptr;
|
||||
t->resource->sendProximityOut();
|
||||
t->sendFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::buttonTool(SP<CTabletTool> tool, uint32_t button, uint32_t state) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client()));
|
||||
t->resource->sendButton(serial, button, (zwpTabletToolV2ButtonState)state);
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::motion(SP<CTabletTool> tool, const Vector2D& value) {
|
||||
for (auto& t : m_vTools) {
|
||||
if (t->tool != tool || !t->current)
|
||||
continue;
|
||||
|
||||
t->resource->sendMotion(wl_fixed_from_double(value.x), wl_fixed_from_double(value.y));
|
||||
t->queueFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::mode(SP<CTabletPad> pad, uint32_t group, uint32_t mode, uint32_t timeMs) {
|
||||
for (auto& t : m_vPads) {
|
||||
if (t->pad != pad)
|
||||
continue;
|
||||
if (t->groups.size() <= group) {
|
||||
LOGM(ERR, "BUG THIS: group >= t->groups.size()");
|
||||
return;
|
||||
}
|
||||
auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client()));
|
||||
t->groups.at(group)->resource->sendModeSwitch(timeMs, serial, mode);
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::buttonPad(SP<CTabletPad> pad, uint32_t button, uint32_t timeMs, uint32_t state) {
|
||||
for (auto& t : m_vPads) {
|
||||
if (t->pad != pad)
|
||||
continue;
|
||||
t->resource->sendButton(timeMs, button, zwpTabletToolV2ButtonState{state});
|
||||
}
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::strip(SP<CTabletPad> pad, uint32_t strip, double position, bool finger, uint32_t timeMs) {
|
||||
LOGM(ERR, "FIXME: STUB: CTabletV2Protocol::strip not implemented");
|
||||
}
|
||||
|
||||
void CTabletV2Protocol::ring(SP<CTabletPad> pad, uint32_t ring, double position, bool finger, uint32_t timeMs) {
|
||||
LOGM(ERR, "FIXME: STUB: CTabletV2Protocol::ring not implemented");
|
||||
}
|
236
src/protocols/Tablet.hpp
Normal file
236
src/protocols/Tablet.hpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "tablet-v2.hpp"
|
||||
#include "../helpers/Vector2D.hpp"
|
||||
|
||||
class CTablet;
|
||||
class CTabletTool;
|
||||
class CTabletPad;
|
||||
class CEventLoopTimer;
|
||||
class CTabletSeat;
|
||||
|
||||
class CTabletPadStripV2Resource {
|
||||
public:
|
||||
CTabletPadStripV2Resource(SP<CZwpTabletPadStripV2> resource_, uint32_t id);
|
||||
|
||||
bool good();
|
||||
|
||||
uint32_t id = 0;
|
||||
|
||||
private:
|
||||
SP<CZwpTabletPadStripV2> resource;
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletPadGroupV2Resource;
|
||||
friend class CTabletV2Protocol;
|
||||
};
|
||||
|
||||
class CTabletPadRingV2Resource {
|
||||
public:
|
||||
CTabletPadRingV2Resource(SP<CZwpTabletPadRingV2> resource_, uint32_t id);
|
||||
|
||||
bool good();
|
||||
|
||||
uint32_t id = 0;
|
||||
|
||||
private:
|
||||
SP<CZwpTabletPadRingV2> resource;
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletPadGroupV2Resource;
|
||||
friend class CTabletV2Protocol;
|
||||
};
|
||||
|
||||
class CTabletPadGroupV2Resource {
|
||||
public:
|
||||
CTabletPadGroupV2Resource(SP<CZwpTabletPadGroupV2> resource_, size_t idx);
|
||||
|
||||
bool good();
|
||||
void sendData(SP<CTabletPad> pad, wlr_tablet_pad_group* group);
|
||||
|
||||
std::vector<WP<CTabletPadRingV2Resource>> rings;
|
||||
std::vector<WP<CTabletPadStripV2Resource>> strips;
|
||||
|
||||
size_t idx = 0;
|
||||
|
||||
private:
|
||||
SP<CZwpTabletPadGroupV2> resource;
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletPadV2Resource;
|
||||
friend class CTabletV2Protocol;
|
||||
};
|
||||
|
||||
class CTabletPadV2Resource {
|
||||
public:
|
||||
CTabletPadV2Resource(SP<CZwpTabletPadV2> resource_, SP<CTabletPad> pad_, SP<CTabletSeat> seat_);
|
||||
|
||||
bool good();
|
||||
void sendData();
|
||||
|
||||
std::vector<WP<CTabletPadGroupV2Resource>> groups;
|
||||
|
||||
WP<CTabletPad> pad;
|
||||
WP<CTabletSeat> seat;
|
||||
|
||||
bool inert = false; // removed was sent
|
||||
|
||||
private:
|
||||
SP<CZwpTabletPadV2> resource;
|
||||
|
||||
void createGroup(wlr_tablet_pad_group* group, size_t idx);
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletV2Protocol;
|
||||
};
|
||||
|
||||
class CTabletV2Resource {
|
||||
public:
|
||||
CTabletV2Resource(SP<CZwpTabletV2> resource_, SP<CTablet> tablet_, SP<CTabletSeat> seat_);
|
||||
|
||||
bool good();
|
||||
void sendData();
|
||||
|
||||
WP<CTablet> tablet;
|
||||
WP<CTabletSeat> seat;
|
||||
|
||||
bool inert = false; // removed was sent
|
||||
|
||||
private:
|
||||
SP<CZwpTabletV2> resource;
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletV2Protocol;
|
||||
};
|
||||
|
||||
class CTabletToolV2Resource {
|
||||
public:
|
||||
CTabletToolV2Resource(SP<CZwpTabletToolV2> resource_, SP<CTabletTool> tool_, SP<CTabletSeat> seat_);
|
||||
~CTabletToolV2Resource();
|
||||
|
||||
bool good();
|
||||
void sendData();
|
||||
void queueFrame();
|
||||
void sendFrame(bool removeSource = true);
|
||||
|
||||
bool current = false;
|
||||
wlr_surface* lastSurf = nullptr; // READ-ONLY
|
||||
|
||||
WP<CTabletTool> tool;
|
||||
WP<CTabletSeat> seat;
|
||||
wl_event_source* frameSource = nullptr;
|
||||
|
||||
bool inert = false; // removed was sent
|
||||
|
||||
private:
|
||||
SP<CZwpTabletToolV2> resource;
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletV2Protocol;
|
||||
};
|
||||
|
||||
class CTabletSeat {
|
||||
public:
|
||||
CTabletSeat(SP<CZwpTabletSeatV2> resource_);
|
||||
|
||||
bool good();
|
||||
void sendData();
|
||||
|
||||
std::vector<WP<CTabletToolV2Resource>> tools;
|
||||
std::vector<WP<CTabletPadV2Resource>> pads;
|
||||
std::vector<WP<CTabletV2Resource>> tablets;
|
||||
|
||||
void sendTool(SP<CTabletTool> tool);
|
||||
void sendPad(SP<CTabletPad> pad);
|
||||
void sendTablet(SP<CTablet> tablet);
|
||||
|
||||
private:
|
||||
SP<CZwpTabletSeatV2> resource;
|
||||
WP<CTabletSeat> self;
|
||||
|
||||
friend class CTabletV2Protocol;
|
||||
};
|
||||
|
||||
class CTabletV2Protocol : public IWaylandProtocol {
|
||||
public:
|
||||
CTabletV2Protocol(const wl_interface* iface, const int& ver, const std::string& name);
|
||||
|
||||
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
|
||||
|
||||
void registerDevice(SP<CTablet> tablet);
|
||||
void registerDevice(SP<CTabletTool> tool);
|
||||
void registerDevice(SP<CTabletPad> pad);
|
||||
|
||||
void unregisterDevice(SP<CTablet> tablet);
|
||||
void unregisterDevice(SP<CTabletTool> tool);
|
||||
void unregisterDevice(SP<CTabletPad> pad);
|
||||
|
||||
void recheckRegisteredDevices();
|
||||
|
||||
// Tablet tool events
|
||||
void pressure(SP<CTabletTool> tool, double value);
|
||||
void distance(SP<CTabletTool> tool, double value);
|
||||
void rotation(SP<CTabletTool> tool, double value);
|
||||
void slider(SP<CTabletTool> tool, double value);
|
||||
void wheel(SP<CTabletTool> tool, double value);
|
||||
void tilt(SP<CTabletTool> tool, const Vector2D& value);
|
||||
void up(SP<CTabletTool> tool);
|
||||
void down(SP<CTabletTool> tool);
|
||||
void proximityIn(SP<CTabletTool> tool, SP<CTablet> tablet, wlr_surface* surf);
|
||||
void proximityOut(SP<CTabletTool> tool);
|
||||
void buttonTool(SP<CTabletTool> tool, uint32_t button, uint32_t state);
|
||||
void motion(SP<CTabletTool> tool, const Vector2D& value);
|
||||
|
||||
// Tablet pad events
|
||||
void mode(SP<CTabletPad> pad, uint32_t group, uint32_t mode, uint32_t timeMs);
|
||||
void buttonPad(SP<CTabletPad> pad, uint32_t button, uint32_t timeMs, uint32_t state);
|
||||
void strip(SP<CTabletPad> pad, uint32_t strip, double position, bool finger, uint32_t timeMs);
|
||||
void ring(SP<CTabletPad> pad, uint32_t ring, double position, bool finger, uint32_t timeMs);
|
||||
|
||||
private:
|
||||
void onManagerResourceDestroy(wl_resource* res);
|
||||
void destroyResource(CTabletSeat* resource);
|
||||
void destroyResource(CTabletToolV2Resource* resource);
|
||||
void destroyResource(CTabletV2Resource* resource);
|
||||
void destroyResource(CTabletPadV2Resource* resource);
|
||||
void destroyResource(CTabletPadGroupV2Resource* resource);
|
||||
void destroyResource(CTabletPadRingV2Resource* resource);
|
||||
void destroyResource(CTabletPadStripV2Resource* resource);
|
||||
void onGetSeat(CZwpTabletManagerV2* pMgr, uint32_t id, wl_resource* seat);
|
||||
|
||||
//
|
||||
std::vector<UP<CZwpTabletManagerV2>> m_vManagers;
|
||||
std::vector<SP<CTabletSeat>> m_vSeats;
|
||||
std::vector<SP<CTabletToolV2Resource>> m_vTools;
|
||||
std::vector<SP<CTabletV2Resource>> m_vTablets;
|
||||
std::vector<SP<CTabletPadV2Resource>> m_vPads;
|
||||
std::vector<SP<CTabletPadGroupV2Resource>> m_vGroups;
|
||||
std::vector<SP<CTabletPadRingV2Resource>> m_vRings;
|
||||
std::vector<SP<CTabletPadStripV2Resource>> m_vStrips;
|
||||
|
||||
// registered
|
||||
std::vector<WP<CTablet>> tablets;
|
||||
std::vector<WP<CTabletTool>> tools;
|
||||
std::vector<WP<CTabletPad>> pads;
|
||||
|
||||
// FIXME: rings and strips are broken, I don't understand how this shit works.
|
||||
// It's 2am.
|
||||
SP<CTabletPadRingV2Resource> ringForID(SP<CTabletPad> pad, uint32_t id);
|
||||
SP<CTabletPadStripV2Resource> stripForID(SP<CTabletPad> pad, uint32_t id);
|
||||
|
||||
friend class CTabletSeat;
|
||||
friend class CTabletToolV2Resource;
|
||||
friend class CTabletV2Resource;
|
||||
friend class CTabletPadV2Resource;
|
||||
friend class CTabletPadGroupV2Resource;
|
||||
friend class CTabletPadRingV2Resource;
|
||||
friend class CTabletPadStripV2Resource;
|
||||
};
|
||||
|
||||
namespace PROTO {
|
||||
inline UP<CTabletV2Protocol> tablet;
|
||||
};
|
Loading…
Reference in a new issue