input-capture: various fixes

This commit is contained in:
Gwilherm Folliot 2024-09-30 17:53:33 +02:00
parent 390474433d
commit 31d3566146
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 <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(); });
}
@ -277,32 +276,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();
}
@ -375,13 +363,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);
@ -391,12 +379,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()) {
@ -500,6 +494,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;

View file

@ -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 {

View file

@ -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();
}

View file

@ -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";

View file

@ -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;
}

View file

@ -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