Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion gui/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

#include "pipemgmt.h"

int select_controller = 0;

void display_cli_help(const char **argv);

int SDL_main(int argc, const char **argv)
Expand All @@ -31,7 +33,10 @@ int SDL_main(int argc, const char **argv)
} else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--fullscreen")) {
override_fs = 1;
consumed = 1;
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
} else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--controller")) {
select_controller = 1;
consumed = 1;
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
display_cli_help(argv);
return 0;
}
Expand Down Expand Up @@ -92,5 +97,6 @@ void display_cli_help(const char **argv) {
vpilog("Options:\n");
vpilog(" -w, --window Run Vanilla in a window (overrides config)\n");
vpilog(" -f, --fullscreen Run Vanilla full screen (overrides config)\n");
vpilog(" -c, --controller Lets you select your controller from a list of detected controllers\n");
vpilog(" -h, --help Show this help message\n");
}
69 changes: 69 additions & 0 deletions gui/menu/menu_gamepad.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#include "menu_gamepad.h"

#include <SDL.h>

#include "config.h"
#include "lang.h"
#include "menu/menu.h"
#include "menu/menu_common.h"
#include "menu/menu_settings.h"
#include "ui/ui_anim.h"
#include "ui/ui_sdl.h"
#include "ui/ui_keyboard.h"
#include "lib/vanilla.h"

Expand Down Expand Up @@ -262,6 +265,69 @@ void vpi_menu_key_bindings(vui_context_t *vui, void *v)
vui_start_passive_animation(vui, animate_button, 0);
}

void vpi_menu_controller_select(vui_context_t *vui, void *v);

static void transition_to_controller_select(vui_context_t *vui, int btn, void *v)
{
vui_clear_key_listener(vui);
int layer = (intptr_t) v;
vui_transition_fade_layer_out(vui, layer, vpi_menu_controller_select, 0);
}

static void on_controller_selected(vui_context_t *vui, int btn, void *v)
{
int selected_index = (intptr_t)v;
vpilog("Changing to game controller \"%s\"\n", SDL_GameControllerNameForIndex(selected_index));

vui_sdl_set_controller(vui, selected_index);

int first_btn_id = btn - selected_index;
for (int i = 0; i < SDL_NumJoysticks(); i++) {
vui_button_update_checked(vui, first_btn_id + i, (i == selected_index) ? 1 : 0);
}
}

void vpi_menu_controller_select(vui_context_t *vui, void *v)
{
vui_reset(vui);
int layer = vui_layer_create(vui);

int SCREEN_WIDTH, SCREEN_HEIGHT;
vui_get_screen_size(vui, &SCREEN_WIDTH, &SCREEN_HEIGHT);

int num_joysticks = SDL_NumJoysticks();
int entries = num_joysticks > 0 ? num_joysticks : 1;

int list_item_width = SCREEN_WIDTH - BTN_SZ - BTN_SZ;
int list_item_height = (SCREEN_HEIGHT - BTN_SZ - BTN_SZ) / entries;

if (list_item_height > 100) list_item_height = 100;

if (num_joysticks == 0) {
vui_button_create(vui, BTN_SZ, BTN_SZ, list_item_width, list_item_height, "No Controllers Found", NULL, VUI_BUTTON_STYLE_LIST, layer, NULL, NULL);
} else {
for (int i = 0; i < num_joysticks; i++) {
const char *name = SDL_GameControllerNameForIndex(i);
if (!name) name = "Unknown Controller";

int btn_id = vui_button_create(vui, BTN_SZ, BTN_SZ + (list_item_height * i), list_item_width, list_item_height, name, NULL, VUI_BUTTON_STYLE_LIST, layer, on_controller_selected, (void *)(intptr_t)i);

vui_button_update_checkable(vui, btn_id, 1);

if (i == active_controller_index) {
vui_button_update_checked(vui, btn_id, 1);
} else {
vui_button_update_checked(vui, btn_id, 0);
}
}
}

vpi_menu_create_back_button(vui, layer, return_to_gamepad, (void *) (intptr_t) layer);

vui_transition_fade_layer_in(vui, layer, 0, 0);
}


void vpi_menu_gamepad(vui_context_t *vui, void *v)
{
vui_reset(vui);
Expand All @@ -280,8 +346,11 @@ void vpi_menu_gamepad(vui_context_t *vui, void *v)

int keyboard_bind_button = vui_button_create(vui, BTN_SZ, BTN_SZ + list_item_height * 1, list_item_width, list_item_height, lang(VPI_LANG_KEYBOARD_CONTROLS), NULL, VUI_BUTTON_STYLE_LIST, layer, transition_to_keybinds, (void *)(intptr_t)layer);

int select_controller_button = vui_button_create(vui, BTN_SZ, BTN_SZ + list_item_height * 2, list_item_width, list_item_height, "Select Controller", NULL, VUI_BUTTON_STYLE_LIST, layer, transition_to_controller_select, (void *)(intptr_t)layer);

// Back button
vpi_menu_create_back_button(vui, layer, return_to_settings, (void *) (intptr_t) layer);

vui_transition_fade_layer_in(vui, layer, 0, 0);
}

