/ 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  }