Warning, /network/kdeconnect-kde/plugins/mousepad/macosremoteinput.mm is written in an unsupported language. File is not indexed.

0001 /**
0002  * SPDX-FileCopyrightText: 2019 Weixuan XIAO <veyx.shaw@gmail.com>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "macosremoteinput.h"
0008 
0009 #include <QCursor>
0010 #include <QDebug>
0011 
0012 #include <CoreGraphics/CGEvent.h>
0013 #include <Carbon/Carbon.h>
0014 #include <ApplicationServices/ApplicationServices.h>
0015 
0016 int SpecialKeysMap[] = {
0017     0,                  // Invalid
0018     kVK_Delete,         // 1
0019     kVK_Tab,            // 2
0020     kVK_Return,         // 3
0021     kVK_LeftArrow,      // 4
0022     kVK_UpArrow,        // 5
0023     kVK_RightArrow,     // 6
0024     kVK_DownArrow,      // 7
0025     kVK_PageUp,         // 8
0026     kVK_PageDown,       // 9
0027     kVK_Home,           // 10
0028     kVK_End,            // 11
0029     kVK_Return,         // 12
0030     kVK_ForwardDelete,  // 13
0031     kVK_Escape,         // 14
0032     0,                  // 15
0033     0,                  // 16
0034     0,                  // 17
0035     0,                  // 18
0036     0,                  // 19
0037     0,                  // 20
0038     kVK_F1,             // 21
0039     kVK_F2,             // 22
0040     kVK_F3,             // 23
0041     kVK_F4,             // 24
0042     kVK_F5,             // 25
0043     kVK_F6,             // 26
0044     kVK_F7,             // 27
0045     kVK_F8,             // 28
0046     kVK_F9,             // 29
0047     kVK_F10,            // 30
0048     kVK_F11,            // 31
0049     kVK_F12,            // 32
0050 };
0051 
0052 template <typename T, size_t N>
0053 size_t arraySize(T(&arr)[N]) { (void)arr; return N; }
0054 
0055 MacOSRemoteInput::MacOSRemoteInput(QObject* parent)
0056     : AbstractRemoteInput(parent)
0057 {
0058     // Ask user to enable accessibility API
0059     NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES};
0060     if (!AXIsProcessTrustedWithOptions((CFDictionaryRef)options)) {
0061         qWarning() << "kdeconnectd is not set as a trusted accessibility, mousepad and keyboard will not work";
0062     }
0063 }
0064 
0065 bool MacOSRemoteInput::handlePacket(const NetworkPacket& np)
0066 {
0067     // Return if not trusted
0068     if (!AXIsProcessTrusted()) {
0069         return false;
0070     }
0071 
0072     float dx = np.get<float>(QStringLiteral("dx"), 0);
0073     float dy = np.get<float>(QStringLiteral("dy"), 0);
0074 
0075     bool isSingleClick = np.get<bool>(QStringLiteral("singleclick"), false);
0076     bool isDoubleClick = np.get<bool>(QStringLiteral("doubleclick"), false);
0077     bool isMiddleClick = np.get<bool>(QStringLiteral("middleclick"), false);
0078     bool isRightClick = np.get<bool>(QStringLiteral("rightclick"), false);
0079     bool isSingleHold = np.get<bool>(QStringLiteral("singlehold"), false);
0080     bool isSingleRelease = np.get<bool>(QStringLiteral("singlerelease"), false);
0081     bool isScroll = np.get<bool>(QStringLiteral("scroll"), false);
0082     QString key = np.get<QString>(QStringLiteral("key"), QLatin1String(""));
0083     int specialKey = np.get<int>(QStringLiteral("specialKey"), 0);
0084 
0085     if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isSingleHold || isSingleRelease || isScroll || !key.isEmpty() || specialKey) {
0086         QPoint point = QCursor::pos();
0087 
0088         if (isSingleClick) {
0089             CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
0090             CGEventPost(kCGHIDEventTap, event);
0091             CGEventSetType(event, kCGEventLeftMouseUp);
0092             CGEventPost(kCGHIDEventTap, event);
0093             CFRelease(event);
0094         } else if (isDoubleClick) {
0095             CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
0096             CGEventPost(kCGHIDEventTap, event);
0097             CGEventSetType(event, kCGEventLeftMouseUp);
0098             CGEventPost(kCGHIDEventTap, event);
0099 
0100             /* Key to access an integer field that contains the mouse button click
0101             state. A click state of 1 represents a single click. A click state of 2
0102             represents a double-click. A click state of 3 represents a
0103             triple-click. */
0104             CGEventSetIntegerValueField(event, kCGMouseEventClickState, 2);
0105 
0106             CGEventSetType(event, kCGEventLeftMouseDown);
0107             CGEventPost(kCGHIDEventTap, event);
0108             CGEventSetType(event, kCGEventLeftMouseUp);
0109             CGEventPost(kCGHIDEventTap, event);
0110             CFRelease(event);
0111                 } else if (isMiddleClick) {
0112             CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventOtherMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
0113             CGEventPost(kCGHIDEventTap, event);
0114             CGEventSetType(event, kCGEventOtherMouseUp);
0115             CGEventPost(kCGHIDEventTap, event);
0116             CFRelease(event);
0117                 } else if (isRightClick) {
0118             CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventRightMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
0119             CGEventPost(kCGHIDEventTap, event);
0120             CGEventSetType(event, kCGEventRightMouseUp);
0121             CGEventPost(kCGHIDEventTap, event);
0122             CFRelease(event);
0123                 } else if (isSingleHold) {
0124             CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
0125             CGEventPost(kCGHIDEventTap, event);
0126             CFRelease(event);
0127         } else if (isSingleRelease) {
0128             CGEventRef event = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseUp, CGPointMake(point.x(), point.y()), kCGMouseButtonLeft);
0129             CGEventPost(kCGHIDEventTap, event);
0130             CFRelease(event);
0131         } else if (isScroll) {
0132             CGEventRef event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, 1, dy);
0133             CGEventPost(kCGHIDEventTap, event);
0134             CFRelease(event);
0135         } else if (!key.isEmpty() || specialKey) {
0136             // Get function keys
0137             bool ctrl = np.get<bool>(QStringLiteral("ctrl"), false);
0138             bool alt = np.get<bool>(QStringLiteral("alt"), false);
0139             bool shift = np.get<bool>(QStringLiteral("shift"), false);
0140             bool super = np.get<bool>(QStringLiteral("super"), false);
0141             
0142 
0143             if (ctrl) {
0144                 CGEventRef ctrlEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Control, true);
0145                 CGEventPost(kCGHIDEventTap, ctrlEvent);
0146                 CFRelease(ctrlEvent);
0147             }
0148             if (alt) {
0149                 CGEventRef optionEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Option, true);
0150                 CGEventPost(kCGHIDEventTap, optionEvent);
0151                 CFRelease(optionEvent);
0152             }
0153             if (shift) {
0154                 CGEventRef shiftEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Shift, true);
0155                 CGEventPost(kCGHIDEventTap, shiftEvent);
0156                 CFRelease(shiftEvent);
0157             }
0158             if (super) {
0159                 CGEventRef commandEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Command, true);
0160                 CGEventPost(kCGHIDEventTap, commandEvent);
0161                 CFRelease(commandEvent);
0162             }
0163 
0164             // Keys
0165             if (specialKey)
0166             {
0167                 if (specialKey >= (int)arraySize(SpecialKeysMap)) {
0168                     qWarning() << "Unsupported special key identifier";
0169                     return false;
0170                 }
0171 
0172                 CGEventRef specialKeyDownEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)SpecialKeysMap[specialKey], true),
0173                            specialKeyUpEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)SpecialKeysMap[specialKey], false);
0174 
0175                 CGEventPost(kCGHIDEventTap, specialKeyDownEvent);
0176                 CGEventPost(kCGHIDEventTap, specialKeyUpEvent);
0177 
0178                 CFRelease(specialKeyDownEvent);
0179                 CFRelease(specialKeyUpEvent);
0180             } else {
0181                 for (int i = 0; i < key.length(); i++) {
0182                     const UniChar unicharData = (const UniChar)key.at(i).unicode();
0183 
0184                     CGEventRef event = CGEventCreateKeyboardEvent(NULL, 0, true);
0185 
0186                     CGEventKeyboardSetUnicodeString(event, 1, &unicharData);
0187                     CGEventPost(kCGSessionEventTap, event);
0188 
0189                     CFRelease(event);
0190                 }
0191 
0192             }
0193 
0194             if (ctrl) {
0195                 CGEventRef ctrlEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Control, false);
0196                 CGEventPost(kCGHIDEventTap, ctrlEvent);
0197                 CFRelease(ctrlEvent);
0198             }
0199             if (alt) {
0200                 CGEventRef optionEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Option, false);
0201                 CGEventPost(kCGHIDEventTap, optionEvent);
0202                 CFRelease(optionEvent);
0203             }
0204             if (shift) {
0205                 CGEventRef shiftEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Shift, false);
0206                 CGEventPost(kCGHIDEventTap, shiftEvent);
0207                 CFRelease(shiftEvent);
0208             }
0209             if (super) {
0210                 CGEventRef commandEvent = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)kVK_Command, false);
0211                 CGEventPost(kCGHIDEventTap, commandEvent);
0212                 CFRelease(commandEvent);
0213             }
0214 
0215         }
0216     } else { //Is a mouse move event
0217         QPoint point = QCursor::pos();
0218         QCursor::setPos(point.x() + (int)dx, point.y() + (int)dy);
0219     }
0220     return true;
0221 }
0222 
0223 bool MacOSRemoteInput::hasKeyboardSupport() {
0224     return true;
0225 }
0226 
0227 #include "moc_macosremoteinput.cpp"