From defb1d43d74fd2e2bf5d4d04192b8ff6e5a7ce2b Mon Sep 17 00:00:00 2001 From: HunterHeard Date: Sun, 5 Jun 2022 21:16:24 -0500 Subject: [PATCH] Add gamepad number, background options (#122) Added two options, one which lets user choose which gamepad to use, and one which allows game to be played with gamepad while in the background. These two features together allow for "splitscreen" (sort of) multiplayer by starting up instances and joining them together and selecting different gamepads for each one. Gamepad choices are 0-7. If a number is chosen that does not correspond to a gamepad, the previous gamepad (last number you were on this session that had a working gamepad) is used. --- .gitignore | 1 + src/pc/configfile.c | 6 +++++- src/pc/configfile.h | 2 ++ src/pc/controller/controller_sdl2.c | 29 +++++++++++++++++----------- src/pc/djui/djui_panel_controls.c | 30 ++++++++++++++++++++++++++++- 5 files changed, 55 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index c3130ebf..e816aad6 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ *.swp .vscode/* .idea/* +*.code-workspace # General project-specific ignores doxygen/doxygen/* diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 0a6fd784..11cb6905 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -140,6 +140,8 @@ unsigned int configDrawDistance = 5; bool configDisablePopups = 0; bool configDisableDownloadedModels = 0; unsigned int configInterpolationMode = 1; +unsigned int configGamepadNumber = 0; +bool configBackgroundGamepad = 1; static const struct ConfigOption options[] = { {.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen}, @@ -221,7 +223,9 @@ static const struct ConfigOption options[] = { {.name = "share_lives", .type = CONFIG_TYPE_BOOL , .boolValue = &configShareLives}, {.name = "disable_popups", .type = CONFIG_TYPE_BOOL , .boolValue = &configDisablePopups}, {.name = "disable_downloaded_models", .type = CONFIG_TYPE_BOOL , .boolValue = &configDisableDownloadedModels}, - {.name = "interpolation_mode", .type = CONFIG_TYPE_UINT , .uintValue = &configInterpolationMode} + {.name = "interpolation_mode", .type = CONFIG_TYPE_UINT , .uintValue = &configInterpolationMode}, + {.name = "gamepad_number", .type = CONFIG_TYPE_UINT , .uintValue = &configGamepadNumber}, + {.name = "background_gamepad", .type = CONFIG_TYPE_UINT , .boolValue = &configBackgroundGamepad} }; // FunctionConfigOption functions diff --git a/src/pc/configfile.h b/src/pc/configfile.h index fa7e3762..8ad9fff0 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -52,6 +52,8 @@ extern unsigned int configKeyDLeft[]; extern unsigned int configKeyDRight[]; extern unsigned int configStickDeadzone; extern unsigned int configRumbleStrength; +extern unsigned int configGamepadNumber; +extern bool configBackgroundGamepad; #ifdef EXTERNAL_DATA extern bool configPrecacheRes; #endif diff --git a/src/pc/controller/controller_sdl2.c b/src/pc/controller/controller_sdl2.c index c7eb3feb..f7417c45 100644 --- a/src/pc/controller/controller_sdl2.c +++ b/src/pc/controller/controller_sdl2.c @@ -52,6 +52,7 @@ static bool joy_buttons[MAX_JOYBUTTONS] = { false }; static u32 mouse_buttons = 0; static u32 last_mouse = VK_INVALID; static u32 last_joybutton = VK_INVALID; +static u32 last_gamepad = 0; static inline void controller_add_binds(const u32 mask, const u32 *btns) { for (u32 i = 0; i < MAX_BINDS; ++i) { @@ -98,6 +99,11 @@ static void controller_sdl_bind(void) { } static void controller_sdl_init(void) { + // Allows game to be controlled by gamepad when not in focus + if (configBackgroundGamepad) { + SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); + } + if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS) != 0) { fprintf(stderr, "SDL init error: %s\n", SDL_GetError()); return; @@ -216,21 +222,22 @@ static void controller_sdl_read(OSContPad *pad) { sdl_haptic = NULL; } - if (sdl_cntrl == NULL) { - for (int i = 0; i < SDL_NumJoysticks(); i++) { - if (SDL_IsGameController(i)) { - sdl_cntrl = SDL_GameControllerOpen(i); - if (sdl_cntrl != NULL) { - sdl_haptic = controller_sdl_init_haptics(i); - break; - } + if (sdl_cntrl == NULL || last_gamepad != configGamepadNumber) { + if (SDL_IsGameController(configGamepadNumber)) { + sdl_cntrl = SDL_GameControllerOpen(configGamepadNumber); + if (sdl_cntrl != NULL) { + sdl_haptic = controller_sdl_init_haptics(configGamepadNumber); + last_gamepad = configGamepadNumber; } - } - if (sdl_cntrl == NULL) { + if (sdl_cntrl == NULL) { + return; + } + } else { + sdl_cntrl = NULL; return; } } - + int16_t leftx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTX); int16_t lefty = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_LEFTY); int16_t rightx = SDL_GameControllerGetAxis(sdl_cntrl, SDL_CONTROLLER_AXIS_RIGHTX); diff --git a/src/pc/djui/djui_panel_controls.c b/src/pc/djui/djui_panel_controls.c index 13603ae6..739281f4 100644 --- a/src/pc/djui/djui_panel_controls.c +++ b/src/pc/djui/djui_panel_controls.c @@ -2,13 +2,14 @@ #include "src/pc/utils/misc.h" #include "src/pc/configfile.h" #include "src/pc/controller/controller_api.h" +#include "src/pc/controller/controller_sdl.h" void djui_panel_controls_value_change(UNUSED struct DjuiBase* caller) { controller_reconfigure(); } void djui_panel_controls_create(struct DjuiBase* caller) { - f32 bodyHeight = 16 * 5 + 32 * 2 + 64 * 3; + f32 bodyHeight = 16 * 6 + 32 * 2 + 64 * 4; struct DjuiBase* defaultBase = NULL; struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\C\\#1be700\\O\\#00b3ff\\N\\#ffef00\\T\\#ff0800\\R\\#1be700\\O\\#00b3ff\\L\\#ffef00\\S"); @@ -25,6 +26,33 @@ void djui_panel_controls_create(struct DjuiBase* caller) { djui_base_set_size(&button2->base, 1.0f, 64); djui_interactable_hook_click(&button2->base, djui_panel_controls_extra_create); + struct DjuiCheckbox* checkboxGB = djui_checkbox_create(&body->base, "Background Gamepad (must restart)", &configBackgroundGamepad); + djui_base_set_size_type(&checkboxGB->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&checkboxGB->base, 1.0f, 32); + // djui_interactable_hook_value_change(&checkboxGB->base, djui_panel_display_uncapped_change); + + int numJoys = SDL_NumJoysticks(); + if (numJoys == 0) { numJoys = 1; } + if (numJoys > 100) { numJoys = 100; } + int strSize = numJoys * 2; + if (numJoys > 10) { + strSize += (numJoys - 10); + } + char* gamepadChoices[numJoys]; + char gamepadChoicesLong[strSize]; + for (int i = 0; i < numJoys; i++) { + int index = i * 2; + if (i > 9) { + index += (i - 9); + } + sprintf(&gamepadChoicesLong[index], "%d\0", i); + gamepadChoices[i] = &gamepadChoicesLong[index]; + } + // char* gamepadChoices[16] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"}; + struct DjuiSelectionbox* selectionboxGamepad = djui_selectionbox_create(&body->base, "Gamepad", gamepadChoices, numJoys, &configGamepadNumber); + djui_base_set_size_type(&selectionboxGamepad->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&selectionboxGamepad->base, 1.0f, 32); + struct DjuiSlider* slider1 = djui_slider_create(&body->base, "Deadzone", &configStickDeadzone, 0, 100); djui_base_set_size_type(&slider1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); djui_base_set_size(&slider1->base, 1.0f, 32);