diff controller_info.c @ 1599:1fc61c844ec5

Allow selecting controller type when controllers have an SDL 2 mapping, but heuristics fail to idenify details
author Michael Pavone <pavone@retrodev.com>
date Fri, 27 Jul 2018 22:40:56 -0700
parents 75aa418d0227
children 7f39c40b4b25
line wrap: on
line diff
--- a/controller_info.c	Wed Jul 25 09:38:40 2018 -0700
+++ b/controller_info.c	Fri Jul 27 22:40:56 2018 -0700
@@ -1,13 +1,14 @@
 #include <string.h>
 #include "render_sdl.h"
 #include "controller_info.h"
+#include "config.h"
 
 typedef struct {
 	char const      *name;
 	controller_info info;
 } heuristic;
 
-heuristic heuristics[] = {
+static heuristic heuristics[] = {
 	//TODO: Add more heuristic rules
 	{"DualShock 4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
 	{"PS4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
@@ -24,15 +25,97 @@
 };
 const uint32_t num_heuristics = sizeof(heuristics)/sizeof(*heuristics);
 
+static tern_node *info_config;
+static uint8_t loaded;
+static const char *subtype_names[] = {
+	"unknown",
+	"xbox",
+	"xbox 360",
+	"xbone",
+	"ps2",
+	"ps3",
+	"ps4",
+	"wiiu",
+	"switch",
+	"genesis",
+	"saturn"
+};
+static const char *variant_names[] = {
+	"normal",
+	"6b bumpers",
+	"6b right"
+};
 controller_info get_controller_info(int joystick)
 {
+	if (!loaded) {
+		info_config = load_overrideable_config("controller_types.cfg", "controller_types.cfg");
+		loaded = 1;
+	}
+	char guid_string[33];
+	SDL_Joystick *stick = render_get_joystick(joystick);
 	SDL_GameController *control = render_get_controller(joystick);
+	SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(stick), guid_string, sizeof(guid_string));
+	tern_node *info = tern_find_node(info_config, guid_string);
+	if (info) {
+		controller_info res;
+		char *subtype = tern_find_ptr(info, "subtype");
+		res.subtype = SUBTYPE_UNKNOWN;
+		if (subtype) {
+			for (int i = 0; i < SUBTYPE_NUM; i++)
+			{
+				if (!strcmp(subtype_names[i], subtype)) {
+					res.subtype = i;
+					break;
+				}
+			}
+		}
+		switch (res.subtype)
+		{
+		case SUBTYPE_XBOX:
+		case SUBTYPE_X360:
+		case SUBTYPE_XBONE:
+			res.type = TYPE_XBOX;
+			break;
+		case SUBTYPE_PS2:
+		case SUBTYPE_PS3:
+		case SUBTYPE_PS4:
+			res.type = TYPE_PSX;
+			break;
+		case SUBTYPE_WIIU:
+		case SUBTYPE_SWITCH:
+			res.type = TYPE_NINTENDO;
+			break;
+		case SUBTYPE_GENESIS:
+		case SUBTYPE_SATURN:
+			res.type = TYPE_SEGA;
+			break;
+		default:
+			res.type = TYPE_UNKNOWN;
+			break;
+		}
+		char *variant = tern_find_ptr(info, "variant");
+		res.variant = VARIANT_NORMAL;
+		if (variant) {
+			for (int i = 0; i < VARIANT_NUM; i++)
+			{
+				if (!strcmp(variant_names[i], variant)) {
+					res.variant = i;
+					break;
+				}
+			}
+		}
+		res.name = control ? SDL_GameControllerName(control) : SDL_JoystickName(stick);
+		if (control) {
+			SDL_GameControllerClose(control);
+		}
+		return res;
+	}
 	if (!control) {
 		return (controller_info) {
 			.type = TYPE_UNKNOWN,
 			.subtype = SUBTYPE_UNKNOWN,
 			.variant = VARIANT_NORMAL,
-			.name = SDL_JoystickName(render_get_joystick(joystick))
+			.name = SDL_JoystickName(stick)
 		};
 	}
 	const char *name = SDL_GameControllerName(control);
@@ -54,6 +137,18 @@
 	};
 }
 
+void save_controller_info(int joystick, controller_info *info)
+{
+	char guid_string[33];
+	SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(render_get_joystick(joystick)), guid_string, sizeof(guid_string));
+	tern_node *existing = tern_find_node(info_config, guid_string);
+	existing = tern_insert_ptr(existing, "subtype", (void *)subtype_names[info->subtype]);
+	existing = tern_insert_ptr(existing, "variant",  (void *)variant_names[info->variant]);
+	info_config = tern_insert_node(info_config, guid_string, existing);
+	persist_config_at(info_config, "controller_types.cfg");
+	
+}
+
 char const *labels_xbox[] = {
 	"A", "B", "X", "Y", "Back", NULL, "Start", "Click", "Click", "White", "Black", "LT", "RT"
 };