CGS work progress

This commit is contained in:
Lubos Dolezel 2020-05-15 10:47:23 +02:00
parent 9c53557e4c
commit b26bedb31c
28 changed files with 4012 additions and 682 deletions

View File

@ -17,202 +17,314 @@
along with Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import "CGEventObjC.h"
#include <CoreGraphics/CGEvent.h>
#import <Foundation/NSKeyedArchiver.h>
#include <CoreGraphics/CGEventSource.h>
#include <stdarg.h>
#import <Foundation/NSKeyedArchiver.h>
#import <CoreGraphics/CoreGraphicsPrivate.h>
#import <CoreGraphics/CGSConnection.h>
#import <CoreGraphics/CGSScreen.h>
#import "CGEventObjC.h"
CFTypeID CGEventGetTypeID(void) {
return (CFTypeID)[CGEvent self];
}
CGEventRef CGEventCreate(CGEventSourceRef source) {
return (CGEventRef)
[[CGEvent alloc] initWithSource: (CGEventSource *) source];
}
CGEventRef CGEventCreateCopy(CGEventRef event) {
return (CGEventRef)[(CGEvent *) event copy];
}
CFDataRef CGEventCreateData(CFAllocatorRef allocator, CGEventRef event) {
CGEvent *e = (CGEvent *) event;
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] init];
[e encodeWithCoder: archiver];
NSData *data = [[archiver encodedData] retain];
[archiver release];
return data;
}
CGEventRef CGEventCreateFromData(CFAllocatorRef allocator, CFDataRef data) {
NSKeyedUnarchiver *unarchiver =
[[NSKeyedUnarchiver alloc] initForReadingWithData: data];
CGEvent *e = [[CGEvent alloc] initWithCoder: unarchiver];
[unarchiver finishDecoding];
[unarchiver release];
return (CGEventRef) e;
}
CGEventType CGEventGetType(CGEventRef event) {
CGEvent *e = (CGEvent *) event;
return e.type;
}
void CGEventSetSource(CGEventRef event, CGEventSourceRef source) {
CGEvent *e = (CGEvent *) event;
e.source = (CGEventSource *) source;
}
CGEventSourceRef CGEventCreateSourceFromEvent(CGEventRef event) {
CGEvent *e = (CGEvent *) event;
return (CGEventSourceRef)[(CGEventSource *) e.source retain];
}
void CGEventSetType(CGEventRef event, CGEventType type) {
CGEvent *e = (CGEvent *) event;
e.type = type;
}
CGEventTimestamp CGEventGetTimestamp(CGEventRef event) {
CGEvent *e = (CGEvent *) event;
return e.timestamp;
}
void CGEventSetTimestamp(CGEventRef event, CGEventTimestamp timestamp) {
CGEvent *e = (CGEvent *) event;
e.timestamp = timestamp;
}
int64_t CGEventGetIntegerValueField(CGEventRef event, CGEventField field) {
CGEvent *e = (CGEvent *) event;
NSNumber *value = e.fields[[NSNumber numberWithInt: field]];
if (!value)
return 0;
return value.longLongValue;
}
void CGEventSetIntegerValueField(CGEventRef event, CGEventField field,
int64_t value)
CFTypeID CGEventGetTypeID(void)
{
CGEvent *e = (CGEvent *) event;
e.fields[[NSNumber numberWithInt: field]] =
[NSNumber numberWithLongLong: value];
return (CFTypeID) [CGEvent self];
}
double CGEventGetDoubleValueField(CGEventRef event, CGEventField field) {
CGEvent *e = (CGEvent *) event;
NSNumber *value = e.fields[[NSNumber numberWithInt: field]];
if (!value)
return 0;
return value.doubleValue;
}
void CGEventSetDoubleValueField(CGEventRef event, CGEventField field,
double value)
CGEventRef CGEventCreate(CGEventSourceRef source)
{
CGEvent *e = (CGEvent *) event;
e.fields[[NSNumber numberWithInt: field]] =
[NSNumber numberWithDouble: value];
return (CGEventRef) [[CGEvent alloc] initWithSource: (CGEventSource*) source];
}
CGEventRef CGEventCreateKeyboardEvent(CGEventSourceRef source,
CGKeyCode virtualKey, bool keyDown)
CGEventRef CGEventCreateCopy(CGEventRef event)
{
CGEventType type = keyDown ? kCGEventKeyDown : kCGEventKeyUp;
CGEvent *event = [[CGEvent alloc] initWithSource: (CGEventSource *) source
type: type];
event.virtualKey = virtualKey;
return (CGEventRef) event;
return (CGEventRef) [(CGEvent*)event copy];
}
CGEventRef CGEventCreateMouseEvent(CGEventSourceRef source,
CGEventType mouseType,
CGPoint mouseCursorPosition,
CGMouseButton mouseButton)
CFDataRef CGEventCreateData(CFAllocatorRef allocator, CGEventRef event)
{
CGEvent *event = [[CGEvent alloc] initWithSource: (CGEventSource *) source
type: mouseType];
event.location = mouseCursorPosition;
event.mouseButton = mouseButton;
return (CGEventRef) event;
CGEvent* e = (CGEvent*) event;
NSData* data = [NSKeyedArchiver archivedDataWithRootObject: e];
return (CFDataRef) [data retain];
}
CGEventRef CGEventCreateScrollWheelEvent(CGEventSourceRef source,
CGScrollEventUnit units,
uint32_t wheelCount, int32_t wheel1,
...)
CGEventRef CGEventCreateFromData(CFAllocatorRef allocator, CFDataRef data)
{
CGEvent *event = [[CGEvent alloc] initWithSource: (CGEventSource *) source
type: kCGEventScrollWheel];
event.scrollEventUnit = units;
event.wheelCount = wheelCount;
event.wheels[0] = wheel1;
NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: (NSData*) data];
CGEvent* e = [unarchiver decodeObject];
if (wheelCount > 1) {
va_list vl;
va_start(vl, wheel1);
event.wheels[1] = va_arg(vl, int32_t);
if (wheelCount > 2)
event.wheels[2] = va_arg(vl, int32_t);
va_end(vl);
}
return (CGEventRef) event;
[unarchiver finishDecoding];
[unarchiver release];
return (CGEventRef) e;
}
CGPoint CGEventGetLocation(CGEventRef event) {
CGEvent *e = (CGEvent *) event;
return e.location;
}
void CGEventSetLocation(CGEventRef event, CGPoint location) {
CGEvent *e = (CGEvent *) event;
e.location = location;
}
void CGEventKeyboardGetUnicodeString(CGEventRef event,
UniCharCount maxStringLength,
UniCharCount *actualStringLength,
UniChar *unicodeString)
CGEventType CGEventGetType(CGEventRef event)
{
CGEvent *e = (CGEvent *) event;
UniChar *savedString = e.unicodeString;
UniCharCount length = 0;
while (length < 5 && savedString[length])
length++;
if (maxStringLength == 0) {
*actualStringLength = length;
}
*actualStringLength = length;
if (maxStringLength < length)
*actualStringLength = maxStringLength;
memcpy(unicodeString, savedString, *actualStringLength * sizeof(UniChar));
CGEvent* e = (CGEvent*) event;
return e.type;
}
void CGEventKeyboardSetUnicodeString(CGEventRef event,
UniCharCount stringLength,
const UniChar *unicodeString)
void CGEventSetSource(CGEventRef event, CGEventSourceRef source)
{
CGEvent *e = (CGEvent *) event;
// This is the maximum CGEvent can save
if (stringLength > 5)
stringLength = 5;
memcpy(e.unicodeString, unicodeString, stringLength * sizeof(UniChar));
CGEvent* e = (CGEvent*) event;
e.source = (CGEventSource*) source;
}
CGEventSourceRef CGEventCreateSourceFromEvent(CGEventRef event)
{
CGEvent* e = (CGEvent*) event;
return (CGEventSourceRef) [(CGEventSource*) e.source retain];
}
void CGEventSetType(CGEventRef event, CGEventType type)
{
CGEvent* e = (CGEvent*) event;
e.type = type;
}
CGEventTimestamp CGEventGetTimestamp(CGEventRef event)
{
CGEvent* e = (CGEvent*) event;
return e.timestamp;
}
void CGEventSetTimestamp(CGEventRef event, CGEventTimestamp timestamp)
{
CGEvent* e = (CGEvent*) event;
e.timestamp = timestamp;
}
int64_t CGEventGetIntegerValueField(CGEventRef event, CGEventField field)
{
CGEvent* e = (CGEvent*) event;
NSNumber* value = e.fields[[NSNumber numberWithInt: field]];
if (!value)
return 0;
return value.longLongValue;
}
void CGEventSetIntegerValueField(CGEventRef event, CGEventField field, int64_t value)
{
CGEvent* e = (CGEvent*) event;
e.fields[[NSNumber numberWithInt: field]] = [NSNumber numberWithLongLong: value];
}
double CGEventGetDoubleValueField(CGEventRef event, CGEventField field)
{
CGEvent* e = (CGEvent*) event;
NSNumber* value = e.fields[[NSNumber numberWithInt: field]];
if (!value)
return 0;
if (field == kCGScrollWheelEventFixedPtDeltaAxis1 || field == kCGScrollWheelEventFixedPtDeltaAxis2
|| field == kCGScrollWheelEventFixedPtDeltaAxis3)
{
int64_t fixedPt = value.longLongValue;
return ((double)fixedPt) / 0x00010000;
}
return value.doubleValue;
}
void CGEventSetDoubleValueField(CGEventRef event, CGEventField field, double value)
{
CGEvent* e = (CGEvent*) event;
if (field == kCGScrollWheelEventFixedPtDeltaAxis1 || field == kCGScrollWheelEventFixedPtDeltaAxis2
|| field == kCGScrollWheelEventFixedPtDeltaAxis3)
{
int64_t fixedPt = (int64_t) (value * 0x00010000);
e.fields[[NSNumber numberWithInt: field]] = [NSNumber numberWithLongLong: fixedPt];
}
else
{
e.fields[[NSNumber numberWithInt: field]] = [NSNumber numberWithDouble: value];
}
}
CGEventRef CGEventCreateKeyboardEvent(CGEventSourceRef source, CGKeyCode virtualKey, bool keyDown)
{
CGEventType type = keyDown ? kCGEventKeyDown : kCGEventKeyUp;
CGEvent* event = [[CGEvent alloc] initWithSource: (CGEventSource*) source type: type];
event.virtualKey = virtualKey;
return (CGEventRef) event;
}
CGEventRef CGEventCreateMouseEvent(CGEventSourceRef source, CGEventType mouseType, CGPoint mouseCursorPosition, CGMouseButton mouseButton)
{
CGEvent* event = [[CGEvent alloc] initWithSource: (CGEventSource*) source type: mouseType];
event.location = mouseCursorPosition;
event.mouseButton = mouseButton;
return (CGEventRef) event;
}
CGEventRef CGEventCreateScrollWheelEvent(CGEventSourceRef source, CGScrollEventUnit units, uint32_t wheelCount, int32_t wheel1, ...)
{
if (!source)
source = (CGEventSourceRef) [CGEventSource hidEventSource];
CGEvent* event = [[CGEvent alloc] initWithSource: (CGEventSource*) source type: kCGEventScrollWheel];
double pixelsPerLine = CGEventSourceGetPixelsPerLine(source);
if (units == kCGScrollEventUnitPixel)
{
event.fields[@(kCGScrollWheelEventDeltaAxis1)] = [NSNumber numberWithInt: (int)(wheel1 / pixelsPerLine)];
event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis1)] = [NSNumber numberWithDouble: wheel1 / pixelsPerLine];
event.fields[@(kCGScrollWheelEventPointDeltaAxis1)] = [NSNumber numberWithInt: wheel1];
}
else
{
event.fields[@(kCGScrollWheelEventDeltaAxis1)] = [NSNumber numberWithInt: wheel1];
event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis1)] = [NSNumber numberWithDouble: wheel1];
event.fields[@(kCGScrollWheelEventPointDeltaAxis1)] = [NSNumber numberWithInt: (int)(wheel1 * pixelsPerLine)];
}
if (wheelCount > 1)
{
va_list vl;
va_start(vl, wheel1);
int32_t wheelN = va_arg(vl, int32_t);
if (units == kCGScrollEventUnitPixel)
{
event.fields[@(kCGScrollWheelEventDeltaAxis2)] = [NSNumber numberWithInt: (int)(wheelN / pixelsPerLine)];
event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis2)] = [NSNumber numberWithDouble: wheelN / pixelsPerLine];
event.fields[@(kCGScrollWheelEventPointDeltaAxis2)] = [NSNumber numberWithInt: wheelN];
}
else
{
event.fields[@(kCGScrollWheelEventDeltaAxis2)] = [NSNumber numberWithInt: wheelN];
event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis2)] = [NSNumber numberWithDouble: wheelN];
event.fields[@(kCGScrollWheelEventPointDeltaAxis2)] = [NSNumber numberWithInt: (int)(wheelN * pixelsPerLine)];
}
if (wheelCount > 2)
{
wheelN = va_arg(vl, int32_t);
if (units == kCGScrollEventUnitPixel)
{
event.fields[@(kCGScrollWheelEventDeltaAxis3)] = [NSNumber numberWithInt: (int)(wheelN / pixelsPerLine)];
event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis3)] = [NSNumber numberWithDouble: wheelN / pixelsPerLine];
event.fields[@(kCGScrollWheelEventPointDeltaAxis3)] = [NSNumber numberWithInt: wheelN];
}
else
{
event.fields[@(kCGScrollWheelEventDeltaAxis3)] = [NSNumber numberWithInt: wheelN];
event.fields[@(kCGScrollWheelEventFixedPtDeltaAxis3)] = [NSNumber numberWithDouble: wheelN];
event.fields[@(kCGScrollWheelEventPointDeltaAxis3)] = [NSNumber numberWithInt: (int)(wheelN * pixelsPerLine)];
}
}
va_end(vl);
}
return (CGEventRef) event;
}
CGPoint CGEventGetLocation(CGEventRef event)
{
CGEvent* e = (CGEvent*) event;
return e.location;
}
// Returns location relative to the LOWER left corner
CGPoint CGEventGetUnflippedLocation(CGEventRef event)
{
CGEvent* e = (CGEvent*) event;
CGPoint pt = CGEventGetLocation(event);
CGSConnection* conn = nil;
if (e.eventRecord)
conn = _CGSConnectionFromEventRecord(e.eventRecord);
if (!conn)
conn = _CGSConnectionForID(CGSDefaultConnection);
// Implementaton should cache this for fast access
NSArray<CGSScreen*>* screens = [conn createScreens];
if (!screens)
return CGPointMake(-1, -1);
// And currentModeHeight is also cached to speed this up
pt.y = [screens[0] currentModeHeight] - pt.y;
[screens release];
return pt;
}
void CGEventSetLocation(CGEventRef event, CGPoint location)
{
CGEvent* e = (CGEvent*) event;
e.location = location;
}
void CGEventKeyboardGetUnicodeString(CGEventRef event, UniCharCount maxStringLength, UniCharCount *actualStringLength, UniChar *unicodeString)
{
CGEvent* e = (CGEvent*) event;
UniChar* savedString = e.unicodeString;
UniCharCount length = 0;
while (length < 5 && savedString[length])
length++;
if (maxStringLength == 0)
{
*actualStringLength = length;
}
*actualStringLength = length;
if (maxStringLength < length)
*actualStringLength = maxStringLength;
memcpy(unicodeString, savedString, *actualStringLength * sizeof(UniChar));
}
void CGEventKeyboardSetUnicodeString(CGEventRef event, UniCharCount stringLength, const UniChar *unicodeString)
{
CGEvent* e = (CGEvent*) event;
// This is the maximum CGEvent can save
if (stringLength > 5)
stringLength = 5;
memcpy(e.unicodeString, unicodeString, stringLength * sizeof(UniChar));
}
CGEventRef CGEventCreateWithEventRecord(const CGSEventRecordPtr event, uint32_t eventRecordSize)
{
CGEvent* e = [[CGEvent alloc] initWithEventRecord: event length: eventRecordSize];
return (CGEventRef) e;
}
CGError CGEventGetEventRecord(CGEventRef event, CGSEventRecordPtr eventRecord, uint32_t eventRecordSize)
{
CGEvent* e = (CGEvent*) event;
if (eventRecordSize < e.eventRecordLength)
return kCGErrorRangeCheck;
memcpy(eventRecord, e.eventRecord, e.eventRecordLength);
return kCGErrorSuccess;
}
CGError CGEventSetEventRecord(CGEventRef event, CGSEventRecordPtr eventRecord, uint32_t eventRecordSize)
{
CGEvent* e = (CGEvent*) event;
// TODO: should this call reset all other values in the CGEvent?
[e setEventRecord: eventRecord length: eventRecordSize];
return kCGErrorSuccess;
}
uint32_t CGEventGetEventRecordSize(CGEventRef event)
{
CGEvent* e = (CGEvent*) event;
return e.eventRecordLength;
}

