comparison controller_info.c @ 1692:5dacaef602a7 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 05 Jan 2019 00:58:08 -0800
parents 84ef1eb2c96a
children 3a8c4ee68568
comparison
equal deleted inserted replaced
1504:95b3a1a8b26c 1692:5dacaef602a7
1 #include <string.h>
2 #include "render_sdl.h"
3 #include "controller_info.h"
4 #include "config.h"
5 #include "util.h"
6
7 typedef struct {
8 char const *name;
9 controller_info info;
10 } heuristic;
11
12 static heuristic heuristics[] = {
13 //TODO: Add more heuristic rules
14 {"DualShock 4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
15 {"PS4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
16 {"PS3", {.type = TYPE_PSX, .subtype = SUBTYPE_PS3}},
17 {"X360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
18 {"Xbox 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
19 {"X-box 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
20 {"Xbox One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}},
21 {"X-box One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}},
22 {"WiiU", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}},
23 {"Wii U", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}},
24 {"Nintendo Switch", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_SWITCH}},
25 {"Saturn", {.type = TYPE_SEGA, .subtype = SUBTYPE_SATURN}}
26 };
27 const uint32_t num_heuristics = sizeof(heuristics)/sizeof(*heuristics);
28
29 static tern_node *info_config;
30 static uint8_t loaded;
31 static const char *subtype_names[] = {
32 "unknown",
33 "xbox",
34 "xbox 360",
35 "xbone",
36 "ps2",
37 "ps3",
38 "ps4",
39 "wiiu",
40 "switch",
41 "genesis",
42 "saturn"
43 };
44 static const char *subtype_human_names[] = {
45 "unknown",
46 "Xbos",
47 "Xbox 360",
48 "Xbox One",
49 "PS2",
50 "PS3",
51 "PS4",
52 "Wii-U",
53 "Switch",
54 "Genesis",
55 "Saturn"
56 };
57 static const char *variant_names[] = {
58 "normal",
59 "6b bumpers",
60 "6b right"
61 };
62
63 static void load_ctype_config(void)
64 {
65 if (!loaded) {
66 info_config = load_overrideable_config("controller_types.cfg", "controller_types.cfg");
67 loaded = 1;
68 }
69 }
70
71 controller_info get_controller_info(int joystick)
72 {
73 load_ctype_config();
74 char guid_string[33];
75 SDL_Joystick *stick = render_get_joystick(joystick);
76 SDL_GameController *control = render_get_controller(joystick);
77 SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(stick), guid_string, sizeof(guid_string));
78 tern_node *info = tern_find_node(info_config, guid_string);
79 if (info) {
80 controller_info res;
81 char *subtype = tern_find_ptr(info, "subtype");
82 res.subtype = SUBTYPE_UNKNOWN;
83 if (subtype) {
84 for (int i = 0; i < SUBTYPE_NUM; i++)
85 {
86 if (!strcmp(subtype_names[i], subtype)) {
87 res.subtype = i;
88 break;
89 }
90 }
91 }
92 switch (res.subtype)
93 {
94 case SUBTYPE_XBOX:
95 case SUBTYPE_X360:
96 case SUBTYPE_XBONE:
97 res.type = TYPE_XBOX;
98 break;
99 case SUBTYPE_PS2:
100 case SUBTYPE_PS3:
101 case SUBTYPE_PS4:
102 res.type = TYPE_PSX;
103 break;
104 case SUBTYPE_WIIU:
105 case SUBTYPE_SWITCH:
106 res.type = TYPE_NINTENDO;
107 break;
108 case SUBTYPE_GENESIS:
109 case SUBTYPE_SATURN:
110 res.type = TYPE_SEGA;
111 break;
112 default:
113 res.type = TYPE_UNKNOWN;
114 break;
115 }
116 char *variant = tern_find_ptr(info, "variant");
117 res.variant = VARIANT_NORMAL;
118 if (variant) {
119 for (int i = 0; i < VARIANT_NUM; i++)
120 {
121 if (!strcmp(variant_names[i], variant)) {
122 res.variant = i;
123 break;
124 }
125 }
126 }
127 res.name = control ? SDL_GameControllerName(control) : SDL_JoystickName(stick);
128 if (control) {
129 SDL_GameControllerClose(control);
130 }
131 return res;
132 }
133 if (!control) {
134 return (controller_info) {
135 .type = TYPE_UNKNOWN,
136 .subtype = SUBTYPE_UNKNOWN,
137 .variant = VARIANT_NORMAL,
138 .name = SDL_JoystickName(stick)
139 };
140 }
141 const char *name = SDL_GameControllerName(control);
142 SDL_GameControllerClose(control);
143 for (uint32_t i = 0; i < num_heuristics; i++)
144 {
145 if (strstr(name, heuristics[i].name)) {
146 controller_info res = heuristics[i].info;
147 res.name = name;
148 return res;
149 }
150 }
151 //default to a 360
152 return (controller_info){
153 .type = TYPE_GENERIC_MAPPING,
154 .subtype = SUBTYPE_UNKNOWN,
155 .variant = VARIANT_NORMAL,
156 .name = name
157 };
158 }
159
160 static void mappings_iter(char *key, tern_val val, uint8_t valtype, void *data)
161 {
162 if (valtype != TVAL_NODE) {
163 return;
164 }
165 char *mapping = tern_find_ptr(val.ptrval, "mapping");
166 if (mapping) {
167 const char *parts[] = {key, ",", mapping};
168 char * full = alloc_concat_m(3, parts);
169 SDL_GameControllerAddMapping(full);
170 free(full);
171 }
172 }
173
174 void controller_add_mappings(void)
175 {
176 load_ctype_config();
177 if (info_config) {
178 tern_foreach(info_config, mappings_iter, NULL);
179 }
180 }
181
182 void save_controller_info(int joystick, controller_info *info)
183 {
184 char guid_string[33];
185 SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(render_get_joystick(joystick)), guid_string, sizeof(guid_string));
186 tern_node *existing = tern_find_node(info_config, guid_string);
187 existing = tern_insert_ptr(existing, "subtype", (void *)subtype_names[info->subtype]);
188 existing = tern_insert_ptr(existing, "variant", (void *)variant_names[info->variant]);
189 info_config = tern_insert_node(info_config, guid_string, existing);
190 persist_config_at(info_config, "controller_types.cfg");
191
192 }
193
194 void save_controller_mapping(int joystick, char *mapping_string)
195 {
196 char guid_string[33];
197 SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(render_get_joystick(joystick)), guid_string, sizeof(guid_string));
198 tern_node *existing = tern_find_node(info_config, guid_string);
199 existing = tern_insert_ptr(existing, "mapping", mapping_string);
200 info_config = tern_insert_node(info_config, guid_string, existing);
201 persist_config_at(info_config, "controller_types.cfg");
202 }
203
204 char const *labels_xbox[] = {
205 "A", "B", "X", "Y", "Back", NULL, "Start", "Click", "Click", "White", "Black", "LT", "RT"
206 };
207 char const *labels_360[] = {
208 "A", "B", "X", "Y", "Back", "Xbox", "Start", "Click", "Click", "LB", "RB", "LT", "RT"
209 };
210 static char const *labels_xbone[] = {
211 "A", "B", "X", "Y", "View", "Xbox", "Menu", "Click", "Click", "LB", "RB", "LT", "RT"
212 };
213 static char const *labels_ps3[] = {
214 "cross", "circle", "square", "triangle", "Select", "PS", "Start", "L3", "R3", "L1", "R1", "L2", "R2"
215 };
216 static char const *labels_ps4[] = {
217 "cross", "circle", "square", "triangle", "Share", "PS", "Options", "L3", "R3", "L1", "R1", "L2", "R2"
218 };
219 static char const *labels_nintendo[] = {
220 "B", "A", "Y", "X", "-", "Home", "+", "Click", "Click", "L", "R", "ZL", "ZR"
221 };
222 static char const *labels_genesis[] = {
223 "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", NULL, "Mode"
224 };
225 static char const *labels_saturn[] = {
226 "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", "LT", "RT"
227 };
228
229 static const char** label_source(controller_info *info)
230 {
231 if (info->type == TYPE_UNKNOWN || info->type == TYPE_GENERIC_MAPPING || info->subtype ==SUBTYPE_X360) {
232 return labels_360;
233 } else if (info->type == TYPE_NINTENDO) {
234 return labels_nintendo;
235 } else if (info->type == TYPE_PSX) {
236 if (info->subtype == SUBTYPE_PS4) {
237 return labels_ps4;
238 } else {
239 return labels_ps3;
240 }
241 } else if (info->type == TYPE_XBOX) {
242 if (info->subtype == SUBTYPE_XBONE) {
243 return labels_xbone;
244 } else {
245 return labels_xbox;
246 }
247 } else {
248 if (info->subtype == SUBTYPE_GENESIS) {
249 return labels_genesis;
250 } else {
251 return labels_saturn;
252 }
253 }
254 }
255
256 const char *get_button_label(controller_info *info, int button)
257 {
258 if (button >= SDL_CONTROLLER_BUTTON_DPAD_UP) {
259 static char const * dirs[] = {"Up", "Down", "Left", "Right"};
260 return dirs[button - SDL_CONTROLLER_BUTTON_DPAD_UP];
261 }
262 return label_source(info)[button];
263 }
264
265 static char const *axis_labels[] = {
266 "Left X", "Left Y", "Right X", "Right Y"
267 };
268 const char *get_axis_label(controller_info *info, int axis)
269 {
270 if (axis < SDL_CONTROLLER_AXIS_TRIGGERLEFT) {
271 return axis_labels[axis];
272 } else {
273 return label_source(info)[axis - SDL_CONTROLLER_AXIS_TRIGGERLEFT + SDL_CONTROLLER_BUTTON_RIGHTSHOULDER + 1];
274 }
275 }
276
277 char *make_controller_type_key(controller_info *info)
278 {
279 const char *subtype;
280 if (info->subtype == SUBTYPE_UNKNOWN) {
281 switch(info->type)
282 {
283 case TYPE_XBOX:
284 subtype = subtype_names[SUBTYPE_X360];
285 break;
286 case TYPE_PSX:
287 subtype = subtype_names[SUBTYPE_PS4];
288 break;
289 case TYPE_NINTENDO:
290 subtype = subtype_names[SUBTYPE_SWITCH];
291 break;
292 default:
293 subtype = "unknown";
294 }
295 } else {
296 subtype = subtype_names[info->subtype];
297 }
298 const char *variant = variant_names[info->variant];
299 const char *parts[] = {subtype, "_", variant};
300 char *ret = alloc_concat_m(3, parts);
301 for (char *cur = ret; *cur; cur++)
302 {
303 if (*cur == ' ')
304 {
305 *cur = '_';
306 }
307 }
308 return ret;
309 }
310
311 char *make_human_readable_type_name(controller_info *info)
312 {
313 const char *base = subtype_human_names[info->subtype];
314 char *prefix;
315 if (info->variant == VARIANT_NORMAL) {
316 prefix = "Normal ";
317 } else {
318 static const char *parts[] = {"6 button (", NULL, "/", NULL, ") "};
319 if (info->variant == VARIANT_6B_BUMPERS) {
320 parts[1] = get_button_label(info, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
321 parts[3] = get_button_label(info, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
322 } else {
323 parts[1] = get_button_label(info, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
324 parts[3] = get_axis_label(info, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
325 }
326 prefix = alloc_concat_m(5, parts);
327 }
328 char *ret = alloc_concat(prefix, base);
329 if (info->variant != VARIANT_NORMAL) {
330 free(prefix);
331 }
332 return ret;
333 }
334