[racket] Scripting on the Mac

From: Thomas Chust (chust at web.de)
Date: Wed Sep 22 06:23:14 EDT 2010

2010/9/22 Michael Smith <mikesmi at nc.rr.com>:
> [...]
> I am a Mac user and have just started to learn Scheme. Many apps on the Mac
> are scriptable via Applescript. Is there any Scheme way to leverage this
> capability, like an Applescript bridge?
> [...]

Hello Micheal,

it should be possible to control other Mac applications from Racket using
Racket's Objective C FFI to access the Cocoa scripting bridge. It should
also be possible to use the NSAppleScript class through the Objective C FFI
in order to embed AppleScript code into a Racket application. Finally, it
should be possible to use the C FFI or the Objective C FFI to manually send
AppleEvents to other applications to control them (which is how AppleScript
is implemented internally).

Check out

  http://docs.racket-lang.org/foreign/Objective-C_FFI.html
  http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ScriptingBridgeConcepts/Introduction/Introduction.html

I don't have a machine running MacOS X at hand, so I can't try this out, but
the code you will need would probably look something like this:

	#lang racket
	(require
		ffi/unsafe
		ffi/unsafe/objc)
	
	;; String conversion helpers
	(import-class NSString)
	
	(define (string->nsstring str)
		(tell
			NSString
			stringWithUTF8String: #:type _string/utf-8
				str))
	
	(define (nsstring->string str)
		(tell _string/utf-8
			str
			UTF8String))
	
	;; Get started by loading the Cocoa scripting bridge bundle.
	(import-class NSBundle)
	
	(define sb-bundle
		(tell
			NSBundle
			bundleWithPath:
				(string->nsstring "/System/Library/Frameworks/ScriptingBridge.framework")))
	
	(unless (tell _BOOL sb-bundle load)
		(error "failed to load Cocoa scripting bridge"))
	
	;; Now import the scripting bridge class and connect to the target
	(import-class SBApplication)
	
	(define iTunes
		(tell
			SBApplication
			applicationWithBundleIdentifier:
				(string->nsstring "com.apple.iTunes")))
	
	;; Do something with the target
	(when (tell _BOOL iTunes isRunning)
		(printf "Now playing: ~a~%" (nsstring->string (tell (tell iTunes
currentTrack) name))))

I hope this helps :-)

Ciao,
Thomas


-- 
When C++ is your hammer, every problem looks like your thumb.


Posted on the users mailing list.