View File

@ -19,72 +19,73 @@
#ifndef CGEVENT_OBJC_H
#define CGEVENT_OBJC_H
#include <CoreFoundation/CFBase.h>
#include <CoreGraphics/CGEvent.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#include <CoreFoundation/CFBase.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSData.h>
@class CGEventSource;
@interface CGEvent : NSObject <NSCopying, NSCoding> {
CGEventSource *_source;
CGEventType _type;
CGEventTimestamp _timestamp;
CGEventFlags _flags;
NSMutableDictionary<NSNumber *, NSNumber *> *_fields;
CGEventSource* _source;
CGEventType _type;
CGEventTimestamp _timestamp;
CGEventFlags _flags;
NSMutableDictionary<NSNumber*, NSNumber*>* _fields;
// keyboard events
CGKeyCode _virtualKey;
UniChar _unicodeString[5];
// keyboard events
CGKeyCode _virtualKey;
UniChar _unicodeString[5];
// mouse button events
CGPoint _location;
CGMouseButton _mouseButton;
// mouse button events
CGPoint _location;
CGMouseButton _mouseButton;
// mouse wheel events
CGScrollEventUnit _scrollEventUnit;
uint32_t _wheelCount;
int32_t _wheels[3];
CGSEventRecordPtr _eventRecord;
uint32_t _eventRecordLength;
}
- (instancetype) initWithSource: (CGEventSource *) source;
- (instancetype) initWithSource: (CGEventSource *) source
type: (CGEventType) type;
- (instancetype) initWithData: (NSData *) data;
-(instancetype) initWithSource:(CGEventSource*) source;
-(instancetype) initWithSource:(CGEventSource*) source
type:(CGEventType) type;
-(instancetype) initWithEventRecord:(const CGSEventRecordPtr) eventRecord
length:(uint32_t) length;
- (void) dealloc;
- (id) copy;
- (CFTypeID) _cfTypeID;
- (NSData *) createData;
-(void) dealloc;
-(id)copy;
-(CFTypeID) _cfTypeID;
-(void) setEventRecord:(CGSEventRecordPtr) record
length:(uint32_t) length;
@property(readonly) uint32_t eventRecordLength;
@property(readonly) CGSEventRecordPtr eventRecord;
@property(readwrite) CGEventType type;
@property(retain) CGEventSource *source;
@property(retain) CGEventSource* source;
@property(readwrite) CGEventTimestamp timestamp;
@property(readwrite) CGEventFlags flags;
@property(readonly) NSMutableDictionary<NSNumber *, NSNumber *> *fields;
@property(readonly) NSMutableDictionary<NSNumber*, NSNumber*>* fields;
@property(readwrite) CGKeyCode virtualKey;
@property(readwrite) CGPoint location;
@property(readwrite) CGMouseButton mouseButton;
@property(readwrite) CGScrollEventUnit scrollEventUnit;
@property(readwrite) uint32_t wheelCount;
@property(readonly) int32_t *wheels;
@property(readonly) UniChar *unicodeString;
@property(readonly) UniChar* unicodeString;
@end
//////////////////////////////////////////////////////////////////////
@interface CGEventSource : NSObject {
CGEventSourceStateID _stateId;
CGEventSourceKeyboardType _keyboardType;
int64_t _userData;
double _pixelsPerLine;
CGEventSourceStateID _stateId;
CGEventSourceKeyboardType _keyboardType;
int64_t _userData;
double _pixelsPerLine;
}
- (instancetype) initWithState: (CGEventSourceStateID) stateId;
- (CFTypeID) _cfTypeID;
-(instancetype) initWithState: (CGEventSourceStateID) stateId;
-(CFTypeID) _cfTypeID;
+(CGEventSource*) hidEventSource;
@property CGEventSourceKeyboardType keyboardType;
@property CGEventSourceStateID stateID;
@ -96,32 +97,33 @@
//////////////////////////////////////////////////////////////////////
@interface CGEventTap : NSObject {
CGEventTapLocation _location;
CGEventTapOptions _options;
CGEventMask _mask;
CGEventTapCallBack _callback;
void *_userInfo;
Boolean _enabled;
CGEventTapLocation _location;
CGEventTapOptions _options;
CGEventMask _mask;
CGEventTapCallBack _callback;
void* _userInfo;
Boolean _enabled;
mach_port_t _machPort;
mach_port_t _machPort;
}
- (instancetype) initWithLocation: (CGEventTapLocation) location
options: (CGEventTapOptions) options
mask: (CGEventMask) mask
callback: (CGEventTapCallBack) callback
userInfo: (void *) userInfo;
-(instancetype) initWithLocation: (CGEventTapLocation) location
options: (CGEventTapOptions) options
mask: (CGEventMask) mask
callback: (CGEventTapCallBack) callback
userInfo: (void*) userInfo;
- (void) dealloc;
- (CFMachPortRef) createCFMachPort;
-(void) dealloc;
-(CFMachPortRef) createCFMachPort;
@property(readonly) mach_port_t machPort;
@property(readonly) CGEventTapOptions options;
@property(readonly) CGEventMask mask;
@property(readonly) CGEventTapCallBack callback;
@property(readonly) void *userInfo;
@property(readonly) void* userInfo;
@property Boolean enabled;
@end
#endif

View File

