![]() |
![]() |
![]() |
A controller button overlay plugin for LaunchBox and Big Box. Instead of a static image per game, it generates the pause-screen overlay dynamically from configuration - picking the right button art and labels automatically per platform, controller variant, and game.
- LaunchBox / Big Box 13.3 or newer on Windows, with the pause-screen feature enabled. 13.3 is the release where LaunchBox moved to .NET 6, which the plugin targets - it cannot load on anything older.
- Download
launchbox-dynamic-controls-ALL-<version>.zipfrom the Releases page. - Extract it into your LaunchBox folder (wherever
LaunchBox.exelives). - In LaunchBox / Big Box's pause-screen settings, set the pause theme to Dynamic Controls.
- Restart LaunchBox / Big Box.
Updating? Re-extract over your existing install. Your customizations live under
Data\Dynamic Controls\User\, and no release zip contains a single file you authored - only the shippedDefaults\andTemplates\folders are overwritten. (The zips do refresh theREADME.txtguides inside theUser\subfolders, so don't keep notes of your own in those files.)
Individual component zips (plugin, assets, pause theme) are also on the Releases page if you need to update one piece at a time.
All data lives under …\LaunchBox\Data\Dynamic Controls\, split into two layers:
Defaults\- shipped files, replaced wholesale on every update.User\- your files, never touched by updates.
Editing Defaults\ is encouraged, with one proviso: contribute the change back. If a button is mapped to the wrong slot, a platform is missing, or a game has no labels, fix it in Defaults\ - the file you test is then byte-identical to the file you submit. Then open a pull request with it. Once merged it ships in the next release, so the update that would have overwritten your edit now delivers it - to you and to everyone else - and you stop having to maintain it. An edit that only ever lives on your machine is one you lose on the next update. (If you do test from User\, delete that copy once your fix ships - otherwise it keeps shadowing the shipped file and later corrections never reach you.)
Keep changes that are specific to your own setup in User\ - your emulator's button assignments, a personal label preference, a per-game remap nobody else wants. Place a copy of the shipped file at the same relative path under User\ and it takes precedence automatically, permanently. Neither layer is quicker to work in - the only question is whether the change would help anyone but you. Two files are merged rather than replaced, because each one holds many independent settings:
GlobalConfig.xml- rather than copying the whole file, include only the settings you want to change; the rest keep their defaults.Labels\{Platform}.xml- your entries are merged over the shipped ones game by game, so labelling one game doesn't cost you the shipped labels for every other game on that platform.
Create User\GlobalConfig.xml to change global settings:
<Config>
<DefaultTemplate>Xbox Series X</DefaultTemplate>
<Debug>false</Debug>
<EnableMame>true</EnableMame>
<EnableRetroArch>true</EnableRetroArch>
</Config>| Setting | Default | Meaning |
|---|---|---|
DefaultTemplate |
Xbox Series X |
Controller artwork to draw - a folder name under Templates\. |
Debug |
false |
true writes a verbose Logs\debug.log on every launch. |
EnableMame |
true |
true reads your MAME .cfg files to pick up game-specific JOYCODE button assignments. |
EnableRetroArch |
true |
true reads RetroArch config and remap files so the overlay reflects your game-specific button remaps and active controller type. |
The plugin works in terms of platform button names - the names printed on the original hardware (A, B, C for Sega Genesis; A, B, X, Y, L, R for Super Nintendo; and so on). These are not the names of buttons on your Xbox or PlayStation controller.
Defaults\Controllers\{Platform}.xml maps each platform button name to a generic input that the controller template knows about. For example, for Sega Genesis:
<!-- Defaults\Controllers\Sega Genesis.xml (excerpt) -->
<Mapping name="A" input="ButtonX" />
<Mapping name="B" input="ButtonA" />
<Mapping name="C" input="ButtonB" />Generic input names (ButtonA, ButtonB, ButtonX, ButtonY, ButtonLeftShoulder, ButtonDpad, AxisLeftStick, …) are the shared vocabulary that connects every part of the plugin. The full list is in docs/templates.md. Controllers.xml maps platform buttons to them; RetroArch and MAME integration resolves to them; and the controller template defines a slot for each one, with a corresponding button image and position. So the Genesis B button maps to ButtonA, which the template renders at the A-button position — but using the platform-specific B.png artwork from the Sega Genesis subfolder, so the player sees the original hardware button label rather than the Xbox one. If no platform-specific image exists, it falls back to the generic ButtonA.png. This file ships for ~50 platforms.
The overlay can only be accurate if this mapping matches what your emulator is actually doing. The shipped files assume the emulator's default generic button assignments for each platform - if your emulator is configured differently, copy the relevant Controllers\{Platform}.xml to User\Controllers\ and edit it to match your configuration.
Some games remap buttons or use a different controller variant. The plugin resolves this from the following sources:
- XML (highest priority) - create
User\InputMappings\{Platform}\{Game}.xmlfor any emulator not covered below, or to explicitly override automatic detection:
<!-- User\InputMappings\Sega Genesis\Aladdin (USA).xml -->
<GameMapping controller="3-Button">
<Mapping name="A" input="ButtonRightShoulder" />
<Unmap name="C" />
</GameMapping><Mapping> replaces whatever generic input that platform button had; <Unmap> removes a button the game doesn't use, putting nothing in its place. Buttons you don't mention keep their baseline assignment. Repeating <Mapping> with the same name and different input values drives several controller slots from one platform button.
- RetroArch (
EnableRetroArch=true) - reads your RetroArch.cfgand remap files automatically to detect the active controller type and any per-game button swaps. - MAME (
EnableMame=true) - reads your MAME.cfgfiles to pick up per-game JOYCODE button assignments.
Labels tell the plugin what each button does in a specific game. All labels for a platform live in a single file: User\Labels\{Platform}.xml. Each game gets a <Game> element; a <Defaults> block sets labels that apply to every game on that platform and is merged in whenever a game's own labels don't define that button.
<!-- User\Labels\Sega Genesis.xml -->
<Labels>
<Defaults>
<Input name="Start">Pause</Input>
</Defaults>
<Game launchBoxId="1234" romName="Sonic the Hedgehog (USA)">
<Input name="A">Jump</Input>
<Input name="B">Spin Dash</Input>
</Game>
</Labels>The launchBoxId attribute is the LaunchBox Games Database ID for the title and is the primary lookup key — using it means the entry is found regardless of your ROM's filename. The romName attribute is a fallback for games without a database ID: it's matched case-insensitively against your ROM's filename, and if that misses, both sides are retried with (...) and [...] groups stripped — so a romName of Sonic the Hedgehog (USA, Europe) still matches a ROM file named Sonic the Hedgehog (World). The name attribute is the button as printed on the original hardware — the same names used in Controllers and InputMappings — and the element's text is what the button does.
A space-separated name describes an action performed by pressing several buttons together, for example <Input name="BUTTON1 BUTTON2">Power Move</Input>. It labels whichever control your configuration binds to all of those buttons at once, and takes precedence over their individual labels there. If nothing on your controller fires them together, it simply doesn't appear.
A name that means a whole control — MAME's JOYSTICK, or a platform's Dpad-Any — follows your emulator's configuration onto every control it ends up driving, and stops labelling any control it has left. If a config binds the joystick directions to the D-pad and the analogue stick at once, a single <Input name="JOYSTICK">Move</Input> labels both, because both move you; if it binds them to the stick alone, the label moves to the stick and leaves the D-pad blank, because pressing the D-pad no longer does anything.
The two halves need different amounts of evidence. A control is only labelled once all four directions reach it — binding just up to the stick doesn't make the stick move you. A control stops being labelled only when every direction has left it, so a two-way joystick, which never drove more than left and right, keeps its label.
The plugin automatically reads a controls.xml database to display what each button does in each game. controls.xml is not distributed with the plugin: download the BYOAC MAME controls database and place it at Data\Dynamic Controls\controls.xml.
Templates support platform-specific hardware button art: when a platform subfolder exists inside the template folder, the overlay substitutes those images for the generic ones automatically. The shipped Xbox Series X template covers over 40 platforms. See docs/templates.md for the image resolution rules and how to add images for additional platforms or controller variants.
- No overlay appears. Confirm
Data\Dynamic Controls\exists at the right path (not underPlugins\), thatDefaultTemplatenames a real folder underTemplates\, and that the pause screen is enabled in LaunchBox. - Plugin doesn't load. Both
DynamicControls.LaunchBox.dllandDynamicControls.Core.dllmust be present inPlugins\DynamicControls.LaunchBox\. - Windows or antivirus flags the download. Right-click the zip → Properties → tick Unblock → OK, then re-extract.
- Dig deeper. Create
User\GlobalConfig.xmlwith<Config><Debug>true</Debug></Config>and checkLogs\debug.logafter the next launch.
- Per-game input mappings match on exact ROM filename.
InputMappings\{Platform}\{Game}.xmlis matched against the ROM filename without its extension; regional variants require their own file. - DirectInput users in RetroArch do not get button swap detection. XInput controllers get full game-level swap detection; DirectInput controllers get controller variant and remap file support but no swap detection through cfg files.
- DirectInput users in MAME do get button swap detection. However, it is not reliable since DirectInput devices do not adhere to a standard layout.
- RetroArch button swap detection covers game-level remaps only. Swaps configured in global, core, or core-remap files are not applied — only game-level remap files are checked. If you configure button swaps at those levels the overlay may not reflect them.
- A RetroArch remap can move a whole control's directions away but never onto another stick. RetroArch remaps target its sixteen digital buttons only, so directions can leave a control — and the label correctly leaves with them — but they can never arrive at an analogue stick the way a MAME config can put them there.
- RetroArch controller variant detection requires a core definition file. The plugin can only detect the active controller variant for RetroArch cores that have a shipped
Emulators/RetroArch/{CoreDisplayName}.xml. Six ship today - Genesis Plus GX, Beetle PSX, Beetle Saturn, Flycast, PCSX-ReARMed and Atari800 - so controller variant detection is a no-op for any other core unless you add one.
The data files that ship with the plugin - button mappings, labels, templates, and emulator definitions - are the most impactful area for contributions. No C# knowledge required for any of these.
- Game labels (
Defaults\Labels\{Platform}.xml) - what each button does in specific games, keyed by platform button name. Add a<Game>entry for any game that doesn't have one. Include the LaunchBox Games Database ID as thelaunchBoxIdattribute so the entry is found regardless of ROM filename. - Default input mappings (
Defaults\Controllers\{Platform}.xml) - how platform buttons map to generic controller slots. Covers ~50 platforms; corrections and new platforms welcome. When adding a new platform, follow the conventions used in the existing files. - Platform button images - PNGs under
Templates\Xbox Series X\{Platform}\. Styled images for any platform not yet covered in the template, or additional controller variants for existing ones. Images must be styled consistently with the existing platform images. - RetroArch device-type IDs (
Defaults\Emulators\RetroArch\{CoreDisplayName}.xml) - maps RetroArch'sinput_libretro_deviceIDs to controller variant names, so the plugin can detect which variant is active. Six cores ship today; every additional core helps.
Open a pull request or issue at github.com/tmstedman/launchbox-dynamic-controls.
Built in two layers: src/Core (net6.0, platform-neutral logic) and src/LaunchBox (net6.0-windows, the LaunchBox/WPF host). Tests run with dotnet test. See docs/architecture.md for architecture, docs/conventions.md for conventions, and .github/workflows/ci.yml for the CI build.
The Dynamic Controls pause theme is based on Pause Shift by Faeran.
Licensed under the MIT License.


