1 /*
2 Copyright (c) 2015, Cong Xu
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
6
7 Redistributions of source code must retain the above copyright notice, this
8 list of conditions and the following disclaimer.
9 Redistributions in binary form must reproduce the above copyright notice,
10 this list of conditions and the following disclaimer in the documentation
11 and/or other materials provided with the distribution.
12
13 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
17 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23 POSSIBILITY OF SUCH DAMAGE.
24 */
25 #include "SDL_joystickbuttonnames.h"
26
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <SDL_pixels.h>
33
34
35 typedef struct
36 {
37 SDL_JoystickGUID guid;
38 char joystickName[256];
39 char buttonNames[SDL_CONTROLLER_BUTTON_MAX][256];
40 SDL_Color buttonColors[SDL_CONTROLLER_BUTTON_MAX];
41 char axisNames[SDL_CONTROLLER_AXIS_MAX][256];
42 SDL_Color axisColors[SDL_CONTROLLER_AXIS_MAX];
43 } JoystickButtonNames;
44
45 const char *err = NULL;
46 JoystickButtonNames *jbn = NULL;
47 int nJBN = 0;
48 JoystickButtonNames jDefault;
49 #include "db.h"
50
51
52 static JoystickButtonNames DefaultJoystickButtonNames(void);
53 static int ReadMappingsString(const char *s);
54
SDLJBN_Init(void)55 int SDLJBN_Init(void)
56 {
57 // Don't reinitialise
58 if (jbn != NULL) return 0;
59
60 jDefault = DefaultJoystickButtonNames();
61
62 ReadMappingsString(db);
63
64 return 0;
65 }
66
SDLJBN_Quit(void)67 void SDLJBN_Quit(void)
68 {
69 SDL_free(jbn);
70 jbn = NULL;
71 }
72
SDLJBN_AddMappingsFromFile(const char * file)73 int SDLJBN_AddMappingsFromFile(const char *file)
74 {
75 int ret = 0;
76 char *s = NULL;
77
78 SDLJBN_Init();
79 SDL_RWops *rwops = SDL_RWFromFile(file, "r");
80 if (rwops == NULL)
81 {
82 err = "Cannot open file";
83 ret = -1;
84 goto bail;
85 }
86
87 // Read file into memory
88 const Sint64 fsize = rwops->size(rwops);
89 if (fsize == -1)
90 {
91 err = "Cannot find file size";
92 ret = -1;
93 goto bail;
94 }
95 s = SDL_malloc((size_t)fsize + 1);
96 if (s == NULL)
97 {
98 err = "Out of memory";
99 ret = -1;
100 goto bail;
101 }
102 if (SDL_RWread(rwops, s, (size_t)fsize, 1) == 0)
103 {
104 err = "Cannot read file";
105 ret = -1;
106 goto bail;
107 }
108 s[fsize] = '\0';
109
110 ret = ReadMappingsString(s);
111
112 bail:
113 if (rwops != NULL)
114 {
115 SDL_RWclose(rwops);
116 }
117 SDL_free(s);
118 return ret;
119 }
120
ReadMappingsString(const char * s)121 static int ReadMappingsString(const char *s)
122 {
123 #define READ_TOKEN(buf, p, end)\
124 if (end == NULL)\
125 {\
126 strcpy(buf, p);\
127 p = NULL;\
128 }\
129 else\
130 {\
131 strncpy(buf, p, end - p);\
132 buf[end - p] = '\0';\
133 p = end + 1;\
134 }
135
136 // Read compiled string button names into memory
137 // Search for a matching GUID + joystickName in the db
138 int read = 0;
139 for (const char *cur = s; cur;)
140 {
141 const char *nl = strchr(cur, '\n');
142 char line[2048];
143 READ_TOKEN(line, cur, nl);
144
145 char buf[256];
146
147 // Check for the platform string
148 sprintf(buf, "platform:%s", SDL_GetPlatform());
149 if (strstr(line, buf) == NULL) continue;
150
151 #define STR_NOT_EQ(expected, actualP, actualEnd)\
152 strlen(expected) != (actualEnd) - (actualP) || \
153 strncmp(expected, actualP, (actualEnd) - (actualP)) != 0
154 const char *curL = line;
155 // Ignore hash comments
156 if (*curL == '#') continue;
157
158 const char *nextComma;
159 JoystickButtonNames j = jDefault;
160
161 // Read GUID
162 nextComma = strchr(curL, ',');
163 if (nextComma == NULL || cur == nextComma) continue;
164 READ_TOKEN(buf, curL, nextComma);
165 j.guid = SDL_JoystickGetGUIDFromString(buf);
166
167 // Read joystick name
168 nextComma = strchr(curL, ',');
169 if (nextComma == NULL || curL == nextComma) continue;
170 READ_TOKEN(j.joystickName, curL, nextComma);
171
172 // Check if GUID+joystick name already exists
173 bool exists = false;
174 for (int i = 0; i < nJBN; i++)
175 {
176 const JoystickButtonNames *jp = jbn + i;
177 if (memcmp(&jp->guid, &j.guid, sizeof j.guid) == 0 &&
178 strcmp(jp->joystickName, j.joystickName) == 0)
179 {
180 exists = true;
181 break;
182 }
183 }
184 if (exists) continue;
185
186 // Read name and colors
187 for (;; curL = nextComma + 1)
188 {
189 nextComma = strchr(curL, ',');
190 if (nextComma == NULL) break;
191
192 const char *nextColon;
193
194 nextColon = strchr(curL, ':');
195 if (nextColon == NULL || curL == nextColon) continue;
196 READ_TOKEN(buf, curL, nextColon);
197 const SDL_GameControllerButton button =
198 SDL_GameControllerGetButtonFromString(buf);
199 const SDL_GameControllerAxis axis =
200 SDL_GameControllerGetAxisFromString(buf);
201 char *name;
202 SDL_Color *color;
203 if (button != SDL_CONTROLLER_BUTTON_INVALID)
204 {
205 name = j.buttonNames[(int)button];
206 color = &j.buttonColors[(int)button];
207 }
208 else if (axis != SDL_CONTROLLER_AXIS_INVALID)
209 {
210 name = j.axisNames[(int)axis];
211 color = &j.axisColors[(int)axis];
212 }
213 else
214 {
215 continue;
216 }
217 // Read the real button/axis name
218 nextColon = strchr(curL, ':');
219 if (nextColon == NULL) continue;
220 READ_TOKEN(name, curL, nextColon);
221 // R
222 nextColon = strchr(curL, ':');
223 if (nextColon == NULL) continue;
224 READ_TOKEN(buf, curL, nextColon);
225 color->r = (Uint8)atoi(buf);
226 // G
227 nextColon = strchr(curL, ':');
228 if (nextColon == NULL) continue;
229 READ_TOKEN(buf, curL, nextColon);
230 color->g = (Uint8)atoi(buf);
231 // B
232 READ_TOKEN(buf, curL, nextComma);
233 color->b = (Uint8)atoi(buf);
234
235 color->a = 255;
236 }
237 nJBN++;
238 read++;
239 jbn = SDL_realloc(jbn, nJBN * sizeof *jbn);
240 memcpy(jbn + nJBN - 1, &j, sizeof j);
241 }
242 return read;
243 }
244
245 static const char *DefaultButtonName(SDL_GameControllerButton button);
246 static const char *DefaultAxisName(SDL_GameControllerAxis axis);
247 static SDL_Color DefaultButtonColor(SDL_GameControllerButton button);
248 static SDL_Color DefaultAxisColor(SDL_GameControllerAxis axis);
249
DefaultJoystickButtonNames(void)250 static JoystickButtonNames DefaultJoystickButtonNames(void)
251 {
252 JoystickButtonNames j;
253 memset(&j, 0, sizeof j);
254 for (SDL_GameControllerButton button = SDL_CONTROLLER_BUTTON_A;
255 button < SDL_CONTROLLER_BUTTON_MAX;
256 button++)
257 {
258 strcpy(j.buttonNames[(int)button], DefaultButtonName(button));
259 j.buttonColors[(int)button] = DefaultButtonColor(button);
260 }
261 for (SDL_GameControllerAxis axis = SDL_CONTROLLER_AXIS_LEFTX;
262 axis < SDL_CONTROLLER_AXIS_MAX;
263 axis++)
264 {
265 strcpy(j.axisNames[(int)axis], DefaultAxisName(axis));
266 j.axisColors[(int)axis] = DefaultAxisColor(axis);
267 }
268 return j;
269 }
270
DefaultButtonName(SDL_GameControllerButton button)271 static const char *DefaultButtonName(SDL_GameControllerButton button)
272 {
273 switch (button)
274 {
275 case SDL_CONTROLLER_BUTTON_A: return "A";
276 case SDL_CONTROLLER_BUTTON_B: return "B";
277 case SDL_CONTROLLER_BUTTON_X: return "X";
278 case SDL_CONTROLLER_BUTTON_Y: return "Y";
279 case SDL_CONTROLLER_BUTTON_BACK: return "Back";
280 case SDL_CONTROLLER_BUTTON_GUIDE: return "Guide";
281 case SDL_CONTROLLER_BUTTON_START: return "Start";
282 case SDL_CONTROLLER_BUTTON_LEFTSTICK: return "Left Stick";
283 case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return "Right Stick";
284 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return "LB";
285 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return "RB";
286 case SDL_CONTROLLER_BUTTON_DPAD_UP: return "D-pad Up";
287 case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return "D-pad Down";
288 case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return "D-pad Left";
289 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return "D-pad Right";
290 default: return "";
291 }
292 }
293
DefaultAxisName(SDL_GameControllerAxis axis)294 static const char *DefaultAxisName(SDL_GameControllerAxis axis)
295 {
296 switch (axis)
297 {
298 case SDL_CONTROLLER_AXIS_LEFTX: return "Left Stick X";
299 case SDL_CONTROLLER_AXIS_LEFTY: return "Left Stick Y";
300 case SDL_CONTROLLER_AXIS_RIGHTX: return "Right Stick X";
301 case SDL_CONTROLLER_AXIS_RIGHTY: return "Right Stick Y";
302 case SDL_CONTROLLER_AXIS_TRIGGERLEFT: return "LT";
303 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: return "RT";
304 default: return "";
305 }
306 }
307
308 static SDL_Color NewColor(Uint8 r, Uint8 g, Uint8 b);
309
DefaultButtonColor(SDL_GameControllerButton button)310 static SDL_Color DefaultButtonColor(SDL_GameControllerButton button)
311 {
312 // Default colors for Xbox 360 controller
313 switch (button)
314 {
315 case SDL_CONTROLLER_BUTTON_A: return NewColor(96, 160, 0);
316 case SDL_CONTROLLER_BUTTON_B: return NewColor(240, 0, 0);
317 case SDL_CONTROLLER_BUTTON_X: return NewColor(0, 96, 208);
318 case SDL_CONTROLLER_BUTTON_Y: return NewColor(255, 160, 0);
319 case SDL_CONTROLLER_BUTTON_BACK: return NewColor(224, 224, 224);
320 case SDL_CONTROLLER_BUTTON_GUIDE: return NewColor(128, 176, 0);
321 case SDL_CONTROLLER_BUTTON_START: return NewColor(224, 224, 224);
322 case SDL_CONTROLLER_BUTTON_LEFTSTICK: return NewColor(96, 128, 128);
323 case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return NewColor(96, 128, 128);
324 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return NewColor(224, 224, 224);
325 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return NewColor(224, 224, 224);
326 case SDL_CONTROLLER_BUTTON_DPAD_UP: return NewColor(96, 128, 128);
327 case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return NewColor(96, 128, 128);
328 case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return NewColor(96, 128, 128);
329 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return NewColor(96, 128, 128);
330 default: return NewColor(0, 0, 0);
331 }
332 }
333
DefaultAxisColor(SDL_GameControllerAxis axis)334 static SDL_Color DefaultAxisColor(SDL_GameControllerAxis axis)
335 {
336 // Default colors for Xbox 360 controller
337 switch (axis)
338 {
339 case SDL_CONTROLLER_AXIS_LEFTX: return NewColor(96, 128, 128);
340 case SDL_CONTROLLER_AXIS_LEFTY: return NewColor(96, 128, 128);
341 case SDL_CONTROLLER_AXIS_RIGHTX: return NewColor(96, 128, 128);
342 case SDL_CONTROLLER_AXIS_RIGHTY: return NewColor(96, 128, 128);
343 case SDL_CONTROLLER_AXIS_TRIGGERLEFT: return NewColor(224, 224, 224);
344 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: return NewColor(224, 224, 224);
345 default: return NewColor(0, 0, 0);
346 }
347 }
348
SDLJBN_GetButtonNameAndColor(SDL_Joystick * joystick,SDL_GameControllerButton button,char * s,Uint8 * r,Uint8 * g,Uint8 * b)349 int SDLJBN_GetButtonNameAndColor(SDL_Joystick *joystick,
350 SDL_GameControllerButton button,
351 char *s, Uint8 *r, Uint8 *g, Uint8 *b)
352 {
353 SDLJBN_Init();
354
355 if (joystick == NULL)
356 {
357 err = "joystick is NULL";
358 return -1;
359 }
360 if (button < SDL_CONTROLLER_BUTTON_A ||
361 button >= SDL_CONTROLLER_BUTTON_MAX)
362 {
363 err = "button is invalid";
364 return -1;
365 }
366 // Use defaults first
367 if (s) strcpy(s, jDefault.buttonNames[(int)button]);
368 if (r) *r = jDefault.buttonColors[(int)button].r;
369 if (g) *g = jDefault.buttonColors[(int)button].g;
370 if (b) *b = jDefault.buttonColors[(int)button].b;
371
372 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
373 const char *joystickName = SDL_JoystickName(joystick);
374 // Search for a matching GUID + joystickName in the db
375 for (int i = 0; i < nJBN; i++)
376 {
377 const JoystickButtonNames *j = jbn + i;
378 if (memcmp(&j->guid, &guid, sizeof guid) == 0 &&
379 strcmp(j->joystickName, joystickName) == 0)
380 {
381 // GUID and joystick name match; read name and colors
382 if (s && strlen(j->buttonNames[(int)button]) > 0)
383 strcpy(s, j->buttonNames[(int)button]);
384 if (r) *r = j->buttonColors[(int)button].r;
385 if (g) *g = j->buttonColors[(int)button].g;
386 if (b) *b = j->buttonColors[(int)button].b;
387 break;
388 }
389 }
390
391 return 0;
392 }
393
394
SDLJBN_GetAxisNameAndColor(SDL_Joystick * joystick,SDL_GameControllerAxis axis,char * s,Uint8 * r,Uint8 * g,Uint8 * b)395 int SDLJBN_GetAxisNameAndColor(SDL_Joystick *joystick,
396 SDL_GameControllerAxis axis,
397 char *s, Uint8 *r, Uint8 *g, Uint8 *b)
398 {
399 SDLJBN_Init();
400
401 if (joystick == NULL)
402 {
403 err = "joystick is NULL";
404 return -1;
405 }
406 if (axis < SDL_CONTROLLER_AXIS_LEFTX || axis >= SDL_CONTROLLER_AXIS_MAX)
407 {
408 err = "axis is invalid";
409 return -1;
410 }
411 // Use defaults first
412 if (s) strcpy(s, jDefault.axisNames[(int)axis]);
413 if (r) *r = jDefault.axisColors[(int)axis].r;
414 if (g) *g = jDefault.axisColors[(int)axis].g;
415 if (b) *b = jDefault.axisColors[(int)axis].b;
416
417 const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
418 const char *joystickName = SDL_JoystickName(joystick);
419 // Search for a matching GUID + joystickName in the db
420 for (int i = 0; i < nJBN; i++)
421 {
422 const JoystickButtonNames *j = jbn + i;
423 if (memcmp(&j->guid, &guid, sizeof guid) == 0 &&
424 strcmp(j->joystickName, joystickName) == 0)
425 {
426 // GUID and joystick name match; read name and colors
427 if (s && strlen(j->axisNames[(int)axis]) > 0)
428 strcpy(s, j->axisNames[(int)axis]);
429 if (r) *r = j->axisColors[(int)axis].r;
430 if (g) *g = j->axisColors[(int)axis].g;
431 if (b) *b = j->axisColors[(int)axis].b;
432 break;
433 }
434 }
435
436 return 0;
437 }
438
NewColor(Uint8 r,Uint8 g,Uint8 b)439 static SDL_Color NewColor(Uint8 r, Uint8 g, Uint8 b)
440 {
441 SDL_Color c;
442 c.r = r;
443 c.g = g;
444 c.b = b;
445 c.a = 255;
446 return c;
447 }
448
SDLJBN_GetError(void)449 const char *SDLJBN_GetError(void)
450 {
451 return err;
452 }
453