From 8d0466312a71d2d6c7cfe49aca0226f720f84189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20Oliv=C3=A9r?= Date: Mon, 16 Jun 2014 16:44:26 +0200 Subject: [PATCH 1/9] lots of enchencements: thread safe AXUIelement function calls. added 2 classes: haxView, hawbutton + extended haxwindow: isFulscreen property. + carbon and cocoa frame capabilities. --- Classes/HAXApplication.h | 2 +- Classes/HAXApplication.m | 10 +- Classes/HAXButton.h | 13 ++ Classes/HAXButton.m | 16 ++ Classes/HAXElement+Protected.h | 5 +- Classes/HAXElement.h | 9 +- Classes/HAXElement.m | 259 ++++++++++++++++++++--- Classes/HAXSystem.h | 2 +- Classes/HAXSystem.m | 6 +- Classes/HAXView.h | 26 +++ Classes/HAXView.m | 114 ++++++++++ Classes/HAXWindow.h | 15 +- Classes/HAXWindow.m | 133 ++++++++++-- Classes/NSScreen+PointConvert.h | 17 ++ Classes/NSScreen+PointConvert.m | 78 +++++++ Haxcessibility.xcodeproj/project.pbxproj | 36 +++- 16 files changed, 677 insertions(+), 64 deletions(-) create mode 100644 Classes/HAXButton.h create mode 100644 Classes/HAXButton.m create mode 100644 Classes/HAXView.h create mode 100644 Classes/HAXView.m create mode 100644 Classes/NSScreen+PointConvert.h create mode 100644 Classes/NSScreen+PointConvert.m diff --git a/Classes/HAXApplication.h b/Classes/HAXApplication.h index b1dcf48..af1ab6f 100644 --- a/Classes/HAXApplication.h +++ b/Classes/HAXApplication.h @@ -2,7 +2,7 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import +#import "HAXElement.h" @class HAXWindow; diff --git a/Classes/HAXApplication.m b/Classes/HAXApplication.m index 1485543..859dc2b 100644 --- a/Classes/HAXApplication.m +++ b/Classes/HAXApplication.m @@ -8,7 +8,8 @@ @implementation HAXApplication -+(instancetype)applicationWithPID:(pid_t)pid; { ++(instancetype)applicationWithPID:(pid_t)pid; +{ AXUIElementRef app = AXUIElementCreateApplication(pid); id result = nil; if (app) { @@ -18,12 +19,14 @@ +(instancetype)applicationWithPID:(pid_t)pid; { return result; } --(HAXWindow *)focusedWindow { +-(HAXWindow *)focusedWindow +{ NSError *error = nil; return [self elementOfClass:[HAXWindow class] forKey:(__bridge NSString *)kAXFocusedWindowAttribute error:&error]; } --(NSArray *)windows { +-(NSArray *)windows +{ NSArray *axWindowObjects = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXWindowsAttribute error:nil]); NSMutableArray *result = [NSMutableArray arrayWithCapacity:[axWindowObjects count]]; for (id axObject in axWindowObjects) { @@ -32,4 +35,5 @@ -(NSArray *)windows { return result; } + @end diff --git a/Classes/HAXButton.h b/Classes/HAXButton.h new file mode 100644 index 0000000..430a3b8 --- /dev/null +++ b/Classes/HAXButton.h @@ -0,0 +1,13 @@ +// +// HAXButton.h +// Sopreso +// +// Created by Kocsis Olivér on 2014.05.21.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// + +#import "HAXView.h" + +@interface HAXButton : HAXView +-(void)press; +@end diff --git a/Classes/HAXButton.m b/Classes/HAXButton.m new file mode 100644 index 0000000..e04f2b4 --- /dev/null +++ b/Classes/HAXButton.m @@ -0,0 +1,16 @@ +// +// HAXButton.m +// Sopreso +// +// Created by Kocsis Olivér on 2014.05.21.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// + +#import "HAXButton.h" +#import "HAXElement+Protected.h" +@implementation HAXButton +-(void)press +{ + [self performAction:(__bridge NSString *)kAXPressAction error:NULL]; +} +@end diff --git a/Classes/HAXElement+Protected.h b/Classes/HAXElement+Protected.h index dbc4489..e0fc419 100644 --- a/Classes/HAXElement+Protected.h +++ b/Classes/HAXElement+Protected.h @@ -2,14 +2,15 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import +#import "HAXElement.h" +#import "NSScreen+PointConvert.h" @interface HAXElement () +(instancetype)elementWithElementRef:(AXUIElementRef)elementRef __attribute__((nonnull(1))); -(instancetype)initWithElementRef:(AXUIElementRef)elementRef __attribute__((nonnull(1))); -@property (nonatomic, readonly) AXUIElementRef elementRef __attribute__((NSObject)); +//@property (nonatomic, readonly) AXUIElementRef elementRef __attribute__((NSObject)); -(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1))); -(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1,2))); diff --git a/Classes/HAXElement.h b/Classes/HAXElement.h index 262c0c0..d6679d7 100644 --- a/Classes/HAXElement.h +++ b/Classes/HAXElement.h @@ -1,7 +1,7 @@ // HAXElement.h // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix - +#import "Cocoa/Cocoa.h" #import @protocol HAXElementDelegate; @@ -9,8 +9,15 @@ @interface HAXElement : NSObject @property (nonatomic, weak) id delegate; +@property (nonatomic, readonly) NSString * title; +@property (nonatomic, readonly) NSString * role; +@property (nonatomic, readonly) BOOL hasChildren; +@property (nonatomic, readonly) NSArray * children; +@property (nonatomic, readonly) NSArray * attributeNames; +@property (readonly) AXUIElementRef elementRef __attribute__((NSObject)); -(bool)isEqualToElement:(HAXElement *)other; +-(NSArray *) buttons; @end diff --git a/Classes/HAXElement.m b/Classes/HAXElement.m index d75427f..23db8eb 100644 --- a/Classes/HAXElement.m +++ b/Classes/HAXElement.m @@ -3,7 +3,7 @@ // Copyright 2011 Rob Rix #import "HAXElement+Protected.h" - +#import "HAXButton.h" @interface HAXElement () @property (nonatomic, strong) AXObserverRef observer __attribute__((NSObject)); @end @@ -11,9 +11,101 @@ @interface HAXElement () @implementation HAXElement @synthesize elementRef = _elementRef; +-(BOOL)hasChildren +{ + NSError * error = nil; + NSArray * result = nil; + result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); + if (error || result == nil) + { + NSLog(@"role getter:: %@", [error debugDescription]); + result = nil; + } + return result ? [result count] : NO; + +} +-(NSArray *)children +{ + NSError * error = nil; + NSArray * axUIElements = nil; + axUIElements = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); + if (error) + { + NSLog(@"childrenElementRefs getter:: %@", [error debugDescription]); + + axUIElements = nil; + } + NSMutableArray * result = [NSMutableArray arrayWithCapacity:[axUIElements count]]; + for (id elementI in axUIElements) + { + [result addObject:[HAXElement elementWithElementRef:(AXUIElementRef)(elementI) ]]; + } + return result; +} +-(NSString *)role +{ + NSError * error = nil; + NSString * result = nil; + result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:&error]); + if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) + { + NSLog(@"role getter:: %@", [error debugDescription]); + result = nil; + } + return result; +} +-(NSArray *) buttons +{ + NSArray *axChildren = self.children; + NSMutableArray *result = [NSMutableArray array]; + + NSString * axRole; + for (HAXElement * haxElementI in axChildren) + { + axRole = [haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; + if ([axRole isEqualToString:(__bridge NSString *)kAXButtonRole]) + { + HAXButton * haxView = [HAXButton elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; + [result addObject:haxView]; + } + } + return [result count] ? result : nil; +} -+(instancetype)elementWithElementRef:(AXUIElementRef)elementRef { +-(NSString *)title +{ + NSError * error = nil; + NSString * result = nil; + result = CFBridgingRelease([self copyAttributeValueForKey:NSAccessibilityTitleAttribute error:&error]); + if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) + { + NSLog(@"title getter:: %@", [error debugDescription]); + result = nil; + } + return result; +} +-(NSArray *)attributeNames +{ + __block CFArrayRef attrNamesRef = NULL; + NSArray *attrNames = nil; + if ([NSThread isMainThread]) + { + AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); + }); + } + attrNames = CFBridgingRelease(attrNamesRef); + return attrNames; +} + ++(instancetype)elementWithElementRef:(AXUIElementRef)elementRef +{ return [[self alloc] initWithElementRef:elementRef]; } @@ -59,10 +151,22 @@ - (void)setDelegate:(id)delegate; } --(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error { +-(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error +{ NSParameterAssert(key != nil); - CFTypeRef attributeRef = NULL; - AXError result = AXUIElementCopyAttributeValue(self.elementRef, (__bridge CFStringRef)key, &attributeRef); + __block CFTypeRef attributeRef = NULL; + __block AXError result = 0; + if ([NSThread isMainThread]) + { + result = AXUIElementCopyAttributeValue(self.elementRef, (__bridge CFStringRef)key, &attributeRef); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + result = AXUIElementCopyAttributeValue(self.elementRef, (__bridge CFStringRef)key, &attributeRef); + }); + } if((result != kAXErrorSuccess) && error) { *error = [NSError errorWithDomain:NSStringFromClass(self.class) code:result userInfo:@{ @"key": key, @@ -72,11 +176,24 @@ -(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error { return attributeRef; } --(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error { +-(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error +{ NSParameterAssert(value != nil); NSParameterAssert(key != nil); - AXError result = AXUIElementSetAttributeValue(self.elementRef, (__bridge CFStringRef)key, value); - if((result != kAXErrorSuccess) && error) { + __block AXError result = 0; + if ([NSThread isMainThread]) + { + AXUIElementSetAttributeValue(self.elementRef, (__bridge CFStringRef)key, value); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + AXUIElementSetAttributeValue(self.elementRef, (__bridge CFStringRef)key, value); + }); + } + + if((result != kAXErrorSuccess) && error) { *error = [NSError errorWithDomain:NSStringFromClass(self.class) code:result userInfo:@{ @"key": key, @"elementRef": (id)self.elementRef @@ -85,10 +202,25 @@ -(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError return result == kAXErrorSuccess; } --(bool)performAction:(NSString *)action error:(NSError **)error { +-(bool)performAction:(NSString *)action error:(NSError **)error +{ NSParameterAssert(action != nil); - AXError result = AXUIElementPerformAction(self.elementRef, (__bridge CFStringRef)action); - if ((result != kAXErrorSuccess) && error) { + __block AXError result = 0; + if ([NSThread isMainThread]) + { + AXUIElementPerformAction(self.elementRef, (__bridge CFStringRef)action); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + AXUIElementPerformAction(self.elementRef, (__bridge CFStringRef)action); + }); + } + + + if ((result != kAXErrorSuccess) && error) + { *error = [NSError errorWithDomain:NSStringFromClass(self.class) code:result userInfo:@{ @"action": action, @"elementRef": (id)self.elementRef @@ -99,10 +231,12 @@ -(bool)performAction:(NSString *)action error:(NSError **)error { } --(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error { +-(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error +{ AXUIElementRef subelementRef = (AXUIElementRef)[self copyAttributeValueForKey:key error:error]; id result = nil; - if (subelementRef) { + if (subelementRef) + { result = [klass elementWithElementRef:subelementRef]; CFRelease(subelementRef); subelementRef = NULL; @@ -111,45 +245,108 @@ -(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error } --(void)addAXObserver { +-(void)addAXObserver +{ if (self.observer) { return; } - AXObserverRef observer; - AXError err; - pid_t pid; + __block AXObserverRef observer = NULL; + __block AXError err = 0; + __block pid_t pid = 0; + + if ([NSThread isMainThread]) + { + err = AXUIElementGetPid(self.elementRef, &pid); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + err = AXUIElementGetPid(self.elementRef, &pid); + }); + } + if (err != kAXErrorSuccess) { return; } + + if ([NSThread isMainThread]) + { + err = AXObserverCreate(pid, axCallback, &observer); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + err = AXObserverCreate(pid, axCallback, &observer); + }); + } - err = AXUIElementGetPid(self.elementRef, &pid); - if (err != kAXErrorSuccess) { return; } - - err = AXObserverCreate(pid, axCallback, &observer); - if (err != kAXErrorSuccess) { return; } - - err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); + if (err != kAXErrorSuccess) { return; } + if ([NSThread isMainThread]) + { + err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); + }); + } + if (err != kAXErrorSuccess) { CFRelease(observer); observer = NULL; return; } - - CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); - + if ([NSThread isMainThread]) + { + err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); + }); + } + + if (err != kAXErrorSuccess) { + CFRelease(observer); + observer = NULL; + return; + } + if ([NSThread isMainThread]) + { + CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); + }); + } + + self.observer = observer; CFRelease(observer); } -static void axCallback(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void *refcon) { +static void axCallback(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void *refcon) +{ [(__bridge HAXElement *)refcon didObserveNotification:(__bridge NSString *)notification]; } --(void)didObserveNotification:(NSString *)notification { +-(void)didObserveNotification:(NSString *)notification +{ id delegate = self.delegate; - if ([notification isEqualToString:(__bridge NSString *)kAXUIElementDestroyedNotification] && [delegate respondsToSelector:@selector(elementWasDestroyed:)]) { + if ([notification isEqualToString:(__bridge NSString *)kAXUIElementDestroyedNotification] && [delegate respondsToSelector:@selector(elementWasDestroyed:)]) + { [delegate elementWasDestroyed:self]; } } --(void)removeAXObserver { +-(void)removeAXObserver +{ if (!self.observer) { return; } (void)AXObserverRemoveNotification(self.observer, self.elementRef, kAXUIElementDestroyedNotification); diff --git a/Classes/HAXSystem.h b/Classes/HAXSystem.h index d608735..7b44a09 100644 --- a/Classes/HAXSystem.h +++ b/Classes/HAXSystem.h @@ -2,7 +2,7 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import +#import "HAXElement.h" @class HAXApplication; diff --git a/Classes/HAXSystem.m b/Classes/HAXSystem.m index 17dceb2..6890638 100644 --- a/Classes/HAXSystem.m +++ b/Classes/HAXSystem.m @@ -8,7 +8,8 @@ @implementation HAXSystem -+(instancetype)system { ++(instancetype)system +{ AXUIElementRef element = AXUIElementCreateSystemWide(); HAXSystem *result = [self elementWithElementRef:element]; CFRelease(element); @@ -16,7 +17,8 @@ +(instancetype)system { } --(HAXApplication *)focusedApplication { +-(HAXApplication *)focusedApplication +{ NSError *error = nil; return [self elementOfClass:[HAXApplication class] forKey:(NSString *)kAXFocusedApplicationAttribute error:&error]; } diff --git a/Classes/HAXView.h b/Classes/HAXView.h new file mode 100644 index 0000000..940d4b8 --- /dev/null +++ b/Classes/HAXView.h @@ -0,0 +1,26 @@ +// +// HAXView.h +// Sopreso +// +// Created by Kocsis Olivér on 2014.05.12.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// + +#import "HAXElement.h" + +@interface HAXView : HAXElement +@property (nonatomic, assign) CGPoint originCarbon; +@property (nonatomic, assign, readonly) CGPoint originCocoa; + +@property (nonatomic, assign) CGSize size; +@property (nonatomic, assign) CGRect frameCarbon; +@property (nonatomic, assign, readonly) CGRect frameCocoa; + +@property (nonatomic, readonly) NSString *title; + +@property (nonatomic, readonly) NSScreen *screen; + +-(BOOL)isFullscreen; + + +@end diff --git a/Classes/HAXView.m b/Classes/HAXView.m new file mode 100644 index 0000000..2207f13 --- /dev/null +++ b/Classes/HAXView.m @@ -0,0 +1,114 @@ +// +// HAXView.m +// Sopreso +// +// Created by Kocsis Olivér on 2014.05.12.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// + +#import "HAXView.h" +#import "HAXElement+Protected.h" +@implementation HAXView +-(BOOL)isFullscreen +{ + BOOL isFullScreen = NO; + NSArray * sceenArray = [NSScreen screens]; + + for (NSScreen * screenI in sceenArray) + { + NSRect screenFrame; + screenFrame = [screenI frame]; + NSRect windowFrame = self.frameCocoa; + + if(NSEqualRects(screenFrame, windowFrame)) + { + isFullScreen = YES; + break; + } + } + return isFullScreen; +} +-(NSScreen *)screen +{ + NSScreen *fullscreenScreen = nil; + for (NSScreen * screenI in [NSScreen screens]) + { + if(NSEqualRects([screenI frame], self.frameCocoa)) + { + fullscreenScreen = screenI; + break; + } + } + return fullscreenScreen; +} +-(CGPoint)originCarbon +{ + CGPoint origin = {0}; + CFTypeRef originRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; + if(originRef) + { + AXValueGetValue(originRef, kAXValueCGPointType, &origin); + CFRelease(originRef); + originRef = NULL; + } + return origin; +} +-(CGPoint)originCocoa +{ + return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon].origin; +} + +-(void)setOriginCarbon:(CGPoint)originCarbon +{ + AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &originCarbon); + [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; + CFRelease(originRef); +} + + +-(CGSize)size +{ + CGSize size = {0}; + CFTypeRef sizeRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; + if(sizeRef) + { + AXValueGetValue(sizeRef, kAXValueCGSizeType, &size); + CFRelease(sizeRef); + sizeRef = NULL; + } + return size; +} + +-(void)setSize:(CGSize)size +{ + AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); + [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; + CFRelease(sizeRef); +} + + +-(CGRect)frameCarbon +{ + return (CGRect){ .origin = self.originCarbon, .size = self.size }; +} +-(CGRect)frameCocoa +{ + return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon]; +} + +-(void)setFrameCarbon:(CGRect)frameCarbon +{ + self.originCarbon = frameCarbon.origin; + self.size = frameCarbon.size; +} + + +-(NSString *)title +{ + return CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]); +} + + + + +@end diff --git a/Classes/HAXWindow.h b/Classes/HAXWindow.h index 65b0e66..1e31fc6 100644 --- a/Classes/HAXWindow.h +++ b/Classes/HAXWindow.h @@ -2,16 +2,25 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import +#import "HAXElement.h" @interface HAXWindow : HAXElement -@property (nonatomic, assign) CGPoint origin; +@property (nonatomic, assign) CGPoint originCarbon; +@property (nonatomic, assign, readonly) CGPoint originCocoa; + @property (nonatomic, assign) CGSize size; -@property (nonatomic, assign) CGRect frame; +@property (nonatomic, assign) CGRect frameCarbon; +@property (nonatomic, assign, readonly) CGRect frameCocoa; @property (nonatomic, readonly) NSString *title; +@property (nonatomic, readonly) NSScreen *screen; + +@property (nonatomic, readonly) NSArray *views; + +-(BOOL)isFullscreen; +-(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon; -(bool)raise; -(bool)close; diff --git a/Classes/HAXWindow.m b/Classes/HAXWindow.m index 4a45f79..b595988 100644 --- a/Classes/HAXWindow.m +++ b/Classes/HAXWindow.m @@ -4,31 +4,102 @@ #import "HAXWindow.h" #import "HAXElement+Protected.h" - +#import "HAXView.h" +CG_INLINE BOOL compareRect(CGRect rect1, CGRect rect2 , unsigned int epsilon) +{ + if (ABS(rect1.size.width - rect2.size.width) > epsilon) + return NO; + if (ABS(rect1.size.height - rect2.size.height) > epsilon) + return NO; + if (ABS(rect1.origin.x - rect2.origin.x) > epsilon) + return NO; + if (ABS(rect1.origin.y - rect2.origin.y) > epsilon) + return NO; + return YES; +} @implementation HAXWindow - --(CGPoint)origin { +-(BOOL)isFullscreen +{ + BOOL isFullScreen = NO; + NSArray * sceenArray = [NSScreen screens]; + + for (NSScreen * screenI in sceenArray) + { + NSRect screenFrame; + screenFrame = [screenI frame]; + NSRect windowFrame = self.frameCocoa; + + if(NSEqualRects(screenFrame, windowFrame)) + { + isFullScreen = YES; + break; + } + } + return isFullScreen; +} +-(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon +{ + BOOL isFullScreen = NO; + NSArray * sceenArray = [NSScreen screens]; + + for (NSScreen * screenI in sceenArray) + { + NSRect screenFrame; + screenFrame = [screenI frame]; + NSRect windowFrame = self.frameCocoa; + + if( compareRect(screenFrame, windowFrame, epsilon) ) + { + isFullScreen = YES; + break; + } + } + return isFullScreen; +} +-(NSScreen *)screen +{ + NSScreen *fullscreenScreen = nil; + for (NSScreen * screenI in [NSScreen screens]) + { + if(NSEqualRects([screenI frame], self.frameCocoa)) + { + fullscreenScreen = screenI; + break; + } + } + return fullscreenScreen; +} +-(CGPoint)originCarbon +{ CGPoint origin = {0}; CFTypeRef originRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; - if(originRef) { + if(originRef) + { AXValueGetValue(originRef, kAXValueCGPointType, &origin); CFRelease(originRef); originRef = NULL; } return origin; } +-(CGPoint)originCocoa +{ + return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon].origin; +} --(void)setOrigin:(CGPoint)origin { - AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &origin); +-(void)setOriginCarbon:(CGPoint)originCarbon +{ + AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &originCarbon); [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; CFRelease(originRef); } --(CGSize)size { +-(CGSize)size +{ CGSize size = {0}; CFTypeRef sizeRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; - if(sizeRef) { + if(sizeRef) + { AXValueGetValue(sizeRef, kAXValueCGSizeType, &size); CFRelease(sizeRef); sizeRef = NULL; @@ -36,33 +107,61 @@ -(CGSize)size { return size; } --(void)setSize:(CGSize)size { +-(void)setSize:(CGSize)size +{ AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; CFRelease(sizeRef); } --(CGRect)frame { - return (CGRect){ .origin = self.origin, .size = self.size }; +-(CGRect)frameCarbon +{ + return (CGRect){ .origin = self.originCarbon, .size = self.size }; +} +-(CGRect)frameCocoa +{ + return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon]; } --(void)setFrame:(CGRect)frame { - self.origin = frame.origin; - self.size = frame.size; +-(void)setFrameCarbon:(CGRect)frameCarbon +{ + self.originCarbon = frameCarbon.origin; + self.size = frameCarbon.size; } --(NSString *)title { +-(NSString *)title +{ return CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]); } +-(NSArray *)views +{ + NSArray *axChildren = self.children; + NSMutableArray *result = [NSMutableArray array]; + + NSString * axRole; + for (HAXElement * haxElementI in axChildren) + { + axRole = [haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; + if ([axRole isEqualToString:@"AXView"]) + { + HAXView * haxView = [HAXView elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; + [result addObject:haxView]; + } + } + return result; +} + --(bool)raise { +-(bool)raise +{ return [self performAction:(__bridge NSString *)kAXRaiseAction error:NULL]; } --(bool)close { +-(bool)close +{ HAXElement *element = [self elementOfClass:[HAXElement class] forKey:(__bridge NSString *)kAXCloseButtonAttribute error:NULL]; return [element performAction:(__bridge NSString *)kAXPressAction error:NULL]; } diff --git a/Classes/NSScreen+PointConvert.h b/Classes/NSScreen+PointConvert.h new file mode 100644 index 0000000..7a5b877 --- /dev/null +++ b/Classes/NSScreen+PointConvert.h @@ -0,0 +1,17 @@ +// +// NSScreen+PointConvert.h +// Sopreso +// +// Created by Kocsis Olivér on 2014.05.05.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// + +#import + +@interface NSScreen (PointConvert) +- (NSRect)frameCarbon; ++ (NSScreen*) screenWithPoint: (NSPoint) p; ++ (NSRect)cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint; ++ (CGPoint)carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint; + +@end diff --git a/Classes/NSScreen+PointConvert.m b/Classes/NSScreen+PointConvert.m new file mode 100644 index 0000000..7184b4d --- /dev/null +++ b/Classes/NSScreen+PointConvert.m @@ -0,0 +1,78 @@ +// +// NSScreen+PointConvert.m +// Sopreso +// +// Created by Kocsis Olivér on 2014.05.05.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// + +#import "NSScreen+PointConvert.h" + +@implementation NSScreen (PointConvert) ++ (NSScreen*) screenWithPoint: (NSPoint) p +{ + NSScreen *screen = nil; + for (NSScreen *screenI in [NSScreen screens]) + { + if (NSPointInRect(p, [screenI frame])) + { + screen = screenI; + break; + } + } + return screen; +} + + +- (NSRect)frameCarbon +{ + NSRect originScreenFrame = ((NSScreen *)[NSScreen screens][0]).frame; + + NSRect carbonFrame; + carbonFrame.origin= NSMakePoint([self frame].origin.x, + originScreenFrame.size.height - + [self frame].origin.y - + [self frame].size.height );; + carbonFrame.size = [self frame].size; + return carbonFrame; +} ++ (NSRect)cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint +{ + NSRect originScreenFrame = ((NSScreen *)[NSScreen screens][0]).frame; + + NSRect cocoaFrame; + cocoaFrame.origin= NSMakePoint(carbonPoint.origin.x, + originScreenFrame.size.height - + carbonPoint.origin.y - + carbonPoint.size.height );; + cocoaFrame.size = carbonPoint.size; + return cocoaFrame; +} ++ (CGPoint)carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint +{ + NSScreen *foundScreen = nil; + CGPoint thePoint; + + for (NSScreen *screen in [NSScreen screens]) + { + if (NSPointInRect(cocoaPoint, [screen frame])) + { + foundScreen = screen; + } + } + + if (foundScreen) + { + CGFloat screenHeight = [foundScreen frame].size.height; + thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1); + } + else + { + thePoint = CGPointMake(0.0, 0.0); + } + + return thePoint; +} + + +@end diff --git a/Haxcessibility.xcodeproj/project.pbxproj b/Haxcessibility.xcodeproj/project.pbxproj index fc15b7e..8a5cfd2 100644 --- a/Haxcessibility.xcodeproj/project.pbxproj +++ b/Haxcessibility.xcodeproj/project.pbxproj @@ -10,6 +10,12 @@ 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; BC3B3B76175E9FD4002AD452 /* HAXElement+Protected.h in Headers */ = {isa = PBXBuildFile; fileRef = D44E051312D75B3D00541D6A /* HAXElement+Protected.h */; settings = {ATTRIBUTES = (Private, ); }; }; + C3E21520194F381400C85776 /* HAXButton.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E2151C194F381400C85776 /* HAXButton.h */; }; + C3E21521194F381400C85776 /* HAXButton.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E2151D194F381400C85776 /* HAXButton.m */; }; + C3E21526194F38BE00C85776 /* NSScreen+PointConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21524194F38BD00C85776 /* NSScreen+PointConvert.h */; }; + C3E21527194F38BE00C85776 /* NSScreen+PointConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E21525194F38BD00C85776 /* NSScreen+PointConvert.m */; }; + C3E2152A194F38FB00C85776 /* HAXView.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21528194F38FB00C85776 /* HAXView.h */; }; + C3E2152B194F38FB00C85776 /* HAXView.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E21529194F38FB00C85776 /* HAXView.m */; }; D4D2103412D6957000509E57 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4D2103312D6957000509E57 /* Carbon.framework */; }; D4D2103712D6959400509E57 /* HAXElement.h in Headers */ = {isa = PBXBuildFile; fileRef = D4D2103512D6959400509E57 /* HAXElement.h */; settings = {ATTRIBUTES = (Public, ); }; }; D4D2103812D6959400509E57 /* HAXElement.m in Sources */ = {isa = PBXBuildFile; fileRef = D4D2103612D6959400509E57 /* HAXElement.m */; }; @@ -28,6 +34,14 @@ 32DBCF5E0370ADEE00C91783 /* Haxcessibility.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Haxcessibility.pch; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8DC2EF5B0486A6940098B216 /* Haxcessibility.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Haxcessibility.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C3E2151C194F381400C85776 /* HAXButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXButton.h; sourceTree = ""; }; + C3E2151D194F381400C85776 /* HAXButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXButton.m; sourceTree = ""; }; + C3E2151E194F381400C85776 /* HAXWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXWindow.h; sourceTree = ""; }; + C3E2151F194F381400C85776 /* HAXWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXWindow.m; sourceTree = ""; }; + C3E21524194F38BD00C85776 /* NSScreen+PointConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSScreen+PointConvert.h"; sourceTree = ""; }; + C3E21525194F38BD00C85776 /* NSScreen+PointConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSScreen+PointConvert.m"; sourceTree = ""; }; + C3E21528194F38FB00C85776 /* HAXView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXView.h; sourceTree = ""; }; + C3E21529194F38FB00C85776 /* HAXView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXView.m; sourceTree = ""; }; D44E051312D75B3D00541D6A /* HAXElement+Protected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "HAXElement+Protected.h"; sourceTree = ""; }; D4D2103312D6957000509E57 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; D4D2103512D6959400509E57 /* HAXElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXElement.h; sourceTree = ""; }; @@ -104,6 +118,8 @@ D4D2102E12D6947D00509E57 /* Classes */ = { isa = PBXGroup; children = ( + C3E21524194F38BD00C85776 /* NSScreen+PointConvert.h */, + C3E21525194F38BD00C85776 /* NSScreen+PointConvert.m */, D4D2106B12D69C8900509E57 /* HAXApplication.h */, D4D2106C12D69C8B00509E57 /* HAXApplication.m */, D4D2103512D6959400509E57 /* HAXElement.h */, @@ -113,6 +129,12 @@ D4D2105412D698F400509E57 /* HAXSystem.m */, D4D2108012D6A08600509E57 /* HAXWindow.h */, D4D2108112D6A08800509E57 /* HAXWindow.m */, + C3E2151C194F381400C85776 /* HAXButton.h */, + C3E2151D194F381400C85776 /* HAXButton.m */, + C3E2151E194F381400C85776 /* HAXWindow.h */, + C3E2151F194F381400C85776 /* HAXWindow.m */, + C3E21528194F38FB00C85776 /* HAXView.h */, + C3E21529194F38FB00C85776 /* HAXView.m */, ); path = Classes; sourceTree = ""; @@ -125,9 +147,13 @@ buildActionMask = 2147483647; files = ( D4D2105912D6991900509E57 /* HAXSystem.h in Headers */, + C3E2152A194F38FB00C85776 /* HAXView.h in Headers */, D4D2103712D6959400509E57 /* HAXElement.h in Headers */, + C3E21522194F381400C85776 /* HAXWindow.h in Headers */, D4D2113E12D6AB0400509E57 /* HAXApplication.h in Headers */, + C3E21520194F381400C85776 /* HAXButton.h in Headers */, D4D2113F12D6AB0400509E57 /* HAXWindow.h in Headers */, + C3E21526194F38BE00C85776 /* NSScreen+PointConvert.h in Headers */, D4D2113D12D6AAF000509E57 /* Haxcessibility.h in Headers */, BC3B3B76175E9FD4002AD452 /* HAXElement+Protected.h in Headers */, ); @@ -162,7 +188,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = HAX; - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0510; ORGANIZATIONNAME = "Rob Rix"; }; buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Haxcessibility" */; @@ -201,10 +227,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C3E2152B194F38FB00C85776 /* HAXView.m in Sources */, D4D2103812D6959400509E57 /* HAXElement.m in Sources */, + C3E21523194F381400C85776 /* HAXWindow.m in Sources */, + C3E21521194F381400C85776 /* HAXButton.m in Sources */, D4D2105512D698F400509E57 /* HAXSystem.m in Sources */, D4D2106D12D69C8B00509E57 /* HAXApplication.m in Sources */, D4D2108212D6A08800509E57 /* HAXWindow.m in Sources */, + C3E21527194F38BE00C85776 /* NSScreen+PointConvert.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -257,7 +287,6 @@ 1DEB91B208733DA50010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES; @@ -267,6 +296,7 @@ GCC_PREPROCESSOR_DEFINITIONS = NS_BUILD_32_LIKE_64; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; @@ -275,7 +305,6 @@ 1DEB91B308733DA50010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_64_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_INCREASE_PRECOMPILED_HEADER_SHARING = YES; @@ -284,6 +313,7 @@ GCC_PREPROCESSOR_DEFINITIONS = NS_BUILD_32_LIKE_64; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = macosx; }; name = Release; From 718c426c2f60d75fc488fd0ca849b9a4d45dcca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kocsis=20Oliv=C3=A9r?= Date: Mon, 16 Jun 2014 16:45:55 +0200 Subject: [PATCH 2/9] end of course a unified header for all of this --- Classes/Haxcessibility.h | 13 +++++++++++++ Classes/Haxcessibility.m | 7 +++++++ 2 files changed, 20 insertions(+) create mode 100644 Classes/Haxcessibility.h create mode 100644 Classes/Haxcessibility.m diff --git a/Classes/Haxcessibility.h b/Classes/Haxcessibility.h new file mode 100644 index 0000000..532ebc2 --- /dev/null +++ b/Classes/Haxcessibility.h @@ -0,0 +1,13 @@ +// +// Haxcessibility.h +// Sopreso +// +// Created by Kocsis Olivér on 2014.04.14.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// + +#import "HAXApplication.h" +#import "HAXSystem.h" +#import "HAXWindow.h" +#import "HAXView.h" +#import "HAXButton.h" \ No newline at end of file diff --git a/Classes/Haxcessibility.m b/Classes/Haxcessibility.m new file mode 100644 index 0000000..a7caf48 --- /dev/null +++ b/Classes/Haxcessibility.m @@ -0,0 +1,7 @@ +// +// Haxcessibility.m +// Sopreso +// +// Created by Kocsis Olivér on 2014.04.14.. +// Copyright (c) 2014 Joinect Technologies. All rights reserved. +// From 26e23e7287c50866ff8e4f604bc0496c8bb32924 Mon Sep 17 00:00:00 2001 From: Scott Perry Date: Thu, 5 Mar 2015 20:24:08 -0800 Subject: [PATCH 3/9] Reorganize, match style, prefix category name and methods. --- Classes/HAXApplication.h | 6 +- Classes/HAXApplication.m | 2 - Classes/HAXButton.h | 10 +- Classes/HAXButton.m | 11 +- Classes/HAXElement+Protected.h | 4 +- Classes/HAXElement.h | 11 +- Classes/HAXElement.m | 201 +++++++++--------- Classes/HAXView.h | 22 +- Classes/HAXView.m | 53 +++-- Classes/HAXWindow.h | 12 +- Classes/HAXWindow.m | 41 ++-- Classes/Haxcessibility.h | 13 -- Classes/Haxcessibility.m | 7 - Classes/NSScreen+HAXPointConvert.h | 14 ++ ...ntConvert.m => NSScreen+HAXPointConvert.m} | 27 ++- Classes/NSScreen+PointConvert.h | 17 -- Haxcessibility.xcodeproj/project.pbxproj | 18 +- Other Sources/Haxcessibility.h | 2 + 18 files changed, 216 insertions(+), 255 deletions(-) delete mode 100644 Classes/Haxcessibility.h delete mode 100644 Classes/Haxcessibility.m create mode 100644 Classes/NSScreen+HAXPointConvert.h rename Classes/{NSScreen+PointConvert.m => NSScreen+HAXPointConvert.m} (78%) delete mode 100644 Classes/NSScreen+PointConvert.h diff --git a/Classes/HAXApplication.h b/Classes/HAXApplication.h index 9127979..5b33548 100644 --- a/Classes/HAXApplication.h +++ b/Classes/HAXApplication.h @@ -10,11 +10,9 @@ @property (nonatomic, readonly) HAXWindow *focusedWindow; @property (nonatomic, readonly) NSArray *windows; - -+(instancetype)applicationWithPID:(pid_t)pid; - @property (nonatomic, copy, readonly) NSString *localizedName; - @property (nonatomic, readonly) pid_t processIdentifier; ++(instancetype)applicationWithPID:(pid_t)pid; + @end diff --git a/Classes/HAXApplication.m b/Classes/HAXApplication.m index 9248765..0dc7c9e 100644 --- a/Classes/HAXApplication.m +++ b/Classes/HAXApplication.m @@ -35,12 +35,10 @@ -(NSArray *)windows return result; } - -(NSString *)localizedName { return [self copyAttributeValueForKey:(NSString *)kAXTitleAttribute error:NULL]; } - -(pid_t)processIdentifier { pid_t processIdentifier = 0; AXUIElementGetPid(self.elementRef, &processIdentifier); diff --git a/Classes/HAXButton.h b/Classes/HAXButton.h index 430a3b8..0c42d57 100644 --- a/Classes/HAXButton.h +++ b/Classes/HAXButton.h @@ -1,13 +1,11 @@ -// // HAXButton.h -// Sopreso -// -// Created by Kocsis Olivér on 2014.05.21.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// +// Created by Kocsis Olivér on 2014-05-21 +// Copyright 2014 Joinect Technologies #import "HAXView.h" @interface HAXButton : HAXView + -(void)press; + @end diff --git a/Classes/HAXButton.m b/Classes/HAXButton.m index e04f2b4..b129b2a 100644 --- a/Classes/HAXButton.m +++ b/Classes/HAXButton.m @@ -1,16 +1,15 @@ -// // HAXButton.m -// Sopreso -// -// Created by Kocsis Olivér on 2014.05.21.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// +// Created by Kocsis Olivér on 2014-05-21 +// Copyright 2014 Joinect Technologies #import "HAXButton.h" #import "HAXElement+Protected.h" + @implementation HAXButton + -(void)press { [self performAction:(__bridge NSString *)kAXPressAction error:NULL]; } + @end diff --git a/Classes/HAXElement+Protected.h b/Classes/HAXElement+Protected.h index e0fc419..e7c526a 100644 --- a/Classes/HAXElement+Protected.h +++ b/Classes/HAXElement+Protected.h @@ -3,14 +3,14 @@ // Copyright 2011 Rob Rix #import "HAXElement.h" -#import "NSScreen+PointConvert.h" +#import "NSScreen+HAXPointConvert.h" @interface HAXElement () +(instancetype)elementWithElementRef:(AXUIElementRef)elementRef __attribute__((nonnull(1))); -(instancetype)initWithElementRef:(AXUIElementRef)elementRef __attribute__((nonnull(1))); -//@property (nonatomic, readonly) AXUIElementRef elementRef __attribute__((NSObject)); +@property (nonatomic, readonly) AXUIElementRef elementRef __attribute__((NSObject)); -(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1))); -(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1,2))); diff --git a/Classes/HAXElement.h b/Classes/HAXElement.h index d6679d7..01af729 100644 --- a/Classes/HAXElement.h +++ b/Classes/HAXElement.h @@ -9,12 +9,11 @@ @interface HAXElement : NSObject @property (nonatomic, weak) id delegate; -@property (nonatomic, readonly) NSString * title; -@property (nonatomic, readonly) NSString * role; +@property (nonatomic, readonly) NSString *title; +@property (nonatomic, readonly) NSString *role; @property (nonatomic, readonly) BOOL hasChildren; -@property (nonatomic, readonly) NSArray * children; -@property (nonatomic, readonly) NSArray * attributeNames; -@property (readonly) AXUIElementRef elementRef __attribute__((NSObject)); +@property (nonatomic, readonly) NSArray *children; +@property (nonatomic, readonly) NSArray *attributeNames; -(bool)isEqualToElement:(HAXElement *)other; -(NSArray *) buttons; @@ -22,6 +21,8 @@ @end @protocol HAXElementDelegate + @optional -(void)elementWasDestroyed:(HAXElement *)element; + @end diff --git a/Classes/HAXElement.m b/Classes/HAXElement.m index 23db8eb..252205e 100644 --- a/Classes/HAXElement.m +++ b/Classes/HAXElement.m @@ -4,105 +4,16 @@ #import "HAXElement+Protected.h" #import "HAXButton.h" -@interface HAXElement () -@property (nonatomic, strong) AXObserverRef observer __attribute__((NSObject)); -@end -@implementation HAXElement -@synthesize elementRef = _elementRef; --(BOOL)hasChildren -{ - NSError * error = nil; - NSArray * result = nil; - result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); - if (error || result == nil) - { - NSLog(@"role getter:: %@", [error debugDescription]); - result = nil; - } - return result ? [result count] : NO; +@interface HAXElement () -} --(NSArray *)children -{ - NSError * error = nil; - NSArray * axUIElements = nil; - axUIElements = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); - if (error) - { - NSLog(@"childrenElementRefs getter:: %@", [error debugDescription]); - - axUIElements = nil; - } - NSMutableArray * result = [NSMutableArray arrayWithCapacity:[axUIElements count]]; - for (id elementI in axUIElements) - { - [result addObject:[HAXElement elementWithElementRef:(AXUIElementRef)(elementI) ]]; - } - return result; -} --(NSString *)role -{ - NSError * error = nil; - NSString * result = nil; - result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:&error]); - if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) - { - NSLog(@"role getter:: %@", [error debugDescription]); - result = nil; - } - return result; +@property (nonatomic, strong) AXObserverRef observer __attribute__((NSObject)); -} --(NSArray *) buttons -{ - NSArray *axChildren = self.children; - NSMutableArray *result = [NSMutableArray array]; - - NSString * axRole; - for (HAXElement * haxElementI in axChildren) - { - axRole = [haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; - if ([axRole isEqualToString:(__bridge NSString *)kAXButtonRole]) - { - HAXButton * haxView = [HAXButton elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; - [result addObject:haxView]; - } - } - return [result count] ? result : nil; -} +@end --(NSString *)title -{ - NSError * error = nil; - NSString * result = nil; - result = CFBridgingRelease([self copyAttributeValueForKey:NSAccessibilityTitleAttribute error:&error]); - if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) - { - NSLog(@"title getter:: %@", [error debugDescription]); - result = nil; - } - return result; -} --(NSArray *)attributeNames -{ - __block CFArrayRef attrNamesRef = NULL; - NSArray *attrNames = nil; - if ([NSThread isMainThread]) - { - AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); - }); - } - attrNames = CFBridgingRelease(attrNamesRef); - return attrNames; -} + +@implementation HAXElement +(instancetype)elementWithElementRef:(AXUIElementRef)elementRef { @@ -126,7 +37,6 @@ -(void)dealloc { } } - -(bool)isEqualToElement:(HAXElement *)other { return [other isKindOfClass:self.class] @@ -141,7 +51,6 @@ -(NSUInteger)hash { return CFHash(self.elementRef); } - - (void)setDelegate:(id)delegate; { if (delegate && !_observer) { @@ -150,7 +59,6 @@ - (void)setDelegate:(id)delegate; _delegate = delegate; } - -(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error { NSParameterAssert(key != nil); @@ -230,7 +138,6 @@ -(bool)performAction:(NSString *)action error:(NSError **)error return result == kAXErrorSuccess; } - -(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error { AXUIElementRef subelementRef = (AXUIElementRef)[self copyAttributeValueForKey:key error:error]; @@ -244,7 +151,6 @@ -(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error return result; } - -(void)addAXObserver { if (self.observer) { return; } @@ -359,4 +265,101 @@ -(void)removeAXObserver self.observer = NULL; } +-(BOOL)hasChildren +{ + NSError * error = nil; + NSArray * result = nil; + result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); + if (error || result == nil) + { + NSLog(@"role getter:: %@", [error debugDescription]); + result = nil; + } + return result ? [result count] : NO; + +} + +-(NSArray *)children +{ + NSError * error = nil; + NSArray * axUIElements = nil; + axUIElements = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); + if (error) + { + NSLog(@"childrenElementRefs getter:: %@", [error debugDescription]); + + axUIElements = nil; + } + NSMutableArray * result = [NSMutableArray arrayWithCapacity:[axUIElements count]]; + for (id elementI in axUIElements) + { + [result addObject:[HAXElement elementWithElementRef:(AXUIElementRef)(elementI) ]]; + } + return result; +} + +-(NSString *)role +{ + NSError * error = nil; + NSString * result = nil; + result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:&error]); + if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) + { + NSLog(@"role getter:: %@", [error debugDescription]); + result = nil; + } + return result; + +} + +-(NSArray *) buttons +{ + NSArray *axChildren = self.children; + NSMutableArray *result = [NSMutableArray array]; + + NSString * axRole; + for (HAXElement * haxElementI in axChildren) + { + axRole = [haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; + if ([axRole isEqualToString:(__bridge NSString *)kAXButtonRole]) + { + HAXButton * haxView = [HAXButton elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; + [result addObject:haxView]; + } + } + return [result count] ? result : nil; +} + +-(NSString *)title +{ + NSError * error = nil; + NSString * result = nil; + result = CFBridgingRelease([self copyAttributeValueForKey:NSAccessibilityTitleAttribute error:&error]); + if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) + { + NSLog(@"title getter:: %@", [error debugDescription]); + result = nil; + } + return result; +} + +-(NSArray *)attributeNames +{ + __block CFArrayRef attrNamesRef = NULL; + NSArray *attrNames = nil; + if ([NSThread isMainThread]) + { + AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); + } + else + { + dispatch_sync(dispatch_get_main_queue(), ^ + { + AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); + }); + } + attrNames = CFBridgingRelease(attrNamesRef); + return attrNames; +} + @end diff --git a/Classes/HAXView.h b/Classes/HAXView.h index 940d4b8..369b906 100644 --- a/Classes/HAXView.h +++ b/Classes/HAXView.h @@ -1,26 +1,18 @@ -// // HAXView.h -// Sopreso -// -// Created by Kocsis Olivér on 2014.05.12.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// +// Created by Kocsis Olivér on 2014-05-12 +// Copyright 2014 Joinect Technologies #import "HAXElement.h" @interface HAXView : HAXElement -@property (nonatomic, assign) CGPoint originCarbon; -@property (nonatomic, assign, readonly) CGPoint originCocoa; - -@property (nonatomic, assign) CGSize size; -@property (nonatomic, assign) CGRect frameCarbon; -@property (nonatomic, assign, readonly) CGRect frameCocoa; - +@property (nonatomic, assign) CGPoint carbonOrigin; +@property (nonatomic, assign, readonly) NSPoint origin; +@property (nonatomic, assign) NSSize size; +@property (nonatomic, assign) CGRect carbonFrame; +@property (nonatomic, assign, readonly) NSRect frame; @property (nonatomic, readonly) NSString *title; - @property (nonatomic, readonly) NSScreen *screen; -(BOOL)isFullscreen; - @end diff --git a/Classes/HAXView.m b/Classes/HAXView.m index 2207f13..20595f6 100644 --- a/Classes/HAXView.m +++ b/Classes/HAXView.m @@ -1,14 +1,13 @@ -// // HAXView.m -// Sopreso -// -// Created by Kocsis Olivér on 2014.05.12.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// +// Created by Kocsis Olivér on 2014-05-12 +// Copyright 2014 Joinect Technologies #import "HAXView.h" #import "HAXElement+Protected.h" + + @implementation HAXView + -(BOOL)isFullscreen { BOOL isFullScreen = NO; @@ -18,7 +17,7 @@ -(BOOL)isFullscreen { NSRect screenFrame; screenFrame = [screenI frame]; - NSRect windowFrame = self.frameCocoa; + NSRect windowFrame = self.frame; if(NSEqualRects(screenFrame, windowFrame)) { @@ -28,12 +27,13 @@ -(BOOL)isFullscreen } return isFullScreen; } + -(NSScreen *)screen { NSScreen *fullscreenScreen = nil; for (NSScreen * screenI in [NSScreen screens]) { - if(NSEqualRects([screenI frame], self.frameCocoa)) + if(NSEqualRects([screenI frame], self.frame)) { fullscreenScreen = screenI; break; @@ -41,7 +41,8 @@ -(NSScreen *)screen } return fullscreenScreen; } --(CGPoint)originCarbon + +-(CGPoint)carbonOrigin { CGPoint origin = {0}; CFTypeRef originRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; @@ -53,20 +54,20 @@ -(CGPoint)originCarbon } return origin; } --(CGPoint)originCocoa + +-(CGPoint)origin { - return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon].origin; + return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.carbonFrame].origin; } --(void)setOriginCarbon:(CGPoint)originCarbon +-(void)setCarbonOrigin:(CGPoint)carbonOrigin { - AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &originCarbon); + AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &carbonOrigin); [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; CFRelease(originRef); } - --(CGSize)size +-(NSSize)size { CGSize size = {0}; CFTypeRef sizeRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; @@ -79,36 +80,32 @@ -(CGSize)size return size; } --(void)setSize:(CGSize)size +-(void)setSize:(NSSize)size { AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; CFRelease(sizeRef); } - --(CGRect)frameCarbon +-(CGRect)carbonFrame { - return (CGRect){ .origin = self.originCarbon, .size = self.size }; + return (CGRect){ .origin = self.carbonOrigin, .size = self.size }; } --(CGRect)frameCocoa + +-(NSRect)frame { - return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon]; + return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.carbonFrame]; } --(void)setFrameCarbon:(CGRect)frameCarbon +-(void)setCarbonFrame:(CGRect)carbonFrame { - self.originCarbon = frameCarbon.origin; - self.size = frameCarbon.size; + self.carbonOrigin = carbonFrame.origin; + self.size = carbonFrame.size; } - -(NSString *)title { return CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]); } - - - @end diff --git a/Classes/HAXWindow.h b/Classes/HAXWindow.h index 1e31fc6..0d43cd7 100644 --- a/Classes/HAXWindow.h +++ b/Classes/HAXWindow.h @@ -6,17 +6,13 @@ @interface HAXWindow : HAXElement -@property (nonatomic, assign) CGPoint originCarbon; -@property (nonatomic, assign, readonly) CGPoint originCocoa; - -@property (nonatomic, assign) CGSize size; +@property (nonatomic, assign) CGPoint carbonOrigin; +@property (nonatomic, assign, readonly) NSPoint origin; +@property (nonatomic, assign) NSSize size; @property (nonatomic, assign) CGRect frameCarbon; -@property (nonatomic, assign, readonly) CGRect frameCocoa; - +@property (nonatomic, assign, readonly) NSRect frame; @property (nonatomic, readonly) NSString *title; - @property (nonatomic, readonly) NSScreen *screen; - @property (nonatomic, readonly) NSArray *views; -(BOOL)isFullscreen; diff --git a/Classes/HAXWindow.m b/Classes/HAXWindow.m index b595988..d1a8786 100644 --- a/Classes/HAXWindow.m +++ b/Classes/HAXWindow.m @@ -5,6 +5,7 @@ #import "HAXWindow.h" #import "HAXElement+Protected.h" #import "HAXView.h" + CG_INLINE BOOL compareRect(CGRect rect1, CGRect rect2 , unsigned int epsilon) { if (ABS(rect1.size.width - rect2.size.width) > epsilon) @@ -17,7 +18,9 @@ CG_INLINE BOOL compareRect(CGRect rect1, CGRect rect2 , unsigned int epsilon) return NO; return YES; } + @implementation HAXWindow + -(BOOL)isFullscreen { BOOL isFullScreen = NO; @@ -27,7 +30,7 @@ -(BOOL)isFullscreen { NSRect screenFrame; screenFrame = [screenI frame]; - NSRect windowFrame = self.frameCocoa; + NSRect windowFrame = self.frame; if(NSEqualRects(screenFrame, windowFrame)) { @@ -37,6 +40,7 @@ -(BOOL)isFullscreen } return isFullScreen; } + -(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon { BOOL isFullScreen = NO; @@ -46,7 +50,7 @@ -(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon { NSRect screenFrame; screenFrame = [screenI frame]; - NSRect windowFrame = self.frameCocoa; + NSRect windowFrame = self.frame; if( compareRect(screenFrame, windowFrame, epsilon) ) { @@ -56,12 +60,13 @@ -(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon } return isFullScreen; } + -(NSScreen *)screen { NSScreen *fullscreenScreen = nil; for (NSScreen * screenI in [NSScreen screens]) { - if(NSEqualRects([screenI frame], self.frameCocoa)) + if(NSEqualRects([screenI frame], self.frame)) { fullscreenScreen = screenI; break; @@ -69,7 +74,8 @@ -(NSScreen *)screen } return fullscreenScreen; } --(CGPoint)originCarbon + +-(CGPoint)carbonOrigin { CGPoint origin = {0}; CFTypeRef originRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; @@ -81,20 +87,20 @@ -(CGPoint)originCarbon } return origin; } --(CGPoint)originCocoa + +-(CGPoint)origin { - return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon].origin; + return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon].origin; } --(void)setOriginCarbon:(CGPoint)originCarbon +-(void)setCarbonOrigin:(CGPoint)carbonOrigin { - AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &originCarbon); + AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &carbonOrigin); [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; CFRelease(originRef); } - --(CGSize)size +-(NSSize)size { CGSize size = {0}; CFTypeRef sizeRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; @@ -107,27 +113,26 @@ -(CGSize)size return size; } --(void)setSize:(CGSize)size +-(void)setSize:(NSSize)size { AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; CFRelease(sizeRef); } - -(CGRect)frameCarbon { - return (CGRect){ .origin = self.originCarbon, .size = self.size }; + return (CGRect){ .origin = self.carbonOrigin, .size = self.size }; } --(CGRect)frameCocoa +-(NSRect)frame { - return [NSScreen cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon]; + return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon]; } --(void)setFrameCarbon:(CGRect)frameCarbon +-(void)setCarbonFrame:(CGRect)carbonFrame { - self.originCarbon = frameCarbon.origin; - self.size = frameCarbon.size; + self.carbonOrigin = carbonFrame.origin; + self.size = carbonFrame.size; } diff --git a/Classes/Haxcessibility.h b/Classes/Haxcessibility.h deleted file mode 100644 index 532ebc2..0000000 --- a/Classes/Haxcessibility.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// Haxcessibility.h -// Sopreso -// -// Created by Kocsis Olivér on 2014.04.14.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// - -#import "HAXApplication.h" -#import "HAXSystem.h" -#import "HAXWindow.h" -#import "HAXView.h" -#import "HAXButton.h" \ No newline at end of file diff --git a/Classes/Haxcessibility.m b/Classes/Haxcessibility.m deleted file mode 100644 index a7caf48..0000000 --- a/Classes/Haxcessibility.m +++ /dev/null @@ -1,7 +0,0 @@ -// -// Haxcessibility.m -// Sopreso -// -// Created by Kocsis Olivér on 2014.04.14.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// diff --git a/Classes/NSScreen+HAXPointConvert.h b/Classes/NSScreen+HAXPointConvert.h new file mode 100644 index 0000000..6b2cda9 --- /dev/null +++ b/Classes/NSScreen+HAXPointConvert.h @@ -0,0 +1,14 @@ +// NSScreen+HAXPointConvert.h +// Created by Kocsis Olivér on 2014-05-05 +// Copyright 2014 Joinect Technologies + +#import + +@interface NSScreen (HAXPointConvert) + +- (NSRect)hax_frameCarbon; ++ (NSScreen*)hax_screenWithPoint:(NSPoint)p; ++ (NSRect)hax_cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint; ++ (CGPoint)hax_carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint; + +@end diff --git a/Classes/NSScreen+PointConvert.m b/Classes/NSScreen+HAXPointConvert.m similarity index 78% rename from Classes/NSScreen+PointConvert.m rename to Classes/NSScreen+HAXPointConvert.m index 7184b4d..b14036b 100644 --- a/Classes/NSScreen+PointConvert.m +++ b/Classes/NSScreen+HAXPointConvert.m @@ -1,15 +1,12 @@ -// -// NSScreen+PointConvert.m -// Sopreso -// -// Created by Kocsis Olivér on 2014.05.05.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// +// NSScreen+HAXPointConvert.m +// Created by Kocsis Olivér on 2014-05-05 +// Copyright 2014 Joinect Technologies -#import "NSScreen+PointConvert.h" +#import "NSScreen+HAXPointConvert.h" -@implementation NSScreen (PointConvert) -+ (NSScreen*) screenWithPoint: (NSPoint) p +@implementation NSScreen (HAXPointConvert) + ++ (NSScreen*)hax_screenWithPoint:(NSPoint)p { NSScreen *screen = nil; for (NSScreen *screenI in [NSScreen screens]) @@ -23,8 +20,7 @@ + (NSScreen*) screenWithPoint: (NSPoint) p return screen; } - -- (NSRect)frameCarbon +- (NSRect)hax_frameCarbon { NSRect originScreenFrame = ((NSScreen *)[NSScreen screens][0]).frame; @@ -36,7 +32,8 @@ - (NSRect)frameCarbon carbonFrame.size = [self frame].size; return carbonFrame; } -+ (NSRect)cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint + ++ (NSRect)hax_cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint { NSRect originScreenFrame = ((NSScreen *)[NSScreen screens][0]).frame; @@ -48,7 +45,8 @@ + (NSRect)cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint cocoaFrame.size = carbonPoint.size; return cocoaFrame; } -+ (CGPoint)carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint + ++ (CGPoint)hax_carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint { NSScreen *foundScreen = nil; CGPoint thePoint; @@ -74,5 +72,4 @@ + (CGPoint)carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint return thePoint; } - @end diff --git a/Classes/NSScreen+PointConvert.h b/Classes/NSScreen+PointConvert.h deleted file mode 100644 index 7a5b877..0000000 --- a/Classes/NSScreen+PointConvert.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// NSScreen+PointConvert.h -// Sopreso -// -// Created by Kocsis Olivér on 2014.05.05.. -// Copyright (c) 2014 Joinect Technologies. All rights reserved. -// - -#import - -@interface NSScreen (PointConvert) -- (NSRect)frameCarbon; -+ (NSScreen*) screenWithPoint: (NSPoint) p; -+ (NSRect)cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint; -+ (CGPoint)carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint; - -@end diff --git a/Haxcessibility.xcodeproj/project.pbxproj b/Haxcessibility.xcodeproj/project.pbxproj index 11f04ca..d4d38eb 100644 --- a/Haxcessibility.xcodeproj/project.pbxproj +++ b/Haxcessibility.xcodeproj/project.pbxproj @@ -12,8 +12,8 @@ BC3B3B76175E9FD4002AD452 /* HAXElement+Protected.h in Headers */ = {isa = PBXBuildFile; fileRef = D44E051312D75B3D00541D6A /* HAXElement+Protected.h */; settings = {ATTRIBUTES = (Private, ); }; }; C3E21520194F381400C85776 /* HAXButton.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E2151C194F381400C85776 /* HAXButton.h */; }; C3E21521194F381400C85776 /* HAXButton.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E2151D194F381400C85776 /* HAXButton.m */; }; - C3E21526194F38BE00C85776 /* NSScreen+PointConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21524194F38BD00C85776 /* NSScreen+PointConvert.h */; }; - C3E21527194F38BE00C85776 /* NSScreen+PointConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E21525194F38BD00C85776 /* NSScreen+PointConvert.m */; }; + C3E21526194F38BE00C85776 /* NSScreen+HAXPointConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21524194F38BD00C85776 /* NSScreen+HAXPointConvert.h */; }; + C3E21527194F38BE00C85776 /* NSScreen+HAXPointConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E21525194F38BD00C85776 /* NSScreen+HAXPointConvert.m */; }; C3E2152A194F38FB00C85776 /* HAXView.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21528194F38FB00C85776 /* HAXView.h */; }; C3E2152B194F38FB00C85776 /* HAXView.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E21529194F38FB00C85776 /* HAXView.m */; }; D4D2103412D6957000509E57 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4D2103312D6957000509E57 /* Carbon.framework */; }; @@ -38,8 +38,8 @@ C3E2151D194F381400C85776 /* HAXButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXButton.m; sourceTree = ""; }; C3E2151E194F381400C85776 /* HAXWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXWindow.h; sourceTree = ""; }; C3E2151F194F381400C85776 /* HAXWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXWindow.m; sourceTree = ""; }; - C3E21524194F38BD00C85776 /* NSScreen+PointConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSScreen+PointConvert.h"; sourceTree = ""; }; - C3E21525194F38BD00C85776 /* NSScreen+PointConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSScreen+PointConvert.m"; sourceTree = ""; }; + C3E21524194F38BD00C85776 /* NSScreen+HAXPointConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSScreen+HAXPointConvert.h"; sourceTree = ""; }; + C3E21525194F38BD00C85776 /* NSScreen+HAXPointConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSScreen+HAXPointConvert.m"; sourceTree = ""; }; C3E21528194F38FB00C85776 /* HAXView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXView.h; sourceTree = ""; }; C3E21529194F38FB00C85776 /* HAXView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXView.m; sourceTree = ""; }; D44E051312D75B3D00541D6A /* HAXElement+Protected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "HAXElement+Protected.h"; sourceTree = ""; }; @@ -118,8 +118,8 @@ D4D2102E12D6947D00509E57 /* Classes */ = { isa = PBXGroup; children = ( - C3E21524194F38BD00C85776 /* NSScreen+PointConvert.h */, - C3E21525194F38BD00C85776 /* NSScreen+PointConvert.m */, + C3E21524194F38BD00C85776 /* NSScreen+HAXPointConvert.h */, + C3E21525194F38BD00C85776 /* NSScreen+HAXPointConvert.m */, D4D2106B12D69C8900509E57 /* HAXApplication.h */, D4D2106C12D69C8B00509E57 /* HAXApplication.m */, D4D2103512D6959400509E57 /* HAXElement.h */, @@ -149,11 +149,10 @@ D4D2105912D6991900509E57 /* HAXSystem.h in Headers */, C3E2152A194F38FB00C85776 /* HAXView.h in Headers */, D4D2103712D6959400509E57 /* HAXElement.h in Headers */, - C3E21522194F381400C85776 /* HAXWindow.h in Headers */, D4D2113E12D6AB0400509E57 /* HAXApplication.h in Headers */, C3E21520194F381400C85776 /* HAXButton.h in Headers */, D4D2113F12D6AB0400509E57 /* HAXWindow.h in Headers */, - C3E21526194F38BE00C85776 /* NSScreen+PointConvert.h in Headers */, + C3E21526194F38BE00C85776 /* NSScreen+HAXPointConvert.h in Headers */, D4D2113D12D6AAF000509E57 /* Haxcessibility.h in Headers */, BC3B3B76175E9FD4002AD452 /* HAXElement+Protected.h in Headers */, ); @@ -229,12 +228,11 @@ files = ( C3E2152B194F38FB00C85776 /* HAXView.m in Sources */, D4D2103812D6959400509E57 /* HAXElement.m in Sources */, - C3E21523194F381400C85776 /* HAXWindow.m in Sources */, C3E21521194F381400C85776 /* HAXButton.m in Sources */, D4D2105512D698F400509E57 /* HAXSystem.m in Sources */, D4D2106D12D69C8B00509E57 /* HAXApplication.m in Sources */, D4D2108212D6A08800509E57 /* HAXWindow.m in Sources */, - C3E21527194F38BE00C85776 /* NSScreen+PointConvert.m in Sources */, + C3E21527194F38BE00C85776 /* NSScreen+HAXPointConvert.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Other Sources/Haxcessibility.h b/Other Sources/Haxcessibility.h index 34da849..48eae4f 100644 --- a/Other Sources/Haxcessibility.h +++ b/Other Sources/Haxcessibility.h @@ -6,3 +6,5 @@ #import #import #import +#import +#import From 48f615dc7aca93cb8aa5c453cb553309bcac022c Mon Sep 17 00:00:00 2001 From: Scott Perry Date: Thu, 5 Mar 2015 20:37:25 -0800 Subject: [PATCH 4/9] Convert headers and reduce import scope as appropriate --- Classes/HAXApplication.h | 2 +- Classes/HAXButton.h | 2 +- Classes/HAXElement+Protected.h | 3 +-- Classes/HAXElement.h | 2 +- Classes/HAXSystem.h | 2 +- Classes/HAXView.h | 3 ++- Classes/HAXView.m | 1 + Classes/HAXWindow.h | 3 ++- Classes/HAXWindow.m | 1 + 9 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Classes/HAXApplication.h b/Classes/HAXApplication.h index 5b33548..29e5c94 100644 --- a/Classes/HAXApplication.h +++ b/Classes/HAXApplication.h @@ -2,7 +2,7 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import "HAXElement.h" +#import @class HAXWindow; diff --git a/Classes/HAXButton.h b/Classes/HAXButton.h index 0c42d57..37e0e2b 100644 --- a/Classes/HAXButton.h +++ b/Classes/HAXButton.h @@ -2,7 +2,7 @@ // Created by Kocsis Olivér on 2014-05-21 // Copyright 2014 Joinect Technologies -#import "HAXView.h" +#import @interface HAXButton : HAXView diff --git a/Classes/HAXElement+Protected.h b/Classes/HAXElement+Protected.h index e7c526a..dbc4489 100644 --- a/Classes/HAXElement+Protected.h +++ b/Classes/HAXElement+Protected.h @@ -2,8 +2,7 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import "HAXElement.h" -#import "NSScreen+HAXPointConvert.h" +#import @interface HAXElement () diff --git a/Classes/HAXElement.h b/Classes/HAXElement.h index 01af729..7ce7e7e 100644 --- a/Classes/HAXElement.h +++ b/Classes/HAXElement.h @@ -1,7 +1,7 @@ // HAXElement.h // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import "Cocoa/Cocoa.h" + #import @protocol HAXElementDelegate; diff --git a/Classes/HAXSystem.h b/Classes/HAXSystem.h index 7b44a09..d608735 100644 --- a/Classes/HAXSystem.h +++ b/Classes/HAXSystem.h @@ -2,7 +2,7 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import "HAXElement.h" +#import @class HAXApplication; diff --git a/Classes/HAXView.h b/Classes/HAXView.h index 369b906..73566ab 100644 --- a/Classes/HAXView.h +++ b/Classes/HAXView.h @@ -2,7 +2,8 @@ // Created by Kocsis Olivér on 2014-05-12 // Copyright 2014 Joinect Technologies -#import "HAXElement.h" +#import +#import @interface HAXView : HAXElement @property (nonatomic, assign) CGPoint carbonOrigin; diff --git a/Classes/HAXView.m b/Classes/HAXView.m index 20595f6..698b9e2 100644 --- a/Classes/HAXView.m +++ b/Classes/HAXView.m @@ -4,6 +4,7 @@ #import "HAXView.h" #import "HAXElement+Protected.h" +#import "NSScreen+HAXPointConvert.h" @implementation HAXView diff --git a/Classes/HAXWindow.h b/Classes/HAXWindow.h index 0d43cd7..c3ec4b6 100644 --- a/Classes/HAXWindow.h +++ b/Classes/HAXWindow.h @@ -2,7 +2,8 @@ // Created by Rob Rix on 2011-01-06 // Copyright 2011 Rob Rix -#import "HAXElement.h" +#import +#import @interface HAXWindow : HAXElement diff --git a/Classes/HAXWindow.m b/Classes/HAXWindow.m index d1a8786..b5e2cb0 100644 --- a/Classes/HAXWindow.m +++ b/Classes/HAXWindow.m @@ -5,6 +5,7 @@ #import "HAXWindow.h" #import "HAXElement+Protected.h" #import "HAXView.h" +#import "NSScreen+HAXPointConvert.h" CG_INLINE BOOL compareRect(CGRect rect1, CGRect rect2 , unsigned int epsilon) { From f2f1d613485b3475dd863a3740b90275c985c7a7 Mon Sep 17 00:00:00 2001 From: Scott Perry Date: Fri, 6 Mar 2015 11:43:07 -0800 Subject: [PATCH 5/9] Fix static analyzer warnings --- Classes/HAXApplication.m | 2 +- Classes/HAXWindow.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/HAXApplication.m b/Classes/HAXApplication.m index 0dc7c9e..0a09969 100644 --- a/Classes/HAXApplication.m +++ b/Classes/HAXApplication.m @@ -36,7 +36,7 @@ -(NSArray *)windows } -(NSString *)localizedName { - return [self copyAttributeValueForKey:(NSString *)kAXTitleAttribute error:NULL]; + return CFBridgingRelease([self copyAttributeValueForKey:(NSString *)kAXTitleAttribute error:NULL]); } -(pid_t)processIdentifier { diff --git a/Classes/HAXWindow.m b/Classes/HAXWindow.m index b5e2cb0..a0649dd 100644 --- a/Classes/HAXWindow.m +++ b/Classes/HAXWindow.m @@ -150,7 +150,7 @@ -(NSArray *)views NSString * axRole; for (HAXElement * haxElementI in axChildren) { - axRole = [haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; + axRole = CFBridgingRelease([haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]); if ([axRole isEqualToString:@"AXView"]) { HAXView * haxView = [HAXView elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; From 39fe0c82ab0b843f0fad36d3f4e4b23467e5707a Mon Sep 17 00:00:00 2001 From: Scott Perry Date: Fri, 6 Mar 2015 12:46:56 -0800 Subject: [PATCH 6/9] Match style, strip threading, strip logging, strip unused error objects, add autoreleasing attribute getter --- Classes/HAXApplication.m | 16 +- Classes/HAXButton.m | 3 +- Classes/HAXElement+Protected.h | 5 +- Classes/HAXElement.h | 6 +- Classes/HAXElement.m | 282 ++++++++--------------------- Classes/HAXSystem.m | 9 +- Classes/HAXView.m | 57 ++---- Classes/HAXWindow.h | 7 +- Classes/HAXWindow.m | 107 +++-------- Classes/NSScreen+HAXPointConvert.m | 31 +--- 10 files changed, 147 insertions(+), 376 deletions(-) diff --git a/Classes/HAXApplication.m b/Classes/HAXApplication.m index 0a09969..ead6247 100644 --- a/Classes/HAXApplication.m +++ b/Classes/HAXApplication.m @@ -8,8 +8,7 @@ @implementation HAXApplication -+(instancetype)applicationWithPID:(pid_t)pid; -{ ++(instancetype)applicationWithPID:(pid_t)pid { AXUIElementRef app = AXUIElementCreateApplication(pid); id result = nil; if (app) { @@ -19,15 +18,12 @@ +(instancetype)applicationWithPID:(pid_t)pid; return result; } --(HAXWindow *)focusedWindow -{ - NSError *error = nil; - return [self elementOfClass:[HAXWindow class] forKey:(NSString *)kAXFocusedWindowAttribute error:&error]; +-(HAXWindow *)focusedWindow { + return [self elementOfClass:[HAXWindow class] forKey:(NSString *)kAXFocusedWindowAttribute error:nil]; } --(NSArray *)windows -{ - NSArray *axWindowObjects = CFBridgingRelease([self copyAttributeValueForKey:(NSString *)kAXWindowsAttribute error:nil]); +-(NSArray *)windows { + NSArray *axWindowObjects = [self getAttributeValueForKey:(NSString *)kAXWindowsAttribute error:nil]; NSMutableArray *result = [NSMutableArray arrayWithCapacity:[axWindowObjects count]]; for (id axObject in axWindowObjects) { [result addObject:[HAXWindow elementWithElementRef:(AXUIElementRef)axObject]]; @@ -36,7 +32,7 @@ -(NSArray *)windows } -(NSString *)localizedName { - return CFBridgingRelease([self copyAttributeValueForKey:(NSString *)kAXTitleAttribute error:NULL]); + return [self getAttributeValueForKey:(NSString *)kAXTitleAttribute error:NULL]; } -(pid_t)processIdentifier { diff --git a/Classes/HAXButton.m b/Classes/HAXButton.m index b129b2a..5155ef9 100644 --- a/Classes/HAXButton.m +++ b/Classes/HAXButton.m @@ -7,8 +7,7 @@ @implementation HAXButton --(void)press -{ +-(void)press { [self performAction:(__bridge NSString *)kAXPressAction error:NULL]; } diff --git a/Classes/HAXElement+Protected.h b/Classes/HAXElement+Protected.h index dbc4489..36a94f9 100644 --- a/Classes/HAXElement+Protected.h +++ b/Classes/HAXElement+Protected.h @@ -11,9 +11,10 @@ @property (nonatomic, readonly) AXUIElementRef elementRef __attribute__((NSObject)); +-(id)getAttributeValueForKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1))); -(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1))); --(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1,2))); --(bool)performAction:(NSString *)action error:(NSError **)error __attribute__((nonnull(1))); +-(BOOL)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1,2))); +-(BOOL)performAction:(NSString *)action error:(NSError **)error __attribute__((nonnull(1))); -(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error __attribute__((nonnull(1,2))); diff --git a/Classes/HAXElement.h b/Classes/HAXElement.h index 7ce7e7e..416862d 100644 --- a/Classes/HAXElement.h +++ b/Classes/HAXElement.h @@ -14,15 +14,13 @@ @property (nonatomic, readonly) BOOL hasChildren; @property (nonatomic, readonly) NSArray *children; @property (nonatomic, readonly) NSArray *attributeNames; +@property (nonatomic, readonly) NSArray *buttons; --(bool)isEqualToElement:(HAXElement *)other; --(NSArray *) buttons; +-(BOOL)isEqualToElement:(HAXElement *)other; @end @protocol HAXElementDelegate - @optional -(void)elementWasDestroyed:(HAXElement *)element; - @end diff --git a/Classes/HAXElement.m b/Classes/HAXElement.m index 252205e..1318e55 100644 --- a/Classes/HAXElement.m +++ b/Classes/HAXElement.m @@ -15,8 +15,7 @@ @interface HAXElement () @implementation HAXElement -+(instancetype)elementWithElementRef:(AXUIElementRef)elementRef -{ ++(instancetype)elementWithElementRef:(AXUIElementRef)elementRef { return [[self alloc] initWithElementRef:elementRef]; } @@ -37,7 +36,7 @@ -(void)dealloc { } } --(bool)isEqualToElement:(HAXElement *)other { +-(BOOL)isEqualToElement:(HAXElement *)other { return [other isKindOfClass:self.class] && CFEqual(self.elementRef, other.elementRef); @@ -51,30 +50,22 @@ -(NSUInteger)hash { return CFHash(self.elementRef); } -- (void)setDelegate:(id)delegate; -{ +-(void)setDelegate:(id)delegate { if (delegate && !_observer) { [self addAXObserver]; } _delegate = delegate; } --(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error -{ +-(id)getAttributeValueForKey:(NSString *)key error:(NSError **)error { + CFTypeRef result = [self copyAttributeValueForKey:key error:error]; + return result ? CFBridgingRelease(result) : nil; +} + +-(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error { NSParameterAssert(key != nil); - __block CFTypeRef attributeRef = NULL; - __block AXError result = 0; - if ([NSThread isMainThread]) - { - result = AXUIElementCopyAttributeValue(self.elementRef, (__bridge CFStringRef)key, &attributeRef); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - result = AXUIElementCopyAttributeValue(self.elementRef, (__bridge CFStringRef)key, &attributeRef); - }); - } + CFTypeRef attributeRef = NULL; + AXError result = AXUIElementCopyAttributeValue(self.elementRef, (__bridge CFStringRef)key, &attributeRef); if((result != kAXErrorSuccess) && error) { *error = [NSError errorWithDomain:NSStringFromClass(self.class) code:result userInfo:@{ @"key": key, @@ -84,24 +75,11 @@ -(CFTypeRef)copyAttributeValueForKey:(NSString *)key error:(NSError **)error return attributeRef; } --(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error -{ +-(BOOL)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError **)error { NSParameterAssert(value != nil); NSParameterAssert(key != nil); - __block AXError result = 0; - if ([NSThread isMainThread]) - { - AXUIElementSetAttributeValue(self.elementRef, (__bridge CFStringRef)key, value); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - AXUIElementSetAttributeValue(self.elementRef, (__bridge CFStringRef)key, value); - }); - } - - if((result != kAXErrorSuccess) && error) { + AXError result = AXUIElementSetAttributeValue(self.elementRef, (__bridge CFStringRef)key, value); + if((result != kAXErrorSuccess) && error) { *error = [NSError errorWithDomain:NSStringFromClass(self.class) code:result userInfo:@{ @"key": key, @"elementRef": (id)self.elementRef @@ -110,25 +88,10 @@ -(bool)setAttributeValue:(CFTypeRef)value forKey:(NSString *)key error:(NSError return result == kAXErrorSuccess; } --(bool)performAction:(NSString *)action error:(NSError **)error -{ +-(BOOL)performAction:(NSString *)action error:(NSError **)error { NSParameterAssert(action != nil); - __block AXError result = 0; - if ([NSThread isMainThread]) - { - AXUIElementPerformAction(self.elementRef, (__bridge CFStringRef)action); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - AXUIElementPerformAction(self.elementRef, (__bridge CFStringRef)action); - }); - } - - - if ((result != kAXErrorSuccess) && error) - { + AXError result = AXUIElementPerformAction(self.elementRef, (__bridge CFStringRef)action); + if ((result != kAXErrorSuccess) && error) { *error = [NSError errorWithDomain:NSStringFromClass(self.class) code:result userInfo:@{ @"action": action, @"elementRef": (id)self.elementRef @@ -138,12 +101,11 @@ -(bool)performAction:(NSString *)action error:(NSError **)error return result == kAXErrorSuccess; } --(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error -{ + +-(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error { AXUIElementRef subelementRef = (AXUIElementRef)[self copyAttributeValueForKey:key error:error]; id result = nil; - if (subelementRef) - { + if (subelementRef) { result = [klass elementWithElementRef:subelementRef]; CFRelease(subelementRef); subelementRef = NULL; @@ -151,108 +113,46 @@ -(id)elementOfClass:(Class)klass forKey:(NSString *)key error:(NSError **)error return result; } --(void)addAXObserver -{ + +-(void)addAXObserver { if (self.observer) { return; } - __block AXObserverRef observer = NULL; - __block AXError err = 0; - __block pid_t pid = 0; - - if ([NSThread isMainThread]) - { - err = AXUIElementGetPid(self.elementRef, &pid); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - err = AXUIElementGetPid(self.elementRef, &pid); - }); - } - if (err != kAXErrorSuccess) { return; } - - if ([NSThread isMainThread]) - { - err = AXObserverCreate(pid, axCallback, &observer); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - err = AXObserverCreate(pid, axCallback, &observer); - }); - } + AXObserverRef observer; + AXError err; + pid_t pid; - if (err != kAXErrorSuccess) { return; } - if ([NSThread isMainThread]) - { - err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); - }); - } - - if (err != kAXErrorSuccess) { - CFRelease(observer); - observer = NULL; - return; - } - if ([NSThread isMainThread]) - { - err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); - }); - } - + err = AXUIElementGetPid(self.elementRef, &pid); + if (err != kAXErrorSuccess) { return; } + + err = AXObserverCreate(pid, axCallback, &observer); + if (err != kAXErrorSuccess) { return; } + + err = AXObserverAddNotification(observer, self.elementRef, kAXUIElementDestroyedNotification, (__bridge void *)(self)); if (err != kAXErrorSuccess) { CFRelease(observer); observer = NULL; return; } - if ([NSThread isMainThread]) - { - CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); - }); - } - - + + CFRunLoopAddSource([[NSRunLoop mainRunLoop] getCFRunLoop], AXObserverGetRunLoopSource(observer), kCFRunLoopDefaultMode); + self.observer = observer; CFRelease(observer); } -static void axCallback(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void *refcon) -{ +static void axCallback(AXObserverRef observer, AXUIElementRef element, CFStringRef notification, void *refcon) { [(__bridge HAXElement *)refcon didObserveNotification:(__bridge NSString *)notification]; } --(void)didObserveNotification:(NSString *)notification -{ +-(void)didObserveNotification:(NSString *)notification { id delegate = self.delegate; - if ([notification isEqualToString:(__bridge NSString *)kAXUIElementDestroyedNotification] && [delegate respondsToSelector:@selector(elementWasDestroyed:)]) - { + if ([notification isEqualToString:(__bridge NSString *)kAXUIElementDestroyedNotification] && [delegate respondsToSelector:@selector(elementWasDestroyed:)]) { [delegate elementWasDestroyed:self]; } } --(void)removeAXObserver -{ +-(void)removeAXObserver { if (!self.observer) { return; } (void)AXObserverRemoveNotification(self.observer, self.elementRef, kAXUIElementDestroyedNotification); @@ -265,101 +165,65 @@ -(void)removeAXObserver self.observer = NULL; } --(BOOL)hasChildren -{ - NSError * error = nil; - NSArray * result = nil; - result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); - if (error || result == nil) - { - NSLog(@"role getter:: %@", [error debugDescription]); - result = nil; - } - return result ? [result count] : NO; - +-(BOOL)hasChildren { + return (self.children.count > 0); } --(NSArray *)children -{ - NSError * error = nil; +-(NSArray *)children { NSArray * axUIElements = nil; - axUIElements = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:&error]); - if (error) - { - NSLog(@"childrenElementRefs getter:: %@", [error debugDescription]); - - axUIElements = nil; - } - NSMutableArray * result = [NSMutableArray arrayWithCapacity:[axUIElements count]]; - for (id elementI in axUIElements) - { - [result addObject:[HAXElement elementWithElementRef:(AXUIElementRef)(elementI) ]]; + NSMutableArray * result = nil; + + axUIElements = [self getAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:nil]; + if (axUIElements != nil) { + result = [NSMutableArray arrayWithCapacity:[axUIElements count]]; + for (id elementI in axUIElements) { + [result addObject:[HAXElement elementWithElementRef:(AXUIElementRef)(elementI)]]; + } } + return result; } --(NSString *)role -{ - NSError * error = nil; - NSString * result = nil; - result = CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:&error]); - if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) - { - NSLog(@"role getter:: %@", [error debugDescription]); +-(NSString *)role { + NSString * result = [self getAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:nil]; + if ([result isKindOfClass:[NSString class]] == NO) { result = nil; } return result; - } --(NSArray *) buttons -{ +-(NSArray *) buttons { NSArray *axChildren = self.children; NSMutableArray *result = [NSMutableArray array]; NSString * axRole; - for (HAXElement * haxElementI in axChildren) - { - axRole = [haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; - if ([axRole isEqualToString:(__bridge NSString *)kAXButtonRole]) - { - HAXButton * haxView = [HAXButton elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; - [result addObject:haxView]; + for (HAXElement *haxElementI in axChildren) { + axRole = CFBridgingRelease([haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]); + if (axRole == nil) { + result = nil; + break; + } + if ([axRole isEqualToString:(__bridge NSString *)kAXButtonRole]) { + HAXButton *button = [HAXButton elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; + [result addObject:button]; } } - return [result count] ? result : nil; + + return result; } --(NSString *)title -{ - NSError * error = nil; - NSString * result = nil; - result = CFBridgingRelease([self copyAttributeValueForKey:NSAccessibilityTitleAttribute error:&error]); - if (error || result == nil || [result isKindOfClass:[NSString class]] == NO ) - { - NSLog(@"title getter:: %@", [error debugDescription]); +-(NSString *)title { + NSString * result = [self getAttributeValueForKey:NSAccessibilityTitleAttribute error:nil]; + if ([result isKindOfClass:[NSString class]] == NO) { result = nil; } return result; } --(NSArray *)attributeNames -{ - __block CFArrayRef attrNamesRef = NULL; - NSArray *attrNames = nil; - if ([NSThread isMainThread]) - { - AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); - } - else - { - dispatch_sync(dispatch_get_main_queue(), ^ - { - AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); - }); - } - attrNames = CFBridgingRelease(attrNamesRef); - return attrNames; +-(NSArray *)attributeNames { + CFArrayRef attrNamesRef = NULL; + AXUIElementCopyAttributeNames(_elementRef, &attrNamesRef); + return attrNamesRef ? CFBridgingRelease(attrNamesRef) : nil; } @end diff --git a/Classes/HAXSystem.m b/Classes/HAXSystem.m index 6890638..a662817 100644 --- a/Classes/HAXSystem.m +++ b/Classes/HAXSystem.m @@ -8,8 +8,7 @@ @implementation HAXSystem -+(instancetype)system -{ ++(instancetype)system { AXUIElementRef element = AXUIElementCreateSystemWide(); HAXSystem *result = [self elementWithElementRef:element]; CFRelease(element); @@ -17,10 +16,8 @@ +(instancetype)system } --(HAXApplication *)focusedApplication -{ - NSError *error = nil; - return [self elementOfClass:[HAXApplication class] forKey:(NSString *)kAXFocusedApplicationAttribute error:&error]; +-(HAXApplication *)focusedApplication { + return [self elementOfClass:[HAXApplication class] forKey:(NSString *)kAXFocusedApplicationAttribute error:nil]; } @end diff --git a/Classes/HAXView.m b/Classes/HAXView.m index 698b9e2..0bebff1 100644 --- a/Classes/HAXView.m +++ b/Classes/HAXView.m @@ -9,19 +9,16 @@ @implementation HAXView --(BOOL)isFullscreen -{ +-(BOOL)isFullscreen { BOOL isFullScreen = NO; NSArray * sceenArray = [NSScreen screens]; - for (NSScreen * screenI in sceenArray) - { + for (NSScreen * screenI in sceenArray) { NSRect screenFrame; screenFrame = [screenI frame]; NSRect windowFrame = self.frame; - if(NSEqualRects(screenFrame, windowFrame)) - { + if(NSEqualRects(screenFrame, windowFrame)) { isFullScreen = YES; break; } @@ -29,13 +26,10 @@ -(BOOL)isFullscreen return isFullScreen; } --(NSScreen *)screen -{ +-(NSScreen *)screen { NSScreen *fullscreenScreen = nil; - for (NSScreen * screenI in [NSScreen screens]) - { - if(NSEqualRects([screenI frame], self.frame)) - { + for (NSScreen * screenI in [NSScreen screens]) { + if(NSEqualRects([screenI frame], self.frame)) { fullscreenScreen = screenI; break; } @@ -43,12 +37,10 @@ -(NSScreen *)screen return fullscreenScreen; } --(CGPoint)carbonOrigin -{ +-(CGPoint)carbonOrigin { CGPoint origin = {0}; - CFTypeRef originRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; - if(originRef) - { + AXValueRef originRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; + if(originRef) { AXValueGetValue(originRef, kAXValueCGPointType, &origin); CFRelease(originRef); originRef = NULL; @@ -56,24 +48,20 @@ -(CGPoint)carbonOrigin return origin; } --(CGPoint)origin -{ +-(CGPoint)origin { return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.carbonFrame].origin; } --(void)setCarbonOrigin:(CGPoint)carbonOrigin -{ +-(void)setCarbonOrigin:(CGPoint)carbonOrigin { AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &carbonOrigin); [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; CFRelease(originRef); } --(NSSize)size -{ +-(NSSize)size { CGSize size = {0}; - CFTypeRef sizeRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; - if(sizeRef) - { + AXValueRef sizeRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; + if(sizeRef) { AXValueGetValue(sizeRef, kAXValueCGSizeType, &size); CFRelease(sizeRef); sizeRef = NULL; @@ -81,32 +69,27 @@ -(NSSize)size return size; } --(void)setSize:(NSSize)size -{ +-(void)setSize:(NSSize)size { AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; CFRelease(sizeRef); } --(CGRect)carbonFrame -{ +-(CGRect)carbonFrame { return (CGRect){ .origin = self.carbonOrigin, .size = self.size }; } --(NSRect)frame -{ +-(NSRect)frame { return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.carbonFrame]; } --(void)setCarbonFrame:(CGRect)carbonFrame -{ +-(void)setCarbonFrame:(CGRect)carbonFrame { self.carbonOrigin = carbonFrame.origin; self.size = carbonFrame.size; } --(NSString *)title -{ - return CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]); +-(NSString *)title { + return [self getAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]; } @end diff --git a/Classes/HAXWindow.h b/Classes/HAXWindow.h index c3ec4b6..1862130 100644 --- a/Classes/HAXWindow.h +++ b/Classes/HAXWindow.h @@ -15,10 +15,9 @@ @property (nonatomic, readonly) NSString *title; @property (nonatomic, readonly) NSScreen *screen; @property (nonatomic, readonly) NSArray *views; +@property (nonatomic, readonly, getter=isFullscreen) BOOL fullscreen; --(BOOL)isFullscreen; --(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon; --(bool)raise; --(bool)close; +-(BOOL)raise; +-(BOOL)close; @end diff --git a/Classes/HAXWindow.m b/Classes/HAXWindow.m index a0649dd..d6a3e29 100644 --- a/Classes/HAXWindow.m +++ b/Classes/HAXWindow.m @@ -7,54 +7,18 @@ #import "HAXView.h" #import "NSScreen+HAXPointConvert.h" -CG_INLINE BOOL compareRect(CGRect rect1, CGRect rect2 , unsigned int epsilon) -{ - if (ABS(rect1.size.width - rect2.size.width) > epsilon) - return NO; - if (ABS(rect1.size.height - rect2.size.height) > epsilon) - return NO; - if (ABS(rect1.origin.x - rect2.origin.x) > epsilon) - return NO; - if (ABS(rect1.origin.y - rect2.origin.y) > epsilon) - return NO; - return YES; -} - @implementation HAXWindow --(BOOL)isFullscreen -{ +-(BOOL)isFullscreen { BOOL isFullScreen = NO; NSArray * sceenArray = [NSScreen screens]; - for (NSScreen * screenI in sceenArray) - { - NSRect screenFrame; - screenFrame = [screenI frame]; - NSRect windowFrame = self.frame; - - if(NSEqualRects(screenFrame, windowFrame)) - { - isFullScreen = YES; - break; - } - } - return isFullScreen; -} - --(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon -{ - BOOL isFullScreen = NO; - NSArray * sceenArray = [NSScreen screens]; - - for (NSScreen * screenI in sceenArray) - { + for (NSScreen * screenI in sceenArray) { NSRect screenFrame; screenFrame = [screenI frame]; NSRect windowFrame = self.frame; - if( compareRect(screenFrame, windowFrame, epsilon) ) - { + if(NSEqualRects(screenFrame, windowFrame)) { isFullScreen = YES; break; } @@ -62,13 +26,10 @@ -(BOOL)isFullscreenWithEpsilon: (unsigned int) epsilon return isFullScreen; } --(NSScreen *)screen -{ +-(NSScreen *)screen { NSScreen *fullscreenScreen = nil; - for (NSScreen * screenI in [NSScreen screens]) - { - if(NSEqualRects([screenI frame], self.frame)) - { + for (NSScreen * screenI in [NSScreen screens]) { + if(NSEqualRects([screenI frame], self.frame)) { fullscreenScreen = screenI; break; } @@ -76,12 +37,10 @@ -(NSScreen *)screen return fullscreenScreen; } --(CGPoint)carbonOrigin -{ +-(CGPoint)carbonOrigin { CGPoint origin = {0}; - CFTypeRef originRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; - if(originRef) - { + AXValueRef originRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; + if(originRef) { AXValueGetValue(originRef, kAXValueCGPointType, &origin); CFRelease(originRef); originRef = NULL; @@ -89,24 +48,20 @@ -(CGPoint)carbonOrigin return origin; } --(CGPoint)origin -{ +-(CGPoint)origin { return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon].origin; } --(void)setCarbonOrigin:(CGPoint)carbonOrigin -{ +-(void)setCarbonOrigin:(CGPoint)carbonOrigin { AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &carbonOrigin); [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; CFRelease(originRef); } --(NSSize)size -{ +-(NSSize)size { CGSize size = {0}; - CFTypeRef sizeRef = [self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; - if(sizeRef) - { + AXValueRef sizeRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; + if(sizeRef) { AXValueGetValue(sizeRef, kAXValueCGSizeType, &size); CFRelease(sizeRef); sizeRef = NULL; @@ -114,45 +69,37 @@ -(NSSize)size return size; } --(void)setSize:(NSSize)size -{ +-(void)setSize:(NSSize)size { AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; CFRelease(sizeRef); } --(CGRect)frameCarbon -{ +-(CGRect)frameCarbon { return (CGRect){ .origin = self.carbonOrigin, .size = self.size }; } --(NSRect)frame -{ +-(NSRect)frame { return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon]; } --(void)setCarbonFrame:(CGRect)carbonFrame -{ +-(void)setCarbonFrame:(CGRect)carbonFrame { self.carbonOrigin = carbonFrame.origin; self.size = carbonFrame.size; } --(NSString *)title -{ - return CFBridgingRelease([self copyAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]); +-(NSString *)title { + return [self getAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]; } --(NSArray *)views -{ +-(NSArray *)views { NSArray *axChildren = self.children; NSMutableArray *result = [NSMutableArray array]; NSString * axRole; - for (HAXElement * haxElementI in axChildren) - { - axRole = CFBridgingRelease([haxElementI copyAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]); - if ([axRole isEqualToString:@"AXView"]) - { + for (HAXElement * haxElementI in axChildren) { + axRole = [haxElementI getAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; + if ([axRole isEqualToString:@"AXView"]) { HAXView * haxView = [HAXView elementWithElementRef:(AXUIElementRef)haxElementI.elementRef]; [result addObject:haxView]; } @@ -161,13 +108,11 @@ -(NSArray *)views } --(bool)raise -{ +-(BOOL)raise { return [self performAction:(__bridge NSString *)kAXRaiseAction error:NULL]; } --(bool)close -{ +-(BOOL)close { HAXElement *element = [self elementOfClass:[HAXElement class] forKey:(__bridge NSString *)kAXCloseButtonAttribute error:NULL]; return [element performAction:(__bridge NSString *)kAXPressAction error:NULL]; } diff --git a/Classes/NSScreen+HAXPointConvert.m b/Classes/NSScreen+HAXPointConvert.m index b14036b..ffde73a 100644 --- a/Classes/NSScreen+HAXPointConvert.m +++ b/Classes/NSScreen+HAXPointConvert.m @@ -6,13 +6,10 @@ @implementation NSScreen (HAXPointConvert) -+ (NSScreen*)hax_screenWithPoint:(NSPoint)p -{ ++ (NSScreen*)hax_screenWithPoint:(NSPoint)p { NSScreen *screen = nil; - for (NSScreen *screenI in [NSScreen screens]) - { - if (NSPointInRect(p, [screenI frame])) - { + for (NSScreen *screenI in [NSScreen screens]) { + if (NSPointInRect(p, [screenI frame])) { screen = screenI; break; } @@ -20,8 +17,7 @@ + (NSScreen*)hax_screenWithPoint:(NSPoint)p return screen; } -- (NSRect)hax_frameCarbon -{ +- (NSRect)hax_frameCarbon { NSRect originScreenFrame = ((NSScreen *)[NSScreen screens][0]).frame; NSRect carbonFrame; @@ -33,8 +29,7 @@ - (NSRect)hax_frameCarbon return carbonFrame; } -+ (NSRect)hax_cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint -{ ++ (NSRect)hax_cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint { NSRect originScreenFrame = ((NSScreen *)[NSScreen screens][0]).frame; NSRect cocoaFrame; @@ -46,26 +41,20 @@ + (NSRect)hax_cocoaScreenFrameFromCarbonScreenFrame:(CGRect)carbonPoint return cocoaFrame; } -+ (CGPoint)hax_carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint -{ ++ (CGPoint)hax_carbonScreenPointFromCocoaScreenPoint:(NSPoint)cocoaPoint { NSScreen *foundScreen = nil; CGPoint thePoint; - for (NSScreen *screen in [NSScreen screens]) - { - if (NSPointInRect(cocoaPoint, [screen frame])) - { + for (NSScreen *screen in [NSScreen screens]) { + if (NSPointInRect(cocoaPoint, [screen frame])) { foundScreen = screen; } } - if (foundScreen) - { + if (foundScreen) { CGFloat screenHeight = [foundScreen frame].size.height; thePoint = CGPointMake(cocoaPoint.x, screenHeight - cocoaPoint.y - 1); - } - else - { + } else { thePoint = CGPointMake(0.0, 0.0); } From c1c30bba769cd533892f2cde25d890af5fe4dd76 Mon Sep 17 00:00:00 2001 From: Scott Perry Date: Fri, 6 Mar 2015 13:07:47 -0800 Subject: [PATCH 7/9] Refactor HAXWindow to subclass HAXView, fix some screen-related correctness and performance issues. --- Classes/HAXView.h | 4 +- Classes/HAXView.m | 120 +++++++++++++++++++++++--------------------- Classes/HAXWindow.h | 12 +---- Classes/HAXWindow.m | 85 ------------------------------- 4 files changed, 66 insertions(+), 155 deletions(-) diff --git a/Classes/HAXView.h b/Classes/HAXView.h index 73566ab..fa717a5 100644 --- a/Classes/HAXView.h +++ b/Classes/HAXView.h @@ -6,6 +6,7 @@ #import @interface HAXView : HAXElement + @property (nonatomic, assign) CGPoint carbonOrigin; @property (nonatomic, assign, readonly) NSPoint origin; @property (nonatomic, assign) NSSize size; @@ -13,7 +14,6 @@ @property (nonatomic, assign, readonly) NSRect frame; @property (nonatomic, readonly) NSString *title; @property (nonatomic, readonly) NSScreen *screen; - --(BOOL)isFullscreen; +@property (nonatomic, readonly, getter=isFullscreen) BOOL fullscreen; @end diff --git a/Classes/HAXView.m b/Classes/HAXView.m index 0bebff1..c4668e6 100644 --- a/Classes/HAXView.m +++ b/Classes/HAXView.m @@ -6,90 +6,94 @@ #import "HAXElement+Protected.h" #import "NSScreen+HAXPointConvert.h" - @implementation HAXView --(BOOL)isFullscreen { - BOOL isFullScreen = NO; - NSArray * sceenArray = [NSScreen screens]; - - for (NSScreen * screenI in sceenArray) { - NSRect screenFrame; - screenFrame = [screenI frame]; - NSRect windowFrame = self.frame; - - if(NSEqualRects(screenFrame, windowFrame)) { - isFullScreen = YES; - break; - } - } - return isFullScreen; -} - --(NSScreen *)screen { - NSScreen *fullscreenScreen = nil; - for (NSScreen * screenI in [NSScreen screens]) { - if(NSEqualRects([screenI frame], self.frame)) { - fullscreenScreen = screenI; - break; - } +-(CGPoint)carbonOrigin { + CGPoint origin = {0}; + AXValueRef originRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; + if(originRef) { + AXValueGetValue(originRef, kAXValueCGPointType, &origin); + CFRelease(originRef); + originRef = NULL; } - return fullscreenScreen; + return origin; } --(CGPoint)carbonOrigin { - CGPoint origin = {0}; - AXValueRef originRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; - if(originRef) { - AXValueGetValue(originRef, kAXValueCGPointType, &origin); - CFRelease(originRef); - originRef = NULL; - } - return origin; +-(void)setCarbonOrigin:(CGPoint)carbonOrigin { + AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &carbonOrigin); + [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; + CFRelease(originRef); } --(CGPoint)origin { +-(NSPoint)origin { return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.carbonFrame].origin; } --(void)setCarbonOrigin:(CGPoint)carbonOrigin { - AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &carbonOrigin); - [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; - CFRelease(originRef); -} - -(NSSize)size { - CGSize size = {0}; - AXValueRef sizeRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; - if(sizeRef) { - AXValueGetValue(sizeRef, kAXValueCGSizeType, &size); - CFRelease(sizeRef); - sizeRef = NULL; - } - return size; + CGSize size = {0}; + AXValueRef sizeRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; + if(sizeRef) { + AXValueGetValue(sizeRef, kAXValueCGSizeType, &size); + CFRelease(sizeRef); + sizeRef = NULL; + } + return size; } -(void)setSize:(NSSize)size { - AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); - [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; - CFRelease(sizeRef); + AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); + [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; + CFRelease(sizeRef); } -(CGRect)carbonFrame { return (CGRect){ .origin = self.carbonOrigin, .size = self.size }; } --(NSRect)frame { - return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.carbonFrame]; +-(void)setCarbonFrame:(CGRect)carbonFrame { + self.carbonOrigin = carbonFrame.origin; + self.size = carbonFrame.size; } --(void)setCarbonFrame:(CGRect)carbonFrame { - self.carbonOrigin = carbonFrame.origin; - self.size = carbonFrame.size; +-(NSRect)frame { + return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.carbonFrame]; } -(NSString *)title { return [self getAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]; } +-(NSScreen *)screen { + NSScreen *matchingScreen = nil; + NSRect viewFrame = self.frame; + NSUInteger bestOverlap = 0; + for (NSScreen * screenI in [NSScreen screens]) { + NSRect intersection = NSIntersectionRect(screenI.frame, viewFrame); + NSUInteger intersectionOverlap = intersection.size.width * intersection.size.height; + if(intersectionOverlap > bestOverlap) { + matchingScreen = screenI; + bestOverlap = intersectionOverlap; + break; + } + } + return matchingScreen; +} + +-(BOOL)isFullscreen { + BOOL isFullScreen = NO; + NSArray * sceenArray = [NSScreen screens]; + NSRect windowFrame = self.frame; + + for (NSScreen * screenI in sceenArray) { + NSRect screenFrame; + screenFrame = [screenI frame]; + if(NSEqualRects(screenFrame, windowFrame)) { + isFullScreen = YES; + break; + } + } + + return isFullScreen; +} + @end diff --git a/Classes/HAXWindow.h b/Classes/HAXWindow.h index 1862130..6f038a4 100644 --- a/Classes/HAXWindow.h +++ b/Classes/HAXWindow.h @@ -3,19 +3,11 @@ // Copyright 2011 Rob Rix #import -#import +#import -@interface HAXWindow : HAXElement +@interface HAXWindow : HAXView -@property (nonatomic, assign) CGPoint carbonOrigin; -@property (nonatomic, assign, readonly) NSPoint origin; -@property (nonatomic, assign) NSSize size; -@property (nonatomic, assign) CGRect frameCarbon; -@property (nonatomic, assign, readonly) NSRect frame; -@property (nonatomic, readonly) NSString *title; -@property (nonatomic, readonly) NSScreen *screen; @property (nonatomic, readonly) NSArray *views; -@property (nonatomic, readonly, getter=isFullscreen) BOOL fullscreen; -(BOOL)raise; -(BOOL)close; diff --git a/Classes/HAXWindow.m b/Classes/HAXWindow.m index d6a3e29..8a33f2f 100644 --- a/Classes/HAXWindow.m +++ b/Classes/HAXWindow.m @@ -4,94 +4,9 @@ #import "HAXWindow.h" #import "HAXElement+Protected.h" -#import "HAXView.h" -#import "NSScreen+HAXPointConvert.h" @implementation HAXWindow --(BOOL)isFullscreen { - BOOL isFullScreen = NO; - NSArray * sceenArray = [NSScreen screens]; - - for (NSScreen * screenI in sceenArray) { - NSRect screenFrame; - screenFrame = [screenI frame]; - NSRect windowFrame = self.frame; - - if(NSEqualRects(screenFrame, windowFrame)) { - isFullScreen = YES; - break; - } - } - return isFullScreen; -} - --(NSScreen *)screen { - NSScreen *fullscreenScreen = nil; - for (NSScreen * screenI in [NSScreen screens]) { - if(NSEqualRects([screenI frame], self.frame)) { - fullscreenScreen = screenI; - break; - } - } - return fullscreenScreen; -} - --(CGPoint)carbonOrigin { - CGPoint origin = {0}; - AXValueRef originRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; - if(originRef) { - AXValueGetValue(originRef, kAXValueCGPointType, &origin); - CFRelease(originRef); - originRef = NULL; - } - return origin; -} - --(CGPoint)origin { - return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon].origin; -} - --(void)setCarbonOrigin:(CGPoint)carbonOrigin { - AXValueRef originRef = AXValueCreate(kAXValueCGPointType, &carbonOrigin); - [self setAttributeValue:originRef forKey:(__bridge NSString *)kAXPositionAttribute error:NULL]; - CFRelease(originRef); -} - --(NSSize)size { - CGSize size = {0}; - AXValueRef sizeRef = (AXValueRef)[self copyAttributeValueForKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; - if(sizeRef) { - AXValueGetValue(sizeRef, kAXValueCGSizeType, &size); - CFRelease(sizeRef); - sizeRef = NULL; - } - return size; -} - --(void)setSize:(NSSize)size { - AXValueRef sizeRef = AXValueCreate(kAXValueCGSizeType, &size); - [self setAttributeValue:sizeRef forKey:(__bridge NSString *)kAXSizeAttribute error:NULL]; - CFRelease(sizeRef); -} - --(CGRect)frameCarbon { - return (CGRect){ .origin = self.carbonOrigin, .size = self.size }; -} --(NSRect)frame { - return [NSScreen hax_cocoaScreenFrameFromCarbonScreenFrame:self.frameCarbon]; -} - --(void)setCarbonFrame:(CGRect)carbonFrame { - self.carbonOrigin = carbonFrame.origin; - self.size = carbonFrame.size; -} - - --(NSString *)title { - return [self getAttributeValueForKey:(__bridge NSString *)kAXTitleAttribute error:NULL]; -} - -(NSArray *)views { NSArray *axChildren = self.children; NSMutableArray *result = [NSMutableArray array]; From cd612731b6b3cb58ff9d4dd0449c14f112e6f942 Mon Sep 17 00:00:00 2001 From: Scott Perry Date: Fri, 6 Mar 2015 13:16:30 -0800 Subject: [PATCH 8/9] Use the right kind of NULL for pointer argument types --- Classes/HAXApplication.m | 4 ++-- Classes/HAXElement.m | 6 +++--- Classes/HAXSystem.m | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Classes/HAXApplication.m b/Classes/HAXApplication.m index ead6247..dfe06d5 100644 --- a/Classes/HAXApplication.m +++ b/Classes/HAXApplication.m @@ -19,11 +19,11 @@ +(instancetype)applicationWithPID:(pid_t)pid { } -(HAXWindow *)focusedWindow { - return [self elementOfClass:[HAXWindow class] forKey:(NSString *)kAXFocusedWindowAttribute error:nil]; + return [self elementOfClass:[HAXWindow class] forKey:(NSString *)kAXFocusedWindowAttribute error:NULL]; } -(NSArray *)windows { - NSArray *axWindowObjects = [self getAttributeValueForKey:(NSString *)kAXWindowsAttribute error:nil]; + NSArray *axWindowObjects = [self getAttributeValueForKey:(NSString *)kAXWindowsAttribute error:NULL]; NSMutableArray *result = [NSMutableArray arrayWithCapacity:[axWindowObjects count]]; for (id axObject in axWindowObjects) { [result addObject:[HAXWindow elementWithElementRef:(AXUIElementRef)axObject]]; diff --git a/Classes/HAXElement.m b/Classes/HAXElement.m index 1318e55..25c84f9 100644 --- a/Classes/HAXElement.m +++ b/Classes/HAXElement.m @@ -173,7 +173,7 @@ -(NSArray *)children { NSArray * axUIElements = nil; NSMutableArray * result = nil; - axUIElements = [self getAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:nil]; + axUIElements = [self getAttributeValueForKey:(__bridge NSString *)kAXChildrenAttribute error:NULL]; if (axUIElements != nil) { result = [NSMutableArray arrayWithCapacity:[axUIElements count]]; for (id elementI in axUIElements) { @@ -185,7 +185,7 @@ -(NSArray *)children { } -(NSString *)role { - NSString * result = [self getAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:nil]; + NSString * result = [self getAttributeValueForKey:(__bridge NSString *)kAXRoleAttribute error:NULL]; if ([result isKindOfClass:[NSString class]] == NO) { result = nil; } @@ -213,7 +213,7 @@ -(NSArray *) buttons { } -(NSString *)title { - NSString * result = [self getAttributeValueForKey:NSAccessibilityTitleAttribute error:nil]; + NSString * result = [self getAttributeValueForKey:NSAccessibilityTitleAttribute error:NULL]; if ([result isKindOfClass:[NSString class]] == NO) { result = nil; } diff --git a/Classes/HAXSystem.m b/Classes/HAXSystem.m index a662817..b5b4eff 100644 --- a/Classes/HAXSystem.m +++ b/Classes/HAXSystem.m @@ -17,7 +17,7 @@ +(instancetype)system { -(HAXApplication *)focusedApplication { - return [self elementOfClass:[HAXApplication class] forKey:(NSString *)kAXFocusedApplicationAttribute error:nil]; + return [self elementOfClass:[HAXApplication class] forKey:(NSString *)kAXFocusedApplicationAttribute error:NULL]; } @end From 9a216b4c7e6b95b37a223175fde6b69b0f82f813 Mon Sep 17 00:00:00 2001 From: Scott Perry Date: Fri, 6 Mar 2015 22:38:23 -0800 Subject: [PATCH 9/9] Fix new header exports, fix a minor bug --- Classes/HAXView.m | 1 - Classes/HAXWindow.m | 1 - Haxcessibility.xcodeproj/project.pbxproj | 16 ++++++---------- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Classes/HAXView.m b/Classes/HAXView.m index c4668e6..096b6a1 100644 --- a/Classes/HAXView.m +++ b/Classes/HAXView.m @@ -73,7 +73,6 @@ -(NSScreen *)screen { if(intersectionOverlap > bestOverlap) { matchingScreen = screenI; bestOverlap = intersectionOverlap; - break; } } return matchingScreen; diff --git a/Classes/HAXWindow.m b/Classes/HAXWindow.m index 8a33f2f..7fd6d7e 100644 --- a/Classes/HAXWindow.m +++ b/Classes/HAXWindow.m @@ -22,7 +22,6 @@ -(NSArray *)views { return result; } - -(BOOL)raise { return [self performAction:(__bridge NSString *)kAXRaiseAction error:NULL]; } diff --git a/Haxcessibility.xcodeproj/project.pbxproj b/Haxcessibility.xcodeproj/project.pbxproj index d4d38eb..7b0299a 100644 --- a/Haxcessibility.xcodeproj/project.pbxproj +++ b/Haxcessibility.xcodeproj/project.pbxproj @@ -10,11 +10,11 @@ 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; BC3B3B76175E9FD4002AD452 /* HAXElement+Protected.h in Headers */ = {isa = PBXBuildFile; fileRef = D44E051312D75B3D00541D6A /* HAXElement+Protected.h */; settings = {ATTRIBUTES = (Private, ); }; }; - C3E21520194F381400C85776 /* HAXButton.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E2151C194F381400C85776 /* HAXButton.h */; }; + C3E21520194F381400C85776 /* HAXButton.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E2151C194F381400C85776 /* HAXButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3E21521194F381400C85776 /* HAXButton.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E2151D194F381400C85776 /* HAXButton.m */; }; C3E21526194F38BE00C85776 /* NSScreen+HAXPointConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21524194F38BD00C85776 /* NSScreen+HAXPointConvert.h */; }; C3E21527194F38BE00C85776 /* NSScreen+HAXPointConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E21525194F38BD00C85776 /* NSScreen+HAXPointConvert.m */; }; - C3E2152A194F38FB00C85776 /* HAXView.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21528194F38FB00C85776 /* HAXView.h */; }; + C3E2152A194F38FB00C85776 /* HAXView.h in Headers */ = {isa = PBXBuildFile; fileRef = C3E21528194F38FB00C85776 /* HAXView.h */; settings = {ATTRIBUTES = (Public, ); }; }; C3E2152B194F38FB00C85776 /* HAXView.m in Sources */ = {isa = PBXBuildFile; fileRef = C3E21529194F38FB00C85776 /* HAXView.m */; }; D4D2103412D6957000509E57 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4D2103312D6957000509E57 /* Carbon.framework */; }; D4D2103712D6959400509E57 /* HAXElement.h in Headers */ = {isa = PBXBuildFile; fileRef = D4D2103512D6959400509E57 /* HAXElement.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -36,8 +36,6 @@ 8DC2EF5B0486A6940098B216 /* Haxcessibility.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Haxcessibility.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C3E2151C194F381400C85776 /* HAXButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXButton.h; sourceTree = ""; }; C3E2151D194F381400C85776 /* HAXButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXButton.m; sourceTree = ""; }; - C3E2151E194F381400C85776 /* HAXWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXWindow.h; sourceTree = ""; }; - C3E2151F194F381400C85776 /* HAXWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HAXWindow.m; sourceTree = ""; }; C3E21524194F38BD00C85776 /* NSScreen+HAXPointConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSScreen+HAXPointConvert.h"; sourceTree = ""; }; C3E21525194F38BD00C85776 /* NSScreen+HAXPointConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSScreen+HAXPointConvert.m"; sourceTree = ""; }; C3E21528194F38FB00C85776 /* HAXView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HAXView.h; sourceTree = ""; }; @@ -122,19 +120,17 @@ C3E21525194F38BD00C85776 /* NSScreen+HAXPointConvert.m */, D4D2106B12D69C8900509E57 /* HAXApplication.h */, D4D2106C12D69C8B00509E57 /* HAXApplication.m */, + C3E2151C194F381400C85776 /* HAXButton.h */, + C3E2151D194F381400C85776 /* HAXButton.m */, D4D2103512D6959400509E57 /* HAXElement.h */, D44E051312D75B3D00541D6A /* HAXElement+Protected.h */, D4D2103612D6959400509E57 /* HAXElement.m */, D4D2105312D698F200509E57 /* HAXSystem.h */, D4D2105412D698F400509E57 /* HAXSystem.m */, - D4D2108012D6A08600509E57 /* HAXWindow.h */, - D4D2108112D6A08800509E57 /* HAXWindow.m */, - C3E2151C194F381400C85776 /* HAXButton.h */, - C3E2151D194F381400C85776 /* HAXButton.m */, - C3E2151E194F381400C85776 /* HAXWindow.h */, - C3E2151F194F381400C85776 /* HAXWindow.m */, C3E21528194F38FB00C85776 /* HAXView.h */, C3E21529194F38FB00C85776 /* HAXView.m */, + D4D2108012D6A08600509E57 /* HAXWindow.h */, + D4D2108112D6A08800509E57 /* HAXWindow.m */, ); path = Classes; sourceTree = "";