Fun with AppleScript (2nd Editon)
Posted: Wed Jun 02, 2010 6:11 am
Hello Board,
last time I showed how to script other applications. Now I want to share a project that shows how to make your Objective Basic application scriptable (this is not for the faint hearted). To learn about AppleScript from start to finish I recommend "AppleScript the definitive Guide, by Matt Neuberg, published by O'Reilly" and lots of experiments. In the advanced section Matt talks about scripting Cocoa apps and I took the code as a starting point.
The general idea is to set up an application that holds internal state via scriptText and scriptDebug. scriptText is a NSString and scriptDebug a Boolean. The application visualizes the state of theses properties in its only window. Here is some AppleScript code that drives the application:
To make your app scriptable you need to define a dictionary that will be interpreted by AppleScript. I used Sdef Editor a programm created by Shadow Lab and distributed for free. The resulting XML looks like this:
Store the resulting sdef in your Resources directory. Now we have to extend Info.plist which is located in the Contents directory:
Now everything behind the scene is ready for showtime. I add a NSWindow subclass in my project (called UKWindow) and use InterfaceBuilder to wire it as the application delegate (not shown here).
Here comes the UKWindowCode (with some comments), I'll attach the project as well:
In the next step I want to add methods that the script can invoke. I already tried this, but this resulted in a corrupt dictionary - although its looking fine neither Sdef Editor nor AppleScript Editor can read it.
Again: Objective-Basic is fun to use and you can now code most of your ideas.
Kind regards
Udo
last time I showed how to script other applications. Now I want to share a project that shows how to make your Objective Basic application scriptable (this is not for the faint hearted). To learn about AppleScript from start to finish I recommend "AppleScript the definitive Guide, by Matt Neuberg, published by O'Reilly" and lots of experiments. In the advanced section Matt talks about scripting Cocoa apps and I took the code as a starting point.
The general idea is to set up an application that holds internal state via scriptText and scriptDebug. scriptText is a NSString and scriptDebug a Boolean. The application visualizes the state of theses properties in its only window. Here is some AppleScript code that drives the application:
- Code: Select all
tell application "scriptApp"
get scriptText
set scriptText to "Hello!"
set scriptDebug to true
set scriptText to "Objective Basic is fun"
end tell
To make your app scriptable you need to define a dictionary that will be interpreted by AppleScript. I used Sdef Editor a programm created by Shadow Lab and distributed for free. The resulting XML looks like this:
- Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary title="Dictionary">
<suite name="scriptMe Suite" code="ScMe" description="Common classes and commands for script Me.">
<cocoa name="NSCoreSuite"/>
<class name="application" code="capp" description="The scriptMe's top-level scripting object.">
<cocoa class="NSApplication"/>
<property name="scriptText" code="ScTx" description="Some text usable in scriptMe" type="text"/>
<property name="scriptDebug" code="ScDb" description="toggles debugging on and of" type="boolean"/>
</class>
</suite>
</dictionary>
Store the resulting sdef in your Resources directory. Now we have to extend Info.plist which is located in the Contents directory:
- Code: Select all
<key>NSAppleScriptEnabled</key>
<string>YES</string>
<key>OSAScriptingDefinition</key>
<string>scriptMe.sdef</string>
Now everything behind the scene is ready for showtime. I add a NSWindow subclass in my project (called UKWindow) and use InterfaceBuilder to wire it as the application delegate (not shown here).
Here comes the UKWindowCode (with some comments), I'll attach the project as well:
- Code: Select all
' idea by U. Killermann 2010
' this file is to test the scriptability of OB applications
' at the start I don't have any concrete idea how this might
' work
' adding the folling To Info.plist marks your application
' To be scriptable
' <key>NSAppleScriptEnabled</key>
' <string>YES</string>
' after compiling your application you can open it with
' AppleScript-Editor
' you can't do this (scripting) with a standard app
' <key>OSAScriptingDefinition</key>
' <string>scriptMe.sdef</string>
'
' allows you to narrow down the classes, properties and methods
' available in the AppleScript dictionary
' the window should show the internal state of the running
' application
' at the moment we only have to attributes, we can visualize
' sdef was created with the free Sdef Editor of Shadow Lab
' http://www.shadowlab.org/softwares/sdefeditor.php
IBOutlet UKscriptDebug As NSButton
Declare Class "NSApplication"
' here I store my internal state
Dim myText As String
' if myDebug is set to YES we show calls to the setter and getter
' of scriptText
Dim myDebug As Boolean
' this delegate is invoked, when the script engine needs to know if the application handles
' a certain key requested by the running script
' it returns YES if the application handles a certain key
Declare Delegate "NSApplication" - (BOOL)application:(NSApplication *)sender delegateHandlesKey:(NSString *)key
' this delegate lies to the calling application by answering YES for any key, as the application
' only handles scriptText and scriptDebug as properties
'
Delegate application(sender As NSApplication, key As NSString) As Boolean
Return Yes
End Delegate
' this method is invoked based on key value coding (KVC) for scriptText,
' the getter has no getZZZ but only ZZZ
Function scriptText() As NSString
If (myDebug) Then
Alert("scripText requested:", myText)
End If
Return(myText)
End Function
' this method is invoked based on key value coding (KVC) for scriptText,
' the setter is named setZZZ
Sub setScriptText(theText As NSString)
myText = theText
UKscriptDebug.Title = myText
If (myDebug) Then
Alert("scriptText set to:", myText)
End If
End Sub
' this method is invoked based on key value coding (KVC) for scriptText,
' the getter has no getZZZ but only ZZZ
Function scriptDebug() As Boolean
Return(myDebug)
End Function
' this method is invoked based on key value coding (KVC) for scriptText,
' the setter is named setZZZ
Sub setScriptDebug(theDebug As Boolean)
myDebug = theDebug
UKscriptDebug.State=theDebug
End Sub
' when the window comes into the foreground I show the current state of
' the properties, thus you can see the interaction between the script and
' the application
'
Event WindowDidBecomeKey()
UKscriptDebug.Title = scriptText()
UKscriptDebug.State= scriptDebug()
End Event
Event Init()
setScriptText("Kuddel")
setScriptDebug(No)
End Event
In the next step I want to add methods that the script can invoke. I already tried this, but this resulted in a corrupt dictionary - although its looking fine neither Sdef Editor nor AppleScript Editor can read it.
Again: Objective-Basic is fun to use and you can now code most of your ideas.
Kind regards
Udo