Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
NSAppleScript category to make calling AppleScript handlers (functions) easier
//
// NSAppleScript+RunHandler.h
// astest
//
// Created by Rob Wells on 30/01/2014.
// Copyright (c) 2014 Rob Wells. All rights reserved.
//
#ifndef kASAppleScriptSuite
#define kASAppleScriptSuite 'ascr'
#endif
#ifndef kASSubroutineEvent
#define kASSubroutineEvent 'psbr'
#endif
#ifndef keyASSubroutineName
#define keyASSubroutineName 'snam'
#endif
#import <Foundation/Foundation.h>
@interface NSAppleScript (RunHandler)
- (id)fetchObjectFromDescriptor:(NSAppleEventDescriptor *)descriptor;
- (NSAppleEventDescriptor *)makeParameters:(NSArray *)paramArray;
- (NSAppleEventDescriptor *)callHandler:(NSString *)handlerName
withParameters:(NSAppleEventDescriptor *)parameters;
- (id)getResultFromHandler:(NSString *)handlerName
withParameters:(NSAppleEventDescriptor *)parameters;
@end
//
// NSAppleScript+RunHandler.m
// astest
//
// Created by Rob Wells on 30/01/2014.
// Copyright (c) 2014 Rob Wells. All rights reserved.
//
#import "NSAppleScript+RunHandler.h"
@implementation NSAppleScript (RunHandler)
- (NSAppleEventDescriptor *)makeParameters:(NSArray *)paramArray {
// Create list of parameters
NSAppleEventDescriptor *paramsDescriptor = [NSAppleEventDescriptor listDescriptor];
// Loop through paramArray, turning the objects into descriptors
int i;
for (i = 0; i < paramArray.count; i++) {
id parameter = paramArray[i];
if ([parameter isKindOfClass:[NSAppleEventDescriptor class]]) {
// Already a descriptor, add it as is
[paramsDescriptor insertDescriptor:parameter atIndex:i + 1];
} else if ([parameter isKindOfClass:[NSString class]]) {
// Create a string descriptor
[paramsDescriptor
insertDescriptor:[NSAppleEventDescriptor
descriptorWithString:parameter]
atIndex:i + 1];
} else if ([parameter respondsToSelector:@selector(intValue)]) {
// Create descriptor with number's int value
[paramsDescriptor
insertDescriptor:[NSAppleEventDescriptor
descriptorWithInt32:[parameter intValue]]
atIndex:i + 1];
} else if ([parameter isKindOfClass:[NSArray class]]) {
// Create a list descriptor from an NSArray
NSAppleEventDescriptor *arrayParam = [self makeParameters:parameter];
[paramsDescriptor insertDescriptor:arrayParam
atIndex:i + 1];
} else {
return nil;
}
}
return paramsDescriptor;
}
- (NSAppleEventDescriptor *)callHandler:(NSString *)handlerName
withParameters:(NSAppleEventDescriptor *)parameters {
// Create the AppleEvent target
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor *target = [NSAppleEventDescriptor
descriptorWithDescriptorType:typeProcessSerialNumber
bytes:&psn
length:sizeof(ProcessSerialNumber)];
// Create descriptor with handler to call
// Routine name must be lowercase
NSAppleEventDescriptor *handler = [NSAppleEventDescriptor
descriptorWithString:[handlerName lowercaseString]];
// Create the event for an AppleScript subroutine,
// set the method name and the list of parameters
NSAppleEventDescriptor *event = [NSAppleEventDescriptor
appleEventWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:target
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
[event setParamDescriptor:handler forKeyword:keyASSubroutineName];
if (parameters) {
[event setParamDescriptor:parameters forKeyword:keyDirectObject];
}
// Call the event in AppleScript
NSDictionary *errorDict;
NSAppleEventDescriptor *returnedDescriptor = [self executeAppleEvent:event
error:&errorDict];
if (!returnedDescriptor) {
NSLog(@"%@: %@", handlerName, errorDict[NSAppleScriptErrorMessage]);
}
return returnedDescriptor;
}
- (id)getResultFromHandler:(NSString *)handlerName
withParameters:(NSAppleEventDescriptor *)parameters {
NSAppleEventDescriptor *rawResult = [self callHandler:handlerName
withParameters:parameters];
return [self fetchObjectFromDescriptor:rawResult];
}
- (id)fetchObjectFromDescriptor:(NSAppleEventDescriptor *)descriptor {
NSString *returnType = NSFileTypeForHFSTypeCode([descriptor descriptorType]);
if ([returnType isEqualToString:@"'utxt'"]) {
// Returned data is a string
return [descriptor stringValue];
} else if ([returnType isEqualToString:@"'long'"]) {
// Integer
return [NSNumber numberWithInt:[descriptor int32Value]];
} else if ([returnType isEqualToString:@"'doub'"]) {
// Floating-point number
CGFloat result;
[[descriptor data] getBytes:&result length:[descriptor data].length];
return [NSNumber numberWithFloat:result];
} else if ([returnType isEqualToString:@"'list'"]) {
// List (array) - note AppleScript is 1-based
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSInteger i;
for (i = 1; i <= [descriptor numberOfItems]; i++) {
[resultArray addObject:
[self fetchObjectFromDescriptor:[descriptor descriptorAtIndex:i]]];
}
return resultArray;
} else if ([returnType isEqualToString:@"'reco'"]) {
// Record (dictionary)
// Stored as a list in the descriptor's internal array of returned
// objects, in the form [key, value, key, value…]
NSArray *recordAsArray = [self fetchObjectFromDescriptor:
[descriptor descriptorAtIndex:1]];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSInteger i;
for (i = 0; i < recordAsArray.count; i += 2) {
[dict setObject:recordAsArray[i + 1] forKey:recordAsArray[i]];
}
return dict;
}
return [NSNull null];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment