Skip to content

Instantly share code, notes, and snippets.

@JohnAtl
Created December 29, 2021 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JohnAtl/f372989ebb6239e834f10b7411d5863d to your computer and use it in GitHub Desktop.
Save JohnAtl/f372989ebb6239e834f10b7411d5863d to your computer and use it in GitHub Desktop.
Keyboard Maestro Window Mover macros that account for the menu bar
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>102</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%WindowFrame%Front%</string>
<key>Variable</key>
<string>W1</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>103</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%ScreenVisible%Front%</string>
<key>Variable</key>
<string>S1</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>104</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%ScreenVisible%Back%</string>
<key>Variable</key>
<string>S2</string>
</dict>
<dict>
<key>Action</key>
<string>MoveAndResize</string>
<key>ActionUID</key>
<integer>105</integer>
<key>HeightExpression</key>
<string>W1.height * S2.height / S1.height</string>
<key>HorizontalExpression</key>
<string>(W1.left - S1.left) * S2.width / S1.width + S2.left</string>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ManipulateWindow</string>
<key>TargetApplication</key>
<dict/>
<key>Targeting</key>
<string>FrontWindow</string>
<key>TargetingType</key>
<string>Front</string>
<key>VerticalExpression</key>
<string>(W1.top - S1.top) * S2.height / S1.height + S2.top</string>
<key>WidthExpression</key>
<string>W1.width * S2.width / S1.width</string>
<key>WindowIndexExpression</key>
<string>2</string>
<key>WindowName</key>
<string></string>
</dict>
</array>
<key>CreationDate</key>
<real>623953677.32074797</real>
<key>ModificationDate</key>
<real>662311957.38352394</real>
<key>Name</key>
<string>Other Display</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>31</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>0810F12B-9814-4F98-892B-CC4B5CB17612</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>97</integer>
<key>Asynchronously</key>
<false/>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteMacro</string>
<key>MacroUID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>UseParameter</key>
<false/>
</dict>
<dict>
<key>ActionUID</key>
<integer>98</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
s = `echo $KMVAR_FB_WindowFramesList`
l = s.split(/\s/)
h = Hash[l.map { |e| e = e.split(':') }]
puts h['win_right']</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>99</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>Comment</string>
<key>StyledText</key>
<data>
cnRmZAAAAAADAAAAAgAAAAcAAABU
WFQucnRmAQAAAC6VAwAAKwAAAAEA
AACNAwAAe1xydGYxXGFuc2lcYW5z
aWNwZzEyNTJcY29jb2FydGYyNTgw
Clxjb2NvYXRleHRzY2FsaW5nMFxj
b2NvYXBsYXRmb3JtMHtcZm9udHRi
bFxmMFxmc3dpc3NcZmNoYXJzZXQw
IEhlbHZldGljYTt9CntcY29sb3J0
Ymw7XHJlZDI1NVxncmVlbjI1NVxi
bHVlMjU1O30Ke1wqXGV4cGFuZGVk
Y29sb3J0Ymw7O30KXHBhcmRcdHg1
NjBcdHgxMTIwXHR4MTY4MFx0eDIy
NDBcdHgyODAwXHR4MzM2MFx0eDM5
MjBcdHg0NDgwXHR4NTA0MFx0eDU2
MDBcdHg2MTYwXHR4NjcyMFxwYXJk
aXJuYXR1cmFsXHBhcnRpZ2h0ZW5m
YWN0b3IwCgpcZjBcZnMyNCBcY2Yw
IGJ1dCB5b3UgbWF5IG5vdCBuZWVk
IGl0LiBJIGhhdmUgdHdvIG1vbml0
b3JzLiBUaGUgc2Vjb25kIG1vbml0
b3IgaXMgc21hbGxlciB0aGFuIHRo
ZSBtYWluIG9uZSBhbmQgaXMgcG9z
aXRpb25lZCB0byB0aGUgcmlnaHQu
XApUaGVzZSB0d28gZmFjdHMgbWVh
biB0aGF0IGlmIGEgd2luZG93IGlz
IHRha2luZyB1cCBhIGxvdCBvZiB0
aGUgbWFpbiBzY3JlZW4sIGFuZCBJ
IG1vdmUgaXQgdXNpbmcgJ1dpbmRv
dyBSaWdodCcgb250byB0aGUgc21h
bGxlciwgcmlnaHQtaGFuZCBzY3Jl
ZW4sIGl0IGVuZHMgdXAgYXMgdGhl
IHdyb25nIHNpemUsIHVubGVzcyBp
dCBpcyBzaHJ1bmsgYmVmb3JlIG1v
dmluZy5cClRoZSBwcm9ibGVtIGRv
ZXMgbm90IGV4aXN0IGZvciBtb3Zp
bmcgbGVmdHdhcmRzIG9udG8gYSBz
bWFsbGVyIHNjcmVlbiwgZHVlIHRv
IHRoZSBuYXR1cmUgb2YgdGhlIHdp
bmRvdyBmcmFtZXMuXApUaGUgc2hy
aW5raW5nIHNsb3dzIHRoZSBtYWNy
byBkb3duIGV2ZXItc28tc2xpZ2h0
bHksIGFuZCBpcyB2aXNpYmxlLCBz
byBpZiB5b3UgZG9uJ3QgdXNlIGEg
c2Vjb25kIHNjcmVlbiB5b3UgbWF5
IHdhbnQgdG8gZGVsZXRlIHRoZSBh
Y3Rpb24gaGVyZS59AQAAACMAAAAB
AAAABwAAAFRYVC5ydGYQAAAAk9KT
YbYBAAAAAAAAAAAAAA==
</data>
<key>Title</key>
<string>The resize to 200 x 600 below has a reason…</string>
</dict>
<dict>
<key>Action</key>
<string>ResizeWindowTo</string>
<key>ActionUID</key>
<integer>100</integer>
<key>HeightExpression</key>
<string>300</string>
<key>HorizontalExpression</key>
<string>200</string>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ManipulateWindow</string>
<key>TargetApplication</key>
<dict/>
<key>Targeting</key>
<string>FrontWindow</string>
<key>TargetingType</key>
<string>Front</string>
<key>VerticalExpression</key>
<string>600</string>
<key>WidthExpression</key>
<string>300</string>
<key>WindowIndexExpression</key>
<string>2</string>
<key>WindowName</key>
<string></string>
</dict>
<dict>
<key>Action</key>
<string>SetWindowFrame</string>
<key>ActionUID</key>
<integer>101</integer>
<key>MacroActionType</key>
<string>UseVariable</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483405</real>
<key>ModificationDate</key>
<real>662311817.22346997</real>
<key>Name</key>
<string>Window Right</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>15</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>4513331A-FCAC-473C-840C-98BF763B0D73</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>93</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%FrontWindowFrame%</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>94</integer>
<key>Asynchronously</key>
<false/>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteMacro</string>
<key>MacroUID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>UseParameter</key>
<false/>
</dict>
<dict>
<key>ActionUID</key>
<integer>95</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
s = `echo $KMVAR_FB_WindowFramesList`
l = s.split(/\s/)
h = Hash[l.map { |e| e = e.split(':') }]
puts h['win_max']</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>Action</key>
<string>SetWindowFrame</string>
<key>ActionUID</key>
<integer>96</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>UseVariable</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483297</real>
<key>ModificationDate</key>
<real>662311804.14367795</real>
<key>Name</key>
<string>Window Maximise</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>20</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>DBA64D22-951E-48DB-B93B-403222E3BF65</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>77</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%FrontWindowFrame%</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>78</integer>
<key>Asynchronously</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteMacro</string>
<key>MacroUID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>UseParameter</key>
<false/>
</dict>
<dict>
<key>ActionUID</key>
<integer>79</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
s = `echo $KMVAR_FB_WindowFramesList`
l = s.split(/\s/)
h = Hash[l.map { |e| e = e.split(':') }]
puts h['win_r2']</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>Action</key>
<string>ResizeWindowTo</string>
<key>ActionUID</key>
<integer>80</integer>
<key>HeightExpression</key>
<string>300</string>
<key>HorizontalExpression</key>
<string>200</string>
<key>MacroActionType</key>
<string>ManipulateWindow</string>
<key>TargetApplication</key>
<dict/>
<key>Targeting</key>
<string>FrontWindow</string>
<key>TargetingType</key>
<string>Front</string>
<key>VerticalExpression</key>
<string>600</string>
<key>WidthExpression</key>
<string>300</string>
<key>WindowIndexExpression</key>
<string>2</string>
<key>WindowName</key>
<string></string>
</dict>
<dict>
<key>Action</key>
<string>SetWindowFrame</string>
<key>ActionUID</key>
<integer>81</integer>
<key>MacroActionType</key>
<string>UseVariable</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483202</real>
<key>ModificationDate</key>
<real>662315039.39794099</real>
<key>Name</key>
<string>Right 33%</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>29</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>7DC65E3C-A319-40EF-AD4E-39DF2B670B5C</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>90</integer>
<key>Asynchronously</key>
<false/>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteMacro</string>
<key>MacroUID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>UseParameter</key>
<false/>
</dict>
<dict>
<key>ActionUID</key>
<integer>91</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
s = `echo $KMVAR_FB_WindowFramesList`
l = s.split(/\s/)
h = Hash[l.map { |e| e = e.split(':') }]
puts h['win_left']</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>Action</key>
<string>SetWindowFrame</string>
<key>ActionUID</key>
<integer>92</integer>
<key>MacroActionType</key>
<string>UseVariable</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483202</real>
<key>ModificationDate</key>
<real>662311833.87092197</real>
<key>Name</key>
<string>Window Left</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>37</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>4BC7FF77-5605-4573-9EB8-C47006B8C252</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>73</integer>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%FrontWindowFrame%</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>74</integer>
<key>Asynchronously</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteMacro</string>
<key>MacroUID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>UseParameter</key>
<false/>
</dict>
<dict>
<key>ActionUID</key>
<integer>75</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
s = `echo $KMVAR_FB_WindowFramesList`
l = s.split(/\s/)
h = Hash[l.map { |e| e = e.split(':') }]
puts h['win_l1']</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>Action</key>
<string>SetWindowFrame</string>
<key>ActionUID</key>
<integer>76</integer>
<key>MacroActionType</key>
<string>UseVariable</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483405</real>
<key>ModificationDate</key>
<real>662315108.18633103</real>
<key>Name</key>
<string>Left 66%</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>19</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>380BF34A-4CFC-4370-B53D-A4170BB0A213</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>87</integer>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%Screen%1%</string>
<key>Variable</key>
<string>FB_Monitor0Frame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>56048</integer>
<key>Delete</key>
<true/>
<key>Destination</key>
<string>Variable</string>
<key>DestinationVariable</key>
<string>FB_Monitor0WH</string>
<key>First</key>
<string>1</string>
<key>MacroActionType</key>
<string>Substring</string>
<key>Second</key>
<string>4</string>
<key>Source</key>
<string>Variable</string>
<key>StringRangeType</key>
<string>Range</string>
<key>Variable</key>
<string>FB_Monitor0Frame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>56049</integer>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>0,24,%Variable%FB_Monitor0WH%</string>
<key>Variable</key>
<string>FB_Monitor0Frame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>88</integer>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%Screen%2%</string>
<key>Variable</key>
<string>FB_Monitor1Frame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>56050</integer>
<key>Delete</key>
<true/>
<key>Destination</key>
<string>Variable</string>
<key>DestinationVariable</key>
<string>FB_Monitor1WH</string>
<key>First</key>
<string>1</string>
<key>MacroActionType</key>
<string>Substring</string>
<key>Second</key>
<string>8</string>
<key>Source</key>
<string>Variable</string>
<key>StringRangeType</key>
<string>Range</string>
<key>Variable</key>
<string>FB_Monitor1Frame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>56052</integer>
<key>Delete</key>
<false/>
<key>Destination</key>
<string>Variable</string>
<key>DestinationVariable</key>
<string>FB_Monitor1X</string>
<key>First</key>
<string>1</string>
<key>MacroActionType</key>
<string>Substring</string>
<key>Second</key>
<string>4</string>
<key>Source</key>
<string>Variable</string>
<key>StringRangeType</key>
<string>Range</string>
<key>Variable</key>
<string>FB_Monitor1Frame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>56051</integer>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%Variable%FB_Monitor1X%,24,%Variable%FB_Monitor1WH%</string>
<key>Variable</key>
<string>FB_Monitor1Frame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>89</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
require 'rational'
def main
window_mover = WindowMover.new
puts window_mover.setup_frame_list
end
class WindowMover
# A class to control the front window of the front application. The window and monitor details are fetched through Keyboard Maestro.
def initialize
# Set up the properties holding the monitor and current frame information.
$keys = ["x", "y", "w", "h"]
@monitor0_frame = get_kbm_var( "FB_Monitor0Frame" )
@monitor1_frame = get_kbm_var( "FB_Monitor1Frame" )
@current_frame = get_kbm_var( "FB_FrontWindowFrame" )
@monitor0_halves = get_halves( @monitor0_frame )
if @monitor1_frame
@monitor1_halves = get_halves( @monitor1_frame )
if @monitor1_frame["x"] &lt; @monitor0_frame["x"]
@monitor1_side = :left
else
@monitor1_side = :right
end
@current_frame_loc = check_loc()
else
@current_frame_loc = 0
end
@current_monitor = [@monitor0_frame, @monitor1_frame][@current_frame_loc]
end
def setup_frame_list
# This makes a list of string values, one for each potential new frame value.
# The idea is that this whole script is held in one macro in Keyboard Maestro,
# and is called by every Window Mover macro. This list below is stored in a
# KBM variable, then the individual macros parse what they want from that variable.
['win_left:' + move_left,
'win_right:' + move_right,
'win_up:' + split_up,
'win_down:' + split_down,
'win_l1:' + get_thirds(:l1),
'win_l2:' + get_thirds(:l2),
'win_r1:' + get_thirds(:r1),
'win_r2:' + get_thirds(:r2),
'win_max:' + make_string( @current_monitor )]
end
def split_up
new_frame = @current_frame.dup
new_frame['h'] /= 2
make_string(new_frame)
end
def split_down
new_frame = @current_frame.dup
new_frame['h'] /= 2
new_frame['y'] += new_frame['h']
make_string(new_frame)
end
def make_string( hash )
# Takes a hash and joins the necessary parts into a string to return a frame.
# eg. make_string( {"x" =&gt; 0, "y" =&gt; 0, "w" =&gt; 200, "h" =&gt; 300, "m" =&gt; 100} ) # =&gt; "0,0,200,300"
arr = []
arr &lt;&lt; hash["x"]
arr &lt;&lt; hash["y"]
arr &lt;&lt; hash["w"]
arr &lt;&lt; hash["h"]
arr.join(",")
end
def get_halves( monitor )
# Takes a monitor of a monitor's frame and calculates and sets up
# some new monitors that hold dimensions for frames that take up
# half of the monitor - left and right, split vertically.
# These are supplied to Keyboard Maestro later as comma-separated
# strings.
# Duplicate the received monitor twice, for left and right.
left = monitor.dup
right = monitor.dup
left = add_midpoint( left )
right = add_midpoint( right )
left_of_monitor1 = ( monitor["x"] &lt; 0 )
if left_of_monitor1
######### left half ##########
left["w"] = (left["x"] / 2).abs
midpoint = left["x"] + (left["w"] / 2)
left["m"] = midpoint
######### right half #########
right["x"] = right["x"] / 2
right["w"] = left["w"]
right = add_midpoint( right )
left_of_monitor1
else
# this means it is not left_of_monitor1
######### left half #########
if monitor["x"] == 0
left["w"] = (left["w"] / 2).abs
else
left["w"] = (left["w"] / 2)
end
midpoint = left["x"] + (left["w"] / 2)
left["m"] = midpoint
######### right half #########
right["w"] = left["w"]
if monitor["x"] == 0
right["x"] = left["w"]
midpoint = right["x"] + (right["w"] / 2)
right["m"] = midpoint
else
right["x"] = right["w"] + right["x"]
midpoint = right["x"] + (right["w"] / 2)
right["m"] = midpoint
end
end
# Return a hash of the two hashes.
{"right" =&gt; right, "left" =&gt; left}
end
def get_thirds( type_of_third )
# Returns a frame string for Keyboard Maestro depending on the type_of_third specified.
# type_of_third can be:
# :l1 =&gt; left %66
# :l2 =&gt; left %33
# :r1 =&gt; right %66
# :r2 =&gt; right %33
result = Hash.new
@current_monitor
l1_width = (@current_monitor['w'] * 0.666666666666666).to_i
l2_width = (@current_monitor['w'] - l1_width)
r1_width = (@current_monitor['w'] * 0.666666666666666).to_i
r2_width = (@current_monitor['w'] - r1_width)
r1_x = @current_monitor['x'] + (r2_width)
r2_x = @current_monitor['x'] + (r1_width)
l1 = @current_monitor.dup
l1['w'] =l1_width
l2 = @current_monitor.dup
l2['w'] = l2_width
r1 = @current_monitor.dup
r1['w'] =r1_width
r1['x'] = r1_x
r2 = @current_monitor.dup
r2['w'] = r2_width
r2['x'] = r2_x
result[:l1] = l1
result[:l2] = l2
result[:r1] = r1
result[:r2] = r2
make_string(result[type_of_third])
end
def check_loc
# This checks which monitor the current window is on.
# If there is only one window, @monitor1_side is nil.
if @monitor1_side == :left
if add_midpoint(@current_frame)["m"] &lt; @monitor0_frame["x"]
1 # Second monitor
else
0 # First monitor
end
else # Either :right or nil.
if add_midpoint(@current_frame)["m"] &gt; @monitor0_frame["w"]
1 # Second monitor
else
0 # First monitor
end
end
end
def move_left
make_string( move_window( false ) )
end
def move_right
make_string( move_window( true ) )
end
def move_window( go_right )
# The go_right variable is true or false, false meaning go_left.
if @current_frame_loc == 0 # First monitor
temp = @monitor0_halves[ (go_right ? "right" : "left") ].dup
temp["y"] = 22 # temp accounts for the 22 pixels in the menu bar.
temp["h"] = temp["h"] - 26 # Not sure why the height is 4px less than the y position.
#p @current_frame.sort
#p @monitor0_halves[ (go_right ? "right" : "left") ].sort
if @current_frame.sort == @monitor0_halves[ (go_right ? "right" : "left") ].sort ||
@current_frame.sort == temp.sort
if @monitor1_frame # Second monitor exists.
return @monitor1_halves[ (go_right ? "left" : "right") ]
else # Just 1 monitor
return @monitor0_halves[ (go_right ? "left" : "right") ]
end
else
return @monitor0_halves[ (go_right ? "right" : "left") ]
end
else # Second monitor
if @current_frame.sort == @monitor1_halves[ (go_right ? "right" : "left") ].sort
return @monitor0_halves[ (go_right ? "left" : "right") ]
else
return @monitor1_halves[ (go_right ? "right" : "left") ]
end
end
end
def get_kbm_var( var_name )
# Return the string held by Keyboard Maestro in the variable var_name.
var = `osascript -e 'tell application "Keyboard Maestro Engine"
set val to value of (make variable with properties {name:"#{var_name}"})
val
end tell'`.split(",")
var = var.map { |e| e.to_i }
if var.inject { |sum, n| sum + n } == 0
# This means that KBM has returned "0,0,0,0", which means that Second monitor does not exit.
false
else
var = Hash[*$keys.zip(var).flatten] # Makes a hash of the array.
var
end
end
def add_midpoint( frame )
# This accepts a hash of a frame and adds a new key, value
# pair to hold the frame's horizontal midpoint.
if frame["x"] &lt; 0
midpoint = frame["x"] + (frame["w"] / 2).abs
else
midpoint = (frame["w"] / 2) + frame["x"]
end
frame["m"] = midpoint
frame
end
end
main()</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_WindowFramesList</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483405</real>
<key>ModificationDate</key>
<real>662480465.29812801</real>
<key>Name</key>
<string>Setup Frames</string>
<key>Triggers</key>
<array/>
<key>UID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>82</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%FrontWindowFrame%</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>83</integer>
<key>Asynchronously</key>
<false/>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteMacro</string>
<key>MacroUID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>UseParameter</key>
<false/>
</dict>
<dict>
<key>ActionUID</key>
<integer>84</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
s = `echo $KMVAR_FB_WindowFramesList`
l = s.split(/\s/)
h = Hash[l.map { |e| e = e.split(':') }]
puts h['win_r1']</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>Action</key>
<string>ResizeWindowTo</string>
<key>ActionUID</key>
<integer>85</integer>
<key>HeightExpression</key>
<string>300</string>
<key>HorizontalExpression</key>
<string>200</string>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>ManipulateWindow</string>
<key>TargetApplication</key>
<dict/>
<key>Targeting</key>
<string>FrontWindow</string>
<key>TargetingType</key>
<string>Front</string>
<key>VerticalExpression</key>
<string>600</string>
<key>WidthExpression</key>
<string>300</string>
<key>WindowIndexExpression</key>
<string>2</string>
<key>WindowName</key>
<string></string>
</dict>
<dict>
<key>Action</key>
<string>SetWindowFrame</string>
<key>ActionUID</key>
<integer>86</integer>
<key>IsDisclosed</key>
<false/>
<key>MacroActionType</key>
<string>UseVariable</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483202</real>
<key>ModificationDate</key>
<real>662311827.09484196</real>
<key>Name</key>
<string>Right 66%</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>25</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>83C75ABA-B9F6-423C-B3EE-FC91A623EDBA</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
<dict>
<key>Activate</key>
<string>OnceAfterTrigger</string>
<key>AddToMacroPalette</key>
<false/>
<key>AddToStatusMenu</key>
<false/>
<key>CreationDate</key>
<real>620338378.17791295</real>
<key>DisplayToggle</key>
<false/>
<key>KeyCode</key>
<integer>32767</integer>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>ActionUID</key>
<integer>69</integer>
<key>MacroActionType</key>
<string>SetVariableToText</string>
<key>Text</key>
<string>%FrontWindowFrame%</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>ActionUID</key>
<integer>70</integer>
<key>Asynchronously</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteMacro</string>
<key>MacroUID</key>
<string>1F442C17-C707-4550-8B8A-88DC2C375946</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>UseParameter</key>
<false/>
</dict>
<dict>
<key>ActionUID</key>
<integer>71</integer>
<key>DisplayKind</key>
<string>Variable</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<false/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>NotifyOnFailure</key>
<false/>
<key>Path</key>
<string></string>
<key>Source</key>
<string>Nothing</string>
<key>StopOnFailure</key>
<false/>
<key>Text</key>
<string>#!/usr/bin/env ruby
s = `echo $KMVAR_FB_WindowFramesList`
l = s.split(/\s/)
h = Hash[l.map { |e| e = e.split(':') }]
puts h['win_l2']</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
<dict>
<key>Action</key>
<string>SetWindowFrame</string>
<key>ActionUID</key>
<integer>72</integer>
<key>MacroActionType</key>
<string>UseVariable</string>
<key>Variable</key>
<string>FB_FrontWindowFrame</string>
</dict>
</array>
<key>CreationDate</key>
<real>620338684.51483297</real>
<key>ModificationDate</key>
<real>662315074.80794704</real>
<key>Name</key>
<string>Left 33%</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>18</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>0</integer>
</dict>
</array>
<key>UID</key>
<string>B17E5615-8783-470B-AA32-EAE75D345407</string>
</dict>
</array>
<key>Modifiers</key>
<integer>0</integer>
<key>Name</key>
<string>- 4 Window</string>
<key>PaletteUnderMouse</key>
<true/>
<key>ToggleMacroUID</key>
<string>67E24014-96C9-4D40-8378-310E3C1455DD</string>
<key>UID</key>
<string>61D3F3A3-4481-4C42-9B67-ABC89CB81DEF</string>
</dict>
</array>
</plist>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment