Push-Nachrichten von MacTechNews.de
Würden Sie gerne aktuelle Nachrichten aus der Apple-Welt direkt über Push-Nachrichten erhalten?
Forum>Entwickler>Probleme beim AppleScript aufrufen

Probleme beim AppleScript aufrufen

Agrajag07.09.0515:27
Ich hab hier ein (für mich) kurioses Problem:

Ich hab ein Haupt-Script, was mit einem Parameter auferufen werden soll. Dazu hab ich diverse Helfer-Scripte (derzeit in App-Bundles verpackte Shell-Scripte), die nichts anderes machen, als das Haupt-Script mit einem Parameter aufzurufen.

Solange ich das mit den Shell-Scripten erledige ist alles OK:

#!/bin/sh
osascript "/Volumes/Users/mike/Library/Scripts/IR Scripts/main.scpt" circle


Rufe ich das Haupt-Script allerdings mit einem AppleScript auf, gibt es merkwürdigerweise einen kleinen Unterschied:

run script file ((path to scripts folder from user domain as string) & "IR Scripts:main.scpt") with parameters {"circle"}


Die normalen Funktionen funktionieren wie gewollt. Drei Tasten sind allerdings 2-fach belegt. Drücke ich z.B. "Circle", dann soll erstmal nur das aktive Programm angezeigt werden. Erst wenn ich innerhalb von 3sec. diese Taste zweimal drücke, soll zum nächsten Programm umgeschaltet werden. Das Ganze hab ich dann noch mit Stop (Stop und Quit) und Menu (nichts machen und Sleep).

Die Zeitsteuerung funktioniert nicht, wenn ich das HauptScript mit einem AppleScript aufrufe, die Zweitfunktionen werden also nie ausgeführt. Das Main-Script behält in beiden Fällen eine Properties, nur scheint es sich nicht die Zeiten zu merken und ich verstehe nur nicht warum. Hier noch mal ein Auszug aus dem Haupt-Script:



property listOfApps : {"VLC", "iTunes"}
property currentAppNr : 1
property currentApp : (item currentAppNr of listOfApps)
property lastCirclePress : 0
property lastMenuPress : 0
property lastStopPress : 0
property scriptPath : (path to scripts folder from user domain as string) & "IR Scripts:"

on run givenParameters

tell application "GrowlHelperApp"
set the notifications to {"Stop", "Play", "Pause", "Previous Track", "Next Track", "Rewind", "Fast Forward", "Circle", "Menu", "Volume Up", "Volume Down", "Mute", "Cursor Keys", "Select"}
set the enabledNotifications to notifications
register as application "IR Scripts" all notifications notifications default notifications enabledNotifications
end tell

----- main

beep

set param to (item 1 of givenParameters) as string

if param = "stop" then pressedStop()
if param = "play" then pressedPlay()
if param = "pause" then pressedPause()

if param = "previous" then pressedPrevious()
if param = "next" then pressedNext()
if param = "rewind" then pressedRewind()
if param = "ffwd" then pressedFfwd()

if param = "circle" then pressedCircle()
if param = "menu" then pressedMenu()


[...]


on pressedCircle()
set currentTime to time of (current date)
set timeLasting to currentTime - lastCirclePress

if (timeLasting ≤ 3) then
set currentAppNr to currentAppNr + 1
if currentAppNr > length of listOfApps then set currentAppNr to 1
set currentApp to (item currentAppNr of listOfApps)
end if

set lastCirclePress to currentTime
tell application "GrowlHelperApp"
notify with name "Circle" title currentApp description "" application name "IR Scripts" icon of application currentApp
end tell

say currentApp
end pressedCircle
0

Kommentare

Agrajag07.09.0515:45
Ich hab jetzt was rausgefunden:

