/ CoreGraphics / CGEvent.m
CGEvent.m
1 /* 2 This file is part of Darling. 3 4 Copyright (C) 2020 Lubos Dolezel 5 6 Darling is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 Darling is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <CoreGraphics/CGEvent.h> 21 #include <CoreGraphics/CGEventSource.h> 22 #include <stdarg.h> 23 #import <Foundation/NSKeyedArchiver.h> 24 #import <CoreGraphics/CoreGraphicsPrivate.h> 25 #import <CoreGraphics/CGSConnection.h> 26 #import <CoreGraphics/CGSScreen.h> 27 #import "CGEventObjC.h" 28 29 CFTypeID CGEventGetTypeID(void) 30 { 31 return (CFTypeID) [CGEvent self]; 32 } 33 34 CGEventRef CGEventCreate(CGEventSourceRef source) 35 { 36 return (CGEventRef) [[CGEvent alloc] initWithSource: (CGEventSource*) source]; 37 } 38 39 CGEventRef CGEventCreateCopy(CGEventRef event) 40 { 41 return (CGEventRef) [(CGEvent*)event copy]; 42 } 43 44 CFDataRef CGEventCreateData(CFAllocatorRef allocator, CGEventRef event) 45 { 46 CGEvent* e = (CGEvent*) event; 47 NSData* data = [NSKeyedArchiver archivedDataWithRootObject: e]; 48 49 return (CFDataRef) [data retain]; 50 } 51 52 CGEventRef CGEventCreateFromData(CFAllocatorRef allocator, CFDataRef data) 53 { 54 NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: (NSData*) data]; 55 56 CGEvent* e = [unarchiver decodeObject]; 57 58 [unarchiver finishDecoding]; 59 [unarchiver release]; 60 61 return (CGEventRef) e; 62 } 63 64 CGEventType CGEventGetType(CGEventRef event) 65 { 66 CGEvent* e = (CGEvent*) event; 67 return e.type; 68 } 69 70 void CGEventSetSource(CGEventRef event, CGEventSourceRef source) 71 { 72 CGEvent* e = (CGEvent*) event; 73 e.source = (CGEventSource*) source; 74 } 75 76 CGEventSourceRef CGEventCreateSourceFromEvent(CGEventRef event) 77 { 78 CGEvent* e = (CGEvent*) event; 79 return (CGEventSourceRef) [(CGEventSource*) e.source retain]; 80 } 81 82 void CGEventSetType(CGEventRef event, CGEventType type) 83 { 84 CGEvent* e = (CGEvent*) event; 85 e.type = type; 86 } 87 88 CGEventTimestamp CGEventGetTimestamp(CGEventRef event) 89 { 90 CGEvent* e = (CGEvent*) event; 91 return e.timestamp; 92 } 93 94 void CGEventSetTimestamp(CGEventRef event, CGEventTimestamp timestamp) 95 { 96 CGEvent* e = (CGEvent*) event; 97 e.timestamp = timestamp; 98 } 99 100 int64_t CGEventGetIntegerValueField(CGEventRef event, CGEventField field) 101 { 102 CGEvent* e = (CGEvent*) event; 103 NSNumber* value = e.fields[[NSNumber numberWithInt: field]]; 104 105 if (!value) 106 return 0; 107 return value.longLongValue; 108 } 109 110 void CGEventSetIntegerValueField(CGEventRef event, CGEventField field, int64_t value) 111 { 112 CGEvent* e = (CGEvent*) event; 113 e.fields[[NSNumber numberWithInt: field]] = [NSNumber numberWithLongLong: value]; 114 } 115 116 double CGEventGetDoubleValueField(CGEventRef event, CGEventField field) 117 { 118 CGEvent* e = (CGEvent*) event; 119 NSNumber* value = e.fields[[NSNumber numberWithInt: field]]; 120 121 if (!value) 122 return 0; 123 124 if (field == kCGScrollWheelEventFixedPtDeltaAxis1 || field == kCGScrollWheelEventFixedPtDeltaAxis2 125 || field == kCGScrollWheelEventFixedPtDeltaAxis3) 126 { 127 int64_t fixedPt = value.longLongValue; 128 return ((double)fixedPt) / 0x00010000; 129 } 130 131 return value.doubleValue; 132 } 133 134 void CGEventSetDoubleValueField(CGEventRef event, CGEventField field, double value) 135 { 136 CGEvent* e = (CGEvent*) event; 137 138 if (field == kCGScrollWheelEventFixedPtDeltaAxis1 || field == kCGScrollWheelEventFixedPtDeltaAxis2 139 || field == kCGScrollWheelEventFixedPtDeltaAxis3) 140 { 141 int64_t fixedPt = (int64_t) (value * 0x00010000); 142 e.fields[[NSNumber numberWithInt: field]] = [NSNumber numberWithLongLong: fixedPt]; 143 } 144 else 145 { 146 e.fields[[NSNumber numberWithInt: field]] = [NSNumber numberWithDouble: value]; 147 } 148 } 149 150 CGEventRef CGEventCreateKeyboardEvent(CGEventSourceRef source, CGKeyCode virtualKey, bool keyDown) 151 { 152 CGEventType type = keyDown ? kCGEventKeyDown : kCGEventKeyUp; 153 CGEvent* event = [[CGEvent alloc] initWithSource: (CGEventSource*) source type: type]; 154 event.virtualKey = virtualKey; 155 156 return (CGEventRef) event; 157 } 158 159 CGEventRef CGEventCreateMouseEvent(CGEventSourceRef source, CGEventType mouseType, CGPoint mouseCursorPosition, CGMouseButton mouseButton) 160 { 161 CGEvent* event = [[CGEvent alloc] initWithSource: (CGEventSource*) source type: mouseType]; 162 event.location = mouseCursorPosition; 163 event.mouseButton = mouseButton; 164 return (CGEventRef) event; 165 } 166 167 CGEventRef CGEventCreateScrollWheelEvent(CGEventSourceRef source, CGScrollEventUnit units, uint32_t wheelCount, int32_t wheel1, ...) 168 { 169 if (!source) 170 source = (CGEventSourceRef) [CGEventSource hidEventSource]; 171 172 CGEvent* event = [[CGEvent alloc] initWithSource: (CGEventSource*) source type: kCGEventScrollWheel]; 173 174 double pixelsPerLine = CGEventSourceGetPixelsPerLine(source); 175 176 if (units == kCGScrollEventUnitPixel) 177 { 178 event.fields[@(kCGScrollWheelEventDeltaAxis1)] = [NSNumber numberWithInt: (int)(wheel1 / pixelsPerLine)]; 179 event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis1)] = [NSNumber numberWithDouble: wheel1 / pixelsPerLine]; 180 event.fields[@(kCGScrollWheelEventPointDeltaAxis1)] = [NSNumber numberWithInt: wheel1]; 181 } 182 else 183 { 184 event.fields[@(kCGScrollWheelEventDeltaAxis1)] = [NSNumber numberWithInt: wheel1]; 185 event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis1)] = [NSNumber numberWithDouble: wheel1]; 186 event.fields[@(kCGScrollWheelEventPointDeltaAxis1)] = [NSNumber numberWithInt: (int)(wheel1 * pixelsPerLine)]; 187 } 188 189 if (wheelCount > 1) 190 { 191 va_list vl; 192 va_start(vl, wheel1); 193 194 int32_t wheelN = va_arg(vl, int32_t); 195 if (units == kCGScrollEventUnitPixel) 196 { 197 event.fields[@(kCGScrollWheelEventDeltaAxis2)] = [NSNumber numberWithInt: (int)(wheelN / pixelsPerLine)]; 198 event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis2)] = [NSNumber numberWithDouble: wheelN / pixelsPerLine]; 199 event.fields[@(kCGScrollWheelEventPointDeltaAxis2)] = [NSNumber numberWithInt: wheelN]; 200 } 201 else 202 { 203 event.fields[@(kCGScrollWheelEventDeltaAxis2)] = [NSNumber numberWithInt: wheelN]; 204 event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis2)] = [NSNumber numberWithDouble: wheelN]; 205 event.fields[@(kCGScrollWheelEventPointDeltaAxis2)] = [NSNumber numberWithInt: (int)(wheelN * pixelsPerLine)]; 206 } 207 208 if (wheelCount > 2) 209 { 210 wheelN = va_arg(vl, int32_t); 211 if (units == kCGScrollEventUnitPixel) 212 { 213 event.fields[@(kCGScrollWheelEventDeltaAxis3)] = [NSNumber numberWithInt: (int)(wheelN / pixelsPerLine)]; 214 event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis3)] = [NSNumber numberWithDouble: wheelN / pixelsPerLine]; 215 event.fields[@(kCGScrollWheelEventPointDeltaAxis3)] = [NSNumber numberWithInt: wheelN]; 216 } 217 else 218 { 219 event.fields[@(kCGScrollWheelEventDeltaAxis3)] = [NSNumber numberWithInt: wheelN]; 220 event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis3)] = [NSNumber numberWithDouble: wheelN]; 221 event.fields[@(kCGScrollWheelEventPointDeltaAxis3)] = [NSNumber numberWithInt: (int)(wheelN * pixelsPerLine)]; 222 } 223 } 224 225 va_end(vl); 226 } 227 return (CGEventRef) event; 228 } 229 230 CGPoint CGEventGetLocation(CGEventRef event) 231 { 232 CGEvent* e = (CGEvent*) event; 233 return e.location; 234 } 235 236 // Returns location relative to the LOWER left corner 237 CGPoint CGEventGetUnflippedLocation(CGEventRef event) 238 { 239 CGEvent* e = (CGEvent*) event; 240 CGPoint pt = CGEventGetLocation(event); 241 242 CGSConnection* conn = nil; 243 244 if (e.eventRecord) 245 conn = _CGSConnectionFromEventRecord(e.eventRecord); 246 247 if (!conn) 248 conn = _CGSConnectionForID(CGSDefaultConnection); 249 250 // Implementaton should cache this for fast access 251 NSArray<CGSScreen*>* screens = [conn createScreens]; 252 253 if (!screens) 254 return CGPointMake(-1, -1); 255 256 // And currentModeHeight is also cached to speed this up 257 pt.y = [screens[0] currentModeHeight] - pt.y; 258 [screens release]; 259 260 return pt; 261 } 262 263 void CGEventSetLocation(CGEventRef event, CGPoint location) 264 { 265 CGEvent* e = (CGEvent*) event; 266 e.location = location; 267 } 268 269 void CGEventKeyboardGetUnicodeString(CGEventRef event, UniCharCount maxStringLength, UniCharCount *actualStringLength, UniChar *unicodeString) 270 { 271 CGEvent* e = (CGEvent*) event; 272 UniChar* savedString = e.unicodeString; 273 274 UniCharCount length = 0; 275 while (length < 5 && savedString[length]) 276 length++; 277 278 if (maxStringLength == 0) 279 { 280 *actualStringLength = length; 281 } 282 283 *actualStringLength = length; 284 if (maxStringLength < length) 285 *actualStringLength = maxStringLength; 286 287 memcpy(unicodeString, savedString, *actualStringLength * sizeof(UniChar)); 288 } 289 290 void CGEventKeyboardSetUnicodeString(CGEventRef event, UniCharCount stringLength, const UniChar *unicodeString) 291 { 292 CGEvent* e = (CGEvent*) event; 293 294 // This is the maximum CGEvent can save 295 if (stringLength > 5) 296 stringLength = 5; 297 298 memcpy(e.unicodeString, unicodeString, stringLength * sizeof(UniChar)); 299 } 300 301 CGEventRef CGEventCreateWithEventRecord(const CGSEventRecordPtr event, uint32_t eventRecordSize) 302 { 303 CGEvent* e = [[CGEvent alloc] initWithEventRecord: event length: eventRecordSize]; 304 return (CGEventRef) e; 305 } 306 307 CGError CGEventGetEventRecord(CGEventRef event, CGSEventRecordPtr eventRecord, uint32_t eventRecordSize) 308 { 309 CGEvent* e = (CGEvent*) event; 310 311 if (eventRecordSize < e.eventRecordLength) 312 return kCGErrorRangeCheck; 313 314 memcpy(eventRecord, e.eventRecord, e.eventRecordLength); 315 return kCGErrorSuccess; 316 } 317 318 CGError CGEventSetEventRecord(CGEventRef event, CGSEventRecordPtr eventRecord, uint32_t eventRecordSize) 319 { 320 CGEvent* e = (CGEvent*) event; 321 // TODO: should this call reset all other values in the CGEvent? 322 [e setEventRecord: eventRecord length: eventRecordSize]; 323 return kCGErrorSuccess; 324 } 325 326 uint32_t CGEventGetEventRecordSize(CGEventRef event) 327 { 328 CGEvent* e = (CGEvent*) event; 329 return e.eventRecordLength; 330 }