Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting full-screen apps with AppleScript

I have been using this script in Automator, which toggles apps between full-screen and windowed mode. I am a frequent user of split-screen applications (introduced in El Capitan), so is there any way to modify this script to enable split-screen? I know there's no keyboard shortcut for splitting, so this is definitely a shot in the dark.

like image 868
Jarrett G. Avatar asked Dec 06 '16 19:12

Jarrett G.


People also ask

How do I split an app in OSX?

Click and hold the full-screen button in the upper-left corner of a window. As you hold the button, the window shrinks and you can drag it to the left or right side of the screen. Release the button, then click a window on the other side of the screen to begin using both windows side by side.


1 Answers

I managed to cobble something together, working off an AppleScript/python thing that I found in this MacScripter post. It does the following:

  1. Pulls a list of open application windows from System Events, and allows the user to select one or two (for full screen or split screen)
  2. Launches "Mission Control"
  3. GUI-scripts the Dock to find references to the various window-buttons and spaces in Mission Control that we need to access
  4. Programmatically drags the buttons around to create a new fullscreen or splitscreen space
  5. Clicks on the newly created space to activate it

You might be able to trim some time down on all the half-second delays, but Mission Control is expecting human interaction and handles things lazily. It will miss GUI requests that come too fast.

(* collect names of open app windows *)
tell application "System Events"
    set windowNames to {}
    set theVisibleProcesses to every process whose visible is true
    repeat with thisProcess in theVisibleProcesses
        set windowNames to windowNames & (name of every window of thisProcess whose role description is "standard window")
    end repeat
end tell

(* choose 1 name for fullscreen, two names for split screen *)
set selectedItems to choose from list windowNames with title "Split It" with prompt "Choose items to add to split view." with multiple selections allowed without empty selection allowed
if selectedItems is false or (count of selectedItems) > 2 then return

set selectedWindow1 to item 1 of selectedItems
if (count of selectedItems) = 2 then
    set selectedWindow2 to item 2 of selectedItems
end if

tell application "Mission Control"
    launch
end tell

(* 
The dock has a set of nested UI elements for Mission Control, with the following structure:
    "Mission Control"'s group 1 (the base container)
        group 1, group 2, .... (groups for each desktop)
            buttons for open windows on each desktop
        group "Spaces Bar" 
            a single button (the '+' buttan to add a new space) 
            a list 
                buttons for the desktops and any already-made spaces 
*)

tell application "System Events"
    tell process "Dock"'s group "Mission Control"'s group 1
        tell group "Spaces Bar"'s list 1
            set {p, s} to {position, size} of last UI element
            set XTarget to (item 1 of p) + (item 1 of s) + 100
            set YTarget to (item 2 of p) + (item 2 of s) + 100
        end tell
        tell group 1
            set viewButton1 to button selectedWindow1
            set {x, y} to get viewButton1's position
            my mouseDrag(x, y, XTarget, YTarget, 0.5)
        end tell
        tell group "Spaces Bar"'s list 1
            set {p, s} to {position, size} of last UI element
            set XTarget to (item 1 of p) + (item 1 of s) + 10
            set YTarget to (item 2 of p) + (item 2 of s) + 10
        end tell
        try
            tell group 1
                set viewButton2 to button selectedWindow2
                set {x, y} to get viewButton2's position
                my mouseDrag(x, y, XTarget, YTarget, 0.5)
            end tell
        end try
        tell group "Spaces Bar"'s list 1
            delay 0.5
            set lastUI to last UI element
            click lastUI
        end tell
    end tell
end tell

on mouseDrag(xDown, yDown, xUp, yUp, delayTime)
    do shell script "

/usr/bin/python <<END

from Quartz.CoreGraphics import CGEventCreateMouseEvent
from Quartz.CoreGraphics import CGEventCreate
from Quartz.CoreGraphics import CGEventPost
from Quartz.CoreGraphics import kCGEventLeftMouseDown
from Quartz.CoreGraphics import kCGEventLeftMouseUp
from Quartz.CoreGraphics import kCGMouseButtonLeft
from Quartz.CoreGraphics import kCGHIDEventTap
from Quartz.CoreGraphics import kCGEventLeftMouseDragged
from Quartz.CoreGraphics import kCGEventMouseMoved
import time

def mouseEvent(type, posx, posy):
          theEvent = CGEventCreateMouseEvent(None, type, (posx,posy), kCGMouseButtonLeft)
          CGEventPost(kCGHIDEventTap, theEvent)

def mousemove(posx,posy):
          mouseEvent(kCGEventMouseMoved, posx,posy);

def mousedrag(posx,posy):
          mouseEvent(kCGEventLeftMouseDragged, posx, posy);

def mousedown(posxdown,posydown):
          mouseEvent(kCGEventLeftMouseDown, posxdown,posydown);

def mouseup(posxup,posyup):
      mouseEvent(kCGEventLeftMouseUp, posxup,posyup);

ourEvent = CGEventCreate(None);

mousemove(" & xDown & "," & yDown & ");
mousedown(" & xDown & "," & yDown & ");
time.sleep(" & (delayTime as text) & ");
mousedrag(" & xUp & "," & yUp & ");
time.sleep(" & (delayTime as text) & ");
mouseup(" & xUp & "," & yUp & ");

END"
end mouseDrag
like image 70
Ted Wrigley Avatar answered Oct 10 '22 05:10

Ted Wrigley