Created
October 29, 2020 15:25
-
-
Save mpoisot/5dc29d3aeb2221a8c344240630453bb2 to your computer and use it in GitHub Desktop.
Set multi-monitor display arrangement for a MacBook based on which USB C port the monitor plugs in to
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env sh | |
# Call this script from an EventScripts trigger. https://www.mousedown.net/software/EventScripts.html | |
# Depends on `displayplacer`. https://github.com/jakehilborn/displayplacer | |
# On my macbook, when my external screen is plugged into the right USB ports I get one contextual ID running `displayplacer list`. When plugged into the left ports I get a different ID. | |
# 27" LG info from `displayplacer list`, connected to right USB ports: | |
# Persistent screen id: 1B2915BF-F01F-DFDA-9605-FB0311DB5E03 | |
# Contextual screen id: 458633946 | |
# EventScripts has an easy GUI to let you add your own script, and set the trigger from a big list of system events. I found both "USB device attached" and "Spaces Changed" work in terms of detecting that my monitor is connected (via a USB C to HDMI dock). The problem is that both events are trigger too often for the simple command line @jakehilborn suggested (`displayplacer [config1] || displayplacer [config2]`). | |
# When my Anker USB C dock is connected, it registers as 6 different USB devices: ethernet, SD card reader, etc etc. With EventScripts triggering on USB Added events, this resulted in my displayplacer script getting called 6 times in a row, and it took a good 15 seconds of screen flickering before things settled down. Yikes. And I would get a flicker for any other USB stuff I might connect, unrelated to the monitor's dock. Grrr. | |
# Next I tried triggering EventScripts based on Spaces Changed. This does result in just one event when I connect the monitor. But it also triggers every time I move around spaces - which I do A LOT. These events queue up and result in absurd amounts of screen flickering. Grrr. | |
# What I needed was for my script to do nothing when the screen is already arranged correctly. I looked at the output of `displayplacer list` and realized I could grep a things and make my script a little smarter. | |
# Is the external monitor connected at all? Is it connected to left or right ports? Is the config already set? Only at the end of all that set the config, otherwise do nothing. Then it doesn't matter how often the script is called with false positives. | |
# One gotcha I encountered is that it's hard to make a shell variable that contains double quotes. I ended up just using the full ugly string twice instead of nicer variables. | |
########################################################################## | |
# EventScripts requires this script to live in a special folder that doesn't have write | |
# permission, and I don't see output from this script in the system console. So log to a | |
# file in my home folder. | |
LOGFILE=/Users/marcel/tmp/display_config.log | |
# Your displayplacer binary. | |
DISPLAY_PLACER=/usr/local/bin/displayplacer | |
# Info regarding external monitor from `displayplacer list` | |
# The permanent ID never changes. The contextual ID depends on a number of factors. | |
# For my macbook with 4 USB C ports, it reports one ID for left ports, another | |
# ID for rights ports. | |
SCREEN_PERM_ID=1B2915BF-F01F-DFDA-9605-FB0311DB5E03 | |
SCREEN_RIGHT_ID=458633946 | |
SCREEN_LEFT_ID=458633945 | |
echo "Starting display_config" > $LOGFILE | |
# EventScripts passes a bunch of extra params. | |
# echo $@ >> $LOGFILE | |
if ${DISPLAY_PLACER} list | grep ${SCREEN_PERM_ID}; then | |
echo "External 27 inch LG screen detected." >> $LOGFILE | |
if ${DISPLAY_PLACER} list | grep ${SCREEN_RIGHT_ID}; then | |
echo "Screen plugged into right port." >> $LOGFILE | |
# Exact command suggested by `displayplacer list` when monitor connected to right ports and arranged correctly. | |
if ${DISPLAY_PLACER} list | grep '"id:1B2915BF-F01F-DFDA-9605-FB0311DB5E03 res:1920x1080 hz:30 color_depth:8 scaling:on origin:(0,0) degree:0" "id:FC1D8AEF-83A6-B0CC-9673-6E13DCF9CCAC res:1440x900 color_depth:8 scaling:on origin:(-1440,874) degree:0"'; then | |
echo "Already set to right config. Ignoring." >> $LOGFILE | |
else | |
echo "Setting right side config." >> $LOGFILE | |
# Same exact same string as above | |
${DISPLAY_PLACER} "id:1B2915BF-F01F-DFDA-9605-FB0311DB5E03 res:1920x1080 hz:30 color_depth:8 scaling:on origin:(0,0) degree:0" "id:FC1D8AEF-83A6-B0CC-9673-6E13DCF9CCAC res:1440x900 color_depth:8 scaling:on origin:(-1440,874) degree:0" | |
fi | |
fi | |
if ${DISPLAY_PLACER} list | grep ${SCREEN_LEFT_ID}; then | |
echo "Screen plugged into left port." >> $LOGFILE | |
# Exact command suggested by `displayplacer list` when monitor connected to left ports and arranged correctly. | |
if ${DISPLAY_PLACER} list | grep '"id:1B2915BF-F01F-DFDA-9605-FB0311DB5E03 res:1920x1080 hz:30 color_depth:8 scaling:on origin:(0,0) degree:0" "id:FC1D8AEF-83A6-B0CC-9673-6E13DCF9CCAC res:1440x900 color_depth:8 scaling:on origin:(259,1080) degree:0"'; then | |
echo "Already set to left config. Ignoring." >> $LOGFILE | |
else | |
echo "Setting left side config." >> $LOGFILE | |
# Same exact same string as above | |
${DISPLAY_PLACER} "id:1B2915BF-F01F-DFDA-9605-FB0311DB5E03 res:1920x1080 hz:30 color_depth:8 scaling:on origin:(0,0) degree:0" "id:FC1D8AEF-83A6-B0CC-9673-6E13DCF9CCAC res:1440x900 color_depth:8 scaling:on origin:(259,1080) degree:0" | |
fi | |
fi | |
fi | |
echo "done" >> $LOGFILE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment