diff --git a/plugins/mousepad/abstractremoteinput.h b/plugins/mousepad/abstractremoteinput.h index 880cdf0f..f6360310 100644 --- a/plugins/mousepad/abstractremoteinput.h +++ b/plugins/mousepad/abstractremoteinput.h @@ -1,38 +1,39 @@ /** * Copyright 2018 Albert Vaca Cintora * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ABSTRACTREMOTEINPUT_H #define ABSTRACTREMOTEINPUT_H #include #include class AbstractRemoteInput : public QObject { Q_OBJECT public: explicit AbstractRemoteInput(QObject* parent = nullptr); virtual bool handlePacket(const NetworkPacket& np) = 0; + virtual bool hasKeyboardSupport() { return false; }; }; #endif diff --git a/plugins/mousepad/kdeconnect_mousepad.json b/plugins/mousepad/kdeconnect_mousepad.json index dc7dba1c..7f781855 100644 --- a/plugins/mousepad/kdeconnect_mousepad.json +++ b/plugins/mousepad/kdeconnect_mousepad.json @@ -1,96 +1,98 @@ { "KPlugin": { "Authors": [ { "Email": "ahmedibrahimkhali@gmail.com", "Name": "Ahmed I. Khalil", "Name[ar]": "أحمد إبراهيم خليل", "Name[sr@ijekavian]": "Ахмед И. Калил", "Name[sr@ijekavianlatin]": "Ahmed I. Kalil", "Name[sr@latin]": "Ahmed I. Kalil", "Name[sr]": "Ахмед И. Калил", "Name[x-test]": "xxAhmed I. Khalilxx" } ], "Description": "Use your phone as a touchpad and keyboard", "Description[ar]": "استخدم الهاتف كفأرة ولوحة مفاتيح", "Description[ca@valencia]": "Empra el telèfon com un ratolí tàctil i teclat", "Description[ca]": "Empra el telèfon com un ratolí tàctil i teclat", "Description[cs]": "Používejte svůj telefon jako touchpad a klávesnici", "Description[da]": "Brug din telefon som touchpad og tastatur", "Description[de]": "Verwendet Ihr Handy als Touchpad und Tastatur", "Description[el]": "Χρήση του τηλεφώνου σας ως οθόνη αφής και πληκτρολογίου", "Description[es]": "Usar teléfono como panel táctil y teclado", "Description[et]": "Telefoni kasutamine puutepadja ja klaviatuurina", "Description[eu]": "Erabili zure telefonoa touchpad eta teklatu gisa", "Description[fi]": "Käytä puhelintasi kosketuslevynä ja näppäimistönä", "Description[fr]": "Utilisez votre téléphone comme un pavé tactile et un clavier", "Description[gl]": "Usar o teléfono móbil como área táctil e teclado.", "Description[hu]": "A telefon használata érintőtáblaként és billentyűzetként", "Description[it]": "Usa il telefono come touchpad e tastiera", "Description[ko]": "휴대폰을 터치패드와 키보드로 사용", "Description[nl]": "Uw telefoon gebruiken als een touchpad en toetsenbord", "Description[nn]": "Bruk telefonen som styreplate og tastatur", "Description[pl]": "Używaj swojego telefonu jako gładzika i klawiatury", "Description[pt]": "Use o seu telefone como um rato e teclado por toque", "Description[pt_BR]": "Use seu telefone como um touchpad e teclado", "Description[ru]": "Использование телефона в качестве сенсорной панели и клавиатуры", "Description[sk]": "Použite váš telefón ako touchpad a klávesnicu", "Description[sr@ijekavian]": "Користите телефон као додирник и тастатуру", "Description[sr@ijekavianlatin]": "Koristite telefon kao dodirnik i tastaturu", "Description[sr@latin]": "Koristite telefon kao dodirnik i tastaturu", "Description[sr]": "Користите телефон као додирник и тастатуру", "Description[sv]": "Använd telefonen som mus och tangentbord", "Description[tr]": "Telefonunuzu dokunmatik yüzey ve klayve olarak kullanın", "Description[uk]": "Скористайтеся телефоном як замінником сенсорної панелі і клавіатури", "Description[x-test]": "xxUse your phone as a touchpad and keyboardxx", "Description[zh_CN]": "用您的手机作为触摸板和键盘", "Description[zh_TW]": "讓您的智慧型手機當作觸碰板與鍵盤", "EnabledByDefault": true, "Icon": "edit-select", "Id": "kdeconnect_mousepad", "License": "GPL", "Name": "Virtual input", "Name[ar]": "دخل وهميّ", "Name[ca@valencia]": "Entrada virtual", "Name[ca]": "Entrada virtual", "Name[cs]": "Virtuální vstup", "Name[da]": "Virtuelt input", "Name[de]": "Virtuelle Eingabe", "Name[el]": "Εικονικά στοιχεία εισόδου", "Name[es]": "Entrada virtual", "Name[et]": "Virtuaalsisestus", "Name[eu]": "Sarrera birtuala", "Name[fi]": "Virtuaalinen syöttö", "Name[fr]": "Entrée virtuelle", "Name[gl]": "Entrada virtual", "Name[hu]": "Virtuális bevitel", "Name[it]": "Inserimento virtuale", "Name[ko]": "가상 입력", "Name[nl]": "Virtuele invoer", "Name[nn]": "Virtuelt tastatur", "Name[pl]": "Wirtualna obsługa", "Name[pt]": "Entrada virtual", "Name[pt_BR]": "Entrada virtual", "Name[ru]": "Виртуальный ввод", "Name[sk]": "Virtuálny vstup", "Name[sr@ijekavian]": "Виртуелни унос", "Name[sr@ijekavianlatin]": "Virtuelni unos", "Name[sr@latin]": "Virtuelni unos", "Name[sr]": "Виртуелни унос", "Name[sv]": "Virtuell inmatning", "Name[tr]": "Sanal içe aktarma", "Name[uk]": "Віртуальне введення даних", "Name[x-test]": "xxVirtual inputxx", "Name[zh_CN]": "虚拟输入", "Name[zh_TW]": "虛擬輸入", "ServiceTypes": [ "KdeConnect/Plugin" ], "Version": "0.1" }, - "X-KdeConnect-OutgoingPacketType": [], + "X-KdeConnect-OutgoingPacketType": [ + "kdeconnect.mousepad.keyboardstate" + ], "X-KdeConnect-SupportedPacketType": [ "kdeconnect.mousepad.request" ] } diff --git a/plugins/mousepad/mousepadplugin.cpp b/plugins/mousepad/mousepadplugin.cpp index aff90487..76eb01b8 100644 --- a/plugins/mousepad/mousepadplugin.cpp +++ b/plugins/mousepad/mousepadplugin.cpp @@ -1,82 +1,89 @@ /** * Copyright 2018 Albert Vaca Cintora * Copyright 2015 Martin Gräßlin * Copyright 2014 Ahmed I. Khalil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mousepadplugin.h" #include #include #include #if HAVE_WINDOWS #include "windowsremoteinput.h" #else #if HAVE_X11 #include "x11remoteinput.h" #endif #if HAVE_WAYLAND #include "waylandremoteinput.h" #endif #endif K_PLUGIN_FACTORY_WITH_JSON( KdeConnectPluginFactory, "kdeconnect_mousepad.json", registerPlugin< MousepadPlugin >(); ) MousepadPlugin::MousepadPlugin(QObject* parent, const QVariantList& args) : KdeConnectPlugin(parent, args) , m_impl(nullptr) { #if HAVE_WINDOWS m_impl = new WindowsRemoteInput(this); #else #if HAVE_X11 if (QGuiApplication::platformName() == QLatin1String("xcb")) { m_impl = new X11RemoteInput(this); } #endif #if HAVE_WAYLAND if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { m_impl = new WaylandRemoteInput(this); } #endif #endif if (!m_impl) { qDebug() << "KDE Connect was built without" << QGuiApplication::platformName() << "support"; } } MousepadPlugin::~MousepadPlugin() { delete m_impl; } bool MousepadPlugin::receivePacket(const NetworkPacket& np) { if (m_impl) { return m_impl->handlePacket(np); } else { return false; } } + +void MousepadPlugin::connected() { + NetworkPacket np(PACKET_TYPE_MOUSEPAD_KEYBOARDSTATE); + np.set(QStringLiteral("state"), m_impl->hasKeyboardSupport()); + sendPacket(np); +} + #include "mousepadplugin.moc" diff --git a/plugins/mousepad/mousepadplugin.h b/plugins/mousepad/mousepadplugin.h index fe41fac9..f230cc57 100644 --- a/plugins/mousepad/mousepadplugin.h +++ b/plugins/mousepad/mousepadplugin.h @@ -1,48 +1,50 @@ /** * Copyright 2018 Albert Vaca Cintora * Copyright 2015 Martin Gräßlin * Copyright 2014 Ahmed I. Khalil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEPADPLUGIN_H #define MOUSEPADPLUGIN_H #include #include #include "abstractremoteinput.h" +#define PACKET_TYPE_MOUSEPAD_KEYBOARDSTATE QLatin1String("kdeconnect.mousepad.keyboardstate") + class MousepadPlugin : public KdeConnectPlugin { Q_OBJECT public: explicit MousepadPlugin(QObject* parent, const QVariantList& args); ~MousepadPlugin() override; bool receivePacket(const NetworkPacket& np) override; - void connected() override { } + void connected() override; private: AbstractRemoteInput* m_impl; }; #endif diff --git a/plugins/mousepad/x11remoteinput.cpp b/plugins/mousepad/x11remoteinput.cpp index 8332b10f..4f4bc971 100644 --- a/plugins/mousepad/x11remoteinput.cpp +++ b/plugins/mousepad/x11remoteinput.cpp @@ -1,215 +1,220 @@ /** * Copyright 2018 Albert Vaca Cintora * Copyright 2014 Ahmed I. Khalil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "x11remoteinput.h" #include #include #include #include #include #include enum MouseButtons { LeftMouseButton = 1, MiddleMouseButton = 2, RightMouseButton = 3, MouseWheelUp = 4, MouseWheelDown = 5 }; //Translation table to keep in sync within all the implementations int SpecialKeysMap[] = { 0, // Invalid XK_BackSpace, // 1 XK_Tab, // 2 XK_Linefeed, // 3 XK_Left, // 4 XK_Up, // 5 XK_Right, // 6 XK_Down, // 7 XK_Page_Up, // 8 XK_Page_Down, // 9 XK_Home, // 10 XK_End, // 11 XK_Return, // 12 XK_Delete, // 13 XK_Escape, // 14 XK_Sys_Req, // 15 XK_Scroll_Lock, // 16 0, // 17 0, // 18 0, // 19 0, // 20 XK_F1, // 21 XK_F2, // 22 XK_F3, // 23 XK_F4, // 24 XK_F5, // 25 XK_F6, // 26 XK_F7, // 27 XK_F8, // 28 XK_F9, // 29 XK_F10, // 30 XK_F11, // 31 XK_F12, // 32 }; template size_t arraySize(T(&arr)[N]) { (void)arr; return N; } X11RemoteInput::X11RemoteInput(QObject* parent) : AbstractRemoteInput(parent) , m_fakekey(nullptr) { } X11RemoteInput::~X11RemoteInput() { if (m_fakekey) { free(m_fakekey); m_fakekey = nullptr; } } bool isLeftHanded(Display * display) { unsigned char map[20]; int num_buttons = XGetPointerMapping(display, map, 20); if( num_buttons == 1 ) { return false; } else if( num_buttons == 2 ) { return ( (int)map[0] == 2 && (int)map[1] == 1 ); } else { return ( (int)map[0] == 3 && (int)map[2] == 1 ); } } bool X11RemoteInput::handlePacket(const NetworkPacket& np) { float dx = np.get(QStringLiteral("dx"), 0); float dy = np.get(QStringLiteral("dy"), 0); bool isSingleClick = np.get(QStringLiteral("singleclick"), false); bool isDoubleClick = np.get(QStringLiteral("doubleclick"), false); bool isMiddleClick = np.get(QStringLiteral("middleclick"), false); bool isRightClick = np.get(QStringLiteral("rightclick"), false); bool isSingleHold = np.get(QStringLiteral("singlehold"), false); bool isSingleRelease = np.get(QStringLiteral("singlerelease"), false); bool isScroll = np.get(QStringLiteral("scroll"), false); QString key = np.get(QStringLiteral("key"), QLatin1String("")); int specialKey = np.get(QStringLiteral("specialKey"), 0); if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isSingleHold || isScroll || !key.isEmpty() || specialKey) { Display* display = QX11Info::display(); if(!display) { return false; } bool leftHanded = isLeftHanded(display); int mainMouseButton = leftHanded? RightMouseButton : LeftMouseButton; int secondaryMouseButton = leftHanded? LeftMouseButton : RightMouseButton; if (isSingleClick) { XTestFakeButtonEvent(display, mainMouseButton, True, 0); XTestFakeButtonEvent(display, mainMouseButton, False, 0); } else if (isDoubleClick) { XTestFakeButtonEvent(display, mainMouseButton, True, 0); XTestFakeButtonEvent(display, mainMouseButton, False, 0); XTestFakeButtonEvent(display, mainMouseButton, True, 0); XTestFakeButtonEvent(display, mainMouseButton, False, 0); } else if (isMiddleClick) { XTestFakeButtonEvent(display, MiddleMouseButton, True, 0); XTestFakeButtonEvent(display, MiddleMouseButton, False, 0); } else if (isRightClick) { XTestFakeButtonEvent(display, secondaryMouseButton, True, 0); XTestFakeButtonEvent(display, secondaryMouseButton, False, 0); } else if (isSingleHold){ //For drag'n drop XTestFakeButtonEvent(display, mainMouseButton, True, 0); } else if (isSingleRelease){ //For drag'n drop. NEVER USED (release is done by tapping, which actually triggers a isSingleClick). Kept here for future-proofnes. XTestFakeButtonEvent(display, mainMouseButton, False, 0); } else if (isScroll) { if (dy < 0) { XTestFakeButtonEvent(display, MouseWheelDown, True, 0); XTestFakeButtonEvent(display, MouseWheelDown, False, 0); } else if (dy > 0) { XTestFakeButtonEvent(display, MouseWheelUp, True, 0); XTestFakeButtonEvent(display, MouseWheelUp, False, 0); } } else if (!key.isEmpty() || specialKey) { bool ctrl = np.get(QStringLiteral("ctrl"), false); bool alt = np.get(QStringLiteral("alt"), false); bool shift = np.get(QStringLiteral("shift"), false); if (ctrl) XTestFakeKeyEvent (display, XKeysymToKeycode(display, XK_Control_L), True, 0); if (alt) XTestFakeKeyEvent (display, XKeysymToKeycode(display, XK_Alt_L), True, 0); if (shift) XTestFakeKeyEvent (display, XKeysymToKeycode(display, XK_Shift_L), True, 0); if (specialKey) { if (specialKey >= (int)arraySize(SpecialKeysMap)) { qWarning() << "Unsupported special key identifier"; return false; } int keycode = XKeysymToKeycode(display, SpecialKeysMap[specialKey]); XTestFakeKeyEvent (display, keycode, True, 0); XTestFakeKeyEvent (display, keycode, False, 0); } else { if (!m_fakekey) { m_fakekey = fakekey_init(display); if (!m_fakekey) { qWarning() << "Failed to initialize libfakekey"; return false; } } //We use fakekey here instead of XTest (above) because it can handle utf characters instead of keycodes. for (int i=0;i * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef X11REMOTEINPUT_H #define X11REMOTEINPUT_H #include "abstractremoteinput.h" struct FakeKey; class X11RemoteInput : public AbstractRemoteInput { Q_OBJECT public: explicit X11RemoteInput(QObject* parent); ~X11RemoteInput() override; bool handlePacket(const NetworkPacket& np) override; + bool hasKeyboardSupport() override; private: FakeKey* m_fakekey; }; #endif