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:
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;