91 changes: 83 additions & 8 deletions gui/ui/ui_sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ void init_gamepad(vui_context_t *ctx)
ctx->default_key_map[SDL_SCANCODE_ESCAPE] = VPI_ACTION_DISCONNECT;
}

int active_controller_index = -1;

extern int select_controller;

void find_valid_controller(vui_sdl_context_t *sdl_ctx)
{
// HACK: This is just for the Steam Deck. The Steam Deck provides a "virtual gamepad"
Expand All @@ -170,17 +174,37 @@ void find_valid_controller(vui_sdl_context_t *sdl_ctx)
// and then use the direct hardware access JUST for the gyros.
int controller = -1;
int steam_virtual_gamepad_index = -1;
int num_joysticks = SDL_NumJoysticks();

vpilog("Looking for game controllers...\n");
for (int i = 0; i < SDL_NumJoysticks(); i++) {
const char *ctrl_name = SDL_GameControllerNameForIndex(i);
vpilog(" Found %i: %s\n", i, ctrl_name);
if (ctrl_name != NULL && !strcmp(ctrl_name, "Steam Virtual Gamepad")) {
steam_virtual_gamepad_index = i;
} else if (controller == -1) {
controller = i;
if (select_controller == 1 && num_joysticks > 0) {
for (int i = 0; i < num_joysticks; i++) {
vpilog(" Found %i: %s\n", i, SDL_GameControllerNameForIndex(i));
}
}
vpilog("Select your controller (use the number assigned to it): ");
char input[10];
if (fgets(input, sizeof(input), stdin)) {
int selected = atoi(input);
if (selected >= 0 && selected < num_joysticks) {
controller = selected;
} else {
vpilog("\nSelected controller is invalid. Falling back to auto-select.\n");
select_controller = 0;
}
}
}

if (select_controller == 0) {
for (int i = 0; i < num_joysticks; i++) {
const char *ctrl_name = SDL_GameControllerNameForIndex(i);
vpilog(" Found %i: %s\n", i, ctrl_name);
if (ctrl_name != NULL && !strcmp(ctrl_name, "Steam Virtual Gamepad")) {
steam_virtual_gamepad_index = i;
} else if (controller == -1) {
controller = i;
}
}
}

SDL_GameController *steam_virtual_gamepad = NULL;
SDL_GameController *c = NULL;
Expand Down Expand Up @@ -209,8 +233,59 @@ void find_valid_controller(vui_sdl_context_t *sdl_ctx)
if (steam_virtual_gamepad) {
sdl_ctx->controller = steam_virtual_gamepad;
sdl_ctx->controller_gyros = c;
active_controller_index = steam_virtual_gamepad_index;
} else {
sdl_ctx->controller = c;
active_controller_index = controller;
}
}

void vui_sdl_set_controller(vui_context_t *ctx, int index)
{
vui_sdl_context_t *sdl_ctx = (vui_sdl_context_t *) ctx->platform_data;

if (sdl_ctx->controller) {
SDL_GameControllerClose(sdl_ctx->controller);
}
if (sdl_ctx->controller_gyros && sdl_ctx->controller_gyros != sdl_ctx->controller) {
SDL_GameControllerClose(sdl_ctx->controller_gyros);
}

sdl_ctx->controller = NULL;
sdl_ctx->controller_gyros = NULL;
active_controller_index = index;

if (index >= 0) {
SDL_GameController *primary = SDL_GameControllerOpen(index);
SDL_GameController *gyros = NULL;

if (primary) {
const char *selected_name = SDL_GameControllerName(primary);
if (selected_name && !strcmp(selected_name, "Steam Virtual Gamepad")) {
for (int i = 0; i < SDL_NumJoysticks(); i++) {
const char *search_name = SDL_GameControllerNameForIndex(i);
if (search_name && strcmp(search_name, "Steam Virtual Gamepad") != 0) {
gyros = SDL_GameControllerOpen(i);
if (gyros) {
SDL_GameControllerSetSensorEnabled(gyros, SDL_SENSOR_ACCEL, 1);
SDL_GameControllerSetSensorEnabled(gyros, SDL_SENSOR_GYRO, 1);
break;
}
}
}
} else {
SDL_GameControllerSetSensorEnabled(primary, SDL_SENSOR_ACCEL, 1);
SDL_GameControllerSetSensorEnabled(primary, SDL_SENSOR_GYRO, 1);
}

sdl_ctx->controller = primary;
sdl_ctx->controller_gyros = gyros;

vpilog("Now using game controller \"%s\"\n", SDL_GameControllerName(primary));
if (gyros) {
vpilog(" with \"%s\" for accelerometer/gyroscope\n", SDL_GameControllerName(gyros));
}
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions gui/ui/ui_sdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

#include "ui.h"

extern int active_controller_index;
void vui_sdl_set_controller(vui_context_t *ctx, int index);

/**
* System-related functions
*/
Expand Down