Just keep CMakeLists as it was
until Wayland supports macOS or Apple brings back X11
This commit is contained in:
parent
af1255ed99
commit
273c2e937a
6 changed files with 292 additions and 2 deletions
|
@ -39,7 +39,7 @@ else()
|
|||
set(QT_MIN_VERSION "5.10.0")
|
||||
set(KF5_REQUIRED_COMPONENTS I18n ConfigWidgets DBusAddons IconThemes Notifications KIO KCMUtils Service Kirigami2)
|
||||
set(KF5_OPTIONAL_COMPONENTS DocTools)
|
||||
if(UNIX)
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(KF5_OPTIONAL_COMPONENTS ${KF5_OPTIONAL_COMPONENTS} Runner)
|
||||
endif()
|
||||
set(QCA_MIN_VERSION "2.1.0")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
if(UNIX)
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(KF5 ${KF5_MIN_VERSION} QUIET OPTIONAL_COMPONENTS Wayland)
|
||||
|
||||
find_package(LibFakeKey QUIET)
|
||||
|
@ -18,6 +18,7 @@ endif()
|
|||
set(HAVE_WINDOWS ${WIN32})
|
||||
set(HAVE_X11 ${LibFakeKey_FOUND})
|
||||
set(HAVE_WAYLAND ${KF5Wayland_FOUND})
|
||||
set(HAVE_MACOS ${APPLE})
|
||||
configure_file(config-mousepad.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-mousepad.h )
|
||||
|
||||
kdeconnect_add_plugin(kdeconnect_mousepad JSON kdeconnect_mousepad.json SOURCES mousepadplugin.cpp abstractremoteinput.cpp)
|
||||
|
@ -37,3 +38,8 @@ if(HAVE_X11)
|
|||
target_sources(kdeconnect_mousepad PUBLIC x11remoteinput.cpp)
|
||||
target_link_libraries(kdeconnect_mousepad Qt5::X11Extras ${X11_LIBRARIES} ${XTEST_LIBRARIES} ${LibFakeKey_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if (HAVE_MACOS)
|
||||
target_sources(kdeconnect_mousepad PUBLIC macosremoteinput.mm)
|
||||
target_link_libraries(kdeconnect_mousepad "-framework CoreGraphics" "-framework ApplicationServices" "-framework Cocoa")
|
||||
endif()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#cmakedefine01 HAVE_WAYLAND
|
||||
#cmakedefine01 HAVE_X11
|
||||
#cmakedefine01 HAVE_WINDOWS
|
||||
#cmakedefine01 HAVE_MACOS
|
||||
|
|
38
plugins/mousepad/macosremoteinput.h
Normal file
38
plugins/mousepad/macosremoteinput.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* Copyright 2019 Weixuan XIAO <veyx.shaw@gmail.com>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MACOSREMOTEINPUT_H
|
||||
#define MACOSREMOTEINPUT_H
|
||||
|
||||
#include "abstractremoteinput.h"
|
||||
|
||||
class MacOSRemoteInput
|
||||
: public AbstractRemoteInput
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MacOSRemoteInput(QObject* parent);
|
||||
|
||||
bool handlePacket(const NetworkPacket& np) override;
|
||||
bool hasKeyboardSupport() override;
|
||||
};
|
||||
|
||||
#endif
|
241
plugins/mousepad/macosremoteinput.mm
Normal file
241
plugins/mousepad/macosremoteinput.mm
Normal file
|
@ -0,0 +1,241 @@
|
|||
/**
|
||||
* Copyright 2019 Weixuan XIAO <veyx.shaw@gmail.com>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "macosremoteinput.h"
|
||||
|
||||
#include <QCursor>
|
||||
#include <QDebug>
|
||||
|
||||
#include <CoreGraphics/CGEvent.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
int SpecialKeysMap[] = {
|
||||
0, // Invalid
|
||||
kVK_Delete, // 1
|
||||
kVK_Tab, // 2
|
||||
kVK_Return, // 3
|
||||
kVK_LeftArrow, // 4
|
||||
kVK_UpArrow, // 5
|
||||
kVK_RightArrow, // 6
|
||||
kVK_DownArrow, // 7
|
||||
kVK_PageUp, // 8
|
||||
kVK_PageDown, // 9
|
||||
kVK_Home, // 10
|
||||
kVK_End, // 11
|
||||
kVK_Return, // 12
|
||||
kVK_ForwardDelete, // 13
|
||||
kVK_Escape, // 14
|
||||
0, // 15
|
||||
0, // 16
|
||||
0, // 17
|
||||
0, // 18
|
||||
0, // 19
|
||||
0, // 20
|
||||
kVK_F1, // 21
|
||||
kVK_F2, // 22
|
||||
kVK_F3, // 23
|
||||
kVK_F4, // 24
|
||||
kVK_F5, // 25
|
||||
kVK_F6, // 26
|
||||
kVK_F7, // 27
|
||||
kVK_F8, // 28
|
||||
kVK_F9, // 29
|
||||
kVK_F10, // 30
|
||||
kVK_F11, // 31
|
||||
kVK_F12, // 32
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
size_t arraySize(T(&arr)[N]) { (void)arr; return N; }
|
||||
|
||||
MacOSRemoteInput::MacOSRemoteInput(QObject* parent)
|
||||
: AbstractRemoteInput(parent)
|
||||
{
|
||||
// Ask user to enable accessibility API
|
||||
NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES};
|
||||
if (!AXIsProcessTrustedWithOptions((CFDictionaryRef)options)) {
|
||||
qWarning() << "kdeconnectd is not set as a trusted accessibility, mousepad and keyboard will not work";
|
||||
}
|
||||
}
|
||||
|
||||
bool MacOSRemoteInput::handlePacket(const NetworkPacket& np)
|
||||
{
|
||||
// Return if not trusted
|
||||
if (!AXIsProcessTrusted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float dx = np.get<float>(QStringLiteral("dx"), 0);
|
||||
float dy = np.get<float>(QStringLiteral("dy"), 0);
|
||||
|
||||
bool isSingleClick = np.get<bool>(QStringLiteral("singleclick"), false);
|
||||
bool isDoubleClick = np.get<bool>(QStringLiteral("doubleclick"), false);
|
||||
bool isMiddleClick = np.get<bool>(QStringLiteral("middleclick"), false);
|
||||
bool isRightClick = np.get<bool>(QStringLiteral("rightclick"), false);
|
||||
bool isSingleHold = np.get<bool>(QStringLiteral("singlehold"), false);
|
||||
bool isSingleRelease = np.get<bool>(QStringLiteral("singlerelease"), false);
|
||||
bool isScroll = np.get<bool>(QStringLiteral("scroll"), false);
|
||||
QString key = np.get<QString>(QStringLiteral("key"), QLatin1String(""));
|
||||
int specialKey = np.get<int>(QStringLiteral("specialKey"), 0);
|
||||
|
||||
if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isSingleHold || isSingleRelease || isScroll || !key.isEmpty() || specialKey) {
|
||||
QPoint point = QCursor::pos();
|
||||
|
||||
if (isSingleClick) {
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CGEventSetType(event, kCGEventLeftMouseUp);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
} else if (isDoubleClick) {
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CGEventSetType(event, kCGEventLeftMouseUp);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
|
||||
/* Key to access an integer field that contains the mouse button click
|
||||
state. A click state of 1 represents a single click. A click state of 2
|
||||
represents a double-click. A click state of 3 represents a
|
||||
triple-click. */
|
||||
CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2);
|
||||
|
||||
CGEventSetType(event, kCGEventLeftMouseDown);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CGEventSetType(event, kCGEventLeftMouseUp);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
} else if (isMiddleClick) {
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventOtherMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CGEventSetType(event, kCGEventOtherMouseUp);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
} else if (isRightClick) {
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventRightMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CGEventSetType(event, kCGEventRightMouseUp);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
} else if (isSingleHold) {
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
} else if (isSingleRelease) {
|
||||
CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
} else if (isScroll) {
|
||||
CGEventRef event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, dy);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
} else if (!key.isEmpty() || specialKey) {
|
||||
// Get function keys
|
||||
bool ctrl = np.get<bool>(QStringLiteral("ctrl"), false);
|
||||
bool alt = np.get<bool>(QStringLiteral("alt"), false);
|
||||
bool shift = np.get<bool>(QStringLiteral("shift"), false);
|
||||
bool super = np.get<bool>(QStringLiteral("super"), false);
|
||||
|
||||
|
||||
if (ctrl) {
|
||||
CGEventRef ctrlEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Control, true);
|
||||
CGEventPost(kCGHIDEventTap, ctrlEvent);
|
||||
CFRelease(ctrlEvent);
|
||||
}
|
||||
if (alt) {
|
||||
CGEventRef optionEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Option, true);
|
||||
CGEventPost(kCGHIDEventTap, optionEvent);
|
||||
CFRelease(optionEvent);
|
||||
}
|
||||
if (shift) {
|
||||
CGEventRef shiftEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Shift, true);
|
||||
CGEventPost(kCGHIDEventTap, shiftEvent);
|
||||
CFRelease(shiftEvent);
|
||||
}
|
||||
if (super) {
|
||||
CGEventRef commandEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Command, true);
|
||||
CGEventPost(kCGHIDEventTap, commandEvent);
|
||||
CFRelease(commandEvent);
|
||||
}
|
||||
|
||||
// Keys
|
||||
if (specialKey)
|
||||
{
|
||||
if (specialKey >= (int)arraySize(SpecialKeysMap)) {
|
||||
qWarning() << "Unsupported special key identifier";
|
||||
return false;
|
||||
}
|
||||
|
||||
CGEventRef specialKeyDownEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)SpecialKeysMap[specialKey], true),
|
||||
specialKeyUpEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)SpecialKeysMap[specialKey], false);
|
||||
|
||||
CGEventPost(kCGHIDEventTap, specialKeyDownEvent);
|
||||
CGEventPost(kCGHIDEventTap, specialKeyUpEvent);
|
||||
|
||||
CFRelease(specialKeyDownEvent);
|
||||
CFRelease(specialKeyUpEvent);
|
||||
} else {
|
||||
for (int i=0;i<key.length();i++) {
|
||||
QByteArray utf8 = QString(key.at(i)).toUtf8();
|
||||
NSData *data = utf8.toNSData(); // Will be autoreleased
|
||||
const UniChar* const unicharData = (const UniChar*)data.bytes;
|
||||
|
||||
CGEventRef event = CGEventCreateKeyboardEvent(NULL, 0, true);
|
||||
|
||||
CGEventKeyboardSetUnicodeString(event, utf8.length(), unicharData);
|
||||
CGEventPost(kCGSessionEventTap, event);
|
||||
|
||||
CFRelease(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ctrl) {
|
||||
CGEventRef ctrlEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Control, false);
|
||||
CGEventPost(kCGHIDEventTap, ctrlEvent);
|
||||
CFRelease(ctrlEvent);
|
||||
}
|
||||
if (alt) {
|
||||
CGEventRef optionEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Option, false);
|
||||
CGEventPost(kCGHIDEventTap, optionEvent);
|
||||
CFRelease(optionEvent);
|
||||
}
|
||||
if (shift) {
|
||||
CGEventRef shiftEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Shift, false);
|
||||
CGEventPost(kCGHIDEventTap, shiftEvent);
|
||||
CFRelease(shiftEvent);
|
||||
}
|
||||
if (super) {
|
||||
CGEventRef commandEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Command, false);
|
||||
CGEventPost(kCGHIDEventTap, commandEvent);
|
||||
CFRelease(commandEvent);
|
||||
}
|
||||
|
||||
}
|
||||
} else { //Is a mouse move event
|
||||
QPoint point = QCursor::pos();
|
||||
QCursor::setPos(point.x() + (int)dx, point.y() + (int)dy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacOSRemoteInput::hasKeyboardSupport() {
|
||||
return true;
|
||||
}
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#if HAVE_WINDOWS
|
||||
#include "windowsremoteinput.h"
|
||||
#elif HAVE_MACOS
|
||||
#include "macosremoteinput.h"
|
||||
#else
|
||||
#if HAVE_X11
|
||||
#include "x11remoteinput.h"
|
||||
|
@ -45,6 +47,8 @@ MousepadPlugin::MousepadPlugin(QObject* parent, const QVariantList& args)
|
|||
{
|
||||
#if HAVE_WINDOWS
|
||||
m_impl = new WindowsRemoteInput(this);
|
||||
#elif HAVE_MACOS
|
||||
m_impl = new MacOSRemoteInput(this);
|
||||
#else
|
||||
#if HAVE_X11
|
||||
if (QGuiApplication::platformName() == QLatin1String("xcb")) {
|
||||
|
|
Loading…
Reference in a new issue