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
|
## 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
|
### 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.
|
- **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 float volume = 0.5f;
|
||||||
static int focus_index = FOCUS_PLAY;
|
static int focus_index = FOCUS_PLAY;
|
||||||
static SDL_GameController* controller = NULL;
|
static SDL_GameController* controller = NULL;
|
||||||
|
static SDL_Joystick* joystick = NULL;
|
||||||
static int debug_mode = 0;
|
static int debug_mode = 0;
|
||||||
|
|
||||||
/* --- Utility --- */
|
/* --- 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");
|
SDL_Surface* controls_surface = IMG_Load("controls.png");
|
||||||
if (!controls_surface) {
|
if (!controls_surface) {
|
||||||
SDL_RWops* rw = SDL_RWFromConstMem(controls_png_data, controls_png_size);
|
SDL_RWops* rw = SDL_RWFromConstMem(controls_png_data, controls_png_size);
|
||||||
@ -763,6 +774,26 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case SDL_CONTROLLERDEVICEADDED:
|
||||||
if (!controller && SDL_IsGameController(e.cdevice.which)) {
|
if (!controller && SDL_IsGameController(e.cdevice.which)) {
|
||||||
controller = SDL_GameControllerOpen(e.cdevice.which);
|
controller = SDL_GameControllerOpen(e.cdevice.which);
|
||||||
@ -786,6 +817,13 @@ int main(int argc, char** argv) {
|
|||||||
printf("Controller removed\n");
|
printf("Controller removed\n");
|
||||||
}
|
}
|
||||||
break;
|
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();
|
decoder_close();
|
||||||
SDL_FreeAudioStream(stream);
|
SDL_FreeAudioStream(stream);
|
||||||
SDL_DestroyTexture(controls_texture);
|
SDL_DestroyTexture(controls_texture);
|
||||||
|
if (joystick) SDL_JoystickClose(joystick);
|
||||||
if (controller) SDL_GameControllerClose(controller);
|
if (controller) SDL_GameControllerClose(controller);
|
||||||
SDL_CloseAudioDevice(audio_device);
|
SDL_CloseAudioDevice(audio_device);
|
||||||
SDL_DestroyRenderer(renderer);
|
SDL_DestroyRenderer(renderer);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user