ref: 68e4735c924239b68c7713a1ebf17235aa1257d4
dir: /src/gamecontrollers.c/
//
// Created by jonne on 8/19/24.
//
#include "gamecontrollers.h"
#include "config.h"
#include "events.h"
#include <SDL3/SDL.h>
#include <stdio.h>
static int num_joysticks = 0;
SDL_Gamepad *game_controllers[MAX_CONTROLLERS];
// Opens available game controllers and returns the amount of opened controllers
int gamecontrollers_initialize() {
SDL_GetJoysticks(&num_joysticks);
int controller_index = 0;
SDL_Log("Looking for game controllers");
SDL_Delay(10); // Some controllers like XBone wired need a little while to get ready
// Try to load the game controller database file
char db_filename[1024] = {0};
snprintf(db_filename, sizeof(db_filename), "%sgamecontrollerdb.txt", SDL_GetPrefPath("", "m8c"));
SDL_Log("Trying to open game controller database from %s", db_filename);
SDL_IOStream *db_rw = SDL_IOFromFile(db_filename, "rb");
if (db_rw == NULL) {
snprintf(db_filename, sizeof(db_filename), "%sgamecontrollerdb.txt", SDL_GetBasePath());
SDL_Log("Trying to open game controller database from %s", db_filename);
db_rw = SDL_IOFromFile(db_filename, "rb");
}
if (db_rw != NULL) {
const int mappings = SDL_AddGamepadMappingsFromIO(db_rw, true);
if (mappings != -1)
SDL_Log("Found %d game controller mappings", mappings);
else
SDL_LogError(SDL_LOG_CATEGORY_INPUT, "Error loading game controller mappings.");
} else {
SDL_LogError(SDL_LOG_CATEGORY_INPUT, "Unable to open game controller database file.");
}
// Open all available game controllers
for (int i = 0; i < num_joysticks; i++) {
if (!SDL_IsGamepad(i))
continue;
if (controller_index >= MAX_CONTROLLERS)
break;
game_controllers[controller_index] = SDL_OpenGamepad(i);
SDL_Log("Controller %d: %s", controller_index + 1,
SDL_GetGamepadName(game_controllers[controller_index]));
controller_index++;
}
return controller_index;
}
// Closes all open game controllers
void gamecontrollers_close() {
for (int i = 0; i < MAX_CONTROLLERS; i++) {
if (game_controllers[i])
SDL_CloseGamepad(game_controllers[i]);
}
}
// Check whether a button is pressed on a gamepad and return 1 if pressed.
static int get_game_controller_button(const config_params_s *conf, SDL_Gamepad *controller,
const int button) {
const int button_mappings[8] = {conf->gamepad_up, conf->gamepad_down, conf->gamepad_left,
conf->gamepad_right, conf->gamepad_opt, conf->gamepad_edit,
conf->gamepad_select, conf->gamepad_start};
// Check digital buttons
if (SDL_GetGamepadButton(controller, button_mappings[button])) {
return 1;
}
// If digital button isn't pressed, check the corresponding analog control
switch (button) {
case INPUT_UP:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_updown) <
-conf->gamepad_analog_threshold;
case INPUT_DOWN:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_updown) >
conf->gamepad_analog_threshold;
case INPUT_LEFT:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_leftright) <
-conf->gamepad_analog_threshold;
case INPUT_RIGHT:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_leftright) >
conf->gamepad_analog_threshold;
case INPUT_OPT:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_opt) >
conf->gamepad_analog_threshold;
case INPUT_EDIT:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_edit) >
conf->gamepad_analog_threshold;
case INPUT_SELECT:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_select) >
conf->gamepad_analog_threshold;
case INPUT_START:
return SDL_GetGamepadAxis(controller, conf->gamepad_analog_axis_start) >
conf->gamepad_analog_threshold;
default:
return 0;
}
}
// Handle game controllers, simply check all buttons and analog axis on every
// cycle
int gamecontrollers_handle_buttons(const config_params_s *conf) {
const int keycodes[8] = {key_up, key_down, key_left, key_right,
key_opt, key_edit, key_select, key_start};
int key = 0;
// Cycle through every active game controller
for (int gc = 0; gc < num_joysticks; gc++) {
// Cycle through all M8 buttons
for (int button = 0; button < INPUT_MAX; button++) {
// If the button is active, add the keycode to the variable containing
// active keys
if (get_game_controller_button(conf, game_controllers[gc], button)) {
key |= keycodes[button];
}
}
}
return key;
}
input_msg_s gamecontrollers_handle_special_messages(const config_params_s *conf) {
input_msg_s msg = {0};
// Read special case game controller buttons quit and reset
for (int gc = 0; gc < num_joysticks; gc++) {
if (SDL_GetGamepadButton(game_controllers[gc], conf->gamepad_quit) &&
(SDL_GetGamepadButton(game_controllers[gc], conf->gamepad_select) ||
SDL_GetGamepadAxis(game_controllers[gc], conf->gamepad_analog_axis_select)))
msg = (input_msg_s){special, msg_quit, 0, 0};
else if (SDL_GetGamepadButton(game_controllers[gc], conf->gamepad_reset) &&
(SDL_GetGamepadButton(game_controllers[gc], conf->gamepad_select) ||
SDL_GetGamepadAxis(game_controllers[gc], conf->gamepad_analog_axis_select)))
msg = (input_msg_s){special, msg_reset_display, 0, 0};
}
return msg;
}