🔥 Advanced Feature

Controller button combos in Running Scripts use The Vault's Universal Button Mapping system, supporting 70+ button aliases across PlayStation, Xbox, and Nintendo controllers.

Controller Button Combos

Running Scripts can be triggered by controller button combinations, giving you complete control over in-game actions without touching the keyboard.

Syntax

Controller combos use the controller+ prefix followed by button names:

::controller+button1+button2 {
    your code here
}

Universal Button Mapping

The Vault's Universal Button Mapping system translates button names across different controller types. This means you can write scripts using friendly names that work with any controller:

PlayStation (DualSense / DualShock)

::controller+share+options {
    -- Uses PlayStation naming
    do shell script "kill -INT {{{PID}}}"
}

Xbox

::controller+view+menu {
    -- Same script, Xbox naming
    do shell script "kill -INT {{{PID}}}"
}

Nintendo Switch Pro

::controller+minus+plus {
    -- Same script, Nintendo naming
    do shell script "kill -INT {{{PID}}}"
}

All three examples above are equivalent! The Universal Button Mapping system normalizes button names, so share = view = minus = select = create.

Common Button Aliases

A few of the most common aliases are shown below. The modifier (the held Select-style button) is create on a DualSense and capture on an NSO GameCube pad:

Button TypePlayStationXboxNintendoGeneric
Face Buttonscross/✕, circle/○, square/□, triangle/△a, b, x, ya, b, x, ybutton1-4
Shouldersl1, r1lb, rbl, r-
Modifier (Center Left)share, createviewminus, captureselect
Center Rightoptionsmenuplusstart

See Appendix C: Controller Reference for the complete Universal Button Mapping reference (70+ aliases across every vendor).

Real-World Examples

Example 1: Graceful Exit (ARMSX2)

Hold Share/Create (PlayStation) or View (Xbox) or Minus (Nintendo), then press Options (PlayStation) or Menu (Xbox) or Plus (Nintendo) to gracefully exit ARMSX2:

::controller+share+options {
    -- Try graceful termination first
    do shell script "kill -INT {{{PID}}}"
    delay 2
    
    -- Force kill if still running
    do shell script "kill -9 {{{PID}}} 2>/dev/null || true"
}
running-script-example-controller.png - Code example: controller combo script (1440x900)

Example 2: Quick Screenshot

Hold L1 (PlayStation) or LB (Xbox) or L (Nintendo), then press Triangle (PlayStation) or Y (Xbox) or X (Nintendo) to take a screenshot:

::controller+l1+triangle {
    do shell script "screencapture ~/Desktop/{{{GAME}}}_screenshot.png"
    display notification "Screenshot saved!" with title "{{{GAME}}}"
}

Example 3: Multiple Triggers

You can define multiple controller combos in one script:

::controller+share+options {
    -- Exit emulator
    do shell script "kill -INT {{{PID}}}"
    delay 2
    do shell script "kill -9 {{{PID}}} 2>/dev/null || true"
}

::controller+l1+triangle {
    -- Screenshot
    do shell script "screencapture ~/Desktop/{{{GAME}}}_screenshot.png"
}

::controller+r1+circle {
    -- Quick save
    tell application "System Events"
        keystroke "f1" using command down
    end tell
}

How It Works (Priority 1 System)

Controller combos in Running Scripts use Priority 1 execution, which means they are checked before controller profile hotkeys (Priority 2). This ensures your custom scripts always take precedence over default hotkey mappings.

Execution Flow

  1. User presses buttons: Share + Options (or View + Menu, or Minus + Plus)
  2. UnifiedControllerService detects input: Normalizes button names using Universal Button Mapping
  3. Priority 1 check: GlobalHotkeyService checks for matching Running Script
  4. Match found: Execute script, stop propagation (Priority 2 not checked)
  5. No match: Continue to Priority 2 (controller profile hotkeys)

Debugging Controller Combos

If your controller combo isn't working:

  1. Check permissions: Ensure Input Monitoring is enabled (System Settings → Privacy & Security)
  2. Test with dialog: Replace your script code with a simple message box to verify detection
    ::controller+share+options {
        display dialog "Combo detected!" buttons {"OK"}
    }
  3. Check console output: Look for "✅ [Priority 1] Found controller running script" in logs
  4. Try different aliases: Use select+start instead of share+options
  5. Verify button names: See Controller Reference for all supported aliases

Best Practices

  • Use friendly names: share+options is clearer than create+buttonmenu
  • Test incrementally: Start with dialog boxes before implementing kill scripts
  • Document your combos: Add comments explaining what each combo does
  • Avoid conflicts: Don't overlap with critical emulator hotkeys (save states, etc.)
  • Graceful > Force: Always try kill -INT before kill -9

💡 Pro Tip

Controller combos work across all emulators that use the same Running Script. Define your combos once in a shared script, then reference it from multiple emulator configurations.