Wenn ich das HauptScript mit dem ShellScript starte, dann merkt er sich die Zeiten, die in lastCirclePress, lastMenuPress und lastStopPress stehen. Wenn ich das HauptScrippt von einem AppleScript aus aufrufe, dann hat sie immer den gleichen Stand. Entweder 0, wenn das HauptScript das erste mal mit "circle" aufgerufen wurde, oder den Wert, den es bekommen hatte, als das HauptScript zum letzten mal mit einem ShellScript aufgerufen wurde.

Ich kann absolut nicht sehen, warum das so ist. Eigendlich sollte es dem aufgerufenen Script doch egal sein, von wem es aufgerufen wurde.

Das vom AppleScript aufgerufene HauptScript benutzt scheinbar auch genau die gleichen Properties wie das vom ShellScript aufgerufene also dürfte auch immer auf das gleiche Script im Speicher zugegriffen werden.

Wo ist das Problem. Liegt es am Aufruf mit "run script file", oder ist das ein Bug?
0
Agrajag07.09.0515:56
Noch was:

Ich hab mal die If-Abfrage in der Funktion "on pressedCircle()" auskommentiert, so daß jeder Tastendruck zum Umschalten führen sollte. Wenn ich z.B. via ShellScript auf "iTunes" umschalte, dann via AppleScript auf "VLC", dann sollte ein erneutes Umschalten via ShellScript wieder auf "iTunes" umschalten -- tut es aber nicht: es schaltet auf VLC um.

Es scheint so zu sein, daß das per AppleScript aufgerufene HauptScript nur mit einer Kopie der Properties arbeitet, sie auch verändern kann. Das per ShellScript aufgerufene HauptScript arbeitet direkt mit den originalen Properties.

Hat jemand dafür eine Erklärung und sogar eine Lösung?
0
Michael Schmidt
Michael Schmidt07.09.0516:02
Könnte es daran liegen, dass per run script jeweils eine neue Instanz des Scripts kreiert wird, die dann natürlich jedesmal eigene und neue properties nur für den einen Aufruf anlegt?

CU
Schmiddl
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Agrajag07.09.0516:44
Ah, Moin Schmiddl -- mein AppleScript-Helfer in der Not

Das war ja meine Vermutung. Interessanterweise legt es sich dann aber nicht einen komplett eigenen Satz Properties an, sondern es kopiert sich den Bestehenden. Wie kann ich das umgehen?

Das Problem ist:

Ich rufe die Scripte über die Keyspan-Software auf. Wenn ich die Shell-Scripte direkt aufrufen lasse, dann öffnet sich jedesmal dazu ein Shell-Fenster. Also hab ich die Shell-Scripte in je ein App-Bundle gepackt. Leider muß das System dann noch mehr Plattenzugriffe machen, damit es weiß, wie es das Bundle zu benutzen hat. Dazu kommt dann nochmal der Aufruf via osascript, was scheinbar auch etwas Zeit kostet.

Jedenfalls dauert es signifikant länger, als wenn man AppleScript auf das Haupt-Script zugreift. Besonders schlimm wird es, wenn das System und/oder die Platte unter Belastung stehen -- dann kann es schon ein paar Sekunden dauern, bis der Befehl ausgeführt wird. Das ist natürlich nicht tragbar, besonders nicht bei den doppel belegten Tasten, da man dann das Zeitfenster nicht mehr einhalten kann.

Es muß doch die Möglichkeit geben aus AppleScript heraus ein Script aufzurufen, mit den gleichen Möglichkeiten/Konsequenzen wie ein Aufruf über osascript.

Immer wenn ich denke AppleScript ist geil, dann kommt sowas um die Ecke *grummel*
0
Michael Schmidt
Michael Schmidt07.09.0518:10
1.
Hm, also du kannst aus einem per run script aufgerufenen Script die properties des aufrufenden Script mit dem Schlüsselwort parent verwenden. Also praktisch die properties im Parentscript setzen und aus den einzelnen Scriptinstanzen heraus ändern. Das umgeht aber nicht das Problem mit dem Aufruf per Shell und wie ich dich verstehe soll ja beides stattfinden, oder?

