Add --debug flag for diagnosing controller input on handheld

Logs joystick enumeration at startup (name, GameController status, GUID)
and all SDL input events in the main loop to help diagnose why the retro
handheld's d-pad/buttons aren't recognized by the GameController API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michael Smith 2026-02-11 16:08:13 +01:00
parent 141dbd97e0
commit e3a2bca794
2 changed files with 104 additions and 6 deletions

View File

@ -36,7 +36,18 @@ This document specifies the functional requirements for an SDL2 based media play
- Keep it simple, apply Casey Muratori's `semantic compression` principles, don't refactor too soon or write code that's too clever for its own good - Keep it simple, apply Casey Muratori's `semantic compression` principles, don't refactor too soon or write code that's too clever for its own good
- Keep a changelog in this functional specification document - Keep a changelog in this functional specification document
## 5. Changelog ## 5. Target Platforms
- **Deployment**: Linux ARM64 (aarch64) on a retro handheld gaming device
- **Development/testing**: macOS Apple Silicon
## 6. Changelog
### 2026-02-11 — Debug flag for input diagnostics
- **`--debug` flag**: New command-line option (`./sdlamp2 --debug [audio_dir]`) that enables verbose logging of all SDL input events to stdout. Designed to diagnose controller issues on retro handheld devices where non-standard controllers may not be recognized by SDL's GameController API.
- **Startup enumeration**: When debug is on, logs the number of detected joysticks, each joystick's name, whether SDL recognizes it as a GameController, and its GUID.
- **Event logging**: Logs `KEYDOWN/UP`, `CONTROLLERBUTTONDOWN/UP`, `JOYBUTTONDOWN/UP`, `JOYHATMOTION`, `JOYAXISMOTION` (with deadzone filter), and device add/remove events with identifying details.
### 2026-02-11 — Lossless M4A concatenation tool ### 2026-02-11 — Lossless M4A concatenation tool

View File

@ -65,6 +65,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 int debug_mode = 0;
/* --- Utility --- */ /* --- Utility --- */
@ -533,8 +534,18 @@ static void activate_focused_button(void) {
/* --- Main --- */ /* --- Main --- */
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc > 1) { /* Parse arguments: [--debug] [audio_directory] */
strncpy(audio_dir, argv[1], sizeof(audio_dir) - 1); int argi = 1;
while (argi < argc && argv[argi][0] == '-') {
if (strcmp(argv[argi], "--debug") == 0) {
debug_mode = 1;
} else {
fprintf(stderr, "Unknown option: %s\n", argv[argi]);
}
argi++;
}
if (argi < argc) {
strncpy(audio_dir, argv[argi], sizeof(audio_dir) - 1);
audio_dir[sizeof(audio_dir) - 1] = '\0'; audio_dir[sizeof(audio_dir) - 1] = '\0';
} }
@ -590,8 +601,21 @@ int main(int argc, char** argv) {
panic_and_abort("Could not open audio device!", SDL_GetError()); panic_and_abort("Could not open audio device!", SDL_GetError());
} }
/* Open first available game controller */ /* Enumerate and open game controllers */
for (int i = 0; i < SDL_NumJoysticks(); i++) { int num_joy = SDL_NumJoysticks();
if (debug_mode) {
printf("[debug] Joysticks detected: %d\n", num_joy);
for (int i = 0; i < num_joy; i++) {
SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(i);
char guid_str[64];
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
printf("[debug] #%d: \"%s\" | GameController=%s | GUID=%s\n", i,
SDL_JoystickNameForIndex(i), SDL_IsGameController(i) ? "yes" : "no", guid_str);
}
fflush(stdout);
}
for (int i = 0; i < num_joy; i++) {
if (SDL_IsGameController(i)) { if (SDL_IsGameController(i)) {
controller = SDL_GameControllerOpen(i); controller = SDL_GameControllerOpen(i);
if (controller) { if (controller) {
@ -627,6 +651,64 @@ int main(int argc, char** argv) {
while (running) { while (running) {
/* --- Event handling --- */ /* --- Event handling --- */
while (SDL_PollEvent(&e)) { while (SDL_PollEvent(&e)) {
/* Debug: log all input-related events */
if (debug_mode) {
switch (e.type) {
case SDL_KEYDOWN:
printf("[debug] KEYDOWN: sym=%s (0x%x) scancode=%d\n",
SDL_GetKeyName(e.key.keysym.sym), e.key.keysym.sym, e.key.keysym.scancode);
break;
case SDL_KEYUP:
printf("[debug] KEYUP: sym=%s (0x%x) scancode=%d\n",
SDL_GetKeyName(e.key.keysym.sym), e.key.keysym.sym, e.key.keysym.scancode);
break;
case SDL_CONTROLLERBUTTONDOWN:
printf("[debug] CONTROLLERBUTTONDOWN: button=%d (%s)\n", e.cbutton.button,
SDL_GameControllerGetStringForButton(e.cbutton.button));
break;
case SDL_CONTROLLERBUTTONUP:
printf("[debug] CONTROLLERBUTTONUP: button=%d (%s)\n", e.cbutton.button,
SDL_GameControllerGetStringForButton(e.cbutton.button));
break;
case SDL_JOYBUTTONDOWN:
printf("[debug] JOYBUTTONDOWN: joy=%d button=%d\n", e.jbutton.which,
e.jbutton.button);
break;
case SDL_JOYBUTTONUP:
printf("[debug] JOYBUTTONUP: joy=%d button=%d\n", e.jbutton.which, e.jbutton.button);
break;
case SDL_JOYHATMOTION:
printf("[debug] JOYHATMOTION: joy=%d hat=%d value=%d\n", e.jhat.which, e.jhat.hat,
e.jhat.value);
break;
case SDL_JOYAXISMOTION:
if (e.jaxis.value > 8000 || e.jaxis.value < -8000) {
printf("[debug] JOYAXISMOTION: joy=%d axis=%d value=%d\n", e.jaxis.which,
e.jaxis.axis, e.jaxis.value);
}
break;
case SDL_CONTROLLERDEVICEADDED: {
SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(e.cdevice.which);
char guid_str[64];
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
printf("[debug] CONTROLLERDEVICEADDED: index=%d name=\"%s\" GUID=%s\n", e.cdevice.which,
SDL_JoystickNameForIndex(e.cdevice.which), guid_str);
break;
}
case SDL_CONTROLLERDEVICEREMOVED:
printf("[debug] CONTROLLERDEVICEREMOVED: id=%d\n", e.cdevice.which);
break;
case SDL_JOYDEVICEADDED:
printf("[debug] JOYDEVICEADDED: index=%d name=\"%s\"\n", e.jdevice.which,
SDL_JoystickNameForIndex(e.jdevice.which));
break;
case SDL_JOYDEVICEREMOVED:
printf("[debug] JOYDEVICEREMOVED: id=%d\n", e.jdevice.which);
break;
}
fflush(stdout);
}
switch (e.type) { switch (e.type) {
case SDL_QUIT: case SDL_QUIT:
running = SDL_FALSE; running = SDL_FALSE;
@ -677,7 +759,12 @@ int main(int argc, char** argv) {
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);
if (controller) { if (controller) {
printf("Controller added: %s\n", SDL_GameControllerName(controller)); SDL_Joystick* joy = SDL_GameControllerGetJoystick(controller);
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
char guid_str[64];
SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
printf("Controller added: %s (GUID: %s)\n", SDL_GameControllerName(controller),
guid_str);
} }
} }
break; break;