33

I periodically have to move my display around (physically1) and this requires also rearranging my display arrangement in System Preferences. Manually doing this all the time is a pain in the neck. Is there any way to do it programmatically?


1 I work on one side of a table when I'm working solo, but when I want to pair with someone I flip to the other side of the table because it has more unused space available for a second person. Flipping the display around to face the other side of the table means the display goes from being to the right of my laptop to being to the left, since the laptop goes on a stand either way.

1
  • 1
    Just a note... I modified the code as there was no need to replicate what I previously did in the if normalOrentation ... statement. That just needed to cover info for the toggle flag. The replicated code has been moved out and set below it. Commented Aug 17, 2016 at 15:05

7 Answers 7

35

Sorry for the late answer. You can use displayplacer to set profiles for both of your arrangements. Save the profiles in a script or use something like BetterTouchTool for a hotkey to change your monitor layout.

https://github.com/jakehilborn/displayplacer

2
  • 11
    There is no reason to apologize for answering after a long period of time. Neither I nor anyone else has a right to expect your answer. Your answer is just as useful to anyone who is searching for a solution to this problem. I appreciate your work—and your answer—and plan to make it a part of my setup. Thanks!
    – iconoclast
    Commented Mar 31, 2018 at 19:19
  • 7
    Can confirm. I'm looking in 2021. Commented Jan 27, 2021 at 17:58
17

I figured out how to automate the display switching using a keyboard shortcut with displayplacer and it works like a charm!😎

I setup a macro using Keyboard Maestro to automatically cycle the desktop arrangement using a keyboard shortcut.

Instructions to setup Keyboard Shortcut

  1. Install displayplacer using Homebrew
  2. Use Keyboard Maestro and create a Macro
  3. Add the Execute Shell Script Action for each display you have (I have 3).
  4. Open System Preferences > Displays and change your arrangement by placing the menu bar to the right by 1 screen (right-to-left type direction)
  5. Open your terminal and run the displayplacer list command
  6. Copy the bottom output, e.g. displayplacer "id:<screenId> res:<width>x<height> hz:<num> color_depth:<num> scaling:<on/off> origin:(<x>,<y>) degree:<0/90/180/270>"
  7. Paste the output into your Macro Action.
  8. Repeat steps 4-7 and stop after you've done the main screen you keep your menu bar on.
  9. Setup a keyboard shortcut for your Macro.
  10. Run your Macro with your new shortcut and watch the magic happen right before your eyes.

Helpful Tips

  1. If you have an issue with running displayplacer from Keyboard Maestro, it's likely that you're using a different bash in your terminal/iTerm like oh-my-zsh when you installed it using Homebrew. If thats the case, follow these instructions from my other post to fix your displayplacer binary reference.

  2. Here's a screenshot to view my working Keyboard Maestro setup with displayplacer.

  3. You may need to run your macro a second time if you accidentally hit your shortcut.

2
  • 1
    Awesome! It works like a charm. Does your KM macro swap them automatically? How can I make that when I trigger the macro it just swaps them?
    – Alex F.
    Commented Oct 17, 2021 at 13:42
  • I am using BetterTouchTool and I set it up to show a context menu when Mission Control button is pressed with two options (left and bottom) for my side car iPad configuration. Works like a charm! Be sure to use full path to the displayplacer when providing command to BetterTouchTool terminal action (/opt/homebrew/bin/displayplacer in my case). Commented May 15, 2023 at 7:26
10

Using my MacBook Pro, which normally sits to the left of my Thunderbolt Display, and my Thunderbolt Display, the following will show how to use hsscreens and AppleScript to toggle the two arrangements programmatically based on how it's currently arranged. The end result is an AppleScript application that when run simply toggles back and forth between the two arrangements. This app can be run in all the normal ways any other application can be run.

In the image below, you see the normal and flipped arrangements of the Displays and Menu bar showing the difference relationships between my MacBook Pro and Thunderbolt Display.

Screen Arrangements

This AppleScript application, along with the hsscreens binary executable file, programmatically toggles between the two arrangements shown in the image above, shifting the MacBook Pro's Display to the right or left of the Thunderbolt Display maintaining the Menu bar on the MacBook Pro's Display.