2.
Auch kannst du glaube ich das Script erst laden (mit load script)
set remoteScript to load script (path to scripts folder from user domain as string) & "IR Scripts:main.scpt")
und dann die Scriptproperties mit z.B.
set remoteScript's lastCirclePress to 3
setzen. Gilt aber dann auch nur für die jetzige Instanz (script "remoteScript").

3.
Wie wäre ein Weg über Voreinstellungen? Auf diese würde dein Script dann zugreifen, egal, von wo es aufgerufen wird
Ich schicke dir da mal ein Script aus der AppleScript Mailing Liste

CU
Schmiddl
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Michael Schmidt
Michael Schmidt07.09.0518:13
Hier ist es, original gepostet von Paul Skinner
script prefer
on existsPreference(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
return true
on error
return false
end try
end existsPreference

on removePreference(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
tell application "Finder"
delete preFilePath
return true
end tell
on error
return false
end try
end removePreference

on makePrefFile(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
return false
on error
try
close access preFilePath
end try
try
set prefRef to open for access preFilePath with write permission
set eof of prefRef to 0
set currentTime to current date
write {initializationDate:currentTime, modificationDate:currentTime} to prefRef as record
close access prefRef
return preFilePath as alias
on error e
try
close access prefRef
return e
end try
end try
end try
end makePrefFile


on readPreferences(prefFileName)
set AppleScript's text item delimiters to ":"
try
set prefs to read file ("" & (path to preferences folder from user domain as string) & prefFileName) as record
on error
return false
end try
return prefs
end readPreferences

on clearPreferences(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
set creationdate to initializationDate of my readPreferences(prefFileName)
try
close access preFilePath
end try
try
set prefRef to open for access preFilePath with write permission
set eof of prefRef to 0
write {initializationDate:creationdate, modificationDate:current date} to prefRef as record
close access prefRef
return true
on error e
try
close access prefRef
return e
end try
end try
on error
return false
end try
end clearPreferences

on writePrefs(prefFileName, preferenceRecord)
try
set prefFile to (("" & (path to preferences folder from user domain as string) & prefFileName) as alias) as text
on error
return false
end try
if preferenceRecord is {} then
set prefs to {initializationDate:current date, modificationDate:current date}
else
set prefs to read file prefFile as record
set prefs to preferenceRecord & prefs & {modificationDate:current date}
end if
try
try
close access file prefFile
end try
set prefRef to open for access file prefFile with write permission
--set eof of prefRef to 0
write prefs to prefRef as record
close access prefRef
--set prefs to read file prefFile as record
return true
on error
try
close access prefRef
return false
end try
end try
end writePrefs
end script

Verwendungsbeispiel:
tell prefer
set prefFileName to "testPref"

if not existsPreference(prefFileName) then
makePrefFile(prefFileName)
else
removePreference(prefFileName)
true
makePrefFile(prefFileName)
alias "batzmaru:Users:paul:Library:Preferences:testPref"
end if
readPreferences(prefFileName)
{initializationDate:date "Friday, November 26, 2004 6:26:52 PM", modificationDate:date "Friday, November 26, 2004 6:26:52 PM"}
writePrefs(prefFileName, {c:"c", a:8})
true
readPreferences(prefFileName)
{c:"c", a:8, initializationDate:date "Friday, November 26, 2004 6:26:10 PM", modificationDate:date "Friday, November 26, 2004 6:26:10 PM"}
writePrefs(prefFileName, {c:"sea", a:888})
true
readPreferences(prefFileName)
{c:"sea", a:888, initializationDate:date "Friday, November 26, 2004 6:34:37 PM", modificationDate:date "Friday, November 26, 2004 6:34:37 PM"}
clearPreferences(prefFileName)
true
readPreferences(prefFileName)
{initializationDate:date "Friday, November 26, 2004 6:27:44 PM", modificationDate:date "Friday, November 26, 2004 6:27:46 PM"}
end tell


CU
Schmiddl
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Michael Schmidt
Michael Schmidt07.09.0518:47
So, habe eben einen kleinen Test gemacht

Nimm von oben alles kursiv dargestellte und kopiere es ans Ende deines Scripts!

Verwenden kannst du es dann so:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Name der Voreinstellungsdatei
property voreinstellungen : "SchmiddlsTestPref"

tell prefer
-- Wenn noch keine Präferenzen da sind, lege welche an und fülle die Werte mit Standardwerten!
if not existsPreference(voreinstellungen) then
makePrefFile(voreinstellungen)
writePrefs(voreinstellungen, {listOfApps:{"VLC", "iTunes"}, currentAppNr:1, currentApp:"VLC", lastCirclePress:0, lastMenuPress:0, lastStopPress:0, scriptPath:(path to scripts folder from user domain as string) & "IR Scripts:"})
end if
end tell

--Zugriff auf die Voreinstellungen:
prefer's writePrefs(voreinstellungen, {lastCirclePress:current date})
display dialog (lastCirclePress of prefer's readPreferences(voreinstellungen)) as Unicode text

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hoffe, es hilft!

CU
Schmiddl
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Michael Schmidt
Michael Schmidt07.09.0519:11
Ich hoffe, du bist noch nicht allzuweit mit der Implementierung:
Du kannst auf das Script-Objekt prefer verzichten!

Also, gehe wie folgt vor:
Setze dies hier alles ans Ende deines Scripts, dadurch hast du kein neues Script-Objekt, sondern nur ein paar Funktionen mehr:
-------------------------------------------
on existsPreference(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
return true
on error
return false
end try
end existsPreference

on removePreference(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
tell application "Finder"
delete preFilePath
return true
end tell
on error
return false
end try
end removePreference

on makePrefFile(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
return false
on error
try
close access preFilePath
end try
try
set prefRef to open for access preFilePath with write permission
set eof of prefRef to 0
set currentTime to current date
write {initializationDate:currentTime, modificationDate:currentTime} to prefRef as record
close access prefRef
return preFilePath as alias
on error e
try
close access prefRef
return e
end try
end try
end try
end makePrefFile


on readPreferences(prefFileName)
set AppleScript's text item delimiters to ":"
try
set prefs to read file ("" & (path to preferences folder from user domain as string) & prefFileName) as record
on error
return false
end try
return prefs
end readPreferences

on clearPreferences(prefFileName)
set preFilePath to "" & ((path to preferences folder from user domain as string) & prefFileName)
try
set preFilePath to preFilePath as alias
set creationdate to initializationDate of my readPreferences(prefFileName)
try
close access preFilePath
end try
try
set prefRef to open for access preFilePath with write permission
set eof of prefRef to 0
write {initializationDate:creationdate, modificationDate:current date} to prefRef as record
close access prefRef
return true
on error e
try
close access prefRef
return e
end try
end try
on error
return false
end try
end clearPreferences

on writePrefs(prefFileName, preferenceRecord)
try
set prefFile to (("" & (path to preferences folder from user domain as string) & prefFileName) as alias) as text
on error
return false
end try
if preferenceRecord is {} then
set prefs to {initializationDate:current date, modificationDate:current date}
else
set prefs to read file prefFile as record
set prefs to preferenceRecord & prefs & {modificationDate:current date}
end if
try
try
close access file prefFile
end try
set prefRef to open for access file prefFile with write permission
--set eof of prefRef to 0
write prefs to prefRef as record
close access prefRef
--set prefs to read file prefFile as record
return true
on error
try
close access prefRef
return false
end try
end try
end writePrefs
-------------------------------------------


Verwenden kannst du sie analog zu obigem Vorschlag so:
property voreinstellungen : "SchmiddlsTestPref"
-- Wenn noch keine Präferenzen da sind, lege welche an und fülle die Werte mit Standardwerten!
if not existsPreference(voreinstellungen) then
makePrefFile(voreinstellungen)
writePrefs(voreinstellungen, {listOfApps:{"VLC", "iTunes"}, currentAppNr:1, currentApp:"VLC", lastCirclePress:0, lastMenuPress:0, lastStopPress:0, scriptPath: (path to scripts folder from user domain as string) & "IR Scripts:"})
end if

--Zugriff auf die Voreinstellungen:
--Schreiben von Voreinstellungen
writePrefs(voreinstellungen, {lastCirclePress:current date})
-- Lesen der Voreinstellungen
set lastClick to lastCirclePress of (readPreferences(voreinstellungen))
display dialog lastClick as unicode text

So, nun aber wirklich viel Spaß damit!!

CU
Schmiddl
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Agrajag07.09.0519:23
Hui, das ist aber üppig Das muss ich gleich mal durchackern. Nur mal kurz eine Anmerkung: Es ist mir wichtig, daß ich mit einem Minimum an Plattenzugriffen pro Tastendruck auskomme -- das ist ja derzeit das Hauptproblem. Die von dir gepostete Lösung scheint noch mehr Zugriffe zu machen, aber ich muss mir das jetzt erstmal in Ruhe ansehen...
0
Michael Schmidt
Michael Schmidt07.09.0519:35
Ja, bei jedem Lesen oder Schreiben von Prefs wird auf die Platte zugegriffen. Aus dem Script heraus ist es aber rasend schnell! Wirklich!

Für dich relevant ist eh nur mein letztes Posting , also nicht erschrecken


Also, los, ran an den Speck!
Du schaffst es!

CU
Schmiddl
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Agrajag08.09.0500:01
So, ich hab's geschafft:



-----8<----------8<----------8<----------8<-----



property prefsFile : "de.mikebrasch.IRScripts"
property scriptPath : (path to scripts folder from user domain as string) & "IR Scripts:"
property listOfApps : {"iTunes", "VLC", "DVD Player", "QuickTime Player", "RealPlayer"}
property interval : 3
global currentAppNr, currentApp, lastCirclePress, lastStopPress, lastMenuPress

on run givenParameters

----- preferences -----
if not existsPreference(prefsFile) then
makePrefFile(prefsFile)
writePrefs(prefsFile, {currentAppNr:1, lastCirclePress:0, lastMenuPress:0, lastStopPress:0})
end if

set prefs to readPreferences(prefsFile)

set currentAppNr to currentAppNr of prefs
set lastCirclePress to lastCirclePress of prefs
set lastStopPress to lastStopPress of prefs
set lastMenuPress to lastMenuPress of prefs

set currentApp to (item currentAppNr of listOfApps)


----- init growl -----
tell application "GrowlHelperApp"
set the notifications to {"Stop", "Play", "Pause", "Previous Track", "Next Track", "Rewind", "Fast Forward", "Circle", "Menu", "Volume Up", "Volume Down", "Mute", "Cursor Keys", "Select"}
set the enabledNotifications to notifications
register as application "IR Scripts" all notifications notifications default notifications enabledNotifications
end tell



[...]



on pressedCircle()
set currentTime to time of (current date)
set timeLasting to currentTime - lastCirclePress
set counter to 0

if (timeLasting &#8804; interval) then
repeat
set counter to counter + 1
set currentAppNr to currentAppNr + 1
if currentAppNr > length of listOfApps then set currentAppNr to 1
set currentApp to (item currentAppNr of listOfApps)
if checkRunning(currentApp) then exit repeat
if counter &#8805; length of listOfApps then
noProgram()
set currentAppNr to 1
set currentApp to (item currentAppNr of listOfApps)
exit repeat
end if
end repeat
end if

set lastCirclePress to currentTime
tell application "GrowlHelperApp"
notify with name "Circle" title currentApp description "" application name "IR Scripts" icon of application currentApp
end tell

say currentApp

writePrefs(prefsFile, {currentAppNr:currentAppNr, lastCirclePress:lastCirclePress, lastMenuPress:lastMenuPress, lastStopPress:lastStopPress})

end pressedCircle



-----8<----------8<----------8<----------8<-----



Aufgerufen wird es z.B. mit:


run script file ((path to scripts folder from user domain as string) & "IR Scripts:main.scpt") with parameters {"circle"}


Es klapp in der Geschwindigkeit, wie ich es mir vorgestellt habe

Zwei Dinge wären da noch:

1) Ich hab im Programmumschalter einen einfachen Mechanismus eingebaut, damit jetzt nicht mehr stur die Liste mit den Programmen durchgewechselt wird. Er prüft nach jedem Wechsel, ob das Programm aktuell läuft. Wenn nicht, dann wechselt er gleich zum nächsten Programm in der Liste -- solange, bis er ein laufendes Programm findet, oder er alle Einträge einmal durch hat. Dann fällt er in den iTunes-Modus, so daß man mit "Play" iTunes starten kann.

Das Problem ist, daß es schon mal eine halbe Minute dauern kann, bis er die Liste durch hat (wenn nur ein Programm oder keins läuft). Interessant wäre, warum das so ist und ob man das vielleicht etwas eleganter hin bekommt.

2) Das ist eigendlich nur ein Bonbon: Könnte man nicht eine echte Plist-Datei für die Prefs erzeugen? Ich bräuchte nur mal einen Wink mit dem Zaunpfahl.



Auf jeden Fall erstmal: Vielen, vielen Dank, Schmiddl. Du hat mir sehr geholfen. :-)


Falls jemand Interesse an dem Script hat, einfach eine Mail schreiben. Das Script kann von allem aufgerufen werden, was AppleScripte starten kann oder sogar selbst ausführen kann. Ich starte das Script über die Fernbedienungssoftware und Butler.

Wie jetzt z.B. einfach mit ALT+F16 ein Titel bei iTunes weiter springen, ohne den Browser verlassen zu müssen, einfach geil...
0
Agrajag08.09.0500:06
Huch... es sind etwas über 500 Zeilen geworden...
0
Agrajag08.09.0514:15
Das Prüfen, ob ein Programm läuft dauert, wie gesagt, sehr lang. Positive Ergebnisse sind sofort da, nur wenn ein Programm nicht läuft dauert die negative Bestätigung ewig.

Wenn ich das Script aber aus dem Script Editor heraus starte, ist das Ergebnis der prüfung sofort da.

Wieso ist das Verhalten so unterschiedlich?
0
Agrajag08.09.0514:41
OK, der Überltäter ist die If-exist-Abfrage in:


tell application "System Events" to if exists process prog then set running to true


Was macht der Script Editor, daß der Aufruf aus ihm heraus nicht nicht das problem hat? Kann man etwas am Script drehen, oder gibt es eine Alternative zu dieser Abfrage?

Ich hab schon ausprobiert, ob es an der dynamischen Abfrage liegt (ich übergebe den zu überprüfenen Prozessnamen ja als Variable), aber das ist es nicht.
0
Michael Schmidt
Michael Schmidt08.09.0514:54
Eine echte plist bekommmst du, wenn du das ganze in XCode oder Facespan oä. baust. Dort kann man dem Projekt eine ID geben, z.B. com.agrajag.proggieswitch
Dann hast du auch die Möglichkeit, per einfacher Applescript-Befehle die Preferences zu lesen und zu schreiben. Also z.B. setzen der Default-Prefs:

on will finish launching theObj
tell user defaults
if not {exists default entry "lastCirclePress"} then
make new default entry at end of default entries with properties {name:"lastCirclePress", contents:{current date}}
end if
end tell
end will finish launching

Als Programmier-Ergebnis hast du jedoch immer eine komplette APP und kein Script mehr. Ich war immer davon ausgegangen, dass du zwingend ein SCRIPT brauchst , weswegen die Preferences-Lösung jetzt ein guter Workaround ist

Sollte es dir egal sein, bzw. wenn du auch gern in XCode eine komplette Applikation bauen möchtest, kannste ja mal Bescheid sagen.

Zur 1. Frage: Wie prüfst du denn, ob ein Programm läuft? Man könnte auch ein ein do shell-Script machen, so wegen top | grep usw. um herauszufiltern ob der zum Programm zugehörige Prozess gerade läuft. Müsste rasend schnell sein

CU
Schmiddl(w00t)
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Michael Schmidt
Michael Schmidt08.09.0515:08
Habe etwas nettes gefunden zu dem Thema, wenn man z.B. den Applikationsnamen weiss:
---------------------------------------------------
property listOfApps : {"iTunes", "VLC", "DVD Player", "QuickTime Player", "RealPlayer"}

repeat with appName in listOfApps
if appIsRunning(appName) then
display dialog appName & " löppt!"
else
display dialog appName & " löppt NICHT!"
end if
end repeat

on appIsRunning(applicationName)
-- Tipp von Chris Nebel himself (AppleScript Engineering, Apple)
tell application "System Events"
return (exists process applicationName)
end tell
end appIsRunning
---------------------------------------------------

CU
Schmiddl
„Trautman: "Er wird kommen und er wird mich hier rausholen." Russischer Offizier: "Was, glaubt dieser Mann, wer er ist? Gott?" Trautman: "Nein, Gott kennt Gnade!"“
0
Agrajag08.09.0515:15
Die Abfrage über die Shell, so wie du sie meinst, hatte ichj auch schon benutzt gehabt. Nur funktionierte es plötzlich beim Wechsel von Panther auf Tiger nicht mehr, weil die Prozessliste von ps plötzlich anders formatiert war. Deswegen hatte ich mich nach einem anderen Weg umgesehen und bin zu dem jetzigen gelangt (ich glaube der Tipp kam auch von dir).

Ich hab jetzt aber was mit Hilfe der Mailingliste AppleScript-users herausgefunden. Das Problem besteht nicht mehr, wenn man folgendes schreibt:


tell application "System Events" to if prog is in name of application processes then set running to true


oder


tell application "System Events" to if exists application process prog then set running to true


Bei ersterem musste nur "application processes" anstelle von "processes" geschrieben werden. Es funktioniert nun so, wie ich es mir vorstelle.

Falls es von interesse ist, hier der Beitrag von kai (ich weiß nicht, ob es ratsam ist die Mailadresse zu nennen, wegen Spam):



-----8<----------8<----------8<----------8<-----



Whichever method you use, Brennan, an external call of some sort is required - be it to Finder, System Events or Shell.

Your reservations about using the Finder for this job are probably valid, since its dictionary shows process, etc. in its legacy suite. These items are now available via the processes suite of System Events, clearly the preferred route for the future. In fact, Finder appears to take up to 33% longer to execute equivalent statements here (and it wouldn't particularly surprise me if they were passed on to System Events anyway).

Given this, the most obvious (but by no means fastest) way to determine the presence of a given process via System Events is probably something like <process "xyz" exists>. (I generally use either this - or, where speed is more critical, the <"xyz" is in name of processes> form.)

Turning to the shell, I wouldn't have expected your 'top' approach to be the fastest or the most reliable shell call, since it also gathers a whole bunch of system usage statistics - rather than mainly process names. The construct also truncates process names longer than 10 characters. In addition, each time the target application is launched here, your script returns a different value (eg: "2422", "2481", "2506") - indicating the current Unix process id (PID). So, as it currently stands, you'd need to do something like count the resulting text to make it in any way useful. Emmanuel's suggested use of 'ps' is more direct - not to mention way faster (by about 8-10 times here).

To give you a better idea of relative performance, I've compared several approaches, starting with your Shell and Finder methods - each adjusted where necessary to return the same boolean value:

-------------
1: shell/top:
-------------

(count (do shell script "top -l1 | grep 'QuickTime*' | cut -f2 -d' '")) > 0

--------------------
2: fndr/compareList:
--------------------

tell application "Finder"
(application processes whose name contains "QuickTime Player") is not {}
end tell

----------------
3: sysEv/exists:
----------------

tell application "System Events"
application process "QuickTime Player" exists
end tell

------------
4: shell/ps:
------------

"QuickTime Player" is in (do shell script "ps -xwwc")

------------------
5: sysEv/isInList:
------------------

tell application "System Events"
"QuickTime Player" is in name of application processes
end tell

------------------

Each script was run 1,000 (10 x 100) times and the averaged results expressed as an index: 100 = fastest overall:

test: index - method
--------------------

1: 968 - shell/top

2: 212 - fndr/compareList

3: 165 - sysEv/exists

4: 113 - shell/ps

5: 100 - sysEv/isInList

--------------------



-----8<----------8<----------8<----------8<-----



Jetzt würde mich nur noch mal interessieren, warum die Laufzeit der negativen Antwort so viel kürzer ist, wenn das Script aus dem Script Editor aufgerufen wird.

Kays Rechnung zufolge ist der Weg über "if prog is in name of application processes" wohl auch etwas schneller (am Schnellsten), also werde ich den nehmen.
0
Agrajag08.09.0515:33
Ah, super Tipp. Ich hätte nicht gedacht, daß man bei AS auch Sachen wie


tell application "System Events" to return (prog is in name of application processes)


schreiben kann




Nochmal zu den Properties: Es muß schon ein richtiges Script sein, da es so vom System gecached wird und somit keine Ladezeiten nach dem ersten Start erfordert.

Das war ja bei meinen Helfer-Scripten in den App-Bundles so ein Problem. Ich hab mir mal überlegt, was für Plattenzugriffe (bei meiner allerersten Variante mit den App-Bundles) bei jedem Tastendruck auf der Fernbedienung passieren:


0. Taste wird gedrückt App-Bundle wird gestartet
1. Das System öffnet die Info.plist, um zu sehen, wie es mit dem Bundle verfahren soll und findet die Startdatei heraus.
2. Die Startdatei (Shell-Script) in Contents/MacOS wird gestartet
3. Im Shell-Script wird osascript gestartet
4. osascript startet das Haupt-Script. Wer weiß, ob osascript nicht noch etwas für die Sprache AS laden muß, da osascript prinzipiell ja mehrere Sprachen bedienen kann.


Das wären also 4-5 kleine Plattenzugriffe (die ja bekanntermaßen nicht wirklich schnell sind), die sich besonders bei ausgelastetem System gravierend auswirken. Allgemein hab ich das Gefühl, das OSX dabei recht langsam ist. Das öffnen von Bundles schein viel Zeit zu kosten.


Das mit der XML-konformen Plist-Datei wäre wirklich nur ein bauchpinselndes Extra, aber nichts weswegen ich auf eine App umsteigen würde. So bin ich jetzt auch zufrieden... bis zur nächsten Idee
0
Agrajag08.09.0516:35
Ach, eine Idee hätte ich vielleicht noch. Und zwar so etwas wie stark vereinfachte PlugIns in Form von Klassen. Für jedes bedienbare Programm eine Klasse.

Der Hintergrund: Jedes Programm benutzt andere AS-Befehle. Ich muß bei jeder Tasten-Funktion Rücksicht auf jedes einzelne Programm nehmen, was Änderungen/Erweiterungen recht aufwändig und unübersichtlich macht. Also für jedes Programm eine eigene Klasse, mit einem definierten Satz an Methoden.

Das noch zu lösende Problem wäre die statische Art, wie tell arbeitet. Ich kann nicht sagen


tell application prog to ...


Ich muß immer den Programmnamen als String schon im Quellcode festlegen, wodurch ich gezwungen bin für jedes Programm sowas zu machen wie


if (prog = "iTunes) then tell application "iTunes" to ...


Gibt es nicht vielleicht doch noch einen Trick, wie ich solche Anfragen dynamisch formulieren kann?
0

Kommentieren

Diese Diskussion ist bereits mehr als 3 Monate alt und kann daher nicht mehr kommentiert werden.