Add raw joystick fallback for non-standard controllers
Open the joystick via SDL_JoystickOpen() when no GameController mapping exists, fixing d-pad and face button input on devices like the Anbernic retro handheld (GUID not in SDL's database). Handles JOYHATMOTION for d-pad navigation and JOYBUTTONDOWN button 0 for activation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
dbc3f11797
commit
2fd764f60f
@ -43,6 +43,12 @@ This document specifies the functional requirements for an SDL2 based media play
|
||||
|
||||
## 6. Changelog
|
||||
|
||||
### 2026-02-13 — Raw joystick fallback for non-standard controllers
|
||||
|
||||
- **Joystick fallback**: When no SDL GameController mapping exists for a connected device, the joystick is now opened directly via `SDL_JoystickOpen()` as a fallback. This fixes d-pad and face button input on devices like the Anbernic retro handheld whose GUID is not in SDL's GameController database.
|
||||
- **Hat/button handling**: `SDL_JOYHATMOTION` events drive d-pad navigation (left/right to move focus, up/down for volume), and `SDL_JOYBUTTONDOWN` button 0 (BTN_SOUTH / A) activates the focused button.
|
||||
- **Hot-unplug**: Raw joystick is properly closed on `SDL_JOYDEVICEREMOVED`.
|
||||
|
||||
### 2026-02-13 — Embed controls spritesheet into binary
|
||||
|
||||
- **Embedded asset**: `controls.png` is now compiled into the binary as a C byte array (`src/controls_png.h`), eliminating the requirement to run from the `build/` directory.
|
||||
|
||||
@ -67,6 +67,7 @@ static int current_file_index = 0;
|
||||
static float volume = 0.5f;
|
||||
static int focus_index = FOCUS_PLAY;
|
||||
static SDL_GameController* controller = NULL;
|
||||
static SDL_Joystick* joystick = NULL;
|
||||
static int debug_mode = 0;
|
||||
|
||||
/* --- Utility --- */
|
||||
@ -627,6 +628,16 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!controller) {
|
||||
for (int i = 0; i < num_joy; i++) {
|
||||
joystick = SDL_JoystickOpen(i);
|
||||
if (joystick) {
|
||||
printf("Joystick: %s\n", SDL_JoystickName(joystick));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface* controls_surface = IMG_Load("controls.png");
|
||||
if (!controls_surface) {
|
||||
SDL_RWops* rw = SDL_RWFromConstMem(controls_png_data, controls_png_size);
|
||||
@ -763,6 +774,26 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYHATMOTION: {
|
||||
Uint8 hat = e.jhat.value;
|
||||
if (hat & SDL_HAT_LEFT) {
|
||||
focus_index = (focus_index - 1 + FOCUS_COUNT) % FOCUS_COUNT;
|
||||
} else if (hat & SDL_HAT_RIGHT) {
|
||||
focus_index = (focus_index + 1) % FOCUS_COUNT;
|
||||
} else if (hat & SDL_HAT_UP) {
|
||||
if (focus_index == FOCUS_VOLUME) adjust_volume(0.05f);
|
||||
} else if (hat & SDL_HAT_DOWN) {
|
||||
if (focus_index == FOCUS_VOLUME) adjust_volume(-0.05f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
if (e.jbutton.button == 0) {
|
||||
activate_focused_button();
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
if (!controller && SDL_IsGameController(e.cdevice.which)) {
|
||||
controller = SDL_GameControllerOpen(e.cdevice.which);
|
||||
@ -786,6 +817,13 @@ int main(int argc, char** argv) {
|
||||
printf("Controller removed\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYDEVICEREMOVED:
|
||||
if (joystick && e.jdevice.which == SDL_JoystickInstanceID(joystick)) {
|
||||
SDL_JoystickClose(joystick);
|
||||
joystick = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -898,6 +936,7 @@ int main(int argc, char** argv) {
|
||||
decoder_close();
|
||||
SDL_FreeAudioStream(stream);
|
||||
SDL_DestroyTexture(controls_texture);
|
||||
if (joystick) SDL_JoystickClose(joystick);
|
||||
if (controller) SDL_GameControllerClose(controller);
|
||||
SDL_CloseAudioDevice(audio_device);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user