Opening multiple windows with Applescript - windows

I am trying to write an Applescript to open three VLC windows in different screen positions. The script opens three instances of VLC but has them one on top of the other (using the position for window 1). Help with the code appreciated:
do shell script "open -n /Applications/Video/VLC.app"
tell application "System Events"
activate
set bounds of first window of application "VLC" to {13, 36, 790, 519}
end tell
do shell script "open -n /Applications/Video/VLC.app"
tell application "System Events"
activate
set bounds of second window of application "VLC" to {13, 544, 790, 1027}
end tell
do shell script "open -n /Applications/Video/VLC.app"
tell application "System Events"
activate
set bounds of third window of application "VLC" to {13, 1043, 790, 1526}
end tell

#khagler's comment provides the right pointer: the VLC instances must be distinguished by their PIDs (process IDs; called unix id in AppleScript) in the System Events context.
The code below should do what you want, arrived at after much toil and trouble -- par for the [AppleScript obstacle] course. One obstacle was that the VLC instances' main windows do not get created right away.
The comments provide more details.
Note that because user-interface elements are programmatically manipulated, the application running your script must be granted assistive access for security reasons.
Note that I'm starting the instances with do shell script "open -na VLC.app", relying on the location of the app being known to Launch services (should that not work for some reason, revert to your method of specifying the full path).
# Specify the desired window bounds.
# !! In the "System Events" context, windows do not
# !! have `bounds` properties, but separate `position` and
# !! `size` properties.
set WIN_POSITIONS to {{13, 36}, {13, 544}, {13, 1043}}
set WIN_SIZES to {{790, 519}, {790, 519}, {790, 519}}
# Launch the VLC instances.
repeat with i from 1 to count of WIN_POSITIONS
do shell script "open -na VLC.app"
end repeat
# Note:
# Instance-specific manipulation must
# be performed in the "System Events" context, because
# we must distinguish the VLC instances by their
# PIDs (process IDs; called `unix id` in AppleScript).
tell application "System Events"
# Get the PIDs (process IDs) of all VLC instances.
set vlcPids to get the unix id of every process whose name is "VLC"
# Loop over all instance PIDs.
# !! It is imperative to *continue* to use object specifiers
# !! with *filters based on the PID* so as to ensure that the
# !! individual instances are targeted.
# !! Attempting to store references to these instances in
# !! variables fails subtly, as evidenced by the "Events"
# !! tab in AppleScript editor later showing the non-specific
# !! process "VLC" of application "System Events" specifiers.
set winNdx to 1
repeat with vlcPid in vlcPids
# WAIT for each instance to create its main window, wich
# sadly, is not available right away.
# Once created, position it.
set haveWin to false
tell (first process whose unix id is vlcPid)
repeat with i from 1 to 25 # times out after 25 * .2 == 5 secs.
if (count of windows of it) > 0 then
set haveWin to true
tell front window of it
# !! In the "System Events" context, windows do not
# !! have `bounds` properties, but separate `position` and
# !! `size` properties.
set position to item winNdx of WIN_POSITIONS
set size to item winNdx of WIN_SIZES
end tell
exit repeat
end if
delay 0.2 # no window yet; sleep some and try again
end repeat
end tell
if not haveWin then error "VLC instance " & vlcPid & " unexpectedly did not create a window within the timeout period."
set winNdx to winNdx + 1
end repeat
end tell
How to make this work with Finder:
Targeting Finder changes the approach for two reasons:
there's only one Finder instance.
you cannot open multiple windows with open -na Finder.app; thankfully, this answer shows how to do it (see the comments there for quirks).
Note that the following blindly opens additional Finder windows.
set WIN_POSITIONS to {{13, 36}, {13, 544}, {13, 1043}}
set WIN_SIZES to {{790, 519}, {790, 519}, {790, 519}}
# Sample target locations for the Finder windows.
# Note the use of the "System Events" context to faciliate use of
# POSIX-style *input* paths; note, however, that the paths are
# *stored* as HFS paths so that Finder accepts them.
tell application "System Events"
set WIN_TARGETS to {¬
path of desktop folder, ¬
path of folder "~/Downloads", ¬
path of folder "/Library/Audio"}
end tell
set winCount to count of WIN_POSITIONS
# Launch the Finder windows.
tell application "Finder"
# Create the windows in reverse orders.
repeat with i from winCount to 1 by -1
set newWin to make new Finder window
set target of newWin to item i of WIN_TARGETS
end repeat
end tell
tell application "System Events"
set i to 1
repeat with i from 1 to winCount
tell window i of application process "Finder"
# !! In the "System Events" context, windows do not
# !! have `bounds` properties, but separate `position` and
# !! `size` properties.
set position to item i of WIN_POSITIONS
set size to item i of WIN_SIZES
end tell
end repeat
end tell

After scouring the internet and much trial & error I have found this works well providing you allow the AppleScript Editor (or automator or your own app, whichever you are using) to control your computer under System Preferences > Security & Privacy > Privacy > Accessibility (OS X 10.9 Mavericks). The first time you run the script/app you'll be prompted to change the setting. After granting access, the second time you run the script/app the windows will be re-positioned.
do shell script "open -n /Applications/VLC.app /path/to/first/file" --edit path
do shell script "open -n /Applications/VLC.app /path/to/second/file" --edit path
delay 3 --wait 3s for VLC to open files, increase if necessary
tell application "System Events"
set pidList to the unix id of (every process whose name contains "VLC")
tell (first process whose unix id is item 1 of pidList)
set the position of the front window to {0, 22} --edit {x,y}
end tell
tell (first process whose unix id is item 2 of pidList)
set the position of the front window to {640, 22} --edit {x,y}
end tell
end tell
It's not as clever as mklement0's answer but, as someone who is new to AppleScript, I could understand what's going on.

Related

reload Terminal preferences .plist after change

I used plutil to edit the plist. then I placed in under /User/<myUsername>/Library/Preferences/com.apple.Terminal.plist. I want it to update the settings without reboot the application. How do I do this? using defaults read com.apple.Terminal doesn't seem to make the changes take effect. I added a terminal profile to the plist and want the changes to take effect.
I tried making an import profile with AppleScript but long story short it's not 100% possible. if you store window 1 so it's the same var in-between delays right after open it errors more times.
on run argv
set importScript to first item of argv
set flag to application "Terminal" is not running
tell application "Terminal"
open importScript
delay 1.0E-5
activate
if flag then close back window
do script "exit" in window 1
delay 0.5
close window 1
end tell
end run
there is no need for editing plists just a simple AppleScript. the limitations of this are you must have _oti_<yourProfileId> in your terminal profile default header and change the title when running your terminal profile to prevent accidental closures when installing the same profile of an already running app
import.applescript
on run argv
set importScript to first item of argv
set closeScript to second item of argv
set profileId to third item of argv
do shell script "open -a Terminal " & importScript
do shell script "osascript " & closeScript & " _oti_" & profileId
end run
closeMe.applescript
on run argv
set c to first item in argv
tell application "Terminal"
set wList to every window
repeat with app_window in wList
set wname to name of app_window
if wname contains c then
do script "exit" in app_window
delay 0.312
close app_window
end if
end repeat
end tell
end run
and then you can call the profile using this AppleScript
on run argv
set flag to application "Terminal" is not running
set scpt to first item in argv
set n to second item in argv
set p to third item in argv
tell application "Terminal"
set newTab to do script scpt
set badFlag to back window is equal to window 1
if p is not equal to "" then set current settings of newTab to settings set p
set custom title of newTab to n
activate
if flag and (not badFlag) then
do script "exit" in back window
delay 0.1
close back window
end if
end tell
end run

Run emacs using applescript and open file

