mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-09-15 07:48:23 +00:00
313 lines
10 KiB
C++
313 lines
10 KiB
C++
#include "InputManager.hpp"
|
|
#include "../../desktop/Window.hpp"
|
|
#include "../../protocols/Tablet.hpp"
|
|
#include "../../devices/Tablet.hpp"
|
|
#include "../../managers/PointerManager.hpp"
|
|
#include "../../managers/SeatManager.hpp"
|
|
#include "../../protocols/PointerConstraints.hpp"
|
|
|
|
static void unfocusTool(SP<CTabletTool> tool) {
|
|
if (!tool->getSurface())
|
|
return;
|
|
|
|
tool->setSurface(nullptr);
|
|
if (tool->m_isDown)
|
|
PROTO::tablet->up(tool);
|
|
for (auto const& b : tool->m_buttonsDown) {
|
|
PROTO::tablet->buttonTool(tool, b, false);
|
|
}
|
|
PROTO::tablet->proximityOut(tool);
|
|
}
|
|
|
|
static void focusTool(SP<CTabletTool> tool, SP<CTablet> tablet, SP<CWLSurfaceResource> 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->m_isDown)
|
|
PROTO::tablet->down(tool);
|
|
for (auto const& b : tool->m_buttonsDown) {
|
|
PROTO::tablet->buttonTool(tool, b, true);
|
|
}
|
|
}
|
|
|
|
static void refocusTablet(SP<CTablet> tab, SP<CTabletTool> tool, bool motion = false) {
|
|
const auto LASTHLSURFACE = CWLSurface::fromResource(g_pSeatManager->m_state.pointerFocus.lock());
|
|
|
|
if (!LASTHLSURFACE || !tool->m_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_pSeatManager->m_state.pointerFocus.lock());
|
|
|
|
if (!motion)
|
|
return;
|
|
|
|
if (LASTHLSURFACE->constraint() && tool->aq()->type != Aquamarine::ITabletTool::AQ_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->m_absolutePos * LASTHLSURFACE->getWindow()->m_realSize->goal();
|
|
else
|
|
local = tool->m_absolutePos * BOX->size();
|
|
|
|
if (LASTHLSURFACE->getWindow() && LASTHLSURFACE->getWindow()->m_isX11)
|
|
local = local * LASTHLSURFACE->getWindow()->m_X11SurfaceScaledBy;
|
|
|
|
PROTO::tablet->motion(tool, local);
|
|
return;
|
|
}
|
|
|
|
auto local = CURSORPOS - BOX->pos();
|
|
|
|
if (LASTHLSURFACE->getWindow() && LASTHLSURFACE->getWindow()->m_isX11)
|
|
local = local * LASTHLSURFACE->getWindow()->m_X11SurfaceScaledBy;
|
|
|
|
PROTO::tablet->motion(tool, local);
|
|
}
|
|
|
|
static Vector2D transformToActiveRegion(const Vector2D pos, const CBox activeArea) {
|
|
auto newPos = pos;
|
|
|
|
//Calculate transformations if active area is set
|
|
if (!activeArea.empty()) {
|
|
if (!std::isnan(pos.x))
|
|
newPos.x = (pos.x - activeArea.x) / (activeArea.w - activeArea.x);
|
|
if (!std::isnan(pos.y))
|
|
newPos.y = (pos.y - activeArea.y) / (activeArea.h - activeArea.y);
|
|
}
|
|
|
|
return newPos;
|
|
}
|
|
|
|
void CInputManager::onTabletAxis(CTablet::SAxisEvent e) {
|
|
const auto PTAB = e.tablet;
|
|
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
|
|
|
if (PTOOL->m_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 Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: {
|
|
g_pPointerManager->move(delta);
|
|
break;
|
|
}
|
|
default: {
|
|
if (!std::isnan(x))
|
|
PTOOL->m_absolutePos.x = x;
|
|
if (!std::isnan(y))
|
|
PTOOL->m_absolutePos.y = y;
|
|
|
|
if (PTAB->m_relativeInput)
|
|
g_pPointerManager->move(delta);
|
|
else
|
|
g_pPointerManager->warpAbsolute(transformToActiveRegion({x, y}, PTAB->m_activeArea), PTAB);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
simulateMouseMovement();
|
|
refocusTablet(PTAB, PTOOL, true);
|
|
m_lastCursorMovement.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->m_tilt.x = e.tilt.x;
|
|
|
|
if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y)
|
|
PTOOL->m_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->m_tilt);
|
|
}
|
|
|
|
void CInputManager::onTabletTip(CTablet::STipEvent e) {
|
|
const auto PTAB = e.tablet;
|
|
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
|
const auto POS = e.tip;
|
|
|
|
if (PTAB->m_relativeInput)
|
|
g_pPointerManager->move({0, 0});
|
|
else
|
|
g_pPointerManager->warpAbsolute(transformToActiveRegion(POS, PTAB->m_activeArea), PTAB);
|
|
|
|
if (e.in)
|
|
refocus();
|
|
|
|
refocusTablet(PTAB, PTOOL, true);
|
|
|
|
if (e.in)
|
|
PROTO::tablet->down(PTOOL);
|
|
else
|
|
PROTO::tablet->up(PTOOL);
|
|
|
|
PTOOL->m_isDown = e.in;
|
|
}
|
|
|
|
void CInputManager::onTabletButton(CTablet::SButtonEvent e) {
|
|
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
|
|
|
if (e.down)
|
|
refocus();
|
|
|
|
PROTO::tablet->buttonTool(PTOOL, e.button, e.down);
|
|
|
|
if (e.down)
|
|
PTOOL->m_buttonsDown.push_back(e.button);
|
|
else
|
|
std::erase(PTOOL->m_buttonsDown, e.button);
|
|
}
|
|
|
|
void CInputManager::onTabletProximity(CTablet::SProximityEvent e) {
|
|
const auto PTAB = e.tablet;
|
|
const auto PTOOL = ensureTabletToolPresent(e.tool);
|
|
|
|
PTOOL->m_active = e.in;
|
|
|
|
if (!e.in) {
|
|
if (PTOOL->getSurface())
|
|
unfocusTool(PTOOL);
|
|
} else {
|
|
simulateMouseMovement();
|
|
refocusTablet(PTAB, PTOOL);
|
|
}
|
|
}
|
|
|
|
void CInputManager::newTablet(SP<Aquamarine::ITablet> pDevice) {
|
|
const auto PNEWTABLET = m_tablets.emplace_back(CTablet::create(pDevice));
|
|
m_hids.emplace_back(PNEWTABLET);
|
|
|
|
try {
|
|
PNEWTABLET->m_hlName = g_pInputManager->getNameForNewDevice(pDevice->getName());
|
|
} catch (std::exception& e) {
|
|
Debug::log(ERR, "Tablet had no name???"); // logic error
|
|
}
|
|
|
|
g_pPointerManager->attachTablet(PNEWTABLET);
|
|
|
|
PNEWTABLET->m_events.destroy.registerStaticListener(
|
|
[this](void* owner, std::any d) {
|
|
auto TABLET = ((CTablet*)owner)->m_self;
|
|
destroyTablet(TABLET.lock());
|
|
},
|
|
PNEWTABLET.get());
|
|
|
|
setTabletConfigs();
|
|
}
|
|
|
|
SP<CTabletTool> CInputManager::ensureTabletToolPresent(SP<Aquamarine::ITabletTool> pTool) {
|
|
|
|
for (auto const& t : m_tabletTools) {
|
|
if (t->aq() == pTool)
|
|
return t;
|
|
}
|
|
|
|
const auto PTOOL = m_tabletTools.emplace_back(CTabletTool::create(pTool));
|
|
m_hids.emplace_back(PTOOL);
|
|
|
|
try {
|
|
PTOOL->m_hlName = g_pInputManager->getNameForNewDevice(pTool->getName());
|
|
} catch (std::exception& e) {
|
|
Debug::log(ERR, "Tablet had no name???"); // logic error
|
|
}
|
|
|
|
PTOOL->m_events.destroy.registerStaticListener(
|
|
[this](void* owner, std::any d) {
|
|
auto TOOL = ((CTabletTool*)owner)->m_self;
|
|
destroyTabletTool(TOOL.lock());
|
|
},
|
|
PTOOL.get());
|
|
|
|
return PTOOL;
|
|
}
|
|
|
|
void CInputManager::newTabletPad(SP<Aquamarine::ITabletPad> pDevice) {
|
|
const auto PNEWPAD = m_tabletPads.emplace_back(CTabletPad::create(pDevice));
|
|
m_hids.emplace_back(PNEWPAD);
|
|
|
|
try {
|
|
PNEWPAD->m_hlName = g_pInputManager->getNameForNewDevice(pDevice->getName());
|
|
} catch (std::exception& e) {
|
|
Debug::log(ERR, "Pad had no name???"); // logic error
|
|
}
|
|
|
|
// clang-format off
|
|
PNEWPAD->m_events.destroy.registerStaticListener([this](void* owner, std::any d) {
|
|
auto PAD = ((CTabletPad*)owner)->m_self;
|
|
destroyTabletPad(PAD.lock());
|
|
}, PNEWPAD.get());
|
|
|
|
PNEWPAD->m_padEvents.button.registerStaticListener([](void* owner, std::any e) {
|
|
const auto E = std::any_cast<CTabletPad::SButtonEvent>(e);
|
|
const auto PPAD = ((CTabletPad*)owner)->m_self.lock();
|
|
|
|
PROTO::tablet->mode(PPAD, 0, E.mode, E.timeMs);
|
|
PROTO::tablet->buttonPad(PPAD, E.button, E.timeMs, E.down);
|
|
}, PNEWPAD.get());
|
|
|
|
PNEWPAD->m_padEvents.strip.registerStaticListener([](void* owner, std::any e) {
|
|
const auto E = std::any_cast<CTabletPad::SStripEvent>(e);
|
|
const auto PPAD = ((CTabletPad*)owner)->m_self.lock();
|
|
|
|
PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs);
|
|
}, PNEWPAD.get());
|
|
|
|
PNEWPAD->m_padEvents.ring.registerStaticListener([](void* owner, std::any e) {
|
|
const auto E = std::any_cast<CTabletPad::SRingEvent>(e);
|
|
const auto PPAD = ((CTabletPad*)owner)->m_self.lock();
|
|
|
|
PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs);
|
|
}, PNEWPAD.get());
|
|
|
|
PNEWPAD->m_padEvents.attach.registerStaticListener([](void* owner, std::any e) {
|
|
const auto PPAD = ((CTabletPad*)owner)->m_self.lock();
|
|
const auto TOOL = std::any_cast<SP<CTabletTool>>(e);
|
|
|
|
PPAD->m_parent = TOOL;
|
|
}, PNEWPAD.get());
|
|
// clang-format on
|
|
}
|