input-capture: various fixes

This commit is contained in:
Gwilherm Folliot 2024-09-30 17:53:33 +02:00
parent 497a2ce308
commit 44ba88d82c
No known key found for this signature in database
GPG key ID: 90236D3623DCD660
7 changed files with 210 additions and 232 deletions

View file

@ -3,7 +3,6 @@
#include "../helpers/MiscFunctions.hpp" #include "../helpers/MiscFunctions.hpp"
#include <pipewire/pipewire.h> #include <pipewire/pipewire.h>
#include <poll.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
@ -19,18 +18,18 @@ SOutput::SOutput(SP<CCWlOutput> output_) : output(output_) {
Debug::log(LOG, "Found output name {}", name); Debug::log(LOG, "Found output name {}", name);
}); });
output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { output->setMode([this](CCWlOutput* r, uint32_t flags, int32_t width_, int32_t height_, int32_t refresh) {
refreshRate = refresh; refreshRate = refresh;
this->width = width; width = width_;
this->height = height; height = height_;
}); });
output->setGeometry( 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_; transform = (wl_output_transform)transform_;
this->x = x; x = x_;
this->y = y; 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(); }); output->setDone([](CCWlOutput* r) { g_pPortalManager->m_sPortals.inputCapture->zonesChanged(); });
} }
@ -276,32 +275,21 @@ void CPortalManager::init() {
} }
void CPortalManager::startEventLoop() { 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[] = { std::thread pollThr([this]() {
{
.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]() {
while (1) { 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) { if (ret < 0) {
Debug::log(CRIT, "[core] Polling fds failed with {}", strerror(errno)); Debug::log(CRIT, "[core] Polling fds failed with {}", strerror(errno));
g_pPortalManager->terminate(); g_pPortalManager->terminate();
} }
for (size_t i = 0; i < 3; ++i) { 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); Debug::log(CRIT, "[core] Disconnected from pollfd id {}", i);
g_pPortalManager->terminate(); g_pPortalManager->terminate();
} }
@ -374,13 +362,13 @@ void CPortalManager::startEventLoop() {
m_mEventLock.lock(); m_mEventLock.lock();
if (pollfds[0].revents & POLLIN /* dbus */) { if (m_sEventLoopInternals.pollFds[0].revents & POLLIN /* dbus */) {
while (m_pConnection->processPendingEvent()) { while (m_pConnection->processPendingRequest()) {
; ;
} }
} }
if (pollfds[1].revents & POLLIN /* wl */) { if (m_sEventLoopInternals.pollFds[1].revents & POLLIN /* wl */) {
wl_display_flush(m_sWaylandConnection.display); wl_display_flush(m_sWaylandConnection.display);
if (wl_display_prepare_read(m_sWaylandConnection.display) == 0) { if (wl_display_prepare_read(m_sWaylandConnection.display) == 0) {
wl_display_read_events(m_sWaylandConnection.display); 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) { 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; std::vector<CTimer*> toRemove;
for (auto& t : m_sTimersThread.timers) { for (auto& t : m_sTimersThread.timers) {
if (t->passed()) { if (t->passed()) {
@ -499,6 +493,20 @@ void CPortalManager::addTimer(const CTimer& timer) {
m_sTimersThread.loopSignal.notify_all(); 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() { void CPortalManager::terminate() {
m_bTerminate = true; m_bTerminate = true;

View file

@ -12,6 +12,7 @@
#include "../helpers/Timer.hpp" #include "../helpers/Timer.hpp"
#include "../shared/ToplevelManager.hpp" #include "../shared/ToplevelManager.hpp"
#include <gbm.h> #include <gbm.h>
#include <poll.h>
#include <xf86drm.h> #include <xf86drm.h>
#include "hyprland-toplevel-export-v1.hpp" #include "hyprland-toplevel-export-v1.hpp"
@ -34,9 +35,11 @@ struct SOutput {
uint32_t id = 0; uint32_t id = 0;
float refreshRate = 60.0; float refreshRate = 60.0;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
uint32_t width, height; uint32_t width = 0;
int32_t x, y; uint32_t height = 0;
int32_t scale; int32_t x = 0;
int32_t y = 0;
int32_t scale = 1;
}; };
struct SDMABUFModifier { struct SDMABUFModifier {
@ -98,6 +101,9 @@ class CPortalManager {
gbm_device* createGBMDevice(drmDevice* dev); 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() // terminate after the event loop has been created. Before we can exit()
void terminate(); void terminate();
@ -112,6 +118,8 @@ class CPortalManager {
std::mutex loopMutex; std::mutex loopMutex;
std::atomic<bool> shouldProcess = false; std::atomic<bool> shouldProcess = false;
std::mutex loopRequestMutex; std::mutex loopRequestMutex;
std::vector<pollfd> pollFds;
std::map<int, std::function<void()>> pollCallbacks;
} m_sEventLoopInternals; } m_sEventLoopInternals;
struct { struct {

View file

@ -13,14 +13,11 @@
#include <unordered_map> #include <unordered_map>
#include <wayland-util.h> #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"); 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) { mgr->setMotion([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)); 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); }); 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->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, "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(); 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, "{} {}x{}", o->name, o->width, o->height);
}
Debug::log(LOG, "[input-capture] init successful"); 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++); std::string sessionId = "input-capture-" + std::to_string(sessionCounter++);
Debug::log(LOG, "[input-capture] | sessionId : {}", sessionId); 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->appid = appID;
session->requestHandle = requestHandle; session->requestHandle = requestHandle;
session->sessionHandle = sessionHandle; session->sessionHandle = sessionHandle;
session->sessionId = sessionId; session->sessionId = sessionId;
session->capabilities = capabilities; session->capabilities = capabilities;
session->activationId = 0;
session->status = CREATED;
session->session = createDBusSession(sessionHandle); session->session = createDBusSession(sessionHandle);
session->session->onDestroy = [session, this]() { session->session->onDestroy = [session, this]() {
if (session->status == ACTIVATED) {
disable(session->sessionHandle); disable(session->sessionHandle);
}
session->eis->stopServer(); session->eis->stopServer();
session->eis = nullptr;
Debug::log(LOG, "[input-capture] Session {} destroyed", session->sessionHandle.c_str()); Debug::log(LOG, "[input-capture] Session {} destroyed", session->sessionHandle.c_str());
session->session.release(); 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 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); 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) { uint32_t CInputCapturePortal::SSession::isColliding(double px, double py, double nx, double ny) {
for (const auto& [key, value] : barriers) { for (const auto& [key, value] : barriers)
if (testCollision(value, px, py, nx, ny)) { if (testCollision(value, px, py, nx, ny))
return key; return key;
}
}
return 0; 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) { for (const auto& [key, session] : sessions) {
int matched = session->isColliding(x, y, x - dx, y - dy); int matched = session->isColliding(x, y, x - dx, y - dy);
if (matched != 0) { if (matched != 0)
activate(key, x, y, matched); activate(key, x, y, matched);
}
session->motion(dx, dy); session->motion(dx, dy);
} }
} }
void CInputCapturePortal::onKey(uint32_t key, bool pressed) { void CInputCapturePortal::onKey(uint32_t id, bool pressed) {
for (const auto& [_, value] : sessions) { for (const auto& [key, value] : sessions)
value->key(key, pressed); value->key(id, pressed);
}
} }
void CInputCapturePortal::onButton(uint32_t button, bool pressed) { void CInputCapturePortal::onButton(uint32_t button, bool pressed) {
for (const auto& [_, session] : sessions) { for (const auto& [key, session] : sessions)
session->button(button, pressed); session->button(button, pressed);
}
} }
void CInputCapturePortal::onAxis(bool axis, double value) { void CInputCapturePortal::onAxis(bool axis, double value) {
for (const auto& [_, session] : sessions) { for (const auto& [key, session] : sessions)
session->axis(axis, value); session->axis(axis, value);
}
} }
void CInputCapturePortal::onAxisValue120(bool axis, int32_t value120) { void CInputCapturePortal::onAxisValue120(bool axis, int32_t value120) {
for (const auto& [_, session] : sessions) { for (const auto& [key, session] : sessions)
session->axisValue120(axis, value120); session->axisValue120(axis, value120);
}
} }
void CInputCapturePortal::onAxisStop(bool axis) { void CInputCapturePortal::onAxisStop(bool axis) {
for (const auto& [_, session] : sessions) { for (const auto& [_, session] : sessions)
session->axisStop(axis); session->axisStop(axis);
}
} }
void CInputCapturePortal::onFrame() { void CInputCapturePortal::onFrame() {
for (const auto& [_, session] : sessions) { for (const auto& [_, session] : sessions)
session->frame(); session->frame();
}
} }
void CInputCapturePortal::activate(sdbus::ObjectPath sessionHandle, double x, double y, uint32_t borderId) { 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); 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) { if (status != ENABLED) {
return false; return false;
} }
@ -467,10 +453,9 @@ void CInputCapturePortal::deactivate(sdbus::ObjectPath sessionHandle) {
m_pObject->emitSignal(signal); m_pObject->emitSignal(signal);
} }
bool CInputCapturePortal::Session::deactivate() { bool CInputCapturePortal::SSession::deactivate() {
if (status != ACTIVATED) { if (status != ACTIVATED)
return false; return false;
}
Debug::log(LOG, "[input-capture] Input released for {}", sessionHandle.c_str()); Debug::log(LOG, "[input-capture] Input released for {}", sessionHandle.c_str());
eis->stopEmulating(); eis->stopEmulating();
@ -500,7 +485,7 @@ void CInputCapturePortal::zonesChanged() {
} }
} }
bool CInputCapturePortal::Session::zoneChanged() { bool CInputCapturePortal::SSession::zoneChanged() {
//TODO: notify EIS //TODO: notify EIS
return true; return true;
} }
@ -510,12 +495,13 @@ void CInputCapturePortal::disable(sdbus::ObjectPath sessionHandle) {
return; return;
auto session = sessions[sessionHandle]; auto session = sessions[sessionHandle];
if (!session->disable())
return;
if (session->status == ACTIVATED) if (session->status == ACTIVATED)
deactivate(sessionHandle); deactivate(sessionHandle);
if (!session->disable())
return;
auto signal = m_pObject->createSignal(INTERFACE_NAME, "Disable"); auto signal = m_pObject->createSignal(INTERFACE_NAME, "Disable");
signal << sessionHandle; signal << sessionHandle;
@ -525,70 +511,74 @@ void CInputCapturePortal::disable(sdbus::ObjectPath sessionHandle) {
m_pObject->emitSignal(signal); m_pObject->emitSignal(signal);
} }
bool CInputCapturePortal::Session::disable() { bool CInputCapturePortal::SSession::disable() {
status = STOPPED; status = STOPPED;
Debug::log(LOG, "[input-capture] Session {} disabled", sessionHandle.c_str()); Debug::log(LOG, "[input-capture] Session {} disabled", sessionHandle.c_str());
return true; return true;
} }
void CInputCapturePortal::Session::motion(double dx, double dy) { void CInputCapturePortal::SSession::motion(double dx, double dy) {
if (status != ACTIVATED) if (status != ACTIVATED)
return; return;
eis->sendMotion(dx, dy); 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) if (status != ACTIVATED)
return; return;
eis->sendKey(key, pressed); 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) if (status != ACTIVATED)
return; return;
eis->sendButton(button, pressed); eis->sendButton(button, pressed);
} }
void CInputCapturePortal::Session::axis(bool axis, double value) { void CInputCapturePortal::SSession::axis(bool axis, double value) {
if (status != ACTIVATED) if (status != ACTIVATED)
return; return;
double x = 0; double x = 0;
double y = 0; double y = 0;
if (axis) { if (axis)
x = value; x = value;
} else { else
y = value; y = value;
}
eis->sendScrollDelta(x, y); 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) if (status != ACTIVATED)
return; return;
int32_t x = 0; int32_t x = 0;
int32_t y = 0; int32_t y = 0;
if (axis) { if (axis)
x = value; x = value;
} else { else
y = value; y = value;
}
eis->sendScrollDiscrete(x, y); eis->sendScrollDiscrete(x, y);
} }
void CInputCapturePortal::Session::axisStop(bool axis) { void CInputCapturePortal::SSession::axisStop(bool axis) {
if (status != ACTIVATED)
return;
eis->sendScrollStop(axis, !axis); eis->sendScrollStop(axis, !axis);
} }
void CInputCapturePortal::Session::frame() { void CInputCapturePortal::SSession::frame() {
if (status != ACTIVATED)
return;
eis->sendPointerFrame(); eis->sendPointerFrame();
} }

View file

@ -5,13 +5,14 @@
#include "../shared/Session.hpp" #include "../shared/Session.hpp"
#include <sdbus-c++/Types.h> #include <sdbus-c++/Types.h>
typedef int ClientStatus; enum ClientStatus {
const ClientStatus CREATED = 0; //Is ready to be activated CREATED, //Is ready to be activated
const ClientStatus ENABLED = 1; //Is ready for receiving inputs ENABLED, //Is ready for receiving inputs
const ClientStatus ACTIVATED = 2; //Currently receiving inputs ACTIVATED, //Currently receiving inputs
const ClientStatus STOPPED = 3; //Can no longer be activated STOPPED //Can no longer be activated
};
struct Barrier { struct SBarrier {
uint id; uint id;
int x1, y1, x2, y2; int x1, y1, x2, y2;
}; };
@ -28,7 +29,7 @@ class CInputCapturePortal {
void onRelease(sdbus::MethodCall& methodCall); void onRelease(sdbus::MethodCall& methodCall);
void onConnectToEIS(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 onKey(uint32_t key, bool pressed);
void onButton(uint32_t button, bool pressed); void onButton(uint32_t button, bool pressed);
void onAxis(bool axis, double value); void onAxis(bool axis, double value);
@ -38,19 +39,19 @@ class CInputCapturePortal {
void zonesChanged(); void zonesChanged();
struct Session { struct SSession {
std::string appid; std::string appid;
sdbus::ObjectPath requestHandle, sessionHandle; sdbus::ObjectPath requestHandle, sessionHandle;
std::string sessionId; std::string sessionId;
uint32_t capabilities; uint32_t capabilities = 0;
std::unique_ptr<SDBusRequest> request; std::unique_ptr<SDBusRequest> request;
std::unique_ptr<SDBusSession> session; std::unique_ptr<SDBusSession> session;
std::unique_ptr<EmulatedInputServer> eis; std::unique_ptr<EmulatedInputServer> eis;
std::unordered_map<uint32_t, Barrier> barriers; std::unordered_map<uint32_t, SBarrier> barriers;
uint32_t activationId; uint32_t activationId = 0;
ClientStatus status; ClientStatus status = CREATED;
// //
bool activate(double x, double y, uint32_t borderId); bool activate(double x, double y, uint32_t borderId);
@ -74,11 +75,11 @@ class CInputCapturePortal {
SP<CCHyprlandInputCaptureManagerV1> manager; SP<CCHyprlandInputCaptureManagerV1> manager;
} m_sState; } 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; std::unique_ptr<sdbus::IObject> m_pObject;
uint sessionCounter; uint sessionCounter = 0;
uint lastZoneSet; uint lastZoneSet = 0;
const std::string INTERFACE_NAME = "org.freedesktop.impl.portal.InputCapture"; const std::string INTERFACE_NAME = "org.freedesktop.impl.portal.InputCapture";
const std::string OBJECT_PATH = "/org/freedesktop/portal/desktop"; const std::string OBJECT_PATH = "/org/freedesktop/portal/desktop";

View file

@ -2,11 +2,9 @@
#include "../core/PortalManager.hpp" #include "../core/PortalManager.hpp"
#include "src/helpers/Log.hpp" #include "src/helpers/Log.hpp"
#include <libeis.h> #include <libeis.h>
#include <sys/poll.h>
#include <thread>
EmulatedInputServer::EmulatedInputServer(std::string socketName) { 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"); const char* xdg = getenv("XDG_RUNTIME_DIR");
if (xdg) if (xdg)
@ -17,37 +15,23 @@ EmulatedInputServer::EmulatedInputServer(std::string socketName) {
return; return;
} }
client.handle = NULL; eisCtx = eis_new(nullptr);
client.seat = NULL;
client.pointer = NULL;
client.keyboard = NULL;
eis = eis_new(NULL);
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); Debug::log(ERR, "[EIS] Cannot init eis socket on {}", socketPath);
return; return;
} }
Debug::log(LOG, "[EIS] Listening on {}", socketPath); Debug::log(LOG, "[EIS] Listening on {}", socketPath);
stop = false; g_pPortalManager->addFdToEventLoop(eis_get_fd(eisCtx), POLLIN, std::bind(&EmulatedInputServer::pollEvents, this));
std::thread thread(&EmulatedInputServer::listen, this);
thread.detach();
} }
void EmulatedInputServer::listen() { void EmulatedInputServer::pollEvents() {
struct pollfd fds = { eis_dispatch(eisCtx);
.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);
//Pull every availaible events //Pull every availaible events
while (true) { while (true) {
eis_event* e = eis_get_event(eis); eis_event* e = eis_get_event(eisCtx);
if (!e) { if (!e) {
eis_event_unref(e); eis_event_unref(e);
@ -59,53 +43,52 @@ void EmulatedInputServer::listen() {
if (rc != 0) if (rc != 0)
break; break;
} }
}
} }
int EmulatedInputServer::onEvent(eis_event* e) { int EmulatedInputServer::onEvent(eis_event* e) {
eis_client* client; eis_client* eisClient = nullptr;
eis_seat* seat; eis_seat* seat = nullptr;
eis_device* device; eis_device* device = nullptr;
switch (eis_event_get_type(e)) { switch (eis_event_get_type(e)) {
case EIS_EVENT_CLIENT_CONNECT: case EIS_EVENT_CLIENT_CONNECT:
client = eis_event_get_client(e); eisClient = eis_event_get_client(e);
Debug::log(LOG, "[EIS] {} client connected: {}", eis_client_is_sender(client) ? "sender" : "receiver", eis_client_get_name(client)); Debug::log(LOG, "[EIS] {} client connected: {}", eis_client_is_sender(eisClient) ? "Sender" : "Receiver", eis_client_get_name(eisClient));
if (eis_client_is_sender(client)) { if (eis_client_is_sender(eisClient)) {
Debug::log(WARN, "[EIS] Unexpected sender client {} connected to input capture session", eis_client_get_name(client)); Debug::log(WARN, "[EIS] Unexpected sender client {} connected to input capture session", eis_client_get_name(eisClient));
eis_client_disconnect(client); eis_client_disconnect(eisClient);
return 0; return 0;
} }
if (this->client.handle != nullptr) { if (client.handle) {
Debug::log(WARN, "[EIS] Unexpected additional client {} connected to input capture session", eis_client_get_name(client)); Debug::log(WARN, "[EIS] Unexpected additional client {} connected to input capture session", eis_client_get_name(eisClient));
eis_client_disconnect(client); eis_client_disconnect(eisClient);
return 0; return 0;
} }
this->client.handle = client; client.handle = eisClient;
eis_client_connect(client); eis_client_connect(eisClient);
Debug::log(LOG, "[EIS] creating new default seat"); Debug::log(LOG, "[EIS] Creating new default seat");
seat = eis_client_new_seat(client, "default"); seat = eis_client_new_seat(eisClient, "default");
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_POINTER); 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_BUTTON);
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_SCROLL); eis_seat_configure_capability(seat, EIS_DEVICE_CAP_SCROLL);
eis_seat_configure_capability(seat, EIS_DEVICE_CAP_KEYBOARD); eis_seat_configure_capability(seat, EIS_DEVICE_CAP_KEYBOARD);
eis_seat_add(seat); eis_seat_add(seat);
this->client.seat = seat; client.seat = seat;
break; break;
case EIS_EVENT_CLIENT_DISCONNECT: case EIS_EVENT_CLIENT_DISCONNECT:
client = eis_event_get_client(e); eisClient = eis_event_get_client(e);
Debug::log(LOG, "[EIS] {} disconnected", eis_client_get_name(client)); Debug::log(LOG, "[EIS] {} disconnected", eis_client_get_name(eisClient));
eis_client_disconnect(client); eis_client_disconnect(eisClient);
eis_seat_unref(this->client.seat); eis_seat_unref(client.seat);
clearPointer(); clearPointer();
clearKeyboard(); clearKeyboard();
this->client.handle = NULL; client.handle = nullptr;
break; break;
case EIS_EVENT_SEAT_BIND: case EIS_EVENT_SEAT_BIND:
Debug::log(LOG, "[EIS] Binding seats..."); Debug::log(LOG, "[EIS] Binding seats...");
@ -123,45 +106,31 @@ int EmulatedInputServer::onEvent(eis_event* e) {
break; break;
case EIS_EVENT_DEVICE_CLOSED: case EIS_EVENT_DEVICE_CLOSED:
device = eis_event_get_device(e); device = eis_event_get_device(e);
if (device == this->client.pointer) { if (device == client.pointer)
clearPointer(); clearPointer();
} else if (device == this->client.keyboard) { else if (device == client.keyboard) {
Debug::log(LOG, "[EIS] Clearing keyboard"); Debug::log(LOG, "[EIS] Clearing keyboard");
clearKeyboard(); clearKeyboard();
} else { } else
Debug::log(WARN, "[EIS] Unknown device to close"); Debug::log(WARN, "[EIS] Unknown device to close");
}
break; break;
case EIS_EVENT_FRAME: Debug::log(LOG, "[EIS] Got event EIS_EVENT_FRAME"); break; default: return 0;
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;
} }
return 0; return 0;
} }
void EmulatedInputServer::ensurePointer(eis_event* event) { void EmulatedInputServer::ensurePointer(eis_event* event) {
if (client.pointer != nullptr) if (client.pointer)
return; 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_name(pointer, "captured relative pointer");
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_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_BUTTON);
eis_device_configure_capability(pointer, EIS_DEVICE_CAP_SCROLL); eis_device_configure_capability(pointer, EIS_DEVICE_CAP_SCROLL);
for (auto& o : g_pPortalManager->getAllOutputs()) { 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_offset(r, o->x, o->y);
eis_region_set_size(r, o->width, o->height); 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) { void EmulatedInputServer::ensureKeyboard(eis_event* event) {
if (client.keyboard != nullptr) if (client.keyboard)
return; 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_name(keyboard, "captured keyboard");
eis_device_configure_capability(keyboard, EIS_DEVICE_CAP_KEYBOARD); eis_device_configure_capability(keyboard, EIS_DEVICE_CAP_KEYBOARD);
// TODO: layout // 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) //TODO: remove and re-add devices when monitors change (see: mutter/meta-input-capture-session.c:1107)
void EmulatedInputServer::clearPointer() { void EmulatedInputServer::clearPointer() {
if (client.pointer == nullptr) if (!client.pointer)
return; return;
Debug::log(LOG, "[EIS] Clearing pointer"); Debug::log(LOG, "[EIS] Clearing pointer");
@ -203,7 +172,7 @@ void EmulatedInputServer::clearPointer() {
} }
void EmulatedInputServer::clearKeyboard() { void EmulatedInputServer::clearKeyboard() {
if (client.keyboard == nullptr) if (!client.keyboard)
return; return;
Debug::log(LOG, "[EIS] Clearing keyboard"); Debug::log(LOG, "[EIS] Clearing keyboard");
@ -213,74 +182,77 @@ void EmulatedInputServer::clearKeyboard() {
} }
int EmulatedInputServer::getFileDescriptor() { int EmulatedInputServer::getFileDescriptor() {
return eis_backend_fd_add_client(eis); return eis_backend_fd_add_client(eisCtx);
} }
void EmulatedInputServer::startEmulating(int sequence) { void EmulatedInputServer::startEmulating(int sequence) {
Debug::log(LOG, "[EIS] Start Emulating"); Debug::log(LOG, "[EIS] Start Emulating");
if (client.pointer != nullptr) if (client.pointer)
eis_device_start_emulating(client.pointer, sequence); eis_device_start_emulating(client.pointer, sequence);
if (client.keyboard != nullptr) if (client.keyboard)
eis_device_start_emulating(client.keyboard, sequence); eis_device_start_emulating(client.keyboard, sequence);
} }
void EmulatedInputServer::stopEmulating() { void EmulatedInputServer::stopEmulating() {
Debug::log(LOG, "[EIS] Stop Emulating"); Debug::log(LOG, "[EIS] Stop Emulating");
if (client.pointer != nullptr) if (client.pointer)
eis_device_stop_emulating(client.pointer); eis_device_stop_emulating(client.pointer);
if (client.keyboard != nullptr) if (client.keyboard)
eis_device_stop_emulating(client.keyboard); eis_device_stop_emulating(client.keyboard);
} }
void EmulatedInputServer::sendMotion(double x, double y) { void EmulatedInputServer::sendMotion(double x, double y) {
if (client.pointer == nullptr) if (!client.pointer)
return; return;
eis_device_pointer_motion(client.pointer, x, y); eis_device_pointer_motion(client.pointer, x, y);
} }
void EmulatedInputServer::sendKey(uint32_t key, bool pressed) { void EmulatedInputServer::sendKey(uint32_t key, bool pressed) {
if (client.keyboard == nullptr) if (!client.keyboard)
return; return;
uint64_t now = eis_now(eis); uint64_t now = eis_now(eisCtx);
eis_device_keyboard_key(client.keyboard, key, pressed); eis_device_keyboard_key(client.keyboard, key, pressed);
eis_device_frame(client.keyboard, now); eis_device_frame(client.keyboard, now);
} }
void EmulatedInputServer::sendButton(uint32_t button, bool pressed) { void EmulatedInputServer::sendButton(uint32_t button, bool pressed) {
if (client.pointer == nullptr) if (!client.pointer)
return; return;
eis_device_button_button(client.pointer, button, pressed); eis_device_button_button(client.pointer, button, pressed);
} }
void EmulatedInputServer::sendScrollDiscrete(int32_t x, int32_t y) { void EmulatedInputServer::sendScrollDiscrete(int32_t x, int32_t y) {
if (client.pointer == nullptr) if (!client.pointer)
return; return;
eis_device_scroll_discrete(client.pointer, x, y); eis_device_scroll_discrete(client.pointer, x, y);
} }
void EmulatedInputServer::sendScrollDelta(double x, double y) { void EmulatedInputServer::sendScrollDelta(double x, double y) {
if (client.pointer == nullptr) if (!client.pointer)
return; return;
eis_device_scroll_delta(client.pointer, x, y); eis_device_scroll_delta(client.pointer, x, y);
} }
void EmulatedInputServer::sendScrollStop(bool x, bool y) { void EmulatedInputServer::sendScrollStop(bool x, bool y) {
if (client.pointer == nullptr) if (!client.pointer)
return; return;
eis_device_scroll_stop(client.pointer, x, y); eis_device_scroll_stop(client.pointer, x, y);
} }
void EmulatedInputServer::sendPointerFrame() { void EmulatedInputServer::sendPointerFrame() {
if (client.pointer == nullptr) if (!client.pointer)
return; return;
uint64_t now = eis_now(eis); uint64_t now = eis_now(eisCtx);
eis_device_frame(client.pointer, now); eis_device_frame(client.pointer, now);
} }
void EmulatedInputServer::stopServer() { 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;
} }

View file

@ -3,14 +3,6 @@
#include <libeis.h> #include <libeis.h>
#include <string> #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 * Responsible to creating a socket for input communication
*/ */
@ -35,12 +27,19 @@ class EmulatedInputServer {
void stopServer(); void stopServer();
private: private:
bool stop; bool stop = false;
struct eis* eis; eis* eisCtx = nullptr;
EisClient client;
struct Client {
eis_client* handle = nullptr;
eis_seat* seat = nullptr;
eis_device* pointer = nullptr;
eis_device* keyboard = nullptr;
} client;
int onEvent(eis_event* e); int onEvent(eis_event* e);
void listen(); void pollEvents();
void ensurePointer(eis_event* event); void ensurePointer(eis_event* event);
void ensureKeyboard(eis_event* event); void ensureKeyboard(eis_event* event);
void clearPointer(); void clearPointer();

@ -1 +1 @@
Subproject commit 53a994b2efbcc19862125fc9a8d5a752a24a0f20 Subproject commit 479cc226451c264396a4c442710d6b56dce2fa46