mirror of
https://github.com/darlinghq/darling-cocotron.git
synced 2024-11-23 12:09:51 +00:00
CGS work progress
This commit is contained in:
parent
9c53557e4c
commit
b26bedb31c
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
43
CoreGraphics/CGSKeyboardLayout.m
Normal file
43
CoreGraphics/CGSKeyboardLayout.m
Normal 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
46
CoreGraphics/CGSScreen.m
Normal 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
|
||||
|
@ -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)
|
||||
|
57
CoreGraphics/X11.backend/CGSConnectionX11.h
Normal file
57
CoreGraphics/X11.backend/CGSConnectionX11.h
Normal 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
|
||||
|
381
CoreGraphics/X11.backend/CGSConnectionX11.m
Normal file
381
CoreGraphics/X11.backend/CGSConnectionX11.m
Normal 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
|
28
CoreGraphics/X11.backend/CGSSurfaceX11.h
Normal file
28
CoreGraphics/X11.backend/CGSSurfaceX11.h
Normal 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
|
||||
|
19
CoreGraphics/X11.backend/CGSSurfaceX11.m
Normal file
19
CoreGraphics/X11.backend/CGSSurfaceX11.m
Normal 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"
|
28
CoreGraphics/X11.backend/CGSWindowX11.h
Normal file
28
CoreGraphics/X11.backend/CGSWindowX11.h
Normal 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
|
||||
|
20
CoreGraphics/X11.backend/CGSWindowX11.m
Normal file
20
CoreGraphics/X11.backend/CGSWindowX11.m
Normal 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"
|
||||
|
55
CoreGraphics/X11.backend/CMakeLists.txt
Normal file
55
CoreGraphics/X11.backend/CMakeLists.txt
Normal 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
|
||||
)
|
238
CoreGraphics/X11.backend/CarbonKeys.h
Normal file
238
CoreGraphics/X11.backend/CarbonKeys.h
Normal 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
|
26
CoreGraphics/X11.backend/Info.plist
Normal file
26
CoreGraphics/X11.backend/Info.plist
Normal 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>
|
7
CoreGraphics/X11.backend/X11KeySymToUCS.h
Normal file
7
CoreGraphics/X11.backend/X11KeySymToUCS.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef X11KEYSYMTOUCS_H
|
||||
#define X11KEYSYMTOUCS_H
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t X11KeySymToUCS(uint32_t x11KeySym);
|
||||
|
||||
#endif
|
1664
CoreGraphics/X11.backend/X11KeySymToUCS.m
Normal file
1664
CoreGraphics/X11.backend/X11KeySymToUCS.m
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
||||
|
42
CoreGraphics/include/CoreGraphics/CGSKeyboardLayout.h
Normal file
42
CoreGraphics/include/CoreGraphics/CGSKeyboardLayout.h
Normal 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
|
42
CoreGraphics/include/CoreGraphics/CGSScreen.h
Normal file
42
CoreGraphics/include/CoreGraphics/CGSScreen.h
Normal 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user