To code this, I needed to determine what the current arrangement was and then act accordingly. To do this I used hmscreens -info in a Terminal twice, once while in each arrangement.

Looking at the outputted information I saw a piece of info that I could grep for, in order to the set a flag to toggle against.


Output of hmscreens -info in a normal arrangement of the Displays:

$ hmscreens -info
Screen ID: 68822100
Size: {1440, 900}
Global Position: {{0, 0}, {1440, 900}}
Color Space: NSCalibratedRGBColorSpace
BitsPerPixel: 32
Resolution(dpi): {144, 144}
Refresh Rate: 0
Uses Quartz Extreme: YES

Screen ID: 68695180
Size: {2560, 1440}
Global Position: {{1440, -540}, {4000, 900}}
Color Space: NSCalibratedRGBColorSpace
BitsPerPixel: 32
Resolution(dpi): {72, 72}
Refresh Rate: 0
Uses Quartz Extreme: YES

$

Output of hmscreens -info in a flipped arrangement of the Displays:

$ hmscreens -info
Screen ID: 68822100
Size: {1440, 900}
Global Position: {{0, 0}, {1440, 900}}
Color Space: NSCalibratedRGBColorSpace
BitsPerPixel: 32
Resolution(dpi): {144, 144}
Refresh Rate: 0
Uses Quartz Extreme: YES

Screen ID: 68695180
Size: {2560, 1440}
Global Position: {{-2560, -540}, {0, 900}}
Color Space: NSCalibratedRGBColorSpace
BitsPerPixel: 32
Resolution(dpi): {72, 72}
Refresh Rate: 0
Uses Quartz Extreme: YES

$

If was obvious, to me, I needed to use info from Global Position: to determine what the current arrangement of the Displays were. I immediately saw -2560 as unique between the output and a way of determining the current arrangement. If I greped for -2560 and found it then I was in the flipped arrangement, not the normal arrangement. So this is what I used to determine the current arrangement and thus toggle between the two arrangements. (Note: -2560 was not the only thing unique, it's just what I focused on first and felt an easy way to parse the information to set a toggle flag with.)

Save the AppleScript code below as an application and place a copy of the hmscreens binary executable file within the <appname>.app/Contents/Resources folder. This way the app, e.g. /Applications/Toggle Displays Arrangements.app is self-contained and not dependent on an external location of the hmscreens binary executable file.

Obviously you'll need to determine what to grep for or use a different method to set the toggle flag and modify the code below accordingly to suite your particular needs (if other then this use case or a different use case).

AppleScript code:

set hms to (path to me as text) & "Contents:Resources:hmscreens"

set screenIDs to paragraphs of (do shell script quoted form of POSIX path of hms & " -screenIDs")
if (count of screenIDs) is greater than 1 then

    set normalOrentation to "1"
    try
        set normalOrentation to do shell script quoted form of POSIX path of hms & " -info | grep '\\-2560'"
    end try
    if normalOrentation is "1" then
        set othersPosition to "left"
    else
        set othersPosition to "right"
    end if

    set secondScreen to item 1 of screenIDs
    do shell script quoted form of POSIX path of hms & " -setMainID " & secondScreen & " -othersStartingPosition " & othersPosition

else

    tell me
        activate
        display dialog "Only one screen is attached to your computer!" buttons {"OK"} default button 1 with icon note
    end tell

end if

The image below shows syntactical highlighting of the AppleScript code.

AppleScript Code

4
  • I am currently unable to get this working. OS X kills hmsscreens instantly, before it can do anything: [1] 9612 killed hmscreens -info. Any ideas how to fix this situation?
    – iconoclast
    Commented Aug 18, 2018 at 20:23
  • @iconoclast, This was posted two years ago, did you test it then and did it work, or are you just doing it for the first time. Also, have you tried re-downloading the file and trying with a fresh copy? Have you rebooted between failure? This still works for me with macOS High Sierra 10.13.5. When I originally posted this, I was using OS X Mountain Lion. Commented Aug 18, 2018 at 20:38
  • I believe it did work originally, but at some point stopped.
    – iconoclast
    Commented Aug 18, 2018 at 21:36
  • It's still working. Just copy the tool to your Applications Folder. Then start it using e.g. /Applications/hmscreens -info from in your command line
    – Karl Adler
    Commented Sep 3, 2018 at 9:10
6

displayplacer is perfect and made the bulk of the process very easy. I used it in an Automator script to switch between two arrangement profiles, and then set up the ability to trigger those scripts from the menu bar. Here's a record of the process I went through.

enter image description here

  • Follow instructions here to install displayplacer and get the commands to set your two layouts.
  • Follow directions here to make an Automator script.
  • In order for my script to run without errors, I had to add the line export PATH=/usr/local/bin:$PATH before running the displayplayer command. Advice taken from here.
  • To run scripts from the menu bar, check out here.
  • My "quick action" Automator scripts were being saved in /Users/alfordsimon/Library/Services, but the previous link expected them to be placed in /Users/alfordsimon/Library/Scripts, so I moved them over.
2
  • 1
    Thanks a lot for collating all the steps! Worked out perfectly for me.
    – runkar
    Commented May 14, 2021 at 6:58
  • Absolutely great solution!
    – Felix
    Commented Mar 15 at 11:57
4

This isn't AppleScript, but here is a python library that that interfaces with PyObjC bindings that provides in-depth control of Mac display settings called "Display Manager". We have updated Display Manager, which is an open-source python library which can modify a individual or fleet of Mac's display settings manually or automatically. It programmatically manages Mac displays, including display resolution, refresh rate, rotation, brightness, screen mirroring, and HDMI underscan. Its primary intended purpose is to allow system administrators and developers to automatically configure any number of Mac displays, by use of the command-line scripts and the Display Manager Python library. It can easily be integrated in Jamf Pro, Outset or Munki or other client management systems.

We use Display Manager in our environment for multiple use cases like on our digital display systems to rotate the display 90 degree's and exactly set the HDMI underscan, on podiums setting video mirroring and allow the instructor quickly toggle mirroring on or off, set default resolution & brightness on shared systems like student labs or staff/faculty systems and reset the default after at times like user login/logout or on demand, etc.

If you are interested in reviewing the code or trying it out see the following GitHub repository...

https://github.com/univ-of-utah-marriott-library-apple/display_manager

Please let us know if you have an question, problems or have feature requests.

3
  • This looks interesting, but possibly overkill for what I want. (But I'm not the down-voter, by the way. In fact... I'm going to upvote, since it does seem potentially useful.) Thanks for posting it!
    – iconoclast
    Commented Aug 18, 2018 at 20:16
  • Sure, np. Let use know if you have any questions, problems or feature requests.
    – user332214
    Commented Aug 20, 2018 at 17:18
  • Just forked this. Looks like exactly what I was after! Commented Dec 11, 2020 at 2:04
4

I used the examples above to create a simple apple script "Swap Screens".

display dialog "Swap Screens?" buttons {"Cancel", "OK"} default button "OK" cancel button "Cancel" giving up after 15

set hms to "Applications:hmscreens"
set screenIDs to paragraphs of (do shell script quoted form of POSIX path of hms & " -screenIDs")
if (count of screenIDs) is greater than 1 then

    set firstScreen to item 1 of screenIDs

    set secondScreen to item 2 of screenIDs

    set othersPosition to "right"

    do shell script quoted form of POSIX path of hms & " -setMainID " & secondScreen & " -othersStartingPosition " & othersPosition

else

    display dialog "Only See One Screen"

end if

It worked like a champ ... I can click one icon and my screens align just like I want them to.

Enjoy! E-

4

You can also use Hammerspoon to do this programmatically. I have this in my Hammerspoon init script:

-- swap which is primary screen: external monitor or laptop
hs.hotkey.bind({"cmd", "alt", "ctrl", "shift"}, "f11", function()
  -- allScreens seems to return the screens in order of primary, non-primary
  -- so with two screens, this always operates on the non-primary 
  hs.screen.allScreens()[2]:setPrimary()
end)
2
  • Swapping position is not the same as swapping which is primary. Does this also swap the physical position of the monitors?
    – iconoclast
    Commented May 24, 2020 at 15:41
  • 1
    In my experience it does not change the physical position of the monitors; it just changes which screen is primary. (I'm using OSX 10.13.6 and Hammerspoon 0.9.78) Commented May 28, 2020 at 10:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .