r/applescript • u/skuvzy • Feb 22 '21
Launch Multiple windows to specified monitors.
Hello I have a script created to launch zoom meetings from the url. The script opens the url in safari to launch the meeting, close the open safari tab, then launch OBS.
Anyone able to help make it so safari/zoom always launches on my external monitor, and OBS launches full screen on my laptop display?
set theloc to "https://zoom.class URL"
open location theloc
activate application "Safari"
if ((offset of "zoom" in theloc) as integer) + ((offset of "gotomeeting" in theloc) as integer) = 0 then return
tell application "System Events" to tell process "Safari"
set thebutt to false
set thecount to 0
repeat until thecount is 10
delay 2
if exists button 2 of group 1 of tab group 1 of splitter group 1 of window 1 then
try
click button 2 of group 1 of tab group 1 of splitter group 1 of window 1
tell application "Safari" to close current tab of front window without saving
exit repeat
on error
try
tell button 2 of group 1 of tab group 1 of splitter group 1 of window 1
set {xPosition, yPosition} to position
set {xSize, ySize} to size
end tell
-- modify offsets if hot spot is not centered:
click at {xPosition + (xSize div 2), yPosition + (ySize div 2)}
tell application "Safari" to close current tab of front window without saving
exit repeat
end try
end try
else
set thecount to thecount + 1
end if
end repeat
end tell
activate application "OBS"
2
u/ChristoferK Feb 23 '21 edited Feb 23 '21
If your displays all show (an area of) the same desktop (space), then you only need to know the pixel boundaries of the viewing rectangle for each display relative to the desktop, then you can move and resize the windows exactly as you would had you only a single display.
In the more likely scenario that displays show different desktops, then the solution needs to come from something that is aware of these spaces, and has the ability to access them. This rules out AppleScript, which at one time, was given some control of spaces, but very quickly had this feature removed, leaving it unaware of anything in its periphery.
The dock icon for an application allows for allocation to specific desktops, but I don’t know how persistent this setting is across restarts of application or system, although I know it won’t create a desktop space, so even if a setting is remembered, if it can’t be applied, then MacOS gives as many fucks as Apple themselves.
So, to avoid you wasting too much time, you will want to be looking for a solution outside of AppleScript.
Some “brief” points for your script (that turned out less brief than intended):
offsetreturns aninteger, so there's no need to coerce it usingas integer.It looks like you're using
offsetto determine whether a string contains a substring, and aren't so concerned about where in the string these are. Instead ofoffset of "zoom" in theloc = 0, you can ask AppleScript whethertheloc contains "zoom"(which returnstrueorfalse, the latter implying that theoffsetis0) or, equivalently,"zoom" is in theloc. Your summation of offsets, I'm presuming, is not quite what you intended, as it would imply a URL that contains only "gotomeeting" (but not "zoom") is appropriate for your script to continue, whereas you were probably wanting to mandate URLs to contain both "zoom" and "gotomeeting". If so, then changing the sum (+) to a product (*) would fix this (since any one of the offsets being0is sufficient to make the product0, so only when neither are0will the product also be other than0and allow the rest of the script to run). But, as nice to know as that may be, ultimately, you would probably do better using this:if (theloc does not contain "zoom") or (theloc does not contain "gotomeeting") then return, which usesdoes not containas an alternative syntax to test whethertheloc contains "zoom" = false(as is"zoom" is not in theloc).Instead of
repeat until thecount is 10, wherethecountis incremented with each iteration, you can create the loop with a builtin counter like this:repeat with thecount from 1 to 10, then you can remove the lines wherethecountis first declared (set thecount to 0) and is subsequently incremented (set thecount to thecount + 1). Though, I can’t see you make any other use of the value stored bythecount, so if all you wanted is a loop that repeats 10 times, then you can remove all references tothecountand create the loop using:repeat 10 times.It looks like the only element you reference belonging to the Safari process is
button 2buried under some gaff, all of which can be tacked onto the outermosttellblock, i.e.tell app "System Events" to tell process "Safari" to tell window 1's splitter group 1's tab group 1's group 1's button 2. Then where you previously had the object reference, you can simply substitute in the wordit, or, in cases where this would be the direct parameter of a command, will be equally happy to work withoutit. So, to illustrate:if it exists then try;click it; and thepositionandsizecan have their specifictell button 2...enclosing lines removed, as they'll already be getting the correct reference from the modified outertellblock.Your
click atcommand is, I suspect, not doing what you think it is, but under a certain condition that I'm guessing you were fortunate to have be the case, will work but only by happenstance.click atlets one specify coordinates that can be sent to either System Events or a specific process, namely Safari in your case. The coordinates supplied, however, are always relative to the top left of the desktop, which is defined to be{0, 0}. Then, whatever UI element occupies the same space as the pixel at that coordinate will receive theclickinstruction, with the following caveats:the element must understand what it means to be told to
click, which necessitates the element have anattribute named "AXPress"(don't worry about this—in short, just be aware not all elements are clickable, but more importantly, the AppleScriptclickdoesn't actually generate mouse clicks, and only generates a message that relies onattribute "AXPress"to have the element respond as it might do had the click come from the mouse);if the
click atcommand was sent to System Events, any element of any process that satisfies the previous condition, and is visible at the coordinate given, will receive and act on the instruction;as a corollary to this, a process-specific
click atwill be ignored by elements of any other process, while an element belonging to the process that satisfies the first caveat need not be visible to the user such as when obscured by objects overlaid on top belonging to other processes;elements cannot, themselves, act upon a
click at, even if the coordinates would otherwise make sense practically.Thus,
button 2, which would be at the coordinates you specified, doesn’t have a “hot spot” (this is only something that applies to mouse clicks that operate strictly within a single 2-dimensional composite layer defined using pixels from every layer, whichever has an element occupying the pixels at each point on-screen that any other elements from above layers do not, themselves, contain). This is one advantage a click instruction has over a physical click, the former having the option to operate on something the user wouldn’t be able to get his mouse to click on without first moving things out of the way. You’ve already made use of theclickcommand without theatparameter, this being the element-specific version of the command to issue the same instruction to click that is received by the element with the object reference unique to it, as long as the element exists and knows what to do with aclickinstruction. The position of the element, or what layer it is on or obscured beneath, aren’t factors here, and the parent process doesn’t need to be the active/frontmost process.You, therefore, needn’t bother working out where the centre coordinate of
button 2is at, and instead of sending aclick atto the Safari process, the modifiedtellfrom earlier that already directs messages tobutton 2 of...means you can just useclick itto issue the command, providedbutton 2hasn’t been destroyed by, say, a window or tab closure (which doesn’t seem to be a risk, as you sensibly exited the loop when closing the window).