Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

NSNick

macrumors regular
Original poster
Jun 27, 2008
162
0
Washington D.C.
Has anyone embedded Applescript in Cocoa/Objective-C applications using NSAppleScript. This seems extremely powerful as it can be used to write a program that controls other programs. Is there a way to control other applications without Applescript?
 

whooleytoo

macrumors 604
Aug 2, 2002
6,607
716
Cork, Ireland.
Has anyone embedded Applescript in Cocoa/Objective-C applications using NSAppleScript. This seems extremely powerful as it can be used to write a program that controls other programs. Is there a way to control other applications without Applescript?

You can also do it via sending AppleEvents.

Some applications also respond to certain NSNotifications, if they are documented you can use these too.
 

cMacSW

macrumors regular
Mar 20, 2006
180
0
I've done this. Basically, you add your applescript to your cocoa project in the resources folder. Then when you want to use in you load it from your bundle like this:

Code:
 NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithContentsOfURL:scriptURL error:&errorDict];

Then add your script arguments then call this:

Code:
returnDescriptor= [scriptObject executeAppleEvent:event error:&errorDict];

K
 

cMacSW

macrumors regular
Mar 20, 2006
180
0
Also I forgot to mention, with Leopard you can use scripting Bridge and communicate with scriptable apps with cocoa calls
 

NSNick

macrumors regular
Original poster
Jun 27, 2008
162
0
Washington D.C.
How would one write this application using script bridges and then without using any Applescript at all?

Also, how would one retrieve the name of the song that is currently playing from iTunes in the form of an NSString?

Code:
#import <Cocoa/Cocoa.h>


@interface AppController : NSObject {
	NSAppleScript *run;
	NSAppleScript *start;
	NSAppleScript *nextTrack;
	NSAppleScript *backTrack;
}
-(IBAction)play:(id)sender;
-(IBAction)next:(id)sender;
-(IBAction)previous:(id)sender;
@end

Code:
#import "AppController.h"


@implementation AppController

-(void)awakeFromNib
{
	NSAppleScript *run = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to run"];
	[run executeAndReturnError:nil];
}

-(IBAction)play:(id)sender
{
	NSAppleScript *start = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to playpause"];
	[start executeAndReturnError:nil];
}

-(IBAction)next:(id)sender
{
	NSAppleScript *nextTrack = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to next track"];
	[nextTrack executeAndReturnError:nil];
}

-(IBAction)previous:(id)sender
{
	NSAppleScript *backTrack = [[NSAppleScript alloc] initWithSource:@"tell application \"iTunes\" to back track"];
	[backTrack executeAndReturnError:nil];
}

@end
 

whooleytoo

macrumors 604
Aug 2, 2002
6,607
716
Cork, Ireland.
Can you elaborate?

Err.. no. ;)

If you mean AppleEvents, then you can communicate with several applications by sending AppleEvents to them. There's only a small core set to which every application will respond; but many applications have a huge set of AppleEvents that would enable you to communicate with them. You build the AppleEvent, and send it via AESendMessage. Also look at the NSAppleEventDescriptor class documentation.

If you mean notifications.. if you're trying to control iTunes then I'm not sure if this is an option as I don't know if you can find out what notifications it responds to. Try googling an application called NotificationWatcher, and using that you might be able to find out which notifications to send.
 

hhas

macrumors regular
Oct 15, 2007
126
0
How would one write this application using script bridges and then without using any Applescript at all?

Using objc-appscript, which provides 99.9% compatibility with existing scriptable applications and runs on 10.3.9 onwards:

Code:
// To create glue:  osaglue  -o ITGlue  -p IT  iTunes

@interface AppController : NSObject {
	ITApplication *itunes;
}
-(IBAction)play:(id)sender;
-(IBAction)next:(id)sender;
-(IBAction)previous:(id)sender;
@end

Code:
@implementation AppController

-(void)awakeFromNib
{
	itunes = [[ITApplication alloc] initWithBundleID: @"com.apple.itunes"];
}

-(void)dealloc {
	[itunes release];
	[super dealloc];
}

-(IBAction)play:(id)sender
{
	[[itunes play] send];
}

-(IBAction)next:(id)sender
{
	[[itunes nextTrack] send];
}

-(IBAction)previous:(id)sender
{
	[[itunes previousTrack] send];
}

@end

Error handling is omitted for clarity; e.g. you might want to check for command errors raised if the user has quit/restarted iTunes while your app is running, and automatically reconnect your ITApplication instance to it if that happens.

Also, how would one retrieve the name of the song that is currently playing from iTunes in the form of an NSString?

The latest version of ASTranslate can convert AppleScript commands to objc-appscript syntax. For example, if you run:

Code:
tell application "iTunes"
	name of current track
end tell

it will return:

Code:
// To create glue:  osaglue  -o ITGlue  -p IT  iTunes

ITApplication *itunes = [[ITApplication alloc] initWithName: @"iTunes"];

ITReference *ref = [[itunes currentTrack] name];

id result = [ref getItem];

Again, you'll want to flesh this out a bit for production code (e.g. iTunes will raise an error if the player is completely stopped, in which case a current track isn't available), but it gives you a useful starting point.

(p.s. Note that the objc-appscript codebase and APIs are currently going through some changes as I'm trying to push it towards a beta release so you might want to keep an eye on the subversion repository for notification of changes.)
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.