Skip to content

Instantly share code, notes, and snippets.

@Strajk
Created December 21, 2025 11:20
Show Gist options
  • Select an option

  • Save Strajk/e2dc780c6fc94c4bae539f39eee87146 to your computer and use it in GitHub Desktop.

Select an option

Save Strajk/e2dc780c6fc94c4bae539f39eee87146 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""
Moom Configuration Generator
This script programmatically generates Moom window management shortcuts.
It creates a grid-based system for positioning windows across multiple displays.
SCREEN LAYOUT:
==============
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”β”β”β”β”β”β”β”β”β”β”“
β”‚ │┃ ┃
β”‚ TOP DISPLAY │┃ ┃
β”‚ │┃ R ┃
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”ƒ I ┃
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” ┃ G ┃
β”‚ β”‚ ┃ H ┃
β”‚ MACBOOK β”‚ ┃ T ┃
β”‚ β”‚ ┃ ┃
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ┗━━━━━━━━━┛
Navigation:
- TOP: Move Left (9), then Up (3)
- BOTTOM: Move Left (9), then Down (7)
- RIGHT: Move Right (5)
IMPORTANT: MOOM HOT KEY BEHAVIOR
=================================
From Moom documentation:
"There are two distinct types of hot keys: Global, which work in any application,
and restricted, which only work when Moom's Keyboard overlay is active.
If you assign a multi-key shortcut (with modifiers), those are GLOBAL shortcuts.
If you assign a single-key shortcut (no modifiers), those are RESTRICTED shortcuts."
This means we CANNOT use modifier keys (Alt, Cmd) to create display-specific shortcuts
that only work within Moom's overlay. Any shortcut with modifiers becomes global and
would trigger everywhere in macOS, which is not desirable.
SOLUTION: We generate single-key shortcuts (no modifiers) that only work when Moom's
keyboard overlay is active. These layouts resize windows on the CURRENT screen without
moving between displays.
KEY LEARNINGS ABOUT MOOM:
========================
1. Move Direction Codes (for "Move to Other Display" action):
- Left = 9
- Up = 3
- Right = 5
- Down = 7
Note: These are NOT the obvious 0-3 or 1-4 patterns! Testing revealed:
- Up, Right, Down follow an odd number pattern (3, 5, 7)
- Left = 9 (discovered through trial and error)
2. Deterministic Navigation:
When moving to top/bottom displays, we must first move LEFT to ensure
we're in the correct display column. This handles the case where the
window might be on the right display, making direct up/down navigation
fail due to relative positioning.
3. Action Codes:
- Action 10001 = Chain (run multiple actions in sequence)
- Action 41 = Move to Display
- Action 19 = Resize
4. Modifier Flags (for keyboard shortcuts):
- 256 = Ctrl+Shift (base)
- 524544 = Ctrl+Shift+Alt (256 + 524288)
- 1048832 = Ctrl+Shift+Cmd (256 + 1048576)
BUT: Due to Moom's global vs restricted shortcut behavior, we use 0 (no modifiers)
for single-key restricted shortcuts.mo
5. Grid System:
Uses a 6Γ—4 grid where relative frames are specified as:
{{x, y}, {width, height}} with values 0.0-1.0 representing percentages
"""
import plistlib
import uuid
import subprocess
import time
# =============================================================================
# CONFIGURATION
# =============================================================================
# Set to True to enable multi-display shortcuts with modifiers
# WARNING: Currently, Moom treats shortcuts with modifiers as GLOBAL (work everywhere),
# not restricted (overlay-only). This means they'll trigger outside of Moom.
# Keep as False until Moom officially supports restricted shortcuts with modifiers.
ENABLE_MULTI_DISPLAY = False
# =============================================================================
src = {
1: ['1', '2', '3', '4', '5', '6'],
2: ['q', 'w', 'e', 'r', 't'],
3: ['a', 's', 'd', 'f'],
4: ['z', 'x', 'c']
}
# Multi-display configuration (used when ENABLE_MULTI_DISPLAY = False)
displays = {
'bottom': {
'directions': [9, 7], # First Left, then Down
'modifier_flags': 256, # Base (Ctrl+Shift)
'label': 'Bottom'
},
'top': {
'directions': [9, 3], # First Left, then Up
'modifier_flags': 524544, # Ctrl+Shift+Alt (256 + 524288)
'label': 'Top'
},
'right': {
'directions': [5], # Right
'modifier_flags': 1048832, # Ctrl+Shift+Cmd (256 + 1048576)
'label': 'Right'
}
}
# TODO: Use some lib for this madness
macos_key_codes = {
'a': 0,
'b': 11,
'c': 8,
'd': 2,
'e': 14,
'f': 3,
'g': 5,
'h': 4,
'i': 34,
'j': 38,
'k': 40,
'l': 37,
'm': 46,
'n': 45,
'o': 31,
'p': 35,
'q': 12,
'r': 15,
's': 1,
't': 17,
'u': 32,
'v': 9,
'w': 13,
'x': 7,
'y': 16,
'z': 6,
'1': 18,
'2': 19,
'3': 20,
'4': 21,
'5': 23,
'6': 22,
'7': 26,
'8': 28,
'9': 25,
'0': 29,
'-': 27,
'=': 24,
'[': 33,
']': 30, # top half
'\\': 42, # bottom half
';': 41,
"'": 39,
',': 43,
'.': 47,
'/': 44,
'`': 50,
}
def generate_hot_key(key_code, modifier_flags=0):
"""Generate a hot key configuration.
modifier_flags=0 creates a RESTRICTED shortcut (only works in Moom overlay)
modifier_flags with values creates a GLOBAL shortcut (works everywhere)
"""
return {
'Visual Representation': key_code,
'Identifier': (str(uuid.uuid4()).upper()),
'Key Code': macos_key_codes[key_code],
'Modifier Flags': modifier_flags
}
def generate_relative_frame(cols, cols_from_left, rows, rows_from_top):
cols_total = 6
rows_total = 4
x = cols_from_left / cols_total
y = rows_from_top / rows_total
width = cols / cols_total
height = rows / rows_total
# Return in the format {{x, y}, {width, height}} for Moom
return f'{{{x}, {y}}}, {{{width}, {height}}}'
# Quit Moom before modifying preferences
print("πŸ›‘ Quitting Moom...")
try:
subprocess.run(['killall', 'Moom'], check=False, capture_output=True)
time.sleep(1)
except Exception as e:
print(f"Note: Could not quit Moom ({e})")
plist_custom_controls = []
if ENABLE_MULTI_DISPLAY:
# Generate multi-display shortcuts with modifiers
print('\n--- Generating multi-display shortcuts (with modifiers) ---')
print('⚠️ WARNING: These will be GLOBAL shortcuts unless Moom adds support for restricted shortcuts with modifiers')
for display_name, display_config in displays.items():
print(f'\n--- {display_config["label"]} display ---')
for cols, keys_list in src.items():
for idx, key in enumerate(keys_list):
hot_key = generate_hot_key(key, display_config['modifier_flags'])
relative_frame = generate_relative_frame(cols, idx, 4, 0)
print(f'Key "{key}": {display_config["label"]} display, {cols} cols width, {idx} cols from left')
title = f'{display_config["label"]} ↔{cols} ↦{idx}'
# Build the children array with move actions
children = []
# Add move actions for each direction
for direction in display_config['directions']:
children.append({
'Identifier': str(uuid.uuid4()).upper(),
'Loop Through Displays': False,
'Action': 41, # Move to Display
'Move Direction': direction,
'Resize Proportionally': False
})
# Add resize action
children.append({
'Identifier': str(uuid.uuid4()).upper(),
'Action': 19, # Resize
'Relative Frame': relative_frame,
'Configuration Grid': {
'Configuration Grid: Rows': 4,
'Configuration Grid: Columns': 6
}
})
item = {
'Action': 10001, # Chain action
'Chain Mode': 0, # Run all
'Chain': True,
'Title': title,
'Children': children,
'Hot Key': hot_key,
'Identifier': hot_key['Identifier']
}
plist_custom_controls.append(item)
else:
# Generate single-key shortcuts for current screen (restricted mode)
print('\n--- Generating single-key shortcuts for current screen (restricted mode) ---')
for cols, keys_list in src.items():
for idx, key in enumerate(keys_list):
hot_key = generate_hot_key(key, modifier_flags=0) # No modifiers = restricted shortcut
relative_frame = generate_relative_frame(cols, idx, 4, 0)
print(f'Key "{key}": Current screen, {cols} cols width, {idx} cols from left')
# Title like "↔3 ↦2" means 3 cols width, 2 cols from left
title = f'↔{cols} ↦{idx}'
# Simple resize action - no display movement
item = {
'Action': 19, # Resize (not a chain, just resize current screen)
'Title': title,
'Relative Frame': relative_frame,
'Configuration Grid': {
'Configuration Grid: Rows': 4,
'Configuration Grid: Columns': 6
},
'Hot Key': hot_key,
'Identifier': hot_key['Identifier']
}
plist_custom_controls.append(item)
# Add top half and bottom half presets (no display movement)
print('\n--- Adding screen half presets ---')
# Top half - key ']'
print('Key "]": Top half of current screen')
top_half = {
'Action': 10001,
'Chain': True,
'Chain Mode': 0,
'Children': [
{
'Action': 19,
'Configuration Grid': {
'Configuration Grid: Columns': 6,
'Configuration Grid: Rows': 4
},
'Identifier': str(uuid.uuid4()).upper(),
'Relative Frame': '{{0, 0.5}, {1, 0.5}}'
}
],
'Children Expanded': True,
'Hot Key': generate_hot_key(']'),
'Identifier': generate_hot_key(']')['Identifier'],
'Title': 'top half'
}
plist_custom_controls.append(top_half)
# Bottom half - key '\'
print('Key "\\": Bottom half of current screen')
bottom_half = {
'Action': 10001,
'Chain': True,
'Chain Mode': 0,
'Children': [
{
'Action': 19,
'Configuration Grid': {
'Configuration Grid: Columns': 6,
'Configuration Grid: Rows': 4
},
'Identifier': str(uuid.uuid4()).upper(),
'Relative Frame': '{{0, 0}, {1, 0.5}}'
}
],
'Children Expanded': True,
'Hot Key': generate_hot_key('\\'),
'Identifier': generate_hot_key('\\')['Identifier'],
'Title': 'bottom half'
}
plist_custom_controls.append(bottom_half)
print("\nπŸ”¨ Generating Moom configuration...")
with open('orig.plist', 'rb') as f:
config = plistlib.load(f)
config['Custom Controls (4001)'] = plist_custom_controls
# Write to version-controlled file
with open('modified.plist', 'wb') as f:
plistlib.dump(config, f, fmt=plistlib.FMT_BINARY)
# Write to system preferences location, just symlinking does not work
import os
with open(os.path.expanduser('~/Library/Preferences/com.manytricks.Moom.plist'), 'wb') as f:
plistlib.dump(config, f, fmt=plistlib.FMT_BINARY)
print("βœ… Configuration written to both locations!")
# Restart Moom
print("\nπŸš€ Restarting Moom...")
try:
subprocess.Popen(['open', '-a', 'Moom'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print("βœ… Done! Moom has been restarted with the new configuration.")
except Exception as e:
print(f"⚠️ Could not restart Moom automatically: {e}")
print(" Please restart Moom manually.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment