Created
October 28, 2025 16:01
-
-
Save rbreaves/4fb528638e29511e980cafe56f59c1d7 to your computer and use it in GitHub Desktop.
Reset Workflow for 3 monitors - macOS
This file contains hidden or 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
| // pre-reqs - homebrew, displayplacer | |
| // brew install displayplacer | |
| // | |
| // How To Run | |
| // osascript -l JavaScript ~/move_to_three_monitors.jxa | |
| ObjC.import('stdlib') | |
| const se = Application('System Events') | |
| const app = Application.currentApplication() | |
| app.includeStandardAdditions = true | |
| // --- read displayplacer output --- | |
| function getDisplayplacerOrigins() { | |
| const output = app.doShellScript("displayplacer list | grep 'origin'") | |
| // Correct regex: origin:(x,y) | |
| const matches = [...output.matchAll(/origin:\(([-\d]+),([-\d]+)\)/g)] | |
| return matches.map(m => ({ x: parseInt(m[1]), y: parseInt(m[2]) })) | |
| } | |
| // --- classify monitors dynamically --- | |
| function classifyDisplays(coords) { | |
| let left = coords[0], right = coords[0], main = coords[0] | |
| coords.forEach(c => { | |
| if (c.x < left.x) left = c | |
| if (c.x > right.x) right = c | |
| if (c.x === 0 && c.y === 0) main = c | |
| }) | |
| return { left, right, main } | |
| } | |
| const coords = getDisplayplacerOrigins() | |
| if (coords.length === 0) { | |
| console.log("⚠️ Could not parse displayplacer output.") | |
| $.exit(1) | |
| } | |
| const { left, right, main } = classifyDisplays(coords) | |
| // --- log what we detected --- | |
| console.log(`Left: (${left.x},${left.y}) | Main: (${main.x},${main.y}) | Right: (${right.x},${right.y})`) | |
| // --- helpers --- | |
| function moveApp(names, dest, label) { | |
| names.forEach(n => { | |
| try { | |
| const proc = se.processes.byName(n) | |
| proc.windows().forEach(w => { | |
| try { w.position = [dest.x, dest.y]; console.log(`Moved ${n} to the ${label}`); } catch (e) {} | |
| }) | |
| } catch (e) {} | |
| }) | |
| } | |
| function moveByExactTitle(titleExact, dest, label) { | |
| se.processes().forEach(proc => { | |
| try { | |
| proc.windows().forEach(w => { | |
| const title = w.name() | |
| if (title === titleExact) { | |
| try { w.position = [dest.x, dest.y]; console.log(`Moved ${n} to the ${label}`); } catch (e) {} | |
| } | |
| }) | |
| } catch (e) {} | |
| }) | |
| } | |
| // --- Move Vivaldi Snapshot --- | |
| moveApp(['Vivaldi Snapshot'], right, "right") | |
| // moveByExactTitle('Vivaldi Snapshot', right, "right") | |
| // --- Move Microsoft Teams --- | |
| moveApp(['Microsoft Teams'], left, "left") | |
| // moveByExactTitle('Microsoft Teams', left, "left") | |
| // --- Everything else -> main monitor --- | |
| se.processes().forEach(proc => { | |
| const name = proc.name().toLowerCase() | |
| // console.log(name); | |
| // Skip known app families | |
| const isVivaldi = | |
| name === "vivaldi snapshot" | |
| const isTeams = | |
| name.startsWith("microsoft teams") || name === "msteams" | |
| if (!isVivaldi && !isTeams) { | |
| try { | |
| proc.windows().forEach(w => { w.position = [main.x, main.y] }) | |
| } catch (e) {} | |
| } | |
| }) | |
| console.log(`Moved everything else to the center.`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment