File indexing completed on 2024-04-14 04:51:48

0001 /**
0002  * SPDX-FileCopyrightText: 2017 Holger Kaelberer <holger.k@elberer.de>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "remotekeyboardplugin.h"
0008 #include "plugin_remotekeyboard_debug.h"
0009 #include <KPluginFactory>
0010 #include <QDebug>
0011 #include <QKeySequence>
0012 #include <QString>
0013 #include <QVariantMap>
0014 
0015 K_PLUGIN_CLASS_WITH_JSON(RemoteKeyboardPlugin, "kdeconnect_remotekeyboard.json")
0016 
0017 // Mapping of Qt::Key to internal codes, corresponds to the mapping in mousepadplugin
0018 QMap<int, int> specialKeysMap = {
0019     // 0,              // Invalid
0020     {Qt::Key_Backspace, 1},
0021     {Qt::Key_Tab, 2},
0022     // XK_Linefeed,    // 3
0023     {Qt::Key_Left, 4},
0024     {Qt::Key_Up, 5},
0025     {Qt::Key_Right, 6},
0026     {Qt::Key_Down, 7},
0027     {Qt::Key_PageUp, 8},
0028     {Qt::Key_PageDown, 9},
0029     {Qt::Key_Home, 10},
0030     {Qt::Key_End, 11},
0031     {Qt::Key_Return, 12},
0032     {Qt::Key_Enter, 12},
0033     {Qt::Key_Delete, 13},
0034     {Qt::Key_Escape, 14},
0035     {Qt::Key_SysReq, 15},
0036     {Qt::Key_ScrollLock, 16},
0037     // 0,              // 17
0038     // 0,              // 18
0039     // 0,              // 19
0040     // 0,              // 20
0041     {Qt::Key_F1, 21},
0042     {Qt::Key_F2, 22},
0043     {Qt::Key_F3, 23},
0044     {Qt::Key_F4, 24},
0045     {Qt::Key_F5, 25},
0046     {Qt::Key_F6, 26},
0047     {Qt::Key_F7, 27},
0048     {Qt::Key_F8, 28},
0049     {Qt::Key_F9, 29},
0050     {Qt::Key_F10, 30},
0051     {Qt::Key_F11, 31},
0052     {Qt::Key_F12, 32},
0053 };
0054 
0055 RemoteKeyboardPlugin::RemoteKeyboardPlugin(QObject *parent, const QVariantList &args)
0056     : KdeConnectPlugin(parent, args)
0057     , m_remoteState(false)
0058 {
0059 }
0060 
0061 void RemoteKeyboardPlugin::receivePacket(const NetworkPacket &np)
0062 {
0063     if (np.type() == PACKET_TYPE_MOUSEPAD_ECHO) {
0064         if (!np.has(QStringLiteral("isAck")) || !np.has(QStringLiteral("key"))) {
0065             qCWarning(KDECONNECT_PLUGIN_REMOTEKEYBOARD) << "Invalid packet of type" << PACKET_TYPE_MOUSEPAD_ECHO;
0066             return;
0067         }
0068         //        qCWarning(KDECONNECT_PLUGIN_REMOTEKEYBOARD) << "Received keypress" << np;
0069         Q_EMIT keyPressReceived(np.get<QString>(QStringLiteral("key")),
0070                                 np.get<int>(QStringLiteral("specialKey"), 0),
0071                                 np.get<int>(QStringLiteral("shift"), false),
0072                                 np.get<int>(QStringLiteral("ctrl"), false),
0073                                 np.get<int>(QStringLiteral("alt"), 0));
0074     } else if (np.type() == PACKET_TYPE_MOUSEPAD_KEYBOARDSTATE) {
0075         //        qCWarning(KDECONNECT_PLUGIN_REMOTEKEYBOARD) << "Received keyboardstate" << np;
0076         if (m_remoteState != np.get<bool>(QStringLiteral("state"))) {
0077             m_remoteState = np.get<bool>(QStringLiteral("state"));
0078             Q_EMIT remoteStateChanged(m_remoteState);
0079         }
0080     }
0081 }
0082 
0083 void RemoteKeyboardPlugin::sendKeyPress(const QString &key, int specialKey, bool shift, bool ctrl, bool alt, bool sendAck) const
0084 {
0085     NetworkPacket np(PACKET_TYPE_MOUSEPAD_REQUEST,
0086                      {{QStringLiteral("key"), key},
0087                       {QStringLiteral("specialKey"), specialKey},
0088                       {QStringLiteral("shift"), shift},
0089                       {QStringLiteral("ctrl"), ctrl},
0090                       {QStringLiteral("alt"), alt},
0091                       {QStringLiteral("sendAck"), sendAck}});
0092     sendPacket(np);
0093 }
0094 
0095 void RemoteKeyboardPlugin::sendQKeyEvent(const QVariantMap &keyEvent, bool sendAck) const
0096 {
0097     if (!keyEvent.contains(QStringLiteral("key"))) {
0098         return;
0099     }
0100     const int key = keyEvent.value(QStringLiteral("key")).toInt();
0101     int k = translateQtKey(key);
0102     int modifiers = keyEvent.value(QStringLiteral("modifiers")).toInt();
0103 
0104     // Qt will be calling xkb_state_key_get_utf8 to create this string.
0105     // As documented, it will be giving us weird strings with Ctrl combinations:
0106     // https://xkbcommon.org/doc/current/group__keysyms.html
0107     // Instead, just use QKeySequence to tell us which key that is and move on
0108     QString text = keyEvent.value(QStringLiteral("text")).toString();
0109     if (!text.isEmpty() && !text[0].isLetterOrNumber() && text != QLatin1String(" ")) {
0110         text = QKeySequence(key).toString().toLower();
0111     }
0112 
0113     sendKeyPress(text, k, modifiers & Qt::ShiftModifier, modifiers & Qt::ControlModifier, modifiers & Qt::AltModifier, sendAck);
0114 }
0115 
0116 int RemoteKeyboardPlugin::translateQtKey(int qtKey) const
0117 {
0118     return specialKeysMap.value(qtKey, 0);
0119 }
0120 
0121 QString RemoteKeyboardPlugin::dbusPath() const
0122 {
0123     return QLatin1String("/modules/kdeconnect/devices/%1/remotekeyboard").arg(device()->id());
0124 }
0125 
0126 #include "moc_remotekeyboardplugin.cpp"
0127 #include "remotekeyboardplugin.moc"