What I would like to do is have an automator script open a file in emacs when I drag a file onto it, and bring terminal to the front.
Right now, when I try to do this with input set to ~/Desktop/test.txt, it either opens up the main page, or it ends up with ~/Desktop/testtxt. Am I doing this wrong? Is there a better way to do this?
This is what I have right now:
set thePath to POSIX path of input
tell application "Terminal" to do script "emacs"
tell application "System Events"
tell process "Terminal"
activate
delay 2
keystroke "x" using control down
delay 1
keystroke "f" using control down
delay 1
keystroke thePath
delay 1
keystroke return
delay 1
end tell
end tell
return input
end run
Use the file path as an argument to emacs
on run {input}
tell application "Terminal"
repeat with i in input
do script "emacs " & quoted form of POSIX path of i
end repeat
activate
end tell
return input
end run

Applescript to Expose all Finder Windows?

I'm trying to figure out how to write an Applescript that will Exposé all Finder Windows.
Application Logic
I think the script needs to have this application logic:
Check a residual setting and get the name of the last "Frontmost
Application" (perhaps use a text file ~/last-application.txt to store this?)
Grab the name of the current Frontmost Application
If the name of the current of the Frontmost Application is Expose, then activate the previous frontmost application
Else, activate finder, and then activate expose for just finder windows
Desired Behavior
When the script is activated all the finder windows (and only the finder windows) will be shown in Exposé
If the script is then run again (and no finder window was selected) the script will just switch back to the last frontmost application
I'm not sure how to get this working though. If there is another utility that does this automatically that'd be great, too.
set f to "/s/x/finderexpose"
set prev to do shell script "touch " & f & "; cat " & f
if prev is not "" then
delay 0.5 -- time to release modifier keys used in a shortcut
tell application "System Events" to key code 53 -- esc, if Exposé is open
delay 0.3 -- for the Exposé animation?
activate application prev
do shell script "echo '' > " & f
else
do shell script "echo " & quoted form of (path to frontmost application as text) & " > " & f
activate application "Finder"
delay 0.05
tell application "System Events" to key code 125 using {control down} -- ⌃↓
end if
It'd be less ugly if the part for switching to the previous application was left out:
activate application "Finder"
delay 0.05
tell application "System Events" to key code 125 using {control down}

AppleScript Focus / Rename File (and clicking anywhere)