@ -17,11 +17,14 @@
along with Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CGEventObjC.h"
#include "CGEventTapInternal.h"
#include <time.h>
#include <CoreGraphics/CGEventSource.h>
#include <CoreGraphics/CGSConnection.h>
#include "CGEventTapInternal.h"
#import <Foundation/NSKeyedArchiver.h>
#import <Foundation/NSString.h>
#include <time.h>
#define CGInvalidPoint CGPointMake(CGFLOAT_MAX, CGFLOAT_MAX)
@implementation CGEvent
@ -32,97 +35,215 @@
@synthesize fields = _fields;
@synthesize virtualKey = _virtualKey;
@synthesize mouseButton = _mouseButton;
@synthesize location = _location;
@synthesize scrollEventUnit = _scrollEventUnit;
@synthesize wheelCount = _wheelCount;
- (instancetype) initWithSource: (CGEventSource *) source {
return [self initWithSource: source type: kCGEventNull];
}
- (instancetype) initWithSource: (CGEventSource *) source
type: (CGEventType) type;
-(instancetype) initWithSource:(CGEventSource*) source
{
_source = [source retain];
_type = type;
_fields = [[NSMutableDictionary alloc] initWithCapacity: 0];
_timestamp = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
return self;
return [self initWithSource: source
type: kCGEventNull];
}
- (instancetype) initWithCoder: (NSCoder *) coder {
NSKeyedUnarchiver *unarchiver = (NSKeyedUnarchiver *) coder;
-(instancetype) initWithSource:(CGEventSource*) source
type:(CGEventType) type;
{
_source = [source retain];
_type = type;
_fields = [[NSMutableDictionary alloc] initWithCapacity: 0];
_timestamp = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
// TODO
return self;
_location = CGInvalidPoint;
return self;
}
- (void) dealloc {
[_source release];
[_fields release];
[super dealloc];
-(instancetype) initWithCoder:(NSCoder*) coder
{
NSKeyedUnarchiver* unarchiver = (NSKeyedUnarchiver*) coder;
// TODO
return self;
}
- (id) copy {
CGEvent *rv = [[CGEvent alloc] initWithSource: _source type: _type];
rv->_timestamp = self->_timestamp;
rv->_flags = self->_flags;
rv->_fields = [_fields copy];
-(void) _fillFromEventRecord
{
_location = _eventRecord->location;
_type = _eventRecord->type; // These types match!
_timestamp = _eventRecord->time;
rv->_virtualKey = _virtualKey;
memcpy(rv->_unicodeString, _unicodeString, sizeof(_unicodeString));
switch (_eventRecord->type)
{
case NX_LMOUSEDOWN:
case NX_LMOUSEUP:
case NX_RMOUSEDOWN:
case NX_RMOUSEUP:
case NX_OMOUSEDOWN:
case NX_OMOUSEUP:
case NX_LMOUSEDRAGGED:
case NX_RMOUSEDRAGGED:
case NX_OMOUSEDRAGGED:
{
_fields[@(kCGMouseEventButtonNumber)] = [NSNumber numberWithInt: _eventRecord->data.mouse.buttonNumber];
_fields[@(kCGMouseEventNumber)] = [NSNumber numberWithInt: _eventRecord->data.mouse.eventNum];
_fields[@(kCGMouseEventPressure)] = [NSNumber numberWithDouble: _eventRecord->data.mouse.pressure / 255.0];
_fields[@(kCGMouseEventClickState)] = [NSNumber numberWithInt: _eventRecord->data.mouse.click];
_fields[@(kCGMouseEventSubtype)] = [NSNumber numberWithInt: _eventRecord->data.mouse.subType];
break;
}
case NX_MOUSEMOVED:
{
_fields[@(kCGMouseEventDeltaX)] = [NSNumber numberWithInt: _eventRecord->data.mouseMove.dx];
_fields[@(kCGMouseEventDeltaY)] = [NSNumber numberWithInt: _eventRecord->data.mouseMove.dy];
_fields[@(kCGMouseEventSubtype)] = [NSNumber numberWithInt: _eventRecord->data.mouseMove.subType];
break;
}
case NX_SCROLLWHEELMOVED:
{
_fields[@(kCGScrollWheelEventDeltaAxis1)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.deltaAxis1];
_fields[@(kCGScrollWheelEventDeltaAxis2)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.deltaAxis2];
_fields[@(kCGScrollWheelEventDeltaAxis3)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.deltaAxis3];
rv->_location = _location;
rv->_mouseButton = _mouseButton;
_fields[@(kCGScrollWheelEventFixedPtDeltaAxis1)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.fixedDeltaAxis1];
_fields[@(kCGScrollWheelEventFixedPtDeltaAxis2)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.fixedDeltaAxis2];
_fields[@(kCGScrollWheelEventFixedPtDeltaAxis3)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.fixedDeltaAxis3];
rv->_scrollEventUnit = _scrollEventUnit;
rv->_wheelCount = _wheelCount;
memcpy(rv->_wheels, _wheels, sizeof(_wheels));
return rv;
_fields[@(kCGScrollWheelEventPointDeltaAxis1)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.pointDeltaAxis1];
_fields[@(kCGScrollWheelEventPointDeltaAxis2)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.pointDeltaAxis2];
_fields[@(kCGScrollWheelEventPointDeltaAxis3)] = [NSNumber numberWithInt: _eventRecord->data.scrollWheel.pointDeltaAxis3];
break;
}
case NX_KEYDOWN:
case NX_KEYUP:
{
break;
}
}
}
- (id) copyWithZone: (NSZone *) zone {
return [self copy];
-(void) _createEventRecord
{
// TODO
}
- (CFTypeID) _cfTypeID {
return CGEventGetTypeID();
-(uint32_t) eventRecordLength
{
if (!_eventRecordLength)
[self _createEventRecord];
return _eventRecordLength;
}
- (int32_t *) wheels {
return _wheels;
-(CGSEventRecordPtr) eventRecord
{
if (!_eventRecord)
[self _createEventRecord];
return _eventRecord;
}
- (UniChar *) unicodeString {
return _unicodeString;
-(instancetype) initWithEventRecord:(const CGSEventRecordPtr) eventRecord
length:(uint32_t) length
{
_eventRecord = malloc(length);
memcpy(_eventRecord, eventRecord, length);
_eventRecordLength = length;
_fields = [[NSMutableDictionary alloc] initWithCapacity: 0];
_source = [[CGEventSource hidEventSource] retain];
[self _fillFromEventRecord];
return self;
}
- (void) encodeWithCoder: (NSCoder *) coder {
NSKeyedArchiver *archiver = (NSKeyedArchiver *) coder;
-(void) setEventRecord:(CGSEventRecordPtr) record
length:(uint32_t) length
{
CGSEventRecordPtr myCopy = (CGSEventRecordPtr) malloc(length);
memcpy(myCopy, record, length);
CGEventSourceStateID stateId = _source.stateID;
[archiver encodeInt: stateId forKey: @"stateId"];
[archiver encodeInt: _type forKey: @"type"];
[archiver encodeInt64: _timestamp forKey: @"timestamp"];
[archiver encodeObject: _fields forKey: @"fields"];
[archiver encodeInt: _virtualKey forKey: @"virtualKey"];
[archiver encodeBytes: (uint8_t *) _unicodeString
length: sizeof(_unicodeString)
forKey: @"unicodeString"];
[archiver encodeDouble: _location.x forKey: @"location.x"];
[archiver encodeDouble: _location.y forKey: @"location.y"];
[archiver encodeInt: _mouseButton forKey: @"mouseButton"];
[archiver encodeInt: _scrollEventUnit forKey: @"scrollEventUnit"];
[archiver encodeInt: _wheelCount forKey: @"wheelCount"];
for (uint32_t i = 0; i < _wheelCount; i++) {
[archiver encodeInt: _wheels[i]
forKey: [NSString stringWithFormat: @"wheel-%d", i]];
}
free(_eventRecord);
_eventRecord = myCopy;
_eventRecordLength = length;
}
-(void) dealloc
{
free(_eventRecord);
[_source release];
[_fields release];
[super dealloc];
}
-(id)copy
{
CGEvent* rv = [[CGEvent alloc] initWithSource: _source type: _type];
rv->_timestamp = self->_timestamp;
rv->_flags = self->_flags;
rv->_fields = [_fields copy];
rv->_virtualKey = _virtualKey;
memcpy(rv->_unicodeString, _unicodeString, sizeof(_unicodeString));
rv->_location = _location;
rv->_mouseButton = _mouseButton;
if (_eventRecord)
{
rv->_eventRecordLength = _eventRecordLength;
rv->_eventRecord = (CGSEventRecordPtr) malloc(_eventRecordLength);
memcpy(rv->_eventRecord, _eventRecord, _eventRecordLength);
}
return rv;
}
- (id)copyWithZone:(NSZone *)zone
{
return [self copy];
}
-(CFTypeID) _cfTypeID
{
return CGEventGetTypeID();
}
-(UniChar*) unicodeString
{
return _unicodeString;
}
-(void) encodeWithCoder:(NSCoder*) coder
{
NSKeyedArchiver* archiver = (NSKeyedArchiver*) coder;
CGEventSourceStateID stateId = _source.stateID;
[archiver encodeInt: stateId forKey:@"stateId"];
[archiver encodeInt: _type forKey: @"type"];
[archiver encodeInt64: _timestamp forKey: @"timestamp"];
[archiver encodeObject: _fields forKey: @"fields"];
[archiver encodeInt: _virtualKey forKey: @"virtualKey"];
[archiver encodeBytes: (uint8_t*) _unicodeString length: sizeof(_unicodeString) forKey: @"unicodeString"];
[archiver encodeDouble: _location.x forKey: @"location.x"];
[archiver encodeDouble: _location.y forKey: @"location.y"];
[archiver encodeInt: _mouseButton forKey: @"mouseButton"];
if (_eventRecord)
[archiver encodeBytes: (uint8_t*)_eventRecord length: _eventRecordLength forKey: @"eventRecord"];
}
-(CGPoint) location
{
const CGPoint invalid = CGInvalidPoint;
if (_location.x == invalid.x && _location.y == invalid.y)
{
_location = [_CGSConnectionForID(CGSDefaultConnection) mouseLocation];
}
return _location;
}
-(void) setLocation:(CGPoint) location
{
_location = location;
}
@end
////////////////////////////////////////////////////////////////
@ -133,45 +254,59 @@
@synthesize userData = _userData;
@synthesize pixelsPerLine = _pixelsPerLine;
- (instancetype) initWithState: (CGEventSourceStateID) stateId {
_stateId = stateId;
return self;
-(instancetype) initWithState: (CGEventSourceStateID) stateId
{
_pixelsPerLine = 10;
_stateId = stateId;
return self;
}
- (CFTypeID) _cfTypeID {
return CGEventSourceGetTypeID();
-(CFTypeID) _cfTypeID
{
return CGEventSourceGetTypeID();
}
+(CGEventSource*) hidEventSource
{
static CGEventSource* instance;
static dispatch_once_t once;
dispatch_once(&once, ^{
instance = [[CGEventSource alloc] initWithState: kCGEventSourceStateHIDSystemState];
});
return instance;
}
@end
////////////////////////////////////////////////////////////////
static void cgEventTapCallout(CFMachPortRef mp, void *msg, CFIndex size,
void *info)
static void cgEventTapCallout(CFMachPortRef mp, void* msg, CFIndex size, void* info)
{
CGEventTap *tap = (CGEventTap *) info;
CGEventTap* tap = (CGEventTap*) info;
struct TapMachMessage *tapMessage = (struct TapMachMessage *) msg;
CGEventRef event = tapMessage->event;
struct TapMachMessage* tapMessage = (struct TapMachMessage*) msg;
CGEventRef event = tapMessage->event;
CGEventType type = CGEventGetType(tapMessage->event);
if (tap.enabled && (CGEventMaskBit(type) & tap.mask) != 0) {
// Invoke callback
CGEventRef returned =
tap.callback(tapMessage->proxy, type, event, tap.userInfo);
CGEventType type = CGEventGetType(tapMessage->event);
if (tap.enabled && (CGEventMaskBit(type) & tap.mask) != 0)
{
// Invoke callback
CGEventRef returned = tap.callback(tapMessage->proxy, type, event, tap.userInfo);
if (!(tap.options & kCGEventTapOptionListenOnly))
event = returned;
}
if (!(tap.options & kCGEventTapOptionListenOnly))
event = returned;
}
// Pass the message on
if (event != NULL) {
CGEventTapPostEvent(tapMessage->proxy, event);
// Pass the message on
if (event != NULL)
{
CGEventTapPostEvent(tapMessage->proxy, event);
if (event != tapMessage->event)
CFRelease(event);
}
if (event != tapMessage->event)
CFRelease(event);
}
CFRelease(tapMessage->event);
CFRelease(tapMessage->event);
}
@implementation CGEventTap
@ -183,55 +318,53 @@ static void cgEventTapCallout(CFMachPortRef mp, void *msg, CFIndex size,
@synthesize userInfo = _userInfo;
@synthesize enabled = _enabled;
- (instancetype) initWithLocation: (CGEventTapLocation) location
options: (CGEventTapOptions) options
mask: (CGEventMask) mask
callback: (CGEventTapCallBack) callback
userInfo: (void *) userInfo
-(instancetype) initWithLocation: (CGEventTapLocation) location
options: (CGEventTapOptions) options
mask: (CGEventMask) mask
callback: (CGEventTapCallBack) callback
userInfo: (void*) userInfo
{
_location = location;
_options = options;
_mask = mask;
_callback = callback;
_userInfo = userInfo;
_enabled = TRUE;
_location = location;
_options = options;
_mask = mask;
_callback = callback;
_userInfo = userInfo;
_enabled = TRUE;
kern_return_t ret = mach_port_allocate(mach_task_self(),
MACH_PORT_RIGHT_RECEIVE, &_machPort);
kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &_machPort);
if (KERN_SUCCESS == ret) {
ret = mach_port_insert_right(mach_task_self(), _machPort, _machPort,
MACH_MSG_TYPE_MAKE_SEND);
ret = mach_port_insert_right(mach_task_self(), _machPort, _machPort, MACH_MSG_TYPE_MAKE_SEND);
}
if (KERN_SUCCESS != ret) {
if (MACH_PORT_NULL != _machPort)
mach_port_destroy(mach_task_self(), _machPort);
[self release];
if (MACH_PORT_NULL != _machPort) mach_port_destroy(mach_task_self(), _machPort);
[self release];
return nil;
}
return self;
return self;
}
- (void) dealloc {
_CGEventTapDestroyed(_location, _machPort);
mach_port_destroy(mach_task_self(), _machPort);
[super dealloc];
-(void) dealloc
{
_CGEventTapDestroyed(_location, _machPort);
mach_port_destroy(mach_task_self(), _machPort);
[super dealloc];
}
- (CFMachPortRef) createCFMachPort {
CFMachPortRef mp;
CFMachPortContext ctxt = {
.copyDescription = NULL,
.info = self,
.release = CFRelease,
.retain = CFRetain,
.version = 0,
};
-(CFMachPortRef) createCFMachPort
{
CFMachPortRef mp;
CFMachPortContext ctxt = {
.copyDescription = NULL,
.info = self,
.release = CFRelease,
.retain = CFRetain,
.version = 0,
};
mp = CFMachPortCreateWithPort(NULL, _machPort, cgEventTapCallout, &ctxt,
NULL);
mp = CFMachPortCreateWithPort(NULL, _machPort, cgEventTapCallout, &ctxt, NULL);
return mp;
return mp;
}
@end

View File

@ -17,54 +17,55 @@
along with Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import "CGEventObjC.h"
#include "CGEventTapInternal.h"
#include <CoreGraphics/CGEvent.h>
#import "CGEventObjC.h"
#include <CoreGraphics/CGEventTapInternal.h>
void CGEventPost(CGEventTapLocation tap, CGEventRef _Nullable event) {
// TODO: Create an appropriate CGEventTapProxy and call
// CGEventTapPostEvent()
}
CFMachPortRef CGEventTapCreate(CGEventTapLocation tap,
CGEventTapPlacement place,
CGEventTapOptions options,
CGEventMask eventsOfInterest,
CGEventTapCallBack callback, void *userInfo)
void CGEventPost(CGEventTapLocation tap, CGEventRef _Nullable event)
{
CGEventTap *newTap = [[CGEventTap alloc] initWithLocation: tap
options: options
mask: eventsOfInterest
callback: callback
userInfo: userInfo];
mach_port_t port = newTap.machPort;
// TODO: Save this port to tapping structures
CFMachPortRef mp = [newTap createCFMachPort];
[newTap release]; // CFMachPortRef now holds a ref
return mp;
// TODO: Create an appropriate CGEventTapProxy and call CGEventTapPostEvent()
// TODO: Finally, invoke callbacks registered with CGSRegisterNotifyProc()
}
void _CGEventTapDestroyed(CGEventTapLocation location, mach_port_t mp) {
// TODO: Deregister the tap
}
void CGEventTapEnable(CFMachPortRef tap, bool enable) {
mach_port_t mp = CFMachPortGetPort(tap);
// TODO: Lookup CGEventTap instance by mp
CGEventTap *tapObj = nil;
tapObj.enabled = enable;
}
void CGEventTapPostEvent(CGEventTapProxy proxy, CGEventRef event) {
}
CGError CGGetEventTapList(uint32_t maxNumberOfTaps,
CGEventTapInformation *tapList,
uint32_t *eventTapCount)
CFMachPortRef CGEventTapCreate(CGEventTapLocation tap, CGEventTapPlacement place,
CGEventTapOptions options, CGEventMask eventsOfInterest, CGEventTapCallBack callback, void *userInfo)
{
CGEventTap* newTap = [[CGEventTap alloc] initWithLocation: tap
options: options
mask: eventsOfInterest
callback: callback
userInfo: userInfo];
mach_port_t port = newTap.machPort;
// TODO: Save this port to tapping structures
CFMachPortRef mp = [newTap createCFMachPort];
[newTap release]; // CFMachPortRef now holds a ref
return mp;
}
void _CGEventTapDestroyed(CGEventTapLocation location, mach_port_t mp)
{
// TODO: Deregister the tap
}
void CGEventTapEnable(CFMachPortRef tap, bool enable)
{
mach_port_t mp = CFMachPortGetPort(tap);
// TODO: Lookup CGEventTap instance by mp
CGEventTap* tapObj = nil;
tapObj.enabled = enable;
}
void CGEventTapPostEvent(CGEventTapProxy proxy, CGEventRef event)
{
}
CGError CGGetEventTapList(uint32_t maxNumberOfTaps, CGEventTapInformation *tapList, uint32_t *eventTapCount)
{
}

View File

@ -18,6 +18,12 @@
*/
#ifndef CGEVENTTAP_INTERNAL_H
#define CGEVENTTAP_INTERNAL_H
#include <CoreGraphics/CGEventTypes.h>
#include <mach/message.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void _CGEventTapDestroyed(CGEventTapLocation loc, mach_port_t mp);
@ -27,4 +33,8 @@ struct TapMachMessage {
CGEventRef event;
};
#ifdef __cplusplus
}
#endif
#endif

View File

@ -16,15 +16,16 @@
You should have received a copy of the GNU General Public License
along with Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import <CoreGraphics/CGSConnection.h>
#import <CoreGraphics/CGSSurface.h>
#import <CoreGraphics/CGSWindow.h>
#include <CoreGraphics/CoreGraphicsPrivate.h>
#import <Foundation/Foundation.h>
#include <dispatch/dispatch.h>
#include <stdatomic.h>
#import <CoreGraphics/CGSConnection.h>
#import <CoreGraphics/CGSWindow.h>
#import <CoreGraphics/CGSSurface.h>
#include <pthread.h>
static NSMutableDictionary<NSNumber *, CGSConnection *> *g_connections = nil;
static NSMutableDictionary<NSNumber*, CGSConnection*>* g_connections = nil;
static Boolean g_denyConnections = FALSE;
static CGSConnectionID g_defaultConnection = -1;
@ -33,158 +34,374 @@ static pthread_mutex_t g_defaultConnectionMutex = PTHREAD_MUTEX_INITIALIZER;
static _Atomic CGSConnectionID g_nextConnectionID = 1;
static Class g_backendClass = nil;
CGError CGSSetDenyWindowServerConnections(Boolean deny) {
// TODO: Instruct our platform abstraction about this
// TODO: Return failure if there's an existing connection
return kCGErrorSuccess;
}
__attribute__((visibility("hidden"))) CFMutableArrayRef g_cgsNotifyProc;
__attribute__((visibility("hidden"))) pthread_mutex_t g_cgsNotifyProcMutex = PTHREAD_MUTEX_INITIALIZER;
void CGSShutdownServerConnections(void) {
// TODO
}
CGError CGSNewWindow(CGSConnectionID conn, CFIndex flags, float x_offset,
float y_offset, const CGSRegionRef region,
CGSWindowID *windowID)
typedef struct
{
CGSConnection *c = _CGSConnectionForID(conn);
if (!c)
return kCGErrorInvalidConnection;
CGSNotifyProcPtr proc;
CGSNotificationType notificationType;
void* private;
} NotifyProcEntry;
CGSWindow *window = [c newWindow: region];
if (!window)
return kCGErrorIllegalArgument;
*windowID = window.windowId;
return kCGSErrorSuccess;
}
CGError CGSReleaseWindow(CGSConnectionID cid, CGSWindowID wid) {
CGSConnection *c = _CGSConnectionForID(cid);
if (!c)
return kCGErrorInvalidConnection;
return [c destroyWindow: wid];
}
CGError CGSSetWindowShape(CGSConnectionID cid, CGSWindowID wid, float x_offset,
float y_offset, const CGSRegionRef shape)
CGError CGSSetDenyWindowServerConnections(Boolean deny)
{
CGSWindow *window;
CGError err = getWindow(cid, wid, &window);
NSUInteger connectionCount;
@synchronized(g_connections)
{
connectionCount = g_connections.count;
}
if (err != kCGSErrorSuccess)
return err;
if (deny && connectionCount > 0)
{
return kCGErrorFailure;
}
return [window setRegion: shape];
g_denyConnections = deny;
return kCGSErrorSuccess;
}
OSStatus CGSOrderWindow(CGSConnectionID cid, CGSWindowID wid,
CGSWindowOrderingMode place,
CGSWindowID relativeToWindow)
void CGSShutdownServerConnections(void)
{
CGSConnection *c = _CGSConnectionForID(cid);
if (!c)
return kCGErrorInvalidConnection;
CGSWindow *window = [c windowForId: wid];
if (!window)
return kCGErrorIllegalArgument;
CGSWindow *relativeTo = [c windowForId: relativeToWindow];
return [window orderWindow: place relativeTo: relativeTo];
@synchronized(g_connections)
{
[g_connections removeAllObjects];
}
g_defaultConnection = -1;
}
CGError CGSMoveWindow(CGSConnectionID cid, CGSWindowID wid,
const CGPoint *window_pos)
__attribute__((constructor))
void CGSInitialize(void)
{
CGSWindow *window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
return [window moveTo: window_pos];
static dispatch_once_t once;
dispatch_once(&once, ^{
g_connections = [[NSMutableDictionary alloc] initWithCapacity: 1];
});
}
extern CGError CGSSetWindowOpacity(CGSConnectionID cid, CGSWindowID wid,
bool isOpaque);
extern CGError CGSSetWindowAlpha(CGSConnectionID cid, CGSWindowID wid,
float alpha);
extern CGError CGSSetWindowLevel(CGSConnectionID cid, CGSWindowID wid,
CGWindowLevel level);
CGError CGSGetWindowProperty(CGSConnectionID cid, CGSWindowID wid,
CFStringRef key, CFTypeRef *outValue)
static void _CGSLoadBackend(void)
{
CGSWindow *window;
CGError err = getWindow(cid, wid, &window);
NSBundle* cgBundle = [NSBundle bundleForClass: [CGSConnection class]];
NSMutableArray<NSBundle*>* backends = [NSMutableArray new];
if (err != kCGSErrorSuccess)
return err;
for (NSString *path in [cgBundle pathsForResourcesOfType: @"backend" inDirectory: @"Backends"])
{
NSBundle* backendBundle = [NSBundle bundleWithPath: path];
if ([backendBundle load])
[backends addObject: backendBundle];
}
return [window getProperty: key value: outValue];
// Sort them according to the NSPriority key in their Info.plist files.
[backends sortUsingComparator: ^(NSBundle *b1, NSBundle *b2) {
NSNumber *p1 = [b1 objectForInfoDictionaryKey: @"NSPriority"];
NSNumber *p2 = [b2 objectForInfoDictionaryKey: @"NSPriority"];
return [p2 compare: p1];
}];
// Try to instantiate them in that order.
for (NSBundle *backendBundle in backends)
{
Class cls = [backendBundle principalClass];
if ([cls isAvailable])
{
g_backendClass = cls;
break;
}
}
[backends release];
}
CGError CGSSetWindowProperty(CGSConnectionID cid, CGSWindowID wid,
CFStringRef key, CFTypeRef value)
CGError CGSNewConnection(CGSDictionaryObj attribs, CGSConnectionID* connId)
{
CGSWindow *window;
CGError err = getWindow(cid, wid, &window);
*connId = -1;
if (err != kCGSErrorSuccess)
return err;
if (g_denyConnections)
return kCGErrorCannotComplete;
return [window setProperty: key value: value];
static dispatch_once_t once;
dispatch_once(&once, ^{
_CGSLoadBackend();
});
if (!g_backendClass)
return kCGErrorCannotComplete;
CGSConnectionID newConnID = g_nextConnectionID++;
CGSConnection* conn = [[g_backendClass alloc] initWithConnectionID: newConnID];
if (conn != nil)
{
*connId = newConnID;
@synchronized(g_connections)
{
[g_connections setObject: conn forKey: [NSNumber numberWithInt: newConnID]];
}
[conn release];
return kCGSErrorSuccess;
}
else
return kCGErrorFailure;
}
CGError getSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid,
CGSSurface **surface)
CGSConnection* _CGSConnectionForID(CGSConnectionID connId)
{
CGSWindow *window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
*surface = [window surfaceForId: sid];
return (*surface) ? kCGSErrorSuccess : kCGErrorIllegalArgument;
@synchronized(g_connections)
{
return [g_connections objectForKey:[NSNumber numberWithInt: connId]];
}
}
CGError CGSAddSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID *sid) {
CGSWindow *window;
void* _CGSNativeDisplay(CGSConnectionID connId)
{
return [_CGSConnectionForID(connId) nativeDisplay];
}
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
void* _CGSNativeWindowForID(CGSConnectionID connId, CGSWindowID winId)
{
CGSConnection* conn = _CGSConnectionForID(connId);
return [[conn windowForId: winId] nativeWindow];
}
CGSSurface *surface = [window createSurface];
if (!surface)
return kCGErrorFailure;
void* _CGSNativeWindowForSurfaceID(CGSConnectionID connId, CGSWindowID winId, CGSSurfaceID surfaceId)
{
CGSConnection* conn = _CGSConnectionForID(connId);
return [[[conn windowForId: winId] surfaceForId: surfaceId] nativeWindow];
}
*sid = surface.surfaceId;
return kCGSErrorSuccess;
CGError CGSReleaseConnection(CGSConnectionID connId)
{
NSNumber* num = [NSNumber numberWithInt:connId];
@synchronized(g_connections)
{
if (![g_connections objectForKey: num])
return kCGErrorInvalidConnection;
[g_connections removeObjectForKey: num];
}
return kCGSErrorSuccess;
}
CGSConnectionID _CGSDefaultConnection(void)
{
return CGSMainConnectionID();
}
CGSConnectionID CGSMainConnectionID(void)
{
if (g_defaultConnection == -1)
{
pthread_mutex_lock(&g_defaultConnectionMutex);
if (g_defaultConnection == -1)
CGSNewConnection(NULL, &g_defaultConnection);
pthread_mutex_unlock(&g_defaultConnectionMutex);
}
return g_defaultConnection;
}
static CGError getWindow(CGSConnectionID cid, CGSWindowID wid, CGSWindow** out)
{
CGSConnection* c = _CGSConnectionForID(cid);
if (!c)
return kCGErrorInvalidConnection;
CGSWindow* window = [c windowForId: wid];
if (!window)
return kCGErrorIllegalArgument;
*out = window;
return kCGSErrorSuccess;
}
CGError CGSNewWindow(CGSConnectionID conn, CFIndex flags, float x_offset, float y_offset, const CGSRegionRef region, CGSWindowID* windowID)
{
CGSConnection* c = _CGSConnectionForID(conn);
if (!c)
return kCGErrorInvalidConnection;
CGSWindow* window = [c newWindow: region];
if (!window)
return kCGErrorIllegalArgument;
*windowID = window.windowId;
return kCGSErrorSuccess;
}
CGError CGSReleaseWindow(CGSConnectionID cid, CGSWindowID wid)
{
CGSConnection* c = _CGSConnectionForID(cid);
if (!c)
return kCGErrorInvalidConnection;
return [c destroyWindow: wid];
}
CGError CGSSetWindowShape(CGSConnectionID cid, CGSWindowID wid, float x_offset, float y_offset, const CGSRegionRef shape)
{
CGSWindow* window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
return [window setRegion: shape];
}
OSStatus CGSOrderWindow(CGSConnectionID cid, CGSWindowID wid, CGSWindowOrderingMode place, CGSWindowID relativeToWindow)
{
CGSConnection* c = _CGSConnectionForID(cid);
if (!c)
return kCGErrorInvalidConnection;
CGSWindow* window = [c windowForId: wid];
if (!window)
return kCGErrorIllegalArgument;
CGSWindow* relativeTo = [c windowForId: relativeToWindow];
return [window orderWindow: place relativeTo: relativeTo];
}
CGError CGSMoveWindow(CGSConnectionID cid, CGSWindowID wid, const CGPoint *window_pos)
{
CGSWindow* window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
return [window moveTo: window_pos];
}
extern CGError CGSSetWindowOpacity(CGSConnectionID cid, CGSWindowID wid, bool isOpaque);
extern CGError CGSSetWindowAlpha(CGSConnectionID cid, CGSWindowID wid, float alpha);
extern CGError CGSSetWindowLevel(CGSConnectionID cid, CGSWindowID wid, CGWindowLevel level);
CGError CGSGetWindowProperty(CGSConnectionID cid, CGSWindowID wid, CFStringRef key, CFTypeRef *outValue)
{
CGSWindow* window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
return [window getProperty: key value: outValue];
}
CGError CGSSetWindowProperty(CGSConnectionID cid, CGSWindowID wid, CFStringRef key, CFTypeRef value)
{
CGSWindow* window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
return [window setProperty: key value: value];
}
CGError getSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid, CGSSurface** surface)
{
CGSWindow* window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
*surface = [window surfaceForId: sid];
return (*surface) ? kCGSErrorSuccess : kCGErrorIllegalArgument;
}
CGError CGSAddSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID *sid)
{
CGSWindow* window;
CGError err = getWindow(cid, wid, &window);
if (err != kCGSErrorSuccess)
return err;
CGSSurface* surface = [window createSurface];
if (!surface)
return kCGErrorFailure;
*sid = surface.surfaceId;
return kCGSErrorSuccess;
}
CGError CGSRemoveSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid)
{
CGSSurface *surface;
CGSSurface* surface;
CGError err = getSurface(cid, wid, sid, &surface);
if (err != kCGSErrorSuccess)
return err;
CGError err = getSurface(cid, wid, sid, &surface);
if (err != kCGSErrorSuccess)
return err;
[surface invalidate];
return kCGSErrorSuccess;
[surface invalidate];
return kCGSErrorSuccess;
}
CGError CGSSetSurfaceBounds(CGSConnectionID cid, CGSWindowID wid,
CGSSurfaceID sid, CGRect rect)
CGError CGSSetSurfaceBounds(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid, CGRect rect)
{
CGSSurface *surface;
CGSSurface* surface;
CGError err = getSurface(cid, wid, sid, &surface);
if (err != kCGSErrorSuccess)
return err;
CGError err = getSurface(cid, wid, sid, &surface);
if (err != kCGSErrorSuccess)
return err;
return [surface setBounds: rect];
return [surface setBounds: rect];
}
CGSConnection* _CGSConnectionFromEventRecord(const CGSEventRecordPtr record)
{
if (!record)
return nil;
return _CGSConnectionForID(record->connection);
}
static void simplyFree(CFAllocatorRef allocator, const void* mem)
{
free((void*) mem);
}
CGError CGSRegisterNotifyProc(CGSNotifyProcPtr proc, CGSNotificationType notificationType, void* private)
{
static dispatch_once_t once;
dispatch_once(&once, ^{
CFArrayCallBacks cb = {
.release = simplyFree,
.version = 0,
};
g_cgsNotifyProc = CFArrayCreateMutable(NULL, 0, &cb);
});
NotifyProcEntry* e = (NotifyProcEntry*) malloc(sizeof(NotifyProcEntry));
e->proc = proc;
e->notificationType = notificationType;
e->private = private;
pthread_mutex_lock(&g_cgsNotifyProcMutex);
CFArrayAppendValue(g_cgsNotifyProc, e);
pthread_mutex_unlock(&g_cgsNotifyProcMutex);
return kCGSErrorSuccess;
}
CGError CGSRemoveNotifyProc(CGSNotifyProcPtr proc, CGSNotificationType notificationType)
{
if (!g_cgsNotifyProc)
return kCGSErrorSuccess;
pthread_mutex_lock(&g_cgsNotifyProcMutex);
// This code is not too efficient, but it is called so rarely (if ever), it doesn't matter.
for (CFIndex i = 0; i < CFArrayGetCount(g_cgsNotifyProc); i++)
{
NotifyProcEntry* e = (NotifyProcEntry*) CFArrayGetValueAtIndex(g_cgsNotifyProc, i);
if (e->proc == proc && e->notificationType == notificationType)
{
CFArrayRemoveValueAtIndex(g_cgsNotifyProc, i);
break;
}
}
pthread_mutex_unlock(&g_cgsNotifyProcMutex);
return kCGSErrorSuccess;
}

View File

@ -17,61 +17,95 @@
along with Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import <CoreGraphics/CGSConnection.h>
#import <CoreGraphics/CGSSurface.h>
#import <CoreGraphics/CGSWindow.h>
#import <CoreGraphics/CGSSurface.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSNumber.h>
#import <Foundation/NSRaise.h>
@implementation CGSConnection
- (instancetype) initWithConnectionID: (CGSConnectionID) connId {
_nextWindowId = 1;
_connectionId = connId;
_windows = [[NSMutableDictionary alloc] initWithCapacity: 1];
return self;
-(instancetype) initWithConnectionID:(CGSConnectionID)connId
{
_nextWindowId = 1;
_connectionId = connId;
_windows = [[NSMutableDictionary alloc] initWithCapacity: 1];
return self;
}
- (CGSWindow *) windowForId: (CGSWindowID) winId {
CGSWindow *rv;
@synchronized(_windows) {
rv = [_windows objectForKey: [NSNumber numberWithInt: winId]];
}
return rv;
-(CGSWindow*) windowForId:(CGSWindowID)winId
{
@synchronized(_windows)
{
return [_windows objectForKey: [NSNumber numberWithInt: winId]];
}
}
- (void) _windowInvalidated: (CGSWindowID) winId {
@synchronized(_windows) {
[_windows removeObjectForKey: [NSNumber numberWithInt: winId]];
}
-(void) _windowInvalidated: (CGSWindowID) winId
{
@synchronized(_windows)
{
[_windows removeObjectForKey: [NSNumber numberWithInt: winId]];
}
}
- (void) dealloc {
[_windows release];
[super dealloc];
-(void) dealloc
{
[_windows release];
[super dealloc];
}
+ (BOOL) isAvailable {
NSInvalidAbstractInvocation();
+(BOOL) isAvailable
{
NSInvalidAbstractInvocation();
}
- (CGSWindow *) newWindow: (CGSRegionRef) region {
NSInvalidAbstractInvocation();
-(CGSKeyboardLayout*) createKeyboardLayout
{
NSInvalidAbstractInvocation();
}
- (void *) nativeDisplay {
NSInvalidAbstractInvocation();
-(CGPoint) mouseLocation
{
NSInvalidAbstractInvocation();
}
- (CGError) destroyWindow: (CGSWindowID) winId {
CGSWindow *win = [self windowForId: winId];
if (win == nil)
return kCGErrorIllegalArgument;
[win invalidate];
-(NSArray *) modesForScreen:(int)screenIndex
{
NSInvalidAbstractInvocation();
}
@synchronized(_windows) {
[_windows removeObjectForKey: [NSNumber numberWithInt: winId]];
}
return kCGSErrorSuccess;
-(BOOL) setMode:(NSDictionary *)mode forScreen:(int)screenIndex
{
NSInvalidAbstractInvocation();
}
-(NSDictionary*) currentModeForScreen:(int)screenIndex
{
NSInvalidAbstractInvocation();
}
-(CGSWindow*) newWindow:(CGSRegionRef)region
{
NSInvalidAbstractInvocation();
}
-(void*) nativeDisplay
{
NSInvalidAbstractInvocation();
}
-(CGError) destroyWindow:(CGSWindowID)winId
{
CGSWindow* win = [self windowForId: winId];
if (win == nil)
return kCGErrorIllegalArgument;
[win invalidate];
@synchronized (_windows)
{
[_windows removeObjectForKey: [NSNumber numberWithInt: winId]];
}
return kCGSErrorSuccess;
}
@end

View File

@ -0,0 +1,43 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import <CoreGraphics/CGSKeyboardLayout.h>
@implementation CGSKeyboardLayout
@synthesize name = _name;
@synthesize fullName = _fullName;
@synthesize layout = _layout;
@synthesize layoutLength = _layoutLength;
-(void) dealloc
{
[_name release];
[_fullName release];
free(_layout);
[super dealloc];
}
-(void) setLayout:(UCKeyboardLayout*) layout length:(uint32_t) length
{
free(_layout);
_layout = (UCKeyboardLayout*) malloc(length);
memcpy(_layout, layout, length);
_layoutLength = length;
}
@end

46
CoreGraphics/CGSScreen.m Normal file
View File

@ -0,0 +1,46 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import <CoreGraphics/CGSScreen.h>
@implementation CGSScreen
@synthesize edid = _edid;
@synthesize modes = _modes;
@synthesize currentMode = _currentMode;
-(void) dealloc
{
[_edid release];
[_modes release];
[super dealloc];
}
-(uint32_t) currentModeHeight
{
if (!_currentModeHeightCached)
{
if (_currentMode < 0 || _currentMode >= [_modes count])
return 0;
NSNumber* height = (NSNumber*) _modes[_currentMode][@"Height"];
_currentModeHeightCached = height.intValue;
}
return _currentModeHeightCached;
}
@end

View File

@ -105,7 +105,9 @@ set(CoreGraphics_sources
CGSConnection.m
CGSWindow.m
CGSSurface.m
CGSKeyboardLayout.m
CGSRegion.m
CGSScreen.m
CGEvent.m
CGEventSource.m
CGEventTap.m
@ -133,3 +135,5 @@ add_framework(CoreGraphics
GL
IOKit
)
add_subdirectory(X11.backend)

View File

@ -0,0 +1,57 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CGSCONNECTIONX11_H
#define CGSCONNECTIONX11_H
#import <CoreGraphics/CGSConnection.h>
#import <X11/Xlib.h>
#import <CoreFoundation/CFRunLoop.h>
#import <CoreFoundation/CFSocket.h>
@interface CGSConnectionX11 : CGSConnection {
Display *_display;
// We use CFRunLoop directly, without going through any Foundation wrapper,
// because Apple's Cocoa has none. Unlike Apple's Cocoa, we need to watch
// over a Unix domain socket, not a Mach port.
CFSocketRef _cfSocket;
CFRunLoopSourceRef _source;
// NOTE: A CGSScreen refers to a 'crtc' in X11 paralance, and *not* to an X11 screen.
// In other words, it refers to a physical monitor.
NSArray<CGSScreen*>* _screens;
CGSKeyboardLayout* _keyboardLayout;
int _keyboardLayoutGroup;
int _xkbEventBase;
int _xrrEventBase;
}
-(instancetype) initWithConnectionID:(CGSConnectionID)connId;
-(void) dealloc;
-(CGSWindow*) newWindow:(CGSRegionRef)region;
-(void) processPendingEvents;
+(BOOL) isAvailable;
@end
#endif

View File

@ -0,0 +1,381 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import "CGSConnectionX11.h"
#import <CoreGraphics/CGSKeyboardLayout.h>
#include "CarbonKeys.h"
#import "X11KeySymToUCS.h"
#import <Foundation/NSDebug.h>
#import <Foundation/NSString.h>
#include <stdlib.h>
#include <stdatomic.h>
#import <X11/Xutil.h>
#import <X11/extensions/Xrandr.h>
#import <X11/XKBlib.h>
#import <X11/extensions/XKBrules.h>
// TODO: Use XInput2:
// https://stackoverflow.com/questions/44095001/getting-double-rawkeypress-events-using-xinput2
// https://github.com/openbsd/xenocara/blob/master/app/xinput/src/test_xi2.c
@implementation CGSConnectionX11
static int errorHandler(Display* display, XErrorEvent* errorEvent)
{
NSLog(@"************** X11 ERROR!");
NSLog(@"Request code: %d:%d", errorEvent->request_code, errorEvent->minor_code);
NSLog(@"Error code: %d", errorEvent->error_code);
return 0;
}
static void socketCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address,
const void *data, void *info)
{
CGSConnectionX11* self = (CGSConnectionX11*) info;
[self processPendingEvents];
}
-(instancetype) initWithConnectionID:(CGSConnectionID)connId
{
_display = XOpenDisplay(NULL);
if (!_display)
_display = XOpenDisplay(":0");
if (!_display)
{
NSLog(@"CGSConnectionX11: XOpenDisplay() failed\n");
[self release];
return nil;
}
self = [super initWithConnectionID: connId];
if (NSDebugEnabled)
XSynchronize(_display, True);
XSetErrorHandler(errorHandler);
int fd = ConnectionNumber(_display);
// There's no need to retain/release the display,
// because the display is guaranteed to outlive
// the socket.
CFSocketContext context = {
.version = 0,
.info = self,
.retain = NULL,
.release = NULL,
.copyDescription = NULL
};
_cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, socketCallback, &context);
_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _cfSocket, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), _source, kCFRunLoopCommonModes);
int errorBase;
if (XRRQueryExtension(_display, &_xrrEventBase, &errorBase))
{
// Sign up for XRandR events
// TODO: Do we need all these?
XRRSelectInput(_display, DefaultRootWindow(_display), RRScreenChangeNotifyMask | RROutputChangeNotifyMask | RRCrtcChangeNotifyMask);
}
int major = XkbMajorVersion, minor = XkbMinorVersion;
if (XkbLibraryVersion(&major, &minor) && XkbQueryExtension(_display, NULL, &_xkbEventBase, &major, &minor, NULL))
{
XkbSelectEvents(_display, XkbUseCoreKbd, /*XkbMapNotifyMask |*/ XkbStateNotifyMask, 1);
}
return self;
}
-(void) dealloc
{
if (_display)
XCloseDisplay(_display);
CFRunLoopRemoveSource(CFRunLoopGetMain(), _source, kCFRunLoopCommonModes);
if (_source != NULL)
CFRelease(_source);
if (_cfSocket != NULL)
CFRelease(_cfSocket);
[_keyboardLayout release];
[super dealloc];
}
-(CGSKeyboardLayout*) createKeyboardLayout
{
@synchronized (self)
{
if (!_keyboardLayout)
[self _doCreateKeyboardLayout];
return [_keyboardLayout retain];
}
}
- (void) _doCreateKeyboardLayout
{
int major = XkbMajorVersion, minor = XkbMinorVersion;
XkbDescPtr pKBDesc;
unsigned char group = 0;
XkbStateRec state;
struct MyLayout
{
UCKeyboardLayout layout;
UCKeyModifiersToTableNum modifierVariants;
UInt8 secondTableNum, thirdTableNum;
UCKeyToCharTableIndex tableIndex;
UInt32 secontTableOffset;
UCKeyOutput table1[128];
UCKeyOutput table2[128];
};
if (!XkbLibraryVersion(&major, &minor))
return;
if (!XkbQueryExtension(_display, NULL, NULL, &major, &minor, NULL))
return;
pKBDesc = XkbGetMap(_display, XkbAllClientInfoMask, XkbUseCoreKbd);
if (!pKBDesc)
return;
XkbDescPtr desc = XkbGetKeyboard(_display, XkbAllComponentsMask, XkbUseCoreKbd);
if (!desc)
return;
if (XkbGetState(_display, XkbUseCoreKbd, &state) == Success)
group = state.group;
struct MyLayout* layout = (struct MyLayout*) malloc(sizeof(struct MyLayout));
layout->layout.keyLayoutHeaderFormat = kUCKeyLayoutHeaderFormat;
layout->layout.keyLayoutDataVersion = 0;
layout->layout.keyLayoutFeatureInfoOffset = 0;
layout->layout.keyboardTypeCount = 1;
memset(layout->layout.keyboardTypeList, 0, sizeof(UCKeyboardTypeHeader));
layout->layout.keyboardTypeList[0].keyModifiersToTableNumOffset = offsetof(struct MyLayout, modifierVariants);
layout->layout.keyboardTypeList[0].keyToCharTableIndexOffset = offsetof(struct MyLayout, tableIndex);
layout->modifierVariants.keyModifiersToTableNumFormat = kUCKeyModifiersToTableNumFormat;
layout->modifierVariants.defaultTableNum = 0;
layout->modifierVariants.modifiersCount = 3;
layout->modifierVariants.tableNum[0] = 0;
layout->modifierVariants.tableNum[1] = 0; // cmd key bit
layout->modifierVariants.tableNum[2] = 1; // shift key bit
layout->tableIndex.keyToCharTableIndexFormat = kUCKeyToCharTableIndexFormat;
layout->tableIndex.keyToCharTableSize = 128;
layout->tableIndex.keyToCharTableCount = 2;
layout->tableIndex.keyToCharTableOffsets[0] = offsetof(struct MyLayout, table1);
layout->tableIndex.keyToCharTableOffsets[1] = offsetof(struct MyLayout, table2);
for (int shift = 0; shift <= 1; shift++)
{
UCKeyOutput* outTable = (shift == 0) ? layout->table1 : layout->table2;
for (int i = 0; i < 128; i++)
{
// Reverse the operation we do in -postXEvent:
const int x11KeyCode = carbonToX11[i];
if (!x11KeyCode)
{
outTable[i] = 0;
continue;
}
// NOTE: Not using the group here. It just works with 0 instead...
KeySym sym = XkbKeycodeToKeysym(_display, x11KeyCode, 0, shift);
if (sym != NoSymbol)
outTable[i] = X11KeySymToUCS(sym);
else
outTable[i] = 0;
}
}
XkbFreeClientMap(pKBDesc, XkbAllClientInfoMask, true);
NSString *name = @"?", *fullName = @"?";
if (fullName != NULL)
{
char *group = XGetAtomName(_display, desc->names->groups[state.group]);
if (group != NULL)
{
fullName = [NSString stringWithUTF8String: group];
XFree(group);
}
}
XkbRF_VarDefsRec vd;
if (name != NULL && XkbRF_GetNamesProp(_display, NULL, &vd))
{
char* saveptr;
char *tok = strtok_r(vd.layout, ",", &saveptr);
for (int i = 0; i < state.group; i++)
{
tok = strtok_r(NULL, ",", &saveptr);
if (tok == NULL)
break;
}
if (tok != NULL)
{
name = [NSString stringWithUTF8String: tok];
}
}
CGSKeyboardLayout* cgsLayout = [CGSKeyboardLayout new];
[cgsLayout setLayout: &layout->layout length: sizeof(struct MyLayout)];
cgsLayout.name = name;
cgsLayout.fullName = fullName;
_keyboardLayout = cgsLayout;
_keyboardLayoutGroup = state.group;
}
-(CGPoint) mouseLocation
{
Window child, root = DefaultRootWindow(_display);
int root_x, root_y;
int win_x, win_y;
unsigned int mask;
XQueryPointer(_display, root, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask);
return CGPointMake(root_x, root_y);
}
-(void) processXEvent:(XEvent*) event
{
switch (event->type)
{
case KeyPress:
case KeyRelease:
break;
case ButtonPress:
break;
case ButtonRelease:
break;
case MotionNotify:
break;
case EnterNotify:
break;
case FocusIn:
break;
case FocusOut:
break;
case KeymapNotify:
break;
case Expose:
break;
case ConfigureNotify:
break;
case ClientMessage:
{
static Atom wmDeleteWindowAtom;
if (!wmDeleteWindowAtom)
wmDeleteWindowAtom = XInternAtom(_display, "WM_DELETE_WINDOW", False);
if (event->xclient.format == 32 && event->xclient.data.l[0] == wmDeleteWindowAtom)
; // platformWindowWillClose
break;
}
default:
if (/*event->type == _xkbEventBase + XkbMapNotify ||*/ event->type == _xkbEventBase + XkbStateNotify)
{
XkbEvent* xkbevt = (XkbEvent*) event;
// Invalidate cached keyboard layout information
if (_keyboardLayout && _keyboardLayoutGroup != xkbevt->state.group)
{
// TODO: Emit kTISNotifySelectedKeyboardInputSourceChanged via NSDistributedNotificationCenter
@synchronized (self)
{
[_keyboardLayout release];
_keyboardLayout = nil;
}
_keyboardLayoutGroup = xkbevt->state.group;
}
break;
}
else if (event->type == _xrrEventBase + RRScreenChangeNotify || event->type == _xrrEventBase + RRNotify)
{
// Invalidate cached information
if (_screens)
{
@synchronized (self)
{
[_screens release];
_screens = nil;
}
}
}
}
}
-(void) processPendingEvents
{
while (XPending(_display) > 0)
{
XEvent event;
if (XNextEvent(_display, &event) == Success)
[self processXEvent: &event];
}
}
-(void) _doGetScreenInformation
{
}
-(NSArray<CGSScreen*>*) createScreens
{
@synchronized (self)
{
if (!_screens)
[self _doGetScreenInformation];
return [_screens retain];
}
}
-(CGSWindow*) newWindow:(CGSRegionRef)region
{
}
+(BOOL) isAvailable
{
if (getenv("DISPLAY") != NULL)
return YES;
// TODO: we could be a little smarter here
return NO;
}
@end

View File

@ -0,0 +1,28 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CGSSURFACEX11_H
#define CGSSURFACEX11_H
#import <CoreGraphics/CGSSurface.h>
@interface CGSSurfaceX11 : CGSSurface
@end
#endif

View File

@ -0,0 +1,19 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import "CGSSurfaceX11.h"

View File

@ -0,0 +1,28 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CGSWINDOWX11_H
#define CGSWINDOWX11_H
#import <CoreGraphics/CGSWindow.h>
@interface CGSWindowX11 : CGSWindow
@end
#endif

View File

@ -0,0 +1,20 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#import "CGSWindowX11.h"

View File

@ -0,0 +1,55 @@
function(add_backend name)
cmake_parse_arguments(BACKEND "" "INFO_PLIST" "SOURCES;DEPENDENCIES;RESOURCES" ${ARGN})
set(path "/System/Library/Frameworks/CoreGraphics.framework/Versions/C/Resources/Backends/${name}.backend/Contents")
set(DYLIB_INSTALL_NAME "${path}/MacOS/${name}")
add_darling_library(${name}_cgbackend SHARED ${BACKEND_SOURCES})
set_target_properties(${name}_cgbackend PROPERTIES OUTPUT_NAME "${name}" SUFFIX "" PREFIX "")
make_fat(${name}_cgbackend)
if (BACKEND_DEPENDENCIES)
target_link_libraries(${name}_cgbackend PRIVATE ${BACKEND_DEPENDENCIES})
endif (BACKEND_DEPENDENCIES)
install(TARGETS ${name}_cgbackend DESTINATION "libexec/darling${path}/MacOS")
install(FILES ${BACKEND_INFO_PLIST} DESTINATION "libexec/darling${path}" RENAME Info.plist)
if (BACKEND_RESOURCES)
while (BACKEND_RESOURCES)
list(GET BACKEND_RESOURCES 0 res_install_path)
list(GET BACKEND_RESOURCES 1 res_source_path)
get_filename_component(res_install_dir ${res_install_path} DIRECTORY)
get_filename_component(res_install_name ${res_install_path} NAME)
install(FILES ${res_source_path}
DESTINATION libexec/darling${path}/Resources/${res_install_dir}
RENAME ${res_install_name})
list(REMOVE_AT BACKEND_RESOURCES 0 1)
endwhile (BACKEND_RESOURCES)
endif (BACKEND_RESOURCES)
endfunction(add_backend)
add_backend(X11
SOURCES
CGSConnectionX11.m
CGSWindowX11.m
CGSSurfaceX11.m
X11KeySymToUCS.m
INFO_PLIST
Info.plist
DEPENDENCIES
objc
system
CoreFoundation
Foundation
AppKit
Onyx2D
CoreGraphics
OpenGL
QuartzCore
# native libraries
X11
XRandR
Xcursor
fontconfig
xkbfile
)

View File

@ -0,0 +1,238 @@
#ifndef _CARBONKEYS_H
#define _CARBONKEYS_H
#include <stdint.h>
#include <HIToolbox/Events.h>
// The contents of this file are hardware specific to a certain degree,
// but this is probably as good as we can do.
// The only hardware-independ codes we can get from X11 are keysyms,
// but those are _after_ the keyboard layout is applied, so definitely
// not something we could easily map to Carbon constants.
// Missing:
// kVK_ANSI_KeypadEquals
// kVK_Function
// kVK_F16
// kVK_F17
// kVK_F18
// kVK_F19
// kVK_F20
// kVK_Help
static const uint8_t x11ToCarbon[256] = {
[38] = kVK_ANSI_A,
[39] = kVK_ANSI_S,
[40] = kVK_ANSI_D,
[41] = kVK_ANSI_F,
[43] = kVK_ANSI_H,
[42] = kVK_ANSI_G,
[52] = kVK_ANSI_Z,
[53] = kVK_ANSI_X,
[54] = kVK_ANSI_C,
[55] = kVK_ANSI_V,
[56] = kVK_ANSI_B,
[24] = kVK_ANSI_Q,
[25] = kVK_ANSI_W,
[26] = kVK_ANSI_E,
[27] = kVK_ANSI_R,
[29] = kVK_ANSI_Y,
[28] = kVK_ANSI_T,
[10] = kVK_ANSI_1,
[11] = kVK_ANSI_2,
[12] = kVK_ANSI_3,
[13] = kVK_ANSI_4,
[15] = kVK_ANSI_6,
[14] = kVK_ANSI_5,
[21] = kVK_ANSI_Equal,
[18] = kVK_ANSI_9,
[16] = kVK_ANSI_7,
[20] = kVK_ANSI_Minus,
[17] = kVK_ANSI_8,
[19] = kVK_ANSI_0,
[35] = kVK_ANSI_RightBracket,
[32] = kVK_ANSI_O,
[30] = kVK_ANSI_U,
[34] = kVK_ANSI_LeftBracket,
[31] = kVK_ANSI_I,
[33] = kVK_ANSI_P,
[46] = kVK_ANSI_L,
[44] = kVK_ANSI_J,
[48] = kVK_ANSI_Quote,
[45] = kVK_ANSI_K,
[47] = kVK_ANSI_Semicolon,
[51] = kVK_ANSI_Backslash,
[59] = kVK_ANSI_Comma,
[61] = kVK_ANSI_Slash,
[57] = kVK_ANSI_N,
[58] = kVK_ANSI_M,
[60] = kVK_ANSI_Period,
[49] = kVK_ANSI_Grave,
[91] = kVK_ANSI_KeypadDecimal,
[63] = kVK_ANSI_KeypadMultiply,
[86] = kVK_ANSI_KeypadPlus,
[77] = kVK_ANSI_KeypadClear,
[106] = kVK_ANSI_KeypadDivide,
[104] = kVK_ANSI_KeypadEnter,
[82] = kVK_ANSI_KeypadMinus,
[90] = kVK_ANSI_Keypad0,
[87] = kVK_ANSI_Keypad1,
[88] = kVK_ANSI_Keypad2,
[89] = kVK_ANSI_Keypad3,
[83] = kVK_ANSI_Keypad4,
[84] = kVK_ANSI_Keypad5,
[85] = kVK_ANSI_Keypad6,
[79] = kVK_ANSI_Keypad7,
[80] = kVK_ANSI_Keypad8,
[81] = kVK_ANSI_Keypad9,
[36] = kVK_Return,
[23] = kVK_Tab,
[65] = kVK_Space,
[22] = kVK_Delete,
[9] = kVK_Escape,
[64] = kVK_Command,
[50] = kVK_Shift,
[66] = kVK_CapsLock,
[133] = kVK_Option,
[37] = kVK_Control,
[62] = kVK_RightShift,
[134] = kVK_RightOption,
[105] = kVK_RightControl,
[123] = kVK_VolumeUp,
[122] = kVK_VolumeDown,
[121] = kVK_Mute,
[71] = kVK_F5,
[72] = kVK_F6,
[73] = kVK_F7,
[69] = kVK_F3,
[74] = kVK_F8,
[75] = kVK_F9,
[95] = kVK_F11,
[107] = kVK_F13,
[78] = kVK_F14,
[76] = kVK_F10,
[96] = kVK_F12,
[127] = kVK_F15,
[110] = kVK_Home,
[112] = kVK_PageUp,
[119] = kVK_ForwardDelete,
[70] = kVK_F4,
[115] = kVK_End,
[68] = kVK_F2,
[117] = kVK_PageDown,
[67] = kVK_F1,
[113] = kVK_LeftArrow,
[114] = kVK_RightArrow,
[116] = kVK_DownArrow,
[111] = kVK_UpArrow,
};
static const uint8_t carbonToX11[256] = {
[kVK_ANSI_A] = 38,
[kVK_ANSI_S] = 39,
[kVK_ANSI_D] = 40,
[kVK_ANSI_F] = 41,
[kVK_ANSI_H] = 43,
[kVK_ANSI_G] = 42,
[kVK_ANSI_Z] = 52,
[kVK_ANSI_X] = 53,
[kVK_ANSI_C] = 54,
[kVK_ANSI_V] = 55,
[kVK_ANSI_B] = 56,
[kVK_ANSI_Q] = 24,
[kVK_ANSI_W] = 25,
[kVK_ANSI_E] = 26,
[kVK_ANSI_R] = 27,
[kVK_ANSI_Y] = 29,
[kVK_ANSI_T] = 28,
[kVK_ANSI_1] = 10,
[kVK_ANSI_2] = 11,
[kVK_ANSI_3] = 12,
[kVK_ANSI_4] = 13,
[kVK_ANSI_6] = 15,
[kVK_ANSI_5] = 14,
[kVK_ANSI_Equal] = 21,
[kVK_ANSI_9] = 18,
[kVK_ANSI_7] = 16,
[kVK_ANSI_Minus] = 20,
[kVK_ANSI_8] = 17,
[kVK_ANSI_0] = 19,
[kVK_ANSI_RightBracket] = 35,
[kVK_ANSI_O] = 32,
[kVK_ANSI_U] = 30,
[kVK_ANSI_LeftBracket] = 34,
[kVK_ANSI_I] = 31,
[kVK_ANSI_P] = 33,
[kVK_ANSI_L] = 46,
[kVK_ANSI_J] = 44,
[kVK_ANSI_Quote] = 48,
[kVK_ANSI_K] = 45,
[kVK_ANSI_Semicolon] = 47,
[kVK_ANSI_Backslash] = 51,
[kVK_ANSI_Comma] = 59,
[kVK_ANSI_Slash] = 61,
[kVK_ANSI_N] = 57,
[kVK_ANSI_M] = 58,
[kVK_ANSI_Period] = 60,
[kVK_ANSI_Grave] = 49,
[kVK_ANSI_KeypadDecimal] = 91,
[kVK_ANSI_KeypadMultiply] = 63,
[kVK_ANSI_KeypadPlus] = 86,
[kVK_ANSI_KeypadClear] = 77,
[kVK_ANSI_KeypadDivide] = 106,
[kVK_ANSI_KeypadEnter] = 104,
[kVK_ANSI_KeypadMinus] = 82,
[kVK_ANSI_Keypad0] = 90,
[kVK_ANSI_Keypad1] = 87,
[kVK_ANSI_Keypad2] = 88,
[kVK_ANSI_Keypad3] = 89,
[kVK_ANSI_Keypad4] = 83,
[kVK_ANSI_Keypad5] = 84,
[kVK_ANSI_Keypad6] = 85,
[kVK_ANSI_Keypad7] = 79,
[kVK_ANSI_Keypad8] = 80,
[kVK_ANSI_Keypad9] = 81,
[kVK_Return] = 36,
[kVK_Tab] = 23,
[kVK_Space] = 65,
[kVK_Delete] = 22,
[kVK_Escape] = 9,
[kVK_Command] = 64,
[kVK_Shift] = 50,
[kVK_CapsLock] = 66,
[kVK_Option] = 133,
[kVK_Control] = 37,
[kVK_RightShift] = 62,
[kVK_RightOption] = 134,
[kVK_RightControl] = 105,
[kVK_VolumeUp] = 123,
[kVK_VolumeDown] = 122,
[kVK_Mute] = 121,
[kVK_F5] = 71,
[kVK_F6] = 72,
[kVK_F7] = 73,
[kVK_F3] = 69,
[kVK_F8] = 74,
[kVK_F9] = 75,
[kVK_F11] = 95,
[kVK_F13] = 107,
[kVK_F14] = 78,
[kVK_F10] = 76,
[kVK_F12] = 96,
[kVK_F15] = 127,
[kVK_Home] = 110,
[kVK_PageUp] = 112,
[kVK_ForwardDelete] = 119,
[kVK_F4] = 70,
[kVK_End] = 115,
[kVK_F2] = 68,
[kVK_PageDown] = 117,
[kVK_F1] = 67,
[kVK_LeftArrow] = 113,
[kVK_RightArrow] = 114,
[kVK_DownArrow] = 116,
[kVK_UpArrow] = 111,
};
#endif

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>X11</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.darlinghq.backends.X11</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>OBJC</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>NSPriority</key>
<integer>200</integer>
<key>NSPrincipalClass</key>
<string>CGSConnectionX11</string>
</dict>
</plist>

View File

@ -0,0 +1,7 @@
#ifndef X11KEYSYMTOUCS_H
#define X11KEYSYMTOUCS_H
#include <stdint.h>
uint32_t X11KeySymToUCS(uint32_t x11KeySym);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -20,16 +20,122 @@
#ifndef _CGEVENT_H_
#define _CGEVENT_H_
#import <CoreGraphics/CGError.h>
#include <CoreGraphics/CGEventTypes.h>
#import <CoreGraphics/CGGeometry.h>
#include <CoreGraphics/CGGeometry.h>
#include <CoreGraphics/CGError.h>
#include <CoreGraphics/CGRemoteOperation.h>
#include <CoreGraphics/CoreGraphicsPrivate.h>
__BEGIN_DECLS
extern void CGEventPost(CGEventTapLocation tapLocation, CGEventRef event);
CGError CGPostMouseEvent(CGPoint mouseCursorPosition,
boolean_t updateMouseCursorPosition,
CGButtonCount buttonCount, boolean_t mouseButtonDown,
...);
extern CFTypeID CGEventGetTypeID(void);
extern CGEventRef _Nullable CGEventCreate(CGEventSourceRef _Nullable source);
extern CFDataRef _Nullable CGEventCreateData(
CFAllocatorRef _Nullable allocator,
CGEventRef _Nullable event);
extern CGEventRef _Nullable CGEventCreateFromData(
CFAllocatorRef _Nullable allocator, CFDataRef _Nullable data);
extern CGEventRef _Nullable CGEventCreateMouseEvent(
CGEventSourceRef _Nullable source,
CGEventType mouseType, CGPoint mouseCursorPosition,
CGMouseButton mouseButton);
extern CGEventRef _Nullable CGEventCreateKeyboardEvent(
CGEventSourceRef _Nullable source,
CGKeyCode virtualKey, bool keyDown);
extern CGEventRef _Nullable CGEventCreateScrollWheelEvent(
CGEventSourceRef _Nullable source,
CGScrollEventUnit units, uint32_t wheelCount, int32_t wheel1, ...);
extern CGEventRef _Nullable CGEventCreateScrollWheelEvent2(
CGEventSourceRef _Nullable source,
CGScrollEventUnit units, uint32_t wheelCount, int32_t wheel1, int32_t wheel2, int32_t wheel3);
extern CGEventRef _Nullable CGEventCreateCopy(CGEventRef _Nullable event);
extern CGEventSourceRef _Nullable CGEventCreateSourceFromEvent(
CGEventRef _Nullable event);
extern void CGEventSetSource(CGEventRef _Nullable event,
CGEventSourceRef _Nullable source);
extern CGEventType CGEventGetType(CGEventRef _Nullable event);
extern void CGEventSetType(CGEventRef _Nullable event, CGEventType type);
extern CGEventTimestamp CGEventGetTimestamp(CGEventRef _Nullable event);
extern void CGEventSetTimestamp(CGEventRef _Nullable event,
CGEventTimestamp timestamp);
extern CGPoint CGEventGetLocation(CGEventRef _Nullable event);
extern CGPoint CGEventGetUnflippedLocation(CGEventRef _Nullable event);
extern void CGEventSetLocation(CGEventRef _Nullable event, CGPoint location);
extern CGEventFlags CGEventGetFlags(CGEventRef _Nullable event);
extern void CGEventSetFlags(CGEventRef _Nullable event, CGEventFlags flags);
extern void CGEventKeyboardGetUnicodeString(CGEventRef _Nullable event,
UniCharCount maxStringLength, UniCharCount *_Nullable actualStringLength,
UniChar * _Nullable unicodeString);
extern void CGEventKeyboardSetUnicodeString(CGEventRef _Nullable event,
UniCharCount stringLength, const UniChar * _Nullable unicodeString);
extern int64_t CGEventGetIntegerValueField(CGEventRef _Nullable event,
CGEventField field);
extern void CGEventSetIntegerValueField(CGEventRef _Nullable event,
CGEventField field, int64_t value);
extern double CGEventGetDoubleValueField(CGEventRef _Nullable event,
CGEventField field);
extern void CGEventSetDoubleValueField(CGEventRef _Nullable event,
CGEventField field, double value);
extern CFMachPortRef _Nullable CGEventTapCreate(CGEventTapLocation tap,
CGEventTapPlacement place, CGEventTapOptions options,
CGEventMask eventsOfInterest, CGEventTapCallBack callback,
void * _Nullable userInfo);
extern CFMachPortRef _Nullable CGEventTapCreateForPSN(
void * processSerialNumber,
CGEventTapPlacement place, CGEventTapOptions options,
CGEventMask eventsOfInterest, CGEventTapCallBack callback,
void *_Nullable userInfo);
extern CFMachPortRef _Nullable CGEventTapCreateForPid(pid_t pid,
CGEventTapPlacement place, CGEventTapOptions options,
CGEventMask eventsOfInterest, CGEventTapCallBack callback,
void * _Nullable userInfo);
extern void CGEventTapEnable(CFMachPortRef tap, bool enable);
extern bool CGEventTapIsEnabled(CFMachPortRef tap);
extern void CGEventTapPostEvent(CGEventTapProxy _Nullable proxy,
CGEventRef _Nullable event);
extern void CGEventPost(CGEventTapLocation tap, CGEventRef _Nullable event);
extern void CGEventPostToPSN(void * _Nullable processSerialNumber,
CGEventRef _Nullable event);
extern void CGEventPostToPid( pid_t pid,
CGEventRef _Nullable event);
extern CGError CGGetEventTapList(uint32_t maxNumberOfTaps,
CGEventTapInformation * _Nullable tapList,
uint32_t * _Nullable eventTapCount);
__END_DECLS
#endif

View File

@ -1,18 +0,0 @@
#ifndef _CGS_H_
#define _CGS_H_
#include <CoreGraphics/CGError.h>
#ifdef __cplusplus
extern "C" {
#endif
// Private APIs
CGError CGSSetDenyWindowServerConnections(Boolean deny);
void CGSShutdownServerConnections(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -18,30 +18,46 @@
*/
#ifndef CGSCONNECTION_H
#define CGSCONNECTION_H
#include <CoreGraphics/CoreGraphicsPrivate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSDictionary.h>
#include <CoreGraphics/CoreGraphicsPrivate.h>
#include <CoreServices/UnicodeUtilities.h>
#include <stdatomic.h>
@class CGSWindow;
@class CGSScreen;
@class CGSKeyboardLayout;
@interface CGSConnection : NSObject {
CGSConnectionID _connectionId;
_Atomic CGSWindowID _nextWindowId;
NSMutableDictionary<NSNumber *, CGSWindow *> *_windows;
CGSConnectionID _connectionId;
_Atomic CGSWindowID _nextWindowId;
NSMutableDictionary<NSNumber*, CGSWindow*>* _windows;
}
- (instancetype) initWithConnectionID: (CGSConnectionID) connId;
- (void) dealloc;
- (CGSWindow *) windowForId: (CGSWindowID) winId;
- (CGSWindow *) newWindow: (CGSRegionRef) region;
- (CGError) destroyWindow: (CGSWindowID) winId;
-(instancetype) initWithConnectionID:(CGSConnectionID)connId;
-(void) dealloc;
-(CGSWindow*) windowForId:(CGSWindowID)winId;
-(CGSWindow*) newWindow:(CGSRegionRef)region;
-(CGError) destroyWindow:(CGSWindowID)winId;
+ (BOOL) isAvailable;
// Mouse location in CG coordinates, i.e. relative to the upper left corner
-(CGPoint) mouseLocation;
- (void) _windowInvalidated: (CGSWindowID) winId;
-(BOOL) setMode:(NSDictionary *)mode forScreen:(int)screenIndex;
// Implementations should cache this information, because it may be accessed frequently
-(NSArray<CGSScreen*>*) createScreens;
// Implementations should also emit kTISNotifySelectedKeyboardInputSourceChanged via NSDistributedNotificationCenter
// if layout changes.
// Implementations should also cache this and return the same pointer if nothing changed.
-(CGSKeyboardLayout*) createKeyboardLayout;
+(BOOL) isAvailable;
-(void) _windowInvalidated: (CGSWindowID) winId;
// For CGL
- (void *) nativeDisplay;
-(void*) nativeDisplay;
@end
#endif

View File

@ -0,0 +1,42 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CGSKEYBOARDLAYOUT_H
#define CGSKEYBOARDLAYOUT_H
#import <Foundation/NSString.h>
#include <CoreServices/UnicodeUtilities.h>
#include <stdint.h>
@interface CGSKeyboardLayout : NSObject {
UCKeyboardLayout* _layout;
uint32_t _layoutLength;
NSString* _name;
NSString* _fullName;
}
@property(readwrite, strong) NSString* name;
@property(readwrite, strong) NSString* fullName;
@property(readonly) UCKeyboardLayout* layout;
@property(readonly) uint32_t layoutLength;
-(void) setLayout:(UCKeyboardLayout*) layout length:(uint32_t) length;
@end
#endif

View File

@ -0,0 +1,42 @@
/*
This file is part of Darling.
Copyright (C) 2020 Lubos Dolezel
Darling 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 3 of the License, or
(at your option) any later version.
Darling 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 Darling. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CGSSCREEN_H
#define CGSSCREEN_H
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSData.h>
@interface CGSScreen : NSObject {
NSData* _edid;
NSArray<NSDictionary*>* _modes;
CFIndex _currentMode;
uint32_t _currentModeHeightCached;
}
@property(readwrite, strong) NSData* edid;
@property(readwrite, strong) NSArray<NSDictionary*>* modes;
@property(readwrite, assign) CFIndex currentMode;
@property(readonly) uint32_t currentModeHeight;
@end
#endif

View File

@ -18,42 +18,42 @@
*/
#ifndef CGSWINDOW_H
#define CGSWINDOW_H
#include <CoreGraphics/CoreGraphicsPrivate.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSDictionary.h>
#include <CoreGraphics/CoreGraphicsPrivate.h>
#include <stdatomic.h>
@class CGSSurface;
@class CGSConnection;
@interface CGSWindow : NSObject {
CGSConnection *_connection;
CGSWindowID _windowId;
_Atomic CGSSurfaceID _nextSurfaceId;
NSMutableDictionary<NSNumber *, CGSSurface *> *_surfaces;
CGSConnection* _connection;
CGSWindowID _windowId;
_Atomic CGSSurfaceID _nextSurfaceId;
NSMutableDictionary<NSNumber*, CGSSurface*>* _surfaces;
}
- (instancetype) initWithRegion: (CGSRegionRef) region
connection: (CGSConnection *) connection
windowID: (CGSWindowID) windowID;
- (void) dealloc;
- (CGSSurface *) surfaceForId: (CGSSurfaceID) surfaceId;
-(instancetype) initWithRegion:(CGSRegionRef) region
connection:(CGSConnection*) connection
windowID:(CGSWindowID) windowID;
-(void) dealloc;
-(CGSSurface*) surfaceForId:(CGSSurfaceID) surfaceId;
- (CGError) orderWindow: (CGSWindowOrderingMode) place
relativeTo: (CGSWindow *) window;
- (CGError) moveTo: (const CGPoint *) point;
- (CGError) setRegion: (CGSRegionRef) region;
- (CGError) getRect: (CGRect *) outRect;
- (CGError) setProperty: (CFStringRef) key value: (CFTypeRef) value;
- (CGError) getProperty: (CFStringRef) key value: (CFTypeRef *) value;
- (void) invalidate;
-(CGError) orderWindow:(CGSWindowOrderingMode) place relativeTo:(CGSWindow*) window;
-(CGError) moveTo:(const CGPoint*) point;
-(CGError) setRegion:(CGSRegionRef) region;
-(CGError) getRect:(CGRect*) outRect;
-(CGError) setProperty:(CFStringRef) key value:(CFTypeRef) value;
-(CGError) getProperty:(CFStringRef) key value:(CFTypeRef*) value;
-(void) invalidate;
// Used, for example, by CGWindowContextCreate()
- (void *) nativeWindow;
- (CGSSurface *) createSurface;
-(void*) nativeWindow;
-(CGSSurface*) createSurface;
@property(readonly) CGSWindowID windowId;
@property (readonly) CGSWindowID windowId;
- (void) _surfaceInvalidated: (CGSSurfaceID) surfaceId;
-(void) _surfaceInvalidated:(CGSSurfaceID) surfaceId;
@end

View File

@ -1,7 +1,8 @@
#ifndef COREGRAPHICSPRIVATE_H
#define COREGRAPHICSPRIVATE_H
#include <CoreFoundation/CoreFoundation.h>
#include <CoreGraphics/CoreGraphics.h>
#include <IOKit/hidsystem/IOLLEvent.h>
#include <CoreFoundation/CoreFoundation.h>
__BEGIN_DECLS
@ -12,31 +13,33 @@ __BEGIN_DECLS
typedef int CGSConnectionID;
typedef int CGSWindowID;
typedef int CGSSurfaceID;
typedef unsigned long CGSNotificationType;
typedef CFMutableDictionaryRef CGSDictionaryObj;
typedef CFTypeRef CGSRegionRef;
#define CGSDefaultConnection _CGSDefaultConnection()
enum {
kCGSErrorSuccess = 0,
enum
{
kCGSErrorSuccess = 0,
};
typedef enum {
kCGSOrderBelow = -1,
kCGSOrderOut, /* hides the window */
kCGSOrderAbove,
kCGSOrderIn /* shows the window */
kCGSOrderBelow = -1,
kCGSOrderOut, /* hides the window */
kCGSOrderAbove,
kCGSOrderIn /* shows the window */
} CGSWindowOrderingMode;
typedef enum {
kCGSBackingNonRetianed,
kCGSBackingRetained,
kCGSBackingBuffered,
kCGSBackingNonRetianed,
kCGSBackingRetained,
kCGSBackingBuffered,
} CGSBackingType;
extern void CGSInitialize(void);
extern CGError CGSNewConnection(_Nullable CGSDictionaryObj attribs,
CGSConnectionID *connId);
extern CGError CGSNewConnection(_Nullable CGSDictionaryObj attribs, CGSConnectionID* connId);
extern CGError CGSReleaseConnection(CGSConnectionID connId);
extern CGSConnectionID _CGSDefaultConnection(void);
extern CGSConnectionID CGSMainConnectionID(void);
@ -44,81 +47,95 @@ extern CGError CGSSetDenyWindowServerConnections(Boolean deny);
extern void CGSShutdownServerConnections(void);
// CGSRegion
extern CGError CGSNewRegionWithRect(const CGRect *rect,
CGSRegionRef *newRegion);
extern CGError CGSNewRegionWithRect(const CGRect * rect, CGSRegionRef *newRegion);
extern void CGSRegionRelease(CGSRegionRef reg);
extern void CGSRegionRetain(CGSRegionRef reg);
extern void
CGSRegionToRect(CGSRegionRef reg,
CGRect *rect); // This is non-standard. We should support
// non-rectangular regions instead
extern void CGSRegionToRect(CGSRegionRef reg, CGRect* rect); // This is non-standard. We should support non-rectangular regions instead
extern bool CGSRegionIsRectangular(CGSRegionRef reg);
extern CGError CGSNewWindow(CGSConnectionID conn, CFIndex flags, float, float,
const CGSRegionRef region, CGSWindowID *windowID);
extern CGError CGSNewWindow(CGSConnectionID conn, CFIndex flags, float, float, const CGSRegionRef region, CGSWindowID* windowID);
extern CGError CGSReleaseWindow(CGSConnectionID cid, CGSWindowID wid);
extern CGError CGSSetWindowShape(CGSConnectionID cid, CGSWindowID wid,
float x_offset, float y_offset,
const CGSRegionRef shape);
extern OSStatus CGSOrderWindow(CGSConnectionID cid, CGSWindowID wid,
CGSWindowOrderingMode place,
CGSWindowID relativeToWindow);
extern CGError CGSMoveWindow(CGSConnectionID cid, CGSWindowID wid,
const CGPoint *window_pos);
extern CGError CGSSetWindowOpacity(CGSConnectionID cid, CGSWindowID wid,
bool isOpaque);
extern CGError CGSSetWindowAlpha(CGSConnectionID cid, CGSWindowID wid,
float alpha);
extern CGError CGSSetWindowLevel(CGSConnectionID cid, CGSWindowID wid,
CGWindowLevel level);
extern CGError CGSSetWindowShape(CGSConnectionID cid, CGSWindowID wid, float x_offset, float y_offset, const CGSRegionRef shape);
extern OSStatus CGSOrderWindow(CGSConnectionID cid, CGSWindowID wid, CGSWindowOrderingMode place, CGSWindowID relativeToWindow);
extern CGError CGSMoveWindow(CGSConnectionID cid, CGSWindowID wid, const CGPoint *window_pos);
extern CGError CGSSetWindowOpacity(CGSConnectionID cid, CGSWindowID wid, bool isOpaque);
extern CGError CGSSetWindowAlpha(CGSConnectionID cid, CGSWindowID wid, float alpha);
extern CGError CGSSetWindowLevel(CGSConnectionID cid, CGSWindowID wid, CGWindowLevel level);
// Subwindows (for CGL)
extern CGError CGSAddSurface(CGSConnectionID cid, CGSWindowID wid,
CGSSurfaceID *sid);
extern CGError CGSRemoveSurface(CGSConnectionID cid, CGSWindowID wid,
CGSSurfaceID sid);
extern CGError CGSSetSurfaceBounds(CGSConnectionID cid, CGSWindowID wid,
CGSSurfaceID sid, CGRect rect);
extern CGError CGSOrderSurface(CGSConnectionID cid, CGSWindowID wid,
CGSSurfaceID sid, int a, int b);
// extern CGLError CGLSetSurface(CGLContextObj gl, CGSConnectionID cid,
// CGSWindowID wid, CGSSurfaceID sid); // in CGL
extern CGError CGSAddSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID *sid);
extern CGError CGSRemoveSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid);
extern CGError CGSSetSurfaceBounds(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid, CGRect rect);
extern CGError CGSOrderSurface(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid, int a, int b);
//extern CGLError CGLSetSurface(CGLContextObj gl, CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid); // in CGL
// extern CGContextRef CGWindowContextCreate(CGSConnectionID cid, CGSWindowID
// wid, CFDictionaryRef options); // in CGL
//extern CGContextRef CGWindowContextCreate(CGSConnectionID cid, CGSWindowID wid, CFDictionaryRef options); // in CGL
extern CGError CGSSetWindowTags(CGSConnectionID cid, CGSWindowID wid,
const int tags[2], size_t tag_size);
extern CGError CGSClearWindowTags(CGSConnectionID cid, CGSWindowID wid,
const int tags[2], size_t tag_size);
extern CGError CGSAddActivationRegion(CGSConnectionID cid, CGSWindowID wid,
CGSRegionRef region);
extern CGError CGSSetWindowTags(CGSConnectionID cid, CGSWindowID wid, const int tags[2], size_t tag_size);
extern CGError CGSClearWindowTags(CGSConnectionID cid, CGSWindowID wid, const int tags[2], size_t tag_size);
extern CGError CGSAddActivationRegion(CGSConnectionID cid, CGSWindowID wid, CGSRegionRef region);
extern CGError CGSClearActivationRegion(CGSConnectionID cid, CGSWindowID wid);
extern CGError CGSAddDragRegion(CGSConnectionID cid, CGSWindowID wid,
CGSRegionRef region);
extern CGError CGSAddDragRegion(CGSConnectionID cid, CGSWindowID wid, CGSRegionRef region);
extern CGError CGSClearDragRegion(CGSConnectionID cid, CGSWindowID wid);
extern CGError CGSAddTrackingRect(CGSConnectionID cid, CGSWindowID wid,
CGRect rect);
extern CGError CGSAddTrackingRect(CGSConnectionID cid, CGSWindowID wid, CGRect rect);
extern CGError CGSRemoveAllTrackingAreas(CGSConnectionID cid, CGSWindowID wid);
extern CFStringRef CGSCopyManagedDisplayForWindow(const CGSConnectionID cid,
CGSWindowID wid);
extern CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid,
CGRect *outRect);
extern CFStringRef CGSCopyManagedDisplayForWindow(const CGSConnectionID cid, CGSWindowID wid);
extern CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid, CGRect *outRect);
extern const CFStringRef kCGSWindowTitle;
extern CGError CGSSetWindowTitle(CGSConnectionID cid, CGSWindowID wid,
CFStringRef title);
extern CGError CGSGetWindowProperty(CGSConnectionID cid, CGSWindowID wid,
CFStringRef key, CFTypeRef *outValue);
extern CGError CGSSetWindowProperty(CGSConnectionID cid, CGSWindowID wid,
CFStringRef key, CFTypeRef value);
extern CGError CGSSetWindowTitle(CGSConnectionID cid, CGSWindowID wid, CFStringRef title);
extern CGError CGSGetWindowProperty(CGSConnectionID cid, CGSWindowID wid, CFStringRef key, CFTypeRef *outValue);
extern CGError CGSSetWindowProperty(CGSConnectionID cid, CGSWindowID wid, CFStringRef key, CFTypeRef value);
typedef uint32_t CGSByteCount;
typedef uint16_t CGSEventRecordVersion;
typedef unsigned long CGSEventType;
typedef uint64_t CGSEventRecordTime; /* nanosecond timer */
typedef unsigned long CGSEventFlag;
typedef NXEventData CGSEventRecordData;
struct _CGSEventRecord
{
CGSEventRecordVersion major;
CGSEventRecordVersion minor;
CGSByteCount length; /* Length of complete event record */
CGSEventType type; /* An event type from above */
CGPoint location; /* Base coordinates (global), from upper-left */
CGPoint windowLocation; /* Coordinates relative to window */
CGSEventRecordTime time; /* nanoseconds since startup */
CGSEventFlag flags; /* key state flags */
CGSWindowID window; /* window number of assigned window */
CGSConnectionID connection; /* connection the event came from */
CGSEventRecordData data; /* type-dependent data: 40 bytes */
};
typedef struct _CGSEventRecord CGSEventRecord;
typedef CGSEventRecord *CGSEventRecordPtr;
typedef void(*CGSNotifyProcPtr)(CGSNotificationType type, void* data, unsigned long dataLength, void* client);
// CGSNotificationType:
// 710 + NX event type from IOLLEvent.h
#define CGSNotificationSingleEventType(event) (701 + event)
#define kCGSNotificationAllEvents 0
extern CGError CGSRegisterNotifyProc(CGSNotifyProcPtr proc, CGSNotificationType notificationType, void* client);
extern CGError CGSRemoveNotifyProc(CGSNotifyProcPtr proc, CGSNotificationType notificationType);
// Darling extras, e.g. for CGL
void *_CGSNativeDisplay(CGSConnectionID connId);
void *_CGSNativeWindowForID(CGSConnectionID connId, CGSWindowID winId);
void *_CGSNativeWindowForSurfaceID(CGSConnectionID connId, CGSWindowID winId,
CGSSurfaceID surfaceId);
void* _CGSNativeDisplay(CGSConnectionID connId);
void* _CGSNativeWindowForID(CGSConnectionID connId, CGSWindowID winId);
void* _CGSNativeWindowForSurfaceID(CGSConnectionID connId, CGSWindowID winId, CGSSurfaceID surfaceId);
extern CGEventRef CGEventCreateWithEventRecord(const CGSEventRecordPtr event, uint32_t eventRecordSize);
extern CGError CGEventGetEventRecord(CGEventRef event, CGSEventRecordPtr eventRecord, uint32_t eventRecordSize);
extern CGError CGEventSetEventRecord(CGEventRef event, CGSEventRecordPtr eventRecord, uint32_t eventRecordSize);
extern uint32_t CGEventGetEventRecordSize(CGEventRef event);
#ifdef __OBJC__
@class CGSConnection;
CGSConnection* _CGSConnectionForID(CGSConnectionID connId);
CGSConnection* _CGSConnectionFromEventRecord(const CGSEventRecordPtr record);
#endif
__END_DECLS