Created
December 21, 2025 11:20
-
-
Save Strajk/e2dc780c6fc94c4bae539f39eee87146 to your computer and use it in GitHub Desktop.
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
| #!/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