Supporting Game Controllers - retrofw/retrofw.github.io GitHub Wiki

Some devices supported by RetroFW (such as the RS-07 RetroArcade Mini) ship with external controllers that can be plugged into the device. These controllers look like this:

alt_text

For the most part these are standard USB gamepads and can be polled via the SDL event framework. However, it’s worth noting that the built-in controls for the consoles all fire as keyboard events with KEYDOWN and KEYUP events. The controllers are slightly different as they fire as gamepads or “joysticks” in SDL terminology. This makes mapping the controls slightly more complex.

In addition, the gamepads that ship with these machines may have a different button mapping than most off-the-shelf pads. We will only deal with the included pads in this tutorial.

Initialization

Before the gamepad(s) can be used, they need to be initialized in the SDL subsystem. Thankfully, this is a straightforward process. Your code needs to identify the number of joysticks available, then loop through, open, and enable each joystick in turn.

u32 joystick_count = SDL_NumJoysticks();

if(joystick_count > 0)
{
    for(u32 i=0; i<joystick_count; i++) SDL_JoystickOpen(i);
    SDL_JoystickEventState(SDL_ENABLE);
}

Buttons

Here is some example code showing how to read the gamepad buttons:

SDL_Event event;
while(SDL_PollEvent(&event))
{
    switch(event.type)
    {
        case SDL_JOYBUTTONDOWN:
            printf("Pressed button %d \n", event.jbutton.button);
            break;

        case SDL_JOYBUTTONUP:
            printf("Released button %d \n", event.jbutton.button);
            break;
    }
}

The value of event.jbutton.button is an integer value and does not directly indicate the name of the face button. The chart below can help you interpret the code to correctly handle the buttons in your program.

Button Code
A 1
B 2
X 0
Y 3
L 4
R 5
Select 8
Start 9

Note that it may be worth ignoring the labels of the buttons and instead aligning the controller with the feel of the buttons to hook into player’s experience and nostalgia. This can be especially important if the system’s original controller is labelled different from the gamepad.

Directional Pad

The expected event for a digital direction pads is the SDL_JOYHATMOTION event type. However, the gamepads shipped with RetroFW systems treat the dpad as a joystick. Which means that the pad must be read as a joystick axis using the SDL_JOYAXISMOTION event type.

The following code demonstrates how to add this type to your code to determine the direction being pressed.

case SDL_JOYAXISMOTION:
    if(event.jaxis.axis == 0)
    {
        printf("X axis: %d \n", event.jaxis.value);
    }
    else if(event.jaxis.axis == 1)
    {
        printf("Y axis: %d \n", event.jaxis.value);
    }
    break;

The following table shows how to interpret the event.jaxis.axis and event.jaxis.value values to determine the dpad position. It’s important to note that each axis has a separate centering event. Be careful not to zero out the handling of both axes in your code when interpreting the center value.

Direction Axis Value
Left 0 -32.767
Right 0 32.767
Up 1 -32,767
Down 1 32,767
Center (X) 0 0
Center (Y) 1 0

2 Players

If your game needs to support multiple players, you’ll need to separate which controller you’re receiving an event from. Without separation, your code will treat both controllers as if they are the same device. The way to do this is to use the event.jaxis.which and event.jbutton.which attributes. These will count up from 0 for each gamepad plugged into the system. Currently, only 2 gamepads are supported meaning that you will receive gamepads 0 and 1.

The following code demonstrates how to identify each controller:

case SDL_JOYBUTTONDOWN:
    printf("Controller %d pressed \n", event.jbutton.which);
    break;

case SDL_JOYBUTTONUP:
    printf("Controller %d releases \n", event.jbutton.which);
    break;

case SDL_JOYAXISMOTION:
    printf("Controller %d dpad \n", event.jaxis.which);
    break;