moteDesktopSession::RemoteDesktopSession()
: iface(new OrgFreedesktopPortalRemoteDesktopInterface(QLatin1String("org.freedesktop.portal.Desktop"),
QLatin1String("/org/freedesktop/portal/desktop"),
QDBusConnection::sessionBus(),
this))
{
}
id RemoteDesktopSession::createSession()
{
if (isValid()) {
qCDebug(KDECONNECT_PLUGIN_MOUSEPAD) << "pass, already created";
return;
}
m_connecting = true;
// create session
const auto handleToken = QStringLiteral("kdeconnect%1").arg(QRandomGenerator::global()->generate());
const auto sessionParameters = QVariantMap{{QLatin1String("session_handle_token"), handleToken}, {QLatin1String("handle_token"), handleToken}};
auto sessionReply = iface->CreateSession(sessionParameters);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(sessionReply);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, sessionReply](QDBusPendingCallWatcher *self) {
self->deleteLater();
if (sessionReply.isError()) {
qCWarning(KDECONNECT_PLUGIN_MOUSEPAD) << "Could not create the remote control session" << sessionReply.error();
m_connecting = false;
return;
}
bool b = QDBusConnection::sessionBus().connect(QString(),
sessionReply.value().path(),
QLatin1String("org.freedesktop.portal.Request"),
QLatin1String("Response"),
this,
SLOT(handleXdpSessionCreated(uint, QVariantMap)));
Q_ASSERT(b);
qCDebug(KDECONNECT_PLUGIN_MOUSEPAD) << "authenticating" << sessionReply.value().path();
});
}
id RemoteDesktopSession::handleXdpSessionCreated(uint code, const QVariantMap &results)
{
if (code != 0) {
qCWarning(KDECONNECT_PLUGIN_MOUSEPAD) << "Failed to create session with code" << code << results;
return;
}
m_connecting = false;
m_xdpPath = QDBusObjectPath(results.value(QLatin1String("session_handle")).toString());
const QVariantMap startParameters = {
{QLatin1String("handle_token"), QStringLiteral("kdeconnect%1").arg(QRandomGenerator::global()->generate())},
{QStringLiteral("types"), QVariant::fromValue(7)}, // request all (KeyBoard, Pointer, TouchScreen)
};
QDBusConnection::sessionBus().connect(QString(),
m_xdpPath.path(),
QLatin1String("org.freedesktop.portal.Session"),
QLatin1String("Closed"),
this,
SLOT(handleXdpSessionFinished(uint, QVariantMap)));
auto reply = iface->SelectDevices(m_xdpPath, startParameters);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, reply](QDBusPendingCallWatcher *self) {
self->deleteLater();
if (reply.isError()) {
qCWarning(KDECONNECT_PLUGIN_MOUSEPAD) << "Could not start the remote control session" << reply.error();
m_connecting = false;
return;
}
bool b = QDBusConnection::sessionBus().connect(QString(),
reply.value().path(),
QLatin1String("org.freedesktop.portal.Request"),
QLatin1String("Response"),
this,
SLOT(handleXdpSessionConfigured(uint, QVariantMap)));
Q_ASSERT(b);
qCDebug(KDECONNECT_PLUGIN_MOUSEPAD) << "configuring" << reply.value().path();
});
}
id RemoteDesktopSession::handleXdpSessionConfigured(uint code, const QVariantMap &results)
{
if (code != 0) {
qCWarning(KDECONNECT_PLUGIN_MOUSEPAD) << "Failed to configure session with code" << code << results;
m_connecting = false;
return;
}
const QVariantMap startParameters = {
{QLatin1String("handle_token"), QStringLiteral("kdeconnect%1").arg(QRandomGenerator::global()->generate())},
};
auto reply = iface->Start(m_xdpPath, {}, startParameters);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, reply](QDBusPendingCallWatcher *self) {
self->deleteLater();
if (reply.isError()) {
qCWarning(KDECONNECT_PLUGIN_MOUSEPAD) << "Could not start the remote control session" << reply.error();
m_connecting = false;
}
});
}
id RemoteDesktopSession::handleXdpSessionFinished(uint /*code*/, const QVariantMap & /*results*/)
{
m_xdpPath = {};
}
ylandRemoteInput::WaylandRemoteInput(QObject *parent)
: AbstractRemoteInput(parent)
{
}
ylandRemoteInput::~WaylandRemoteInput()
{
}
ol WaylandRemoteInput::handlePacket(const NetworkPacket &np)
{
if (!s_session->isValid()) {
qCWarning(KDECONNECT_PLUGIN_MOUSEPAD) << "Unable to handle remote input. RemoteDesktop portal not authenticated";
s_session->createSession();
return false;
}
const float dx = np.get(QStringLiteral("dx"), 0);
const float dy = np.get(QStringLiteral("dy"), 0);
const bool isSingleClick = np.get(QStringLiteral("singleclick"), false);
const bool isDoubleClick = np.get(QStringLiteral("doubleclick"), false);
const bool isMiddleClick = np.get(QStringLiteral("middleclick"), false);
const bool isRightClick = np.get(QStringLiteral("rightclick"), false);
const bool isSingleHold = np.get(QStringLiteral("singlehold"), false);
const bool isSingleRelease = np.get(QStringLiteral("singlerelease"), false);
const bool isScroll = np.get(QStringLiteral("scroll"), false);
const QString key = np.get(QStringLiteral("key"), QLatin1String(""));
const int specialKey = np.get(QStringLiteral("specialKey"), 0);
if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isSingleHold || isSingleRelease || isScroll || !key.isEmpty() || specialKey) {
if (isSingleClick) {
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 1);
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 0);
} else if (isDoubleClick) {
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 1);
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 0);
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 1);
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 0);
} else if (isMiddleClick) {
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_MIDDLE, 1);
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_MIDDLE, 0);
} else if (isRightClick) {
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_RIGHT, 1);
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_RIGHT, 0);
} else if (isSingleHold) {
// For drag'n drop
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 1);
} else if (isSingleRelease) {
// For drag'n drop. NEVER USED (release is done by tapping, which actually triggers a isSingleClick). Kept here for future-proofness.
s_session->iface->NotifyPointerButton(s_session->m_xdpPath, {}, BTN_LEFT, 0);
} else if (isScroll) {
s_session->iface->NotifyPointerAxis(s_session->m_xdpPath, {}, dx, dy);
} else if (specialKey) {
s_session->iface->NotifyKeyboardKeycode(s_session->m_xdpPath, {}, SpecialKeysMap[specialKey], 1);
s_session->iface->NotifyKeyboardKeycode(s_session->m_xdpPath, {}, SpecialKeysMap[specialKey], 0);
} else if (!key.isEmpty()) {
for (const QChar character : key) {
const auto keysym = xkb_utf32_to_keysym(character.unicode());
if (keysym != XKB_KEY_NoSymbol) {
s_session->iface->NotifyKeyboardKeysym(s_session->m_xdpPath, {}, keysym, 1).waitForFinished();
s_session->iface->NotifyKeyboardKeysym(s_session->m_xdpPath, {}, keysym, 0).waitForFinished();
} else {
qCDebug(KDECONNECT_PLUGIN_MOUSEPAD) << "Cannot send character" << character;
}
}
}
} else { // Is a mouse move event
s_session->iface->NotifyPointerMotion(s_session->m_xdpPath, {}, dx, dy);
}
return true;
}