#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 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 tool, SP tablet, SP 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 tab, SP 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 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 CInputManager::ensureTabletToolPresent(SP 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 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(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(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(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>(e); PPAD->m_parent = TOOL; }, PNEWPAD.get()); // clang-format on }