mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-24 23:25:58 +01:00
input-capture: various fixes
This commit is contained in:
parent
497a2ce308
commit
44ba88d82c
7 changed files with 210 additions and 232 deletions
|
@ -3,7 +3,6 @@
|
|||
#include "../helpers/MiscFunctions.hpp"
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <poll.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
@ -19,18 +18,18 @@ SOutput::SOutput(SP<CCWlOutput> output_) : output(output_) {
|
|||
|
||||
Debug::log(LOG, "Found output name {}", name);
|
||||
});
|
||||
output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
||||
refreshRate = refresh;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width_, int32_t height_, int32_t refresh) {
|
||||
refreshRate = refresh;
|
||||
width = width_;
|
||||
height = height_;
|
||||
});
|
||||
output->setGeometry(
|
||||
[this](CCWlOutput* r, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make, const char* model, int32_t transform_) {
|
||||
[this](CCWlOutput* r, int32_t x_, int32_t y_, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char* make, const char* model, int32_t transform_) {
|
||||
transform = (wl_output_transform)transform_;
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
x = x_;
|
||||
y = y_;
|
||||
});
|
||||
output->setScale([this](CCWlOutput* r, uint32_t factor) { this->scale = factor; });
|
||||
output->setScale([this](CCWlOutput* r, uint32_t factor_) { scale = factor_; });
|
||||
output->setDone([](CCWlOutput* r) { g_pPortalManager->m_sPortals.inputCapture->zonesChanged(); });
|
||||
}
|
||||
|
||||
|
@ -276,32 +275,21 @@ void CPortalManager::init() {
|
|||
}
|
||||
|
||||
void CPortalManager::startEventLoop() {
|
||||
addFdToEventLoop(m_pConnection->getEventLoopPollData().fd, POLLIN, nullptr);
|
||||
addFdToEventLoop(wl_display_get_fd(m_sWaylandConnection.display), POLLIN, nullptr);
|
||||
addFdToEventLoop(pw_loop_get_fd(m_sPipewire.loop), POLLIN, nullptr);
|
||||
|
||||
pollfd pollfds[] = {
|
||||
{
|
||||
.fd = m_pConnection->getEventLoopPollData().fd,
|
||||
.events = POLLIN,
|
||||
},
|
||||
{
|
||||
.fd = wl_display_get_fd(m_sWaylandConnection.display),
|
||||
.events = POLLIN,
|
||||
},
|
||||
{
|
||||
.fd = pw_loop_get_fd(m_sPipewire.loop),
|
||||
.events = POLLIN,
|
||||
},
|
||||
};
|
||||
|
||||
std::thread pollThr([this, &pollfds]() {
|
||||
std::thread pollThr([this]() {
|
||||
while (1) {
|
||||
int ret = poll(pollfds, 3, 5000 /* 5 seconds, reasonable. It's because we might need to terminate */);
|
||||
|
||||
int ret = poll(m_sEventLoopInternals.pollFds.data(), m_sEventLoopInternals.pollFds.size(), 5000 /* 5 seconds, reasonable. It's because we might need to terminate */);
|
||||
if (ret < 0) {
|
||||
Debug::log(CRIT, "[core] Polling fds failed with {}", strerror(errno));
|
||||
g_pPortalManager->terminate();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (pollfds[i].revents & POLLHUP) {
|
||||
if (m_sEventLoopInternals.pollFds.data()->revents & POLLHUP) {
|
||||
Debug::log(CRIT, "[core] Disconnected from pollfd id {}", i);
|
||||
g_pPortalManager->terminate();
|
||||
}
|
||||
|
@ -374,13 +362,13 @@ void CPortalManager::startEventLoop() {
|
|||
|
||||
m_mEventLock.lock();
|
||||
|
||||
if (pollfds[0].revents & POLLIN /* dbus */) {
|
||||
while (m_pConnection->processPendingEvent()) {
|
||||
if (m_sEventLoopInternals.pollFds[0].revents & POLLIN /* dbus */) {
|
||||
while (m_pConnection->processPendingRequest()) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (pollfds[1].revents & POLLIN /* wl */) {
|
||||
if (m_sEventLoopInternals.pollFds[1].revents & POLLIN /* wl */) {
|
||||
wl_display_flush(m_sWaylandConnection.display);
|
||||
if (wl_display_prepare_read(m_sWaylandConnection.display) == 0) {
|
||||
wl_display_read_events(m_sWaylandConnection.display);
|
||||
|
@ -390,12 +378,18 @@ void CPortalManager::startEventLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
if (pollfds[2].revents & POLLIN /* pw */) {
|
||||
if (m_sEventLoopInternals.pollFds[2].revents & POLLIN /* pw */) {
|
||||
while (pw_loop_iterate(m_sPipewire.loop, 0) != 0) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
for (pollfd p : m_sEventLoopInternals.pollFds) {
|
||||
if (p.revents & POLLIN && m_sEventLoopInternals.pollCallbacks.contains(p.fd)) {
|
||||
m_sEventLoopInternals.pollCallbacks[p.fd]();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CTimer*> toRemove;
|
||||
for (auto& t : m_sTimersThread.timers) {
|
||||
if (t->passed()) {
|
||||
|
@ -499,6 +493,20 @@ void CPortalManager::addTimer(const CTimer& timer) {
|
|||
m_sTimersThread.loopSignal.notify_all();
|
||||
}
|
||||
|
||||
void CPortalManager::addFdToEventLoop(int fd, short events, std::function<void()> callback) {
|
||||
m_sEventLoopInternals.pollFds.emplace_back(pollfd{.fd = fd, .events = POLLIN});
|
||||
|
||||
if (callback == nullptr)
|
||||
return;
|
||||
|
||||
m_sEventLoopInternals.pollCallbacks[fd] = callback;
|
||||
}
|
||||
|
||||
void CPortalManager::removeFdFromEventLoop(int fd) {
|
||||
std::erase_if(m_sEventLoopInternals.pollFds, [fd](const pollfd& p) { return p.fd == fd; });
|
||||
m_sEventLoopInternals.pollCallbacks.erase(fd);
|
||||
}
|
||||
|
||||
void CPortalManager::terminate() {
|
||||
m_bTerminate = true;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../helpers/Timer.hpp"
|
||||
#include "../shared/ToplevelManager.hpp"
|
||||
#include <gbm.h>
|
||||
#include <poll.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
#include "hyprland-toplevel-export-v1.hpp"
|
||||
|
@ -34,9 +35,11 @@ struct SOutput {
|
|||
uint32_t id = 0;
|
||||
float refreshRate = 60.0;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
uint32_t width, height;
|
||||
int32_t x, y;
|
||||
int32_t scale;
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
int32_t x = 0;
|
||||
int32_t y = 0;
|
||||
int32_t scale = 1;
|
||||
};
|
||||
|
||||
struct SDMABUFModifier {
|
||||
|
@ -50,8 +53,8 @@ class CPortalManager {
|
|||
|
||||
void init();
|
||||
|
||||
void onGlobal(uint32_t name, const char* interface, uint32_t version);
|
||||
void onGlobalRemoved(uint32_t name);
|
||||
void onGlobal(uint32_t name, const char* interface, uint32_t version);
|
||||
void onGlobalRemoved(uint32_t name);
|
||||
|
||||
sdbus::IConnection* getConnection();
|
||||
SOutput* getOutputFromName(const std::string& name);
|
||||
|
@ -98,6 +101,9 @@ class CPortalManager {
|
|||
|
||||
gbm_device* createGBMDevice(drmDevice* dev);
|
||||
|
||||
void addFdToEventLoop(int fd, short events, std::function<void()> callback);
|
||||
void removeFdFromEventLoop(int fd);
|
||||
|
||||
// terminate after the event loop has been created. Before we can exit()
|
||||
void terminate();
|
||||
|
||||
|
@ -108,10 +114,12 @@ class CPortalManager {
|
|||
pid_t m_iPID = 0;
|
||||
|
||||
struct {
|
||||
std::condition_variable loopSignal;
|
||||
std::mutex loopMutex;
|
||||
std::atomic<bool> shouldProcess = false;
|
||||
std::mutex loopRequestMutex;
|
||||
std::condition_variable loopSignal;
|
||||
std::mutex loopMutex;
|
||||
std::atomic<bool> shouldProcess = false;
|
||||
std::mutex loopRequestMutex;
|
||||
std::vector<pollfd> pollFds;
|
||||
std::map<int, std::function<void()>> pollCallbacks;
|
||||
} m_sEventLoopInternals;
|
||||
|
||||
struct {
|
||||
|
|
|
@ -13,14 +13,11 @@
|
|||
#include <unordered_map>
|
||||
#include <wayland-util.h>
|
||||
|
||||
CInputCapturePortal::CInputCapturePortal(SP<CCHyprlandInputCaptureManagerV1> mgr) {
|
||||
CInputCapturePortal::CInputCapturePortal(SP<CCHyprlandInputCaptureManagerV1> mgr) : m_sState(mgr) {
|
||||
Debug::log(LOG, "[input-capture] initializing input capture portal");
|
||||
m_sState.manager = mgr;
|
||||
sessionCounter = 0;
|
||||
lastZoneSet = 0;
|
||||
|
||||
mgr->setAbsoluteMotion([this](CCHyprlandInputCaptureManagerV1* r, wl_fixed_t x, wl_fixed_t y, wl_fixed_t dx, wl_fixed_t dy) {
|
||||
onAbsoluteMotion(wl_fixed_to_double(x), wl_fixed_to_double(y), wl_fixed_to_double(dx), wl_fixed_to_double(dy));
|
||||
mgr->setMotion([this](CCHyprlandInputCaptureManagerV1* r, wl_fixed_t x, wl_fixed_t y, wl_fixed_t dx, wl_fixed_t dy) {
|
||||
onMotion(wl_fixed_to_double(x), wl_fixed_to_double(y), wl_fixed_to_double(dx), wl_fixed_to_double(dy));
|
||||
});
|
||||
|
||||
mgr->setKey([this](CCHyprlandInputCaptureManagerV1* r, uint32_t key, hyprlandInputCaptureManagerV1KeyState state) { onKey(key, state); });
|
||||
|
@ -46,13 +43,12 @@ CInputCapturePortal::CInputCapturePortal(SP<CCHyprlandInputCaptureManagerV1> mgr
|
|||
m_pObject->registerMethod(INTERFACE_NAME, "ConnectToEIS", "osa{sv}", "h", [&](sdbus::MethodCall c) { onConnectToEIS(c); });
|
||||
|
||||
m_pObject->registerProperty(INTERFACE_NAME, "SupportedCapabilities", "u", [](sdbus::PropertyGetReply& reply) { reply << (uint)(1 | 2); });
|
||||
m_pObject->registerProperty(INTERFACE_NAME, "version", "u", [](sdbus::PropertyGetReply& reply) { reply << (uint)1; });
|
||||
m_pObject->registerProperty(INTERFACE_NAME, "version", "u", [](sdbus::PropertyGetReply& reply) { reply << (uint32_t)1; });
|
||||
|
||||
m_pObject->finishRegistration();
|
||||
|
||||
for (auto& o : g_pPortalManager->getAllOutputs()) {
|
||||
for (auto& o : g_pPortalManager->getAllOutputs())
|
||||
Debug::log(LOG, "{} {}x{}", o->name, o->width, o->height);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "[input-capture] init successful");
|
||||
}
|
||||
|
@ -91,22 +87,20 @@ void CInputCapturePortal::onCreateSession(sdbus::MethodCall& call) {
|
|||
std::string sessionId = "input-capture-" + std::to_string(sessionCounter++);
|
||||
Debug::log(LOG, "[input-capture] | sessionId : {}", sessionId);
|
||||
|
||||
const std::shared_ptr<Session> session = std::make_shared<Session>();
|
||||
const std::shared_ptr<SSession> session = std::make_shared<SSession>();
|
||||
|
||||
session->appid = appID;
|
||||
session->requestHandle = requestHandle;
|
||||
session->sessionHandle = sessionHandle;
|
||||
session->sessionId = sessionId;
|
||||
session->capabilities = capabilities;
|
||||
session->activationId = 0;
|
||||
session->status = CREATED;
|
||||
|
||||
session->session = createDBusSession(sessionHandle);
|
||||
session->session->onDestroy = [session, this]() {
|
||||
if (session->status == ACTIVATED) {
|
||||
disable(session->sessionHandle);
|
||||
}
|
||||
disable(session->sessionHandle);
|
||||
|
||||
session->eis->stopServer();
|
||||
session->eis = nullptr;
|
||||
Debug::log(LOG, "[input-capture] Session {} destroyed", session->sessionHandle.c_str());
|
||||
|
||||
session->session.release();
|
||||
|
@ -351,64 +345,56 @@ bool get_line_intersection(double p0_x, double p0_y, double p1_x, double p1_y, d
|
|||
return 0; // No collision
|
||||
}
|
||||
|
||||
bool testCollision(Barrier barrier, double px, double py, double nx, double ny) {
|
||||
bool testCollision(SBarrier barrier, double px, double py, double nx, double ny) {
|
||||
return get_line_intersection(barrier.x1, barrier.y1, barrier.x2, barrier.y2, px, py, nx, ny, nullptr, nullptr);
|
||||
}
|
||||
|
||||
uint32_t CInputCapturePortal::Session::isColliding(double px, double py, double nx, double ny) {
|
||||
for (const auto& [key, value] : barriers) {
|
||||
if (testCollision(value, px, py, nx, ny)) {
|
||||
uint32_t CInputCapturePortal::SSession::isColliding(double px, double py, double nx, double ny) {
|
||||
for (const auto& [key, value] : barriers)
|
||||
if (testCollision(value, px, py, nx, ny))
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CInputCapturePortal::onAbsoluteMotion(double x, double y, double dx, double dy) {
|
||||
void CInputCapturePortal::onMotion(double x, double y, double dx, double dy) {
|
||||
for (const auto& [key, session] : sessions) {
|
||||
int matched = session->isColliding(x, y, x - dx, y - dy);
|
||||
if (matched != 0) {
|
||||
if (matched != 0)
|
||||
activate(key, x, y, matched);
|
||||
}
|
||||
|
||||
session->motion(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
void CInputCapturePortal::onKey(uint32_t key, bool pressed) {
|
||||
for (const auto& [_, value] : sessions) {
|
||||
value->key(key, pressed);
|
||||
}
|
||||
void CInputCapturePortal::onKey(uint32_t id, bool pressed) {
|
||||
for (const auto& [key, value] : sessions)
|
||||
value->key(id, pressed);
|
||||
}
|
||||
|
||||
void CInputCapturePortal::onButton(uint32_t button, bool pressed) {
|
||||
for (const auto& [_, session] : sessions) {
|
||||
for (const auto& [key, session] : sessions)
|
||||
session->button(button, pressed);
|
||||
}
|
||||
}
|
||||
|
||||
void CInputCapturePortal::onAxis(bool axis, double value) {
|
||||
for (const auto& [_, session] : sessions) {
|
||||
for (const auto& [key, session] : sessions)
|
||||
session->axis(axis, value);
|
||||
}
|
||||
}
|
||||
|
||||
void CInputCapturePortal::onAxisValue120(bool axis, int32_t value120) {
|
||||
for (const auto& [_, session] : sessions) {
|
||||
for (const auto& [key, session] : sessions)
|
||||
session->axisValue120(axis, value120);
|
||||
}
|
||||
}
|
||||
|
||||
void CInputCapturePortal::onAxisStop(bool axis) {
|
||||
for (const auto& [_, session] : sessions) {
|
||||
for (const auto& [_, session] : sessions)
|
||||
session->axisStop(axis);
|
||||
}
|
||||
}
|
||||
|
||||
void CInputCapturePortal::onFrame() {
|
||||
for (const auto& [_, session] : sessions) {
|
||||
for (const auto& [_, session] : sessions)
|
||||
session->frame();
|
||||
}
|
||||
}
|
||||
|
||||
void CInputCapturePortal::activate(sdbus::ObjectPath sessionHandle, double x, double y, uint32_t borderId) {
|
||||
|
@ -435,7 +421,7 @@ void CInputCapturePortal::activate(sdbus::ObjectPath sessionHandle, double x, do
|
|||
m_pObject->emitSignal(signal);
|
||||
}
|
||||
|
||||
bool CInputCapturePortal::Session::activate(double x, double y, uint32_t borderId) {
|
||||
bool CInputCapturePortal::SSession::activate(double x, double y, uint32_t borderId) {
|
||||
if (status != ENABLED) {
|
||||
return false;
|
||||
}
|
||||
|
@ -467,10 +453,9 @@ void CInputCapturePortal::deactivate(sdbus::ObjectPath sessionHandle) {
|
|||
m_pObject->emitSignal(signal);
|
||||
}
|
||||
|
||||
bool CInputCapturePortal::Session::deactivate() {
|
||||
if (status != ACTIVATED) {
|
||||
bool CInputCapturePortal::SSession::deactivate() {
|
||||
if (status != ACTIVATED)
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "[input-capture] Input released for {}", sessionHandle.c_str());
|
||||
eis->stopEmulating();
|
||||
|
@ -500,7 +485,7 @@ void CInputCapturePortal::zonesChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
bool CInputCapturePortal::Session::zoneChanged() {
|
||||
bool CInputCapturePortal::SSession::zoneChanged() {
|
||||
//TODO: notify EIS
|
||||
return true;
|
||||
}
|
||||
|
@ -510,12 +495,13 @@ void CInputCapturePortal::disable(sdbus::ObjectPath sessionHandle) {
|
|||
return;
|
||||
|
||||
auto session = sessions[sessionHandle];
|
||||
if (!session->disable())
|
||||
return;
|
||||
|
||||
if (session->status == ACTIVATED)
|
||||
deactivate(sessionHandle);
|
||||
|
||||
if (!session->disable())
|
||||
return;
|
||||
|
||||
auto signal = m_pObject->createSignal(INTERFACE_NAME, "Disable");
|
||||
signal << sessionHandle;
|
||||
|
||||
|
@ -525,70 +511,74 @@ void CInputCapturePortal::disable(sdbus::ObjectPath sessionHandle) {
|
|||
m_pObject->emitSignal(signal);
|
||||
}
|
||||
|
||||
bool CInputCapturePortal::Session::disable() {
|
||||
bool CInputCapturePortal::SSession::disable() {
|
||||
status = STOPPED;
|
||||
|
||||
Debug::log(LOG, "[input-capture] Session {} disabled", sessionHandle.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void CInputCapturePortal::Session::motion(double dx, double dy) {
|
||||
void CInputCapturePortal::SSession::motion(double dx, double dy) {
|
||||
if (status != ACTIVATED)
|
||||
return;
|
||||
|
||||
eis->sendMotion(dx, dy);
|
||||
}
|
||||
|
||||
void CInputCapturePortal::Session::key(uint32_t key, bool pressed) {
|
||||
void CInputCapturePortal::SSession::key(uint32_t key, bool pressed) {
|
||||
if (status != ACTIVATED)
|
||||
return;
|
||||
|
||||
eis->sendKey(key, pressed);
|
||||
}
|
||||
|
||||
void CInputCapturePortal::Session::button(uint32_t button, bool pressed) {
|
||||
void CInputCapturePortal::SSession::button(uint32_t button, bool pressed) {
|
||||
if (status != ACTIVATED)
|
||||
return;
|
||||
|
||||
eis->sendButton(button, pressed);
|
||||
}
|
||||
|
||||
void CInputCapturePortal::Session::axis(bool axis, double value) {
|
||||
void CInputCapturePortal::SSession::axis(bool axis, double value) {
|
||||
if (status != ACTIVATED)
|
||||
return;
|
||||
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
|
||||
if (axis) {
|
||||
if (axis)
|
||||
x = value;
|
||||
} else {
|
||||
else
|
||||
y = value;
|
||||
}
|
||||
|
||||
eis->sendScrollDelta(x, y);
|
||||
}
|
||||
|
||||
void CInputCapturePortal::Session::axisValue120(bool axis, int32_t value) {
|
||||
void CInputCapturePortal::SSession::axisValue120(bool axis, int32_t value) {
|
||||
if (status != ACTIVATED)
|
||||
return;
|
||||
|
||||
int32_t x = 0;
|
||||
int32_t y = 0;
|
||||
|
||||
if (axis) {
|
||||
if (axis)
|
||||
x = value;
|
||||
} else {
|
||||
else
|
||||
y = value;
|
||||
}
|
||||
|
||||
eis->sendScrollDiscrete(x, y);
|
||||
}
|
||||
|
||||
void CInputCapturePortal::Session::axisStop(bool axis) {
|
||||
void CInputCapturePortal::SSession::axisStop(bool axis) {
|
||||
if (status != ACTIVATED)
|
||||
return;
|
||||
|
||||
eis->sendScrollStop(axis, !axis);
|
||||
}
|
||||
|
||||
void CInputCapturePortal::Session::frame() {
|
||||
void CInputCapturePortal::SSession::frame() {
|
||||
if (status != ACTIVATED)
|
||||
return;
|
||||
|
||||
eis->sendPointerFrame();
|
||||
}
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
#include "../shared/Session.hpp"
|
||||
#include <sdbus-c++/Types.h>
|
||||
|
||||
typedef int ClientStatus;
|
||||
const ClientStatus CREATED = 0; //Is ready to be activated
|
||||
const ClientStatus ENABLED = 1; //Is ready for receiving inputs
|
||||
const ClientStatus ACTIVATED = 2; //Currently receiving inputs
|
||||
const ClientStatus STOPPED = 3; //Can no longer be activated
|
||||
enum ClientStatus {
|
||||
CREATED, //Is ready to be activated
|
||||
ENABLED, //Is ready for receiving inputs
|
||||
ACTIVATED, //Currently receiving inputs
|
||||
STOPPED //Can no longer be activated
|
||||
};
|
||||
|
||||
struct Barrier {
|
||||
struct SBarrier {
|
||||
uint id;
|
||||
int x1, y1, x2, y2;
|
||||
};
|
||||
|
@ -28,7 +29,7 @@ class CInputCapturePortal {
|
|||
void onRelease(sdbus::MethodCall& methodCall);
|
||||
void onConnectToEIS(sdbus::MethodCall& methodCall);
|
||||
|
||||
void onAbsoluteMotion(double x, double y, double dx, double dy);
|
||||
void onMotion(double x, double y, double dx, double dy);
|
||||
void onKey(uint32_t key, bool pressed);
|
||||
void onButton(uint32_t button, bool pressed);
|
||||
void onAxis(bool axis, double value);
|
||||
|
@ -38,19 +39,19 @@ class CInputCapturePortal {
|
|||
|
||||
void zonesChanged();
|
||||
|
||||
struct Session {
|
||||
std::string appid;
|
||||
sdbus::ObjectPath requestHandle, sessionHandle;
|
||||
std::string sessionId;
|
||||
uint32_t capabilities;
|
||||
struct SSession {
|
||||
std::string appid;
|
||||
sdbus::ObjectPath requestHandle, sessionHandle;
|
||||
std::string sessionId;
|
||||
uint32_t capabilities = 0;
|
||||
|
||||
std::unique_ptr<SDBusRequest> request;
|
||||
std::unique_ptr<SDBusSession> session;
|
||||
std::unique_ptr<EmulatedInputServer> eis;
|
||||
std::unique_ptr<SDBusRequest> request;
|
||||
std::unique_ptr<SDBusSession> session;
|
||||
std::unique_ptr<EmulatedInputServer> eis;
|
||||
|
||||
std::unordered_map<uint32_t, Barrier> barriers;
|
||||
uint32_t activationId;
|
||||
ClientStatus status;
|
||||
std::unordered_map<uint32_t, SBarrier> barriers;
|
||||
uint32_t activationId = 0;
|
||||
ClientStatus status = CREATED;
|
||||
|
||||
//
|
||||
bool activate(double x, double y, uint32_t borderId);
|
||||
|
@ -74,11 +75,11 @@ class CInputCapturePortal {
|
|||
SP<CCHyprlandInputCaptureManagerV1> manager;
|
||||
} m_sState;
|
||||
|
||||
std::unordered_map<std::string, const std::shared_ptr<Session>> sessions;
|
||||
std::unordered_map<std::string, const std::shared_ptr<SSession>> sessions;
|
||||
//
|
||||
std::unique_ptr<sdbus::IObject> m_pObject;
|
||||
uint sessionCounter;
|
||||
uint lastZoneSet;
|
||||
uint sessionCounter = 0;
|
||||
uint lastZoneSet = 0;
|
||||
|
||||
const std::string INTERFACE_NAME = "org.freedesktop.impl.portal.InputCapture";
|
||||
const std::string OBJECT_PATH = "/org/freedesktop/portal/desktop";
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
#include "../core/PortalManager.hpp"
|
||||
#include "src/helpers/Log.hpp"
|
||||
#include <libeis.h>
|
||||
#include <sys/poll.h>
|
||||
#include <thread>
|
||||
|
||||
EmulatedInputServer::EmulatedInputServer(std::string socketName) {
|
||||
Debug::log(LOG, "[EIS] init socket: {}", socketName);
|
||||
Debug::log(LOG, "[EIS] Init socket: {}", socketName);
|
||||
|
||||
const char* xdg = getenv("XDG_RUNTIME_DIR");
|
||||
if (xdg)
|
||||
|
@ -17,95 +15,80 @@ EmulatedInputServer::EmulatedInputServer(std::string socketName) {
|
|||
return;
|
||||
}
|
||||
|
||||
client.handle = NULL;
|
||||
client.seat = NULL;
|
||||
client.pointer = NULL;
|
||||
client.keyboard = NULL;
|
||||
eis = eis_new(NULL);
|
||||
eisCtx = eis_new(nullptr);
|
||||
|
||||
if (eis_setup_backend_socket(eis, socketPath.c_str())) {
|
||||
if (eis_setup_backend_socket(eisCtx, socketPath.c_str())) {
|
||||
Debug::log(ERR, "[EIS] Cannot init eis socket on {}", socketPath);
|
||||
return;
|
||||
}
|
||||
Debug::log(LOG, "[EIS] Listening on {}", socketPath);
|
||||
|
||||
stop = false;
|
||||
std::thread thread(&EmulatedInputServer::listen, this);
|
||||
thread.detach();
|
||||
g_pPortalManager->addFdToEventLoop(eis_get_fd(eisCtx), POLLIN, std::bind(&EmulatedInputServer::pollEvents, this));
|
||||
}
|
||||
|
||||
void EmulatedInputServer::listen() {
|
||||
struct pollfd fds = {
|
||||
.fd = eis_get_fd(eis),
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
};
|
||||
int nevents;
|
||||
//Pull foverer events
|
||||
while (!stop && (nevents = poll(&fds, 1, 1000)) > -1) {
|
||||
eis_dispatch(eis);
|
||||
void EmulatedInputServer::pollEvents() {
|
||||
eis_dispatch(eisCtx);
|
||||
|
||||
//Pull every availaible events
|
||||
while (true) {
|
||||
eis_event* e = eis_get_event(eis);
|
||||
//Pull every availaible events
|
||||
while (true) {
|
||||
eis_event* e = eis_get_event(eisCtx);
|
||||
|
||||
if (!e) {
|
||||
eis_event_unref(e);
|
||||
break;
|
||||
}
|
||||
|
||||
int rc = onEvent(e);
|
||||
if (!e) {
|
||||
eis_event_unref(e);
|
||||
if (rc != 0)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
int rc = onEvent(e);
|
||||
eis_event_unref(e);
|
||||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int EmulatedInputServer::onEvent(eis_event* e) {
|
||||
eis_client* client;
|
||||
eis_seat* seat;
|
||||
eis_device* device;
|
||||
eis_client* eisClient = nullptr;
|
||||
eis_seat* seat = nullptr;
|
||||
eis_device* device = nullptr;
|
||||
|
||||
switch (eis_event_get_type(e)) {
|
||||
case EIS_EVENT_CLIENT_CONNECT:
|
||||
client = eis_event_get_client(e);
|
||||
Debug::log(LOG, "[EIS] {} client connected: {}", eis_client_is_sender(client) ? "sender" : "receiver", eis_client_get_name(client));
|
||||
eisClient = eis_event_get_client(e);
|
||||
Debug::log(LOG, "[EIS] {} client connected: {}", eis_client_is_sender(eisClient) ? "Sender" : "Receiver", eis_client_get_name(eisClient));
|
||||
|
||||
if (eis_client_is_sender(client)) {
|
||||
Debug::log(WARN, "[EIS] Unexpected sender client {} connected to input capture session", eis_client_get_name(client));
|
||||
eis_client_disconnect(client);
|
||||
if (eis_client_is_sender(eisClient)) {
|
||||
Debug::log(WARN, "[EIS] Unexpected sender client {} connected to input capture session", eis_client_get_name(eisClient));
|
||||
eis_client_disconnect(eisClient);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this->client.handle != nullptr) {
|
||||
Debug::log(WARN, "[EIS] Unexpected additional client {} connected to input capture session", eis_client_get_name(client));
|
||||
eis_client_disconnect(client);
|
||||
if (client.handle) {
|
||||
Debug::log(WARN, "[EIS] Unexpected additional client {} connected to input capture session", eis_client_get_name(eisClient));
|
||||
eis_client_disconnect(eisClient);
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->client.handle = client;
|
||||
client.handle = eisClient;
|
||||
|
||||
eis_client_connect(client);
|
||||
Debug::log(LOG, "[EIS] creating new default seat");
|
||||
seat = eis_client_new_seat(client, "default");
|
||||
eis_client_connect(eisClient);
|
||||
Debug::log(LOG, "[EIS] Creating new default seat");
|
||||
seat = eis_client_new_seat(eisClient, "default");
|
||||
|
||||
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_POINTER);
|
||||
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_BUTTON);
|
||||
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_SCROLL);
|
||||
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_KEYBOARD);
|
||||
eis_seat_add(seat);
|
||||
this->client.seat = seat;
|
||||
client.seat = seat;
|
||||
break;
|
||||
case EIS_EVENT_CLIENT_DISCONNECT:
|
||||
client = eis_event_get_client(e);
|
||||
Debug::log(LOG, "[EIS] {} disconnected", eis_client_get_name(client));
|
||||
eis_client_disconnect(client);
|
||||
eisClient = eis_event_get_client(e);
|
||||
Debug::log(LOG, "[EIS] {} disconnected", eis_client_get_name(eisClient));
|
||||
eis_client_disconnect(eisClient);
|
||||
|
||||
eis_seat_unref(this->client.seat);
|
||||
eis_seat_unref(client.seat);
|
||||
clearPointer();
|
||||
clearKeyboard();
|
||||
this->client.handle = NULL;
|
||||
client.handle = nullptr;
|
||||
break;
|
||||
case EIS_EVENT_SEAT_BIND:
|
||||
Debug::log(LOG, "[EIS] Binding seats...");
|
||||
|
@ -123,45 +106,31 @@ int EmulatedInputServer::onEvent(eis_event* e) {
|
|||
break;
|
||||
case EIS_EVENT_DEVICE_CLOSED:
|
||||
device = eis_event_get_device(e);
|
||||
if (device == this->client.pointer) {
|
||||
if (device == client.pointer)
|
||||
clearPointer();
|
||||
} else if (device == this->client.keyboard) {
|
||||
else if (device == client.keyboard) {
|
||||
Debug::log(LOG, "[EIS] Clearing keyboard");
|
||||
clearKeyboard();
|
||||
} else {
|
||||
} else
|
||||
Debug::log(WARN, "[EIS] Unknown device to close");
|
||||
}
|
||||
break;
|
||||
case EIS_EVENT_FRAME: Debug::log(LOG, "[EIS] Got event EIS_EVENT_FRAME"); break;
|
||||
case EIS_EVENT_DEVICE_START_EMULATING: Debug::log(LOG, "[EIS] Got event EIS_EVENT_DEVICE_START_EMULATING"); break;
|
||||
case EIS_EVENT_DEVICE_STOP_EMULATING: Debug::log(LOG, "[EIS] Got event EIS_EVENT_DEVICE_STOP_EMULATING"); break;
|
||||
case EIS_EVENT_POINTER_MOTION: Debug::log(LOG, "[EIS] Got event EIS_EVENT_POINTER_MOTION"); break;
|
||||
case EIS_EVENT_POINTER_MOTION_ABSOLUTE: Debug::log(LOG, "[EIS] Got event EIS_EVENT_POINTER_MOTION_ABSOLUTE"); break;
|
||||
case EIS_EVENT_BUTTON_BUTTON: Debug::log(LOG, "[EIS] Got event EIS_EVENT_BUTTON_BUTTON"); break;
|
||||
case EIS_EVENT_SCROLL_DELTA: Debug::log(LOG, "[EIS] Got event EIS_EVENT_SCROLL_DELTA"); break;
|
||||
case EIS_EVENT_SCROLL_STOP: Debug::log(LOG, "[EIS] Got event EIS_EVENT_SCROLL_STOP"); break;
|
||||
case EIS_EVENT_SCROLL_CANCEL: Debug::log(LOG, "[EIS] Got event EIS_EVENT_SCROLL_CANCEL"); break;
|
||||
case EIS_EVENT_SCROLL_DISCRETE: Debug::log(LOG, "[EIS] Got event EIS_EVENT_SCROLL_DISCRETE"); break;
|
||||
case EIS_EVENT_KEYBOARD_KEY: Debug::log(LOG, "[EIS] Got event EIS_EVENT_KEYBOARD_KEY"); break;
|
||||
case EIS_EVENT_TOUCH_DOWN: Debug::log(LOG, "[EIS] Got event EIS_EVENT_TOUCH_DOWN"); break;
|
||||
case EIS_EVENT_TOUCH_UP: Debug::log(LOG, "[EIS] Got event EIS_EVENT_TOUCH_UP"); break;
|
||||
case EIS_EVENT_TOUCH_MOTION: Debug::log(LOG, "[EIS] Got event EIS_EVENT_TOUCH_MOTION"); break;
|
||||
default: return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EmulatedInputServer::ensurePointer(eis_event* event) {
|
||||
if (client.pointer != nullptr)
|
||||
if (client.pointer)
|
||||
return;
|
||||
|
||||
struct eis_device* pointer = eis_seat_new_device(client.seat);
|
||||
eis_device* pointer = eis_seat_new_device(client.seat);
|
||||
eis_device_configure_name(pointer, "captured relative pointer");
|
||||
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_POINTER);
|
||||
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_BUTTON);
|
||||
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_SCROLL);
|
||||
|
||||
for (auto& o : g_pPortalManager->getAllOutputs()) {
|
||||
struct eis_region* r = eis_device_new_region(pointer);
|
||||
eis_region* r = eis_device_new_region(pointer);
|
||||
|
||||
eis_region_set_offset(r, o->x, o->y);
|
||||
eis_region_set_size(r, o->width, o->height);
|
||||
|
@ -177,10 +146,10 @@ void EmulatedInputServer::ensurePointer(eis_event* event) {
|
|||
}
|
||||
|
||||
void EmulatedInputServer::ensureKeyboard(eis_event* event) {
|
||||
if (client.keyboard != nullptr)
|
||||
if (client.keyboard)
|
||||
return;
|
||||
|
||||
struct eis_device* keyboard = eis_seat_new_device(client.seat);
|
||||
eis_device* keyboard = eis_seat_new_device(client.seat);
|
||||
eis_device_configure_name(keyboard, "captured keyboard");
|
||||
eis_device_configure_capability(keyboard, EIS_DEVICE_CAP_KEYBOARD);
|
||||
// TODO: layout
|
||||
|
@ -193,7 +162,7 @@ void EmulatedInputServer::ensureKeyboard(eis_event* event) {
|
|||
//TODO: remove and re-add devices when monitors change (see: mutter/meta-input-capture-session.c:1107)
|
||||
|
||||
void EmulatedInputServer::clearPointer() {
|
||||
if (client.pointer == nullptr)
|
||||
if (!client.pointer)
|
||||
return;
|
||||
Debug::log(LOG, "[EIS] Clearing pointer");
|
||||
|
||||
|
@ -203,7 +172,7 @@ void EmulatedInputServer::clearPointer() {
|
|||
}
|
||||
|
||||
void EmulatedInputServer::clearKeyboard() {
|
||||
if (client.keyboard == nullptr)
|
||||
if (!client.keyboard)
|
||||
return;
|
||||
Debug::log(LOG, "[EIS] Clearing keyboard");
|
||||
|
||||
|
@ -213,74 +182,77 @@ void EmulatedInputServer::clearKeyboard() {
|
|||
}
|
||||
|
||||
int EmulatedInputServer::getFileDescriptor() {
|
||||
return eis_backend_fd_add_client(eis);
|
||||
return eis_backend_fd_add_client(eisCtx);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::startEmulating(int sequence) {
|
||||
Debug::log(LOG, "[EIS] Start Emulating");
|
||||
|
||||
if (client.pointer != nullptr)
|
||||
if (client.pointer)
|
||||
eis_device_start_emulating(client.pointer, sequence);
|
||||
|
||||
if (client.keyboard != nullptr)
|
||||
if (client.keyboard)
|
||||
eis_device_start_emulating(client.keyboard, sequence);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::stopEmulating() {
|
||||
Debug::log(LOG, "[EIS] Stop Emulating");
|
||||
|
||||
if (client.pointer != nullptr)
|
||||
if (client.pointer)
|
||||
eis_device_stop_emulating(client.pointer);
|
||||
|
||||
if (client.keyboard != nullptr)
|
||||
if (client.keyboard)
|
||||
eis_device_stop_emulating(client.keyboard);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::sendMotion(double x, double y) {
|
||||
if (client.pointer == nullptr)
|
||||
if (!client.pointer)
|
||||
return;
|
||||
eis_device_pointer_motion(client.pointer, x, y);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::sendKey(uint32_t key, bool pressed) {
|
||||
if (client.keyboard == nullptr)
|
||||
if (!client.keyboard)
|
||||
return;
|
||||
uint64_t now = eis_now(eis);
|
||||
uint64_t now = eis_now(eisCtx);
|
||||
eis_device_keyboard_key(client.keyboard, key, pressed);
|
||||
eis_device_frame(client.keyboard, now);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::sendButton(uint32_t button, bool pressed) {
|
||||
if (client.pointer == nullptr)
|
||||
if (!client.pointer)
|
||||
return;
|
||||
eis_device_button_button(client.pointer, button, pressed);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::sendScrollDiscrete(int32_t x, int32_t y) {
|
||||
if (client.pointer == nullptr)
|
||||
if (!client.pointer)
|
||||
return;
|
||||
eis_device_scroll_discrete(client.pointer, x, y);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::sendScrollDelta(double x, double y) {
|
||||
if (client.pointer == nullptr)
|
||||
if (!client.pointer)
|
||||
return;
|
||||
eis_device_scroll_delta(client.pointer, x, y);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::sendScrollStop(bool x, bool y) {
|
||||
if (client.pointer == nullptr)
|
||||
if (!client.pointer)
|
||||
return;
|
||||
eis_device_scroll_stop(client.pointer, x, y);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::sendPointerFrame() {
|
||||
if (client.pointer == nullptr)
|
||||
if (!client.pointer)
|
||||
return;
|
||||
uint64_t now = eis_now(eis);
|
||||
uint64_t now = eis_now(eisCtx);
|
||||
eis_device_frame(client.pointer, now);
|
||||
}
|
||||
|
||||
void EmulatedInputServer::stopServer() {
|
||||
stop = true;
|
||||
g_pPortalManager->removeFdFromEventLoop(eis_get_fd(eisCtx));
|
||||
Debug::log(LOG, "[EIS] Server fd {} destroyed", eis_get_fd(eisCtx));
|
||||
eis_unref(eisCtx);
|
||||
eisCtx = nullptr;
|
||||
}
|
||||
|
|
|
@ -3,14 +3,6 @@
|
|||
#include <libeis.h>
|
||||
#include <string>
|
||||
|
||||
struct EisClient {
|
||||
struct eis_client* handle;
|
||||
struct eis_seat* seat;
|
||||
|
||||
struct eis_device* pointer;
|
||||
struct eis_device* keyboard;
|
||||
};
|
||||
|
||||
/*
|
||||
* Responsible to creating a socket for input communication
|
||||
*/
|
||||
|
@ -35,14 +27,21 @@ class EmulatedInputServer {
|
|||
void stopServer();
|
||||
|
||||
private:
|
||||
bool stop;
|
||||
struct eis* eis;
|
||||
EisClient client;
|
||||
bool stop = false;
|
||||
eis* eisCtx = nullptr;
|
||||
|
||||
int onEvent(eis_event* e);
|
||||
void listen();
|
||||
void ensurePointer(eis_event* event);
|
||||
void ensureKeyboard(eis_event* event);
|
||||
void clearPointer();
|
||||
void clearKeyboard();
|
||||
struct Client {
|
||||
eis_client* handle = nullptr;
|
||||
eis_seat* seat = nullptr;
|
||||
|
||||
eis_device* pointer = nullptr;
|
||||
eis_device* keyboard = nullptr;
|
||||
} client;
|
||||
|
||||
int onEvent(eis_event* e);
|
||||
void pollEvents();
|
||||
void ensurePointer(eis_event* event);
|
||||
void ensureKeyboard(eis_event* event);
|
||||
void clearPointer();
|
||||
void clearKeyboard();
|
||||
};
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 53a994b2efbcc19862125fc9a8d5a752a24a0f20
|
||||
Subproject commit 479cc226451c264396a4c442710d6b56dce2fa46
|
Loading…
Reference in a new issue