Integrating AppleScript to your app

Mac OSX specific forum
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Integrating AppleScript to your app

Post by deseven »

Have you ever wanted to send some commands to your app via AppleScript? Well, that's totally possible with PureBasic! :)

First, edit you Info.plist like that:

Code: Select all

<key>NSAppleScriptEnabled</key>
<true/>
<key>OSAScriptingDefinition</key>
<string>as.sdef</string>
Also make sure that your bundle id is unique.

Then, create as.sdef inside your app bundle's Contents/Resources dir, put this definition inside:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">

<dictionary title="myCoolApp">
    <suite name="myCoolApp Suite" code="mApp" description="myCoolApp Scripts">
        <command name="test" code="cmndtest" description="test command">
            <cocoa class="myTestCommand"/>
            <direct-parameter description="argument">
                <type type="text"/>
            </direct-parameter>
        </command>
    </suite>
</dictionary>
After that, return to PB:

Code: Select all

; there is a big room for improvement, but that should be a good start
ProcedureC myTestCommand(command.i)
  Protected argument.i = CocoaMessage(0,command,"evaluatedArguments")
  If argument
    Protected string = CocoaMessage(0,CocoaMessage(0,argument,"valueForKey:$",@""),"UTF8String")
    If string
      MessageRequester("test",PeekS(string,-1,#PB_UTF8))
    Else
      MessageRequester("test","no string")
    EndIf
  Else
    MessageRequester("test","no arguments passed")
  EndIf
EndProcedure

Define subClass = objc_allocateClassPair_(objc_getClass_("NSScriptCommand"),"myTestCommand",0)
class_addMethod_(subClass,sel_registerName_("performDefaultImplementation"),@myTestCommand(),"v@")
objc_registerClassPair_(subClass)
And that's it.

Now you can call your app from AppleScript:

Code: Select all

tell application "myCoolApp"
  test "hello"
end tell
Useful info:
creating sdef file
SO question
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Integrating AppleScript to your app

Post by deseven »

More on that, string output example:

Code: Select all

<command name="getTitle" code="cmndgtit" description="get title">
    <cocoa class="asGetTitle"/>
    <result type="text" description="current title"/>
</command>

Code: Select all

ProcedureC asGetTitle(command.i)
  Shared currentTitle.s
  Protected answer = CocoaMessage(0,0,"NSString stringWithString:$",@currentTitle)
  ProcedureReturn answer
EndProcedure
User avatar
robertfern
User
User
Posts: 23
Joined: Fri Feb 02, 2018 10:33 pm
Location: New Jersey

Re: Integrating AppleScript to your app

Post by robertfern »

Can you show a modified version that gets a list as a parameter, and returns a list that AppleScript understands.
Also how to modify the last three commands to handle multiple commands.

Code: Select all

Define subClass = objc_allocateClassPair_(objc_getClass_("NSScriptCommand"),"myTestCommand",0)
class_addMethod_(subClass,sel_registerName_("performDefaultImplementation"),@myTestCommand(),"v@")
objc_registerClassPair_(subClass)
Mac OSX Ventura & Windows 10, PB 6.04
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Integrating AppleScript to your app

Post by deseven »

You can bind as many commands as you want, see here for example.

List input is something i never touched, but list output should be easy, i think you have to return NSArray, you can build it like that (untested):

Code: Select all

list = CocoaMessage(0,0,"NSArray arrayWithObject:$",@val1)
list = CocoaMessage(0,list,"arrayByAddingObject:$",@val2)
list = CocoaMessage(0,list,"arrayByAddingObject:$",@val3)
Use something like that for definition:

Code: Select all

<command name="getList" code="cmndglst" description="get list">
    <cocoa class="asGetList"/>
    <result type="text" list="yes" description="a list"/>
</command>
User avatar
Piero
Enthusiast
Enthusiast
Posts: 288
Joined: Sat Apr 29, 2023 6:04 pm
Location: Italy

Re: Integrating AppleScript to your app

Post by Piero »

Thanks deseven!

info.plist

Code: Select all

  <key>NSAppleScriptEnabled</key>
  <true/>
  <key>OSAScriptingDefinition</key>
  <string>as.sdef</string>
  <key>CFBundleURLTypes</key>
   <array>
       <dict>
           <key>CFBundleURLName</key>
           <string>pure</string>
           <key>CFBundleURLSchemes</key>
           <array>
               <string>pppp</string>
           </array>
       </dict>
   </array>
as.sdef

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">

<dictionary title="myCoolApp">
    <suite name="urlloc Suite" code="mApp" description="myCoolApp Scripts">
        <command name="open location" code="GURLGURL" description="open url">
            <cocoa class="myTestCommand"/>
            <direct-parameter description="argument">
                <type type="text"/>
            </direct-parameter>
        </command>
    </suite>
</dictionary>
"Firefox bookmark"

Code: Select all

javascript:window.location='pppp://'+window.location;
PB

Code: Select all

Enumeration CustomEvent #PB_Event_FirstCustomValue
   #MyEvent_OpenUrl
EndEnumeration

Global Url$

ProcedureC myTestCommand(command.i)
   Protected argument.i = CocoaMessage(0,command,"evaluatedArguments")
   If argument
      Protected string = CocoaMessage(0,CocoaMessage(0,argument,"valueForKey:$",@""),"UTF8String")
      If string
         Url$ = PeekS(string,-1,#PB_UTF8)
         if Url$ : PostEvent(#MyEvent_OpenUrl) : EndIf
      EndIf
   EndIf
EndProcedure

Define subClass = objc_allocateClassPair_(objc_getClass_("NSScriptCommand"),"myTestCommand",0)
class_addMethod_(subClass,sel_registerName_("performDefaultImplementation"),@myTestCommand(),"v@")
objc_registerClassPair_(subClass)

If OpenWindow(0, 0, 0, 820, 620, "OpenLink", #PB_Window_SystemMenu | #PB_Window_ScreenCentered )
   
   EditorGadget(0, 10, 10, 800, 600)
   
   if Url$ : PostEvent(#MyEvent_OpenUrl) : EndIf
   
   Repeat
      Select WaitWindowEvent()
         Case #MyEvent_OpenUrl
            if Url$
               AddGadgetItem(0, -1, Url$)
               Url$=""
            EndIf
         Case #PB_Event_CloseWindow
            end
      EndSelect
   Until EventMenu() = #PB_Menu_Quit
   
EndIf
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Integrating AppleScript to your app

Post by deseven »

Oh, I didn't know that you can register url handlers that way, nice.
User avatar
Piero
Enthusiast
Enthusiast
Posts: 288
Joined: Sat Apr 29, 2023 6:04 pm
Location: Italy

Re: Integrating AppleScript to your app

Post by Piero »

deseven wrote: Mon Jan 22, 2024 10:22 am url handlers that way
Thanks again deseven (and not only for this…)

My Cocoa is very, very rusty, so here's what I did:

I made an Applescript with "open location" in Script Debugger, then I used Menu/View/Show Raw (Chevron) Syntax
This way I got the GURLGULRL code (if it's something like "aevtodoc", I think you must use "odoc"... no time to test...)
I'm almost sure there's a simpler way to "register" this, "similar" to what Fred did with "open files callback", but if it's also scriptable, better, right?

Thanks……… again!
Post Reply