Taming Controllers with MAME on Mac

Blasteroids Copyright Atari

I finally solved the mystery of how to play games with MAME on Mac without the controllers getting scrambled!

Multiple Arcade Machine Emulator lets you play old arcade games on your PC. It’s amazing, but in the past it had one big problem for Mac users. It seemed like every time you ran it, it would forget which controller was which, and all that effort you had put into mapping your controls would go down the toilet. This was true even though it was possible to save all those controls into files to load later. The issue is that MAME gets to controllers via the SDL2 library, and that library matches your actual controller to MAME’s internal controllers by and internal OS value that can change when things are plugged in, unplugged, or the system is rebooted.

To simplify, every time you add or remove a new USB device or reboot your system, which controller MAME thinks is JOYCODE_1 and which is JOYCODE_2 can change, at which point all your hard work nitpiggling your controls to be *JUST RIGHT* can change and nothing works anymore.

There was a solution added to solve this problem and the official documentation for it is here:

There are a few specifics on Mac that it took me a long time to piece together, so I’m writing this in the hope that I can save others time and searching.

I’ll give my specific example:

I wanted to play Blasteroids on MAME 0.226 for Mac, which I downloaded from here: I’m running OS X Catalina 10.15.7.

I had previously tried the Macports version of MAME, but it was too early to support stable controllers. I also tried hand-compiling MAME using XCode, but naturally ran into obscure compiling errors. I was happy to find a pre-compiled binary that had support for stable controller IDs.

Once I installed MAME, I put my magically legally acquired Blasteroids rom, “blstroid.zip” into the “roms” directory.

The next trick is to plug in the controllers you want to use. In my case I have a Sony Dualshock 3 controller and a Logitech RumblePad 2 USB controller. I’ll cover the Logitech first because it’s simpler.

After plugging the controllers in, I ran MAME with the -v option. This outputs a lot of debug info onto the screen, part of which tells me which ID MAME is getting for my Logitech. I’m running MAME from the command line, and

 mame0226-64bit$ ./mame64 -v blstroid.zip

In the middle of all that output is this:

 Joystick: Start initialization
 Input: Adding joystick #0: LogitechRumblePad2USB (device id: 030000006d04000018c2000000010000)
 Joystick: Logitech RumblePad 2 USB [GUID 030000006d04000018c2000000010000
 Joystick:   ...  4 axes, 12 buttons 1 hats 0 balls
 Joystick:   ...  Physical id 0 mapped to logical id 1
 Joystick:   ...  Does not have haptic capability
 Joystick: End initialization 

The number I want is the device id shown above, “030000006d04000018c2000000010000”

Let’s say I want this device to always be JOYCODE_1 inside MAME. To make this happen, I created my own bitmaster.cfg file in the “ctrlr” directory inside MAME. You can use whatever editor you want, just make sure it ends with .cfg and not .txt as is the default for TextEdit.

I will specify when I run MAME that I want it to load this config file when I run it on the command line later. It’s worth noting that MAME loads a bunch of files for config, and order is important. That’s documented here: The most important thing to keep in mind right now is that MAME will create a config file for each game, in this case “blstroid.cfg” inside the “cfg” directory. THIS FILE IS LOADED *AFTER* our “bitmaster.cfg” and will OVERRIDE ANY CONFLICTING SETTINGS. Also, the “blstroid.cfg” file will be COMPLETELY OVERWRITTEN each time we make changes to the controls while MAME is running. So the reason we put our controller overrides into a separate file in the “ctrlr” directory is so that they don’t get magically overwritten when we change controls inside MAME.

So inside my “ctrlr/thebitmaster.cfg” file I put this:

 
 <mameconfig version="10">
 <system name="default">
 

 <!-- Scotts attempt to make a custom input configuration file -->
 

         <input>           
             <mapdevice device="030000006d04000018c2000000010000" controller="JOYCODE_1" />
          </input>
 </system>
 </mameconfig> 

That “<mapdevice>” tag is what tells MAME that “I always want my Logitech controller to be Joystick 1 in MAME.”

Now, to test, I run MAME again, this time telling it I want to use my custom config file:

 mame0226-64bit$ ./mame64 -v blstroid.zip -ctrlr bitmaster 

Note that I did *not* put “.cfg” at the end of “thebitmaster.” MAME adds this automatically.

Close to the end of the output, I see this:


 Starting Blasteroids (rev 4) ':'
 Attempting to parse: bitmaster.cfg
 Input: Remapped joystick #1: LogitechRumblePad2USB (device id: 030000006d04000018c2000000010000)
 Attempting to parse: default.cfg
 Attempting to parse: blstroid.cfg 

The “Input: Remapped…” line confirms the override worked. MAME will now *always* use my Logitech for Joystick 1 no matter how many other things I plug in.

Also notice the two lines with “Attempting to parse” below that. Changes in those files are made *after* the ones in my customer “thebitmaster.cfg” file and will override them.

So now I’ve solved the main problem of making sure our controllers stay put. Next I want to set up my custom controls for my Logitech in Blasteroids.

Inside the game you can do TAB to bring up the MAME menu, then choose Input(this Machine) to set your controls for the game. I’m not going to cover how to do that as it’s documented extensively elsewhere.

Once you have the controls set in MAME, you should be good to go. MAME will load “thebitmaster.cfg” file from the “ctrlr” directory first, which will make sure your devices keep the right IDS. The changes you make to each game’s controls will live in the config file for that game, in this case “cfg/blstroid.cfg”.

Since that per-game file is overwritten each time you make a change inside MAME, it might be worth making a backup copy once you get everything set to your liking. That way if your little brother screws up all your controls later, you can just copy it back.

The Dualshock 3 is a little more complicated to set up because it uses Bluetooth. The *main* thing to realize is that once it’s installed via Bluetooth, *if* it is still plugged in via USB, IT WILL SHOW UP IN MAME TWICE, AND BOTH IDS WILL BE THE SAME.

 Joystick: Start initialization
 Input: Adding joystick #0: PLAYSTATION(R)3Controller (device id: 030000004c0500006802000000010000)
 Joystick: PLAYSTATION(R)3 Controller [GUID 030000004c0500006802000000010000]
 Joystick:   ...  4 axes, 19 buttons 0 hats 0 balls
 Joystick:   ...  Physical id 0 mapped to logical id 1
 Joystick:   ...  Does not have haptic capability
 Input: Adding joystick #1: PLAYSTATION(R)3Controller (device id: 030000004c0500006802000000010000)
 Joystick: PLAYSTATION(R)3 Controller [GUID 030000004c0500006802000000010000]
 Joystick:   ...  4 axes, 19 buttons 0 hats 0 balls
 Joystick:   ...  Physical id 1 mapped to logical id 2
 Joystick:   ...  Does not have haptic capability
 Input: Adding joystick #2: LogitechRumblePad2USB (device id: 030000006d04000018c2000000010000)
 Joystick: Logitech RumblePad 2 USB [GUID 030000006d04000018c2000000010000]
 Joystick:   ...  4 axes, 12 buttons 1 hats 0 balls
 Joystick:   ...  Physical id 2 mapped to logical id 3
 Joystick:   ...  Does not have haptic capability
 Joystick: End initialization 

This can *also* happen if you have two controllers that are identical, like, say, two Logitech Rumblepad 2s. I *think* that means you can’t have a separate <mapdevice> for each one. That means, at the very least, that which controller MAME thinks is J1 vs J2 might change. That might mean that you have to just switch controllers with your friend (or bitter enemy), or it might mean it doesn’t work at all.

To fix the problem on a single Dualshock 3, though, all you have to do is make sure that, once you’ve confirmed you’ve connected through Bluetooth to your DS3, you need to unplug the USB cable so it *only* shows up via Bluetooth BEFORE YOU RUN MAME. If you unplug controllers on the version of MAME that I’m running, it will segfault and crash. When you run MAME, if you see only the one DualShock 3 showing up in the init code, then you know it worked.

In my case I chose to copy all the custom config info from “blstroid.cfg” into my “thebitmaster.cfg” That way it won’t get erased if I change the controls inside the game. My final config file, which maps both my my Sony Dualshock 3 and my Logitech Rumblepad 2 all their controls for P1 and P2 is here:

    <!-- Scotts attempt to make a custom input configuration file -->

    <input>
        <mapdevice device="030000004c0500006802000000010000" controller="JOYCODE_1" />
        <mapdevice device="030000006d04000018c2000000010000" controller="JOYCODE_2" />
        <port tag=":DIAL0" type="P1_DIAL" mask="255" defvalue="0">
            <newseq type="increment">
                JOYCODE_1_BUTTON6
            </newseq>
            <newseq type="decrement">
                JOYCODE_1_BUTTON8
            </newseq>
        </port>
        <port tag=":IN0" type="P1_BUTTON1" mask="1" defvalue="1">
            <newseq type="standard">
                JOYCODE_1_BUTTON9 OR JOYCODE_1_BUTTON10
            </newseq>
        </port>
        <port tag=":IN0" type="P1_BUTTON2" mask="2" defvalue="2">
            <newseq type="standard">
                JOYCODE_1_BUTTON15 OR JOYCODE_1_BUTTON9
            </newseq>
        </port>
        <port tag=":IN0" type="P1_BUTTON3" mask="4" defvalue="4">
            <newseq type="standard">
                JOYCODE_1_ZAXIS_NEG_SWITCH OR JOYCODE_1_BUTTON9
            </newseq>
        </port>
        <port tag=":IN0" type="P1_BUTTON4" mask="8" defvalue="8">
            <newseq type="standard">
                JOYCODE_1_BUTTON13
            </newseq>
        </port>
        <port tag=":DIAL1" type="P2_DIAL" mask="255" defvalue="0">
            <newseq type="standard">
                NONE
            </newseq>
        </port>
        <port tag=":DIAL1" type="P2_DIAL" mask="255" defvalue="0">
            <newseq type="increment">
                JOYCODE_2_HAT1RIGHT
            </newseq>
            <newseq type="decrement">
                JOYCODE_2_HAT1LEFT
            </newseq>
        </port>
        <port tag=":IN1" type="P2_BUTTON1" mask="1" defvalue="1">
            <newseq type="standard">
                JOYCODE_2_BUTTON7 OR JOYCODE_2_BUTTON8
            </newseq>
        </port>
        <port tag=":IN1" type="P2_BUTTON2" mask="2" defvalue="2">
            <newseq type="standard">
                JOYCODE_2_BUTTON7 OR JOYCODE_2_BUTTON2
            </newseq>
        </port>
        <port tag=":IN1" type="P2_BUTTON3" mask="4" defvalue="4">
            <newseq type="standard">
                JOYCODE_2_BUTTON7 OR JOYCODE_2_ZAXIS_NEG_SWITCH
            </newseq>
        </port>
        <port tag=":IN1" type="P2_BUTTON4" mask="8" defvalue="8">
            <newseq type="standard">
                JOYCODE_2_BUTTON4
            </newseq>
        </port>

    </input>
</system>

And so when I run:

mame0226-64bit$ ./mame64 -v blstroid.zip -ctrlr bitmaster

I get:

...
 
 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Monaco; color: #000000} span.s1 {font-variant-ligatures: no-common-ligatures} 
 Joystick: Start initialization
 Input: Adding joystick #0: LogitechRumblePad2USB (device id: 030000006d04000018c2000000010000)
 Joystick: Logitech RumblePad 2 USB [GUID 030000006d04000018c2000000010000]
 Joystick:   ...  4 axes, 12 buttons 1 hats 0 balls
 Joystick:   ...  Physical id 0 mapped to logical id 1
 Joystick:   ...  Does not have haptic capability
 Input: Adding joystick #1: PLAYSTATION(R)3Controller (device id: 030000004c0500006802000000010000)
 Joystick: PLAYSTATION(R)3 Controller [GUID 030000004c0500006802000000010000]
 Joystick:   ...  4 axes, 19 buttons 0 hats 0 balls
 Joystick:   ...  Physical id 1 mapped to logical id 2
 Joystick:   ...  Does not have haptic capability
 Joystick: End initialization 
...
 
 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Monaco; color: #000000} span.s1 {font-variant-ligatures: no-common-ligatures} 
 Input: Remapped joystick #0: PLAYSTATION(R)3Controller (device id: 030000004c0500006802000000010000)
 Input: Remapped joystick #1: LogitechRumblePad2USB (device id: 030000006d04000018c2000000010000)
 Attempting to parse: default.cfg
 Attempting to parse: blstroid.cfg 

I hope this helps people who were stuck with scrambled controllers on Mac like I was. Feel free to ask questions or suggest improvements.

This entry was posted in Uncategorized and tagged , , , , , , , , , , , . Bookmark the permalink.

Leave a comment