From de60a0ae4433a4a06c2df4f27b141563c7bbaa10 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 c3130ebfb..e816aad68 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 0a6fd7844..11cb6905a 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 fa7e37626..8ad9fff0e 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 c7eb3febc..f7417c450 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 13603ae64..739281f4b 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);