on run {input}
set filepath to POSIX path of input
do shell script "touch " & quoted form of filepath & "untitled"
return input
end run
Is what I have so far, and it works, but is there a way to then focus on the file then trigger a rename? I dont want the rename to be automatic, just trigger the event (like pressing "return" while you have a file selected). And I dont want to use any sort of modal...
Quick Side question: is there a way to set this so that i dont have to select a folder or file directly, but can do it by, lets say, clicking in a white space in a folder as long as it's in Finder? Right now I have my "Service receives selected" to "files or folders" in Finder.app.
== UPDATED CODE ==
on run {input}
set filepath to POSIX path of input
do shell script "touch " & quoted form of filepath & "untitled"
tell application "Finder"
activate
set target of Finder window 1 to POSIX file "/Users/oscargodson/Documents/designs/untitled"
end tell
tell application "System Events"
tell process "Finder"
keystroke return
end tell
end tell
return input
end run
If i hardcode the path it works! But how do I get it as a var that works?
Here's one way. I think a modal window where you ask for the name would be better but you can try this. Notice you do not use "POSIX path" in this code. Applescript doesn't use POSIX paths. Also {input}, as indicated by the brackets around it, is a list of items. Therefore you act on the items of the list, and in this case we act on the first item.
set filepath to item 1 of input
tell application "Finder"
activate
reveal filepath
end tell
tell application "System Events"
tell process "Finder"
keystroke return
end tell
end tell
EDIT: With your updated code, here's a working script...
on run {input}
if (class of input) is not list then set input to {input}
set theFolder to (item 1 of input) as text
try
alias theFolder
tell application "Finder"
if (class of item theFolder) is not folder then error "input is not a folder."
activate
set theFile to make new file at folder theFolder with properties {name:"untitled"}
reveal theFile
end tell
delay 0.2
tell application "System Events"
tell process "Finder"
keystroke return
end tell
end tell
on error theError number errorNumber
tell me
activate
display dialog "There was an error: " & (errorNumber as text) & return & return & theError buttons {"OK"} default button 1 with icon stop
return
end tell
end try
return input
end run
tell application "Finder"
activate
reopen -- in case there are no open windows
set target of Finder window 1 to POSIX file "/Applications/Safari.app"
end tell
reveal and select always open a new window, set target and set selection don't.
I don't know why, but when set selection it used in column view, you can only select items in the entire contents of the target of the front window. The same thing doesn't happen in other views, so it seems like a bug.
Fix for the code in the edited question:
on go(input)
set p to POSIX path of (input as text)
set p2 to p & "untitled"
do shell script "touch " & p2
tell application "Finder"
reopen
activate
set target of Finder window 1 to POSIX file p2
end tell
delay 0.3 -- time to release modifier keys
tell application "System Events" to keystroke return
end go
tell application "Finder"
set fold to folder (path to documents folder)
end tell
go(fold)
(That on go and the last lines are just for testing.)
I've created an AppleScript based on the #regulus6633's one, but with some improvements.
Note: This answer was originally posted as an AskDifferent answer. I'm copy/pasting here for convenience.
The idea is to create an Automator workflow and assigning a shortcut to it using the following steps:
Open Automator and create a Service;
Set the input to no input, and the application to Finder.app;
Drag and Drop the Run AppleScript workflow element onto the grey space;
Put the contents of this AppleScript in the textbox;
Save the workflow with a reasonable name (like New File);
Go to Settings -> Keyboard -> Shortcuts -> Services and assign a shortcut to it.
Now, let's show the AppleScript:
set file_name to "untitled"
set file_ext to ".txt"
set is_desktop to false
-- get folder path and if we are in desktop (no folder opened)
try
tell application "Finder"
set this_folder to (folder of the front Finder window) as alias
end tell
on error
-- no open folder windows
set this_folder to path to desktop folder as alias
set is_desktop to true
end try
-- get the new file name (do not override an already existing file)
tell application "System Events"
set file_list to get the name of every disk item of this_folder
end tell
set new_file to file_name & file_ext
set x to 1
repeat
if new_file is in file_list then
set new_file to file_name & " " & x & file_ext
set x to x + 1
else
exit repeat
end if
end repeat
-- create and select the new file
tell application "Finder"
activate
set the_file to make new file at folder this_folder with properties {name:new_file}
if is_desktop is false then
reveal the_file
else
select window of desktop
set selection to the_file
delay 0.1
end if
end tell
-- press enter (rename)
tell application "System Events"
tell process "Finder"
keystroke return
end tell
end tell
For convenience, I'm putting this AppleScript in this GitHub Gist.

Using AppleScript to choose a file in Safari

I am trying to write some automation code (primarily in Ruby Selenium). At some point, a file chooser is opened in Safari so that the user can select a file for upload. Selenium cannot handle this, but I think AppleScript should be able to. I am new to AppleScript and haven't been able to find any boilerplate code of someone automating a file chooser dialog. I'm reading through the AppleScript docs, but any ideas would be most helpful.
Some more searching and I found a great answer here: Applescript file dialog with UI scripting
Here's what I ended up using:
on run argv
tell application "Safari"
activate
-- Usage check
set argc to count argv
if argc is not greater than 0 then
return "Usage: SafariFileChooser file_name [window_name]"
end if
-- The file we will choose to open
set file_name to item 1 of argv
-- Flip to the named window, if specified
if argc is equal to 2 then
set window_name to item 2 of argv
set flip_count to index of window window_name
repeat (flip_count - 1) times
activate
tell application "System Events" to keystroke "`" using command down
end repeat
end if
-- Interact with the dialog using System Events (thanks mcgrailm)
tell front window
activate
tell application "System Events"
keystroke "g" using {shift down, command down}
keystroke file_name
delay 1
keystroke return
delay 1
keystroke return
end tell
end tell
end tell
return 0
end run
Another option I just discovered is to specify the directory using the command-line:
do shell script "defaults write com.apple.Safari NSNavLastRootDirectory /path/to/directory"
This way you can do slightly less in UI scripting. Run this command before you open the file chooser, and it will put you into the directory specified. Include all the files you need in this directory, and you can just script command+a to select them all, and return.

Resources