/
controllermap.c
790 lines (700 loc) · 30.5 KB
1
/*
2
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/
/* Game controller mapping generator */
/* Gabriel Jacobo <gabomdq@gmail.com> */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"
#ifndef SDL_JOYSTICK_DISABLED
24
25
26
/* Define this for verbose output while mapping controllers */
#define DEBUG_CONTROLLERMAP
27
28
29
30
31
#ifdef __IPHONEOS__
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 480
#else
#define SCREEN_WIDTH 512
32
#define SCREEN_HEIGHT 320
33
34
35
36
37
#endif
#define MARKER_BUTTON 1
#define MARKER_AXIS 2
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
enum
{
SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
SDL_CONTROLLER_BINDING_AXIS_MAX,
};
#define BINDING_COUNT (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_MAX)
54
55
static struct
56
57
58
59
60
{
int x, y;
double angle;
int marker;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
} s_arrBindingDisplay[BINDING_COUNT] = {
{ 387, 167, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_A */
{ 431, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_B */
{ 342, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_X */
{ 389, 101, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_Y */
{ 174, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_BACK */
{ 233, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_GUIDE */
{ 289, 132, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_START */
{ 75, 154, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_LEFTSTICK */
{ 305, 230, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_RIGHTSTICK */
{ 77, 40, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_LEFTSHOULDER */
{ 396, 36, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_RIGHTSHOULDER */
{ 154, 188, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_UP */
{ 154, 249, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_DOWN */
{ 116, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_LEFT */
{ 186, 217, 0.0, MARKER_BUTTON }, /* SDL_CONTROLLER_BUTTON_DPAD_RIGHT */
77
78
79
80
81
82
83
84
85
86
{ 74, 153, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE */
{ 74, 153, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE */
{ 74, 153, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE */
{ 74, 153, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE */
{ 306, 231, 270.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE */
{ 306, 231, 90.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE */
{ 306, 231, 0.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE */
{ 306, 231, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE */
{ 91, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT */
{ 375, -20, 180.0, MARKER_AXIS }, /* SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT */
87
88
89
90
91
92
93
};
static int s_arrBindingOrder[BINDING_COUNT] = {
SDL_CONTROLLER_BUTTON_A,
SDL_CONTROLLER_BUTTON_B,
SDL_CONTROLLER_BUTTON_Y,
SDL_CONTROLLER_BUTTON_X,
94
95
96
97
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE,
98
SDL_CONTROLLER_BUTTON_LEFTSTICK,
99
100
101
102
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE,
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE,
103
104
SDL_CONTROLLER_BUTTON_RIGHTSTICK,
SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
105
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT,
106
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
107
SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT,
108
109
110
111
112
113
114
115
116
SDL_CONTROLLER_BUTTON_DPAD_UP,
SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
SDL_CONTROLLER_BUTTON_DPAD_DOWN,
SDL_CONTROLLER_BUTTON_DPAD_LEFT,
SDL_CONTROLLER_BUTTON_BACK,
SDL_CONTROLLER_BUTTON_GUIDE,
SDL_CONTROLLER_BUTTON_START,
};
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
typedef struct
{
SDL_GameControllerBindType bindType;
union
{
int button;
struct {
int axis;
int axis_min;
int axis_max;
} axis;
struct {
int hat;
int hat_mask;
} hat;
} value;
137
138
SDL_bool committed;
139
140
141
142
143
144
145
} SDL_GameControllerExtendedBind;
static SDL_GameControllerExtendedBind s_arrBindings[BINDING_COUNT];
typedef struct
{
SDL_bool m_bMoving;
146
int m_nLastValue;
147
148
149
150
151
152
153
int m_nStartingValue;
int m_nFarthestValue;
} AxisState;
static int s_nNumAxes;
static AxisState *s_arrAxisState;
154
155
156
static int s_iCurrentBinding;
static Uint32 s_unPendingAdvanceTime;
static SDL_bool s_bBindingComplete;
157
158
SDL_Texture *
159
LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent)
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
{
SDL_Surface *temp;
SDL_Texture *texture;
/* Load the sprite image */
temp = SDL_LoadBMP(file);
if (temp == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s", file, SDL_GetError());
return NULL;
}
/* Set transparent pixel as the pixel at (0,0) */
if (transparent) {
if (temp->format->palette) {
SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
}
}
/* Create textures from the image */
texture = SDL_CreateTextureFromSurface(renderer, temp);
if (!texture) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError());
SDL_FreeSurface(temp);
return NULL;
}
SDL_FreeSurface(temp);
/* We're ready to roll. :) */
return texture;
}
191
192
static int
StandardizeAxisValue(int nValue)
193
{
194
195
196
197
198
199
200
201
202
203
204
205
if (nValue > SDL_JOYSTICK_AXIS_MAX/2) {
return SDL_JOYSTICK_AXIS_MAX;
} else if (nValue < SDL_JOYSTICK_AXIS_MIN/2) {
return SDL_JOYSTICK_AXIS_MIN;
} else {
return 0;
}
}
static void
SetCurrentBinding(int iBinding)
{
206
int iIndex;
207
SDL_GameControllerExtendedBind *pBinding;
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
if (iBinding < 0) {
return;
}
if (iBinding == BINDING_COUNT) {
s_bBindingComplete = SDL_TRUE;
return;
}
s_iCurrentBinding = iBinding;
pBinding = &s_arrBindings[s_arrBindingOrder[s_iCurrentBinding]];
SDL_zerop(pBinding);
223
224
225
for (iIndex = 0; iIndex < s_nNumAxes; ++iIndex) {
s_arrAxisState[iIndex].m_nFarthestValue = s_arrAxisState[iIndex].m_nStartingValue;
}
226
227
228
229
s_unPendingAdvanceTime = 0;
}
230
231
232
233
234
235
236
237
238
239
240
241
242
static SDL_bool
BBindingContainsBinding(const SDL_GameControllerExtendedBind *pBindingA, const SDL_GameControllerExtendedBind *pBindingB)
{
if (pBindingA->bindType != pBindingB->bindType)
{
return SDL_FALSE;
}
switch (pBindingA->bindType)
{
case SDL_CONTROLLER_BINDTYPE_AXIS:
if (pBindingA->value.axis.axis != pBindingB->value.axis.axis) {
return SDL_FALSE;
}
243
244
245
if (!pBindingA->committed) {
return SDL_FALSE;
}
246
247
248
249
250
251
252
253
254
255
256
257
258
{
int minA = SDL_min(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
int maxA = SDL_max(pBindingA->value.axis.axis_min, pBindingA->value.axis.axis_max);
int minB = SDL_min(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
int maxB = SDL_max(pBindingB->value.axis.axis_min, pBindingB->value.axis.axis_max);
return (minA <= minB && maxA >= maxB);
}
/* Not reached */
default:
return SDL_memcmp(pBindingA, pBindingB, sizeof(*pBindingA)) == 0;
}
}
259
static void
260
ConfigureBinding(const SDL_GameControllerExtendedBind *pBinding)
261
{
262
SDL_GameControllerExtendedBind *pCurrent;
263
264
265
266
267
int iIndex;
int iCurrentElement = s_arrBindingOrder[s_iCurrentBinding];
/* Do we already have this binding? */
for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
268
269
pCurrent = &s_arrBindings[iIndex];
if (BBindingContainsBinding(pCurrent, pBinding)) {
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
if (iIndex == SDL_CONTROLLER_BUTTON_A && iCurrentElement != SDL_CONTROLLER_BUTTON_B) {
/* Skip to the next binding */
SetCurrentBinding(s_iCurrentBinding + 1);
return;
}
if (iIndex == SDL_CONTROLLER_BUTTON_B) {
/* Go back to the previous binding */
SetCurrentBinding(s_iCurrentBinding - 1);
return;
}
/* Already have this binding, ignore it */
return;
}
}
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#ifdef DEBUG_CONTROLLERMAP
switch ( pBinding->bindType )
{
case SDL_CONTROLLER_BINDTYPE_NONE:
break;
case SDL_CONTROLLER_BINDTYPE_BUTTON:
SDL_Log("Configuring button binding for button %d\n", pBinding->value.button);
break;
case SDL_CONTROLLER_BINDTYPE_AXIS:
SDL_Log("Configuring axis binding for axis %d %d/%d committed = %s\n", pBinding->value.axis.axis, pBinding->value.axis.axis_min, pBinding->value.axis.axis_max, pBinding->committed ? "true" : "false");
break;
case SDL_CONTROLLER_BINDTYPE_HAT:
SDL_Log("Configuring hat binding for hat %d %d\n", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
break;
}
#endif /* DEBUG_CONTROLLERMAP */
304
305
306
307
308
309
310
311
312
313
314
/* Should the new binding override the existing one? */
pCurrent = &s_arrBindings[iCurrentElement];
if (pCurrent->bindType != SDL_CONTROLLER_BINDTYPE_NONE) {
SDL_bool bNativeDPad, bCurrentDPad;
SDL_bool bNativeAxis, bCurrentAxis;
bNativeDPad = (iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_UP ||
iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_DOWN ||
iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_LEFT ||
iCurrentElement == SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
bCurrentDPad = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_HAT);
315
if (bNativeDPad && bCurrentDPad) {
316
317
318
319
320
321
/* We already have a binding of the type we want, ignore the new one */
return;
}
bNativeAxis = (iCurrentElement >= SDL_CONTROLLER_BUTTON_MAX);
bCurrentAxis = (pCurrent->bindType == SDL_CONTROLLER_BINDTYPE_AXIS);
322
323
324
if (bNativeAxis == bCurrentAxis &&
(pBinding->bindType != SDL_CONTROLLER_BINDTYPE_AXIS ||
pBinding->value.axis.axis != pCurrent->value.axis.axis)) {
325
326
327
328
329
330
331
/* We already have a binding of the type we want, ignore the new one */
return;
}
}
*pCurrent = *pBinding;
332
333
334
335
336
if (pBinding->committed) {
s_unPendingAdvanceTime = SDL_GetTicks();
} else {
s_unPendingAdvanceTime = 0;
}
337
338
}
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
static SDL_bool
BMergeAxisBindings(int iIndex)
{
SDL_GameControllerExtendedBind *pBindingA = &s_arrBindings[iIndex];
SDL_GameControllerExtendedBind *pBindingB = &s_arrBindings[iIndex+1];
if (pBindingA->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
pBindingB->bindType == SDL_CONTROLLER_BINDTYPE_AXIS &&
pBindingA->value.axis.axis == pBindingB->value.axis.axis) {
if (pBindingA->value.axis.axis_min == pBindingB->value.axis.axis_min) {
pBindingA->value.axis.axis_min = pBindingA->value.axis.axis_max;
pBindingA->value.axis.axis_max = pBindingB->value.axis.axis_max;
pBindingB->bindType = SDL_CONTROLLER_BINDTYPE_NONE;
return SDL_TRUE;
}
}
return SDL_FALSE;
}
357
static void
358
359
360
361
362
363
WatchJoystick(SDL_Joystick * joystick)
{
SDL_Window *window = NULL;
SDL_Renderer *screen = NULL;
SDL_Texture *background, *button, *axis, *marker;
const char *name = NULL;
364
SDL_bool done = SDL_FALSE;
365
366
367
368
SDL_Event event;
SDL_Rect dst;
Uint8 alpha=200, alpha_step = -1;
Uint32 alpha_ticks = 0;
369
SDL_JoystickID nJoystickID;
370
int iIndex;
371
372
373
374
375
376
377
/* Create a window to display joystick axis position */
window = SDL_CreateWindow("Game Controller Map", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
SCREEN_HEIGHT, 0);
if (window == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError());
378
return;
379
380
381
382
383
384
}
screen = SDL_CreateRenderer(window, -1, 0);
if (screen == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
385
return;
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
}
background = LoadTexture(screen, "controllermap.bmp", SDL_FALSE);
button = LoadTexture(screen, "button.bmp", SDL_TRUE);
axis = LoadTexture(screen, "axis.bmp", SDL_TRUE);
SDL_RaiseWindow(window);
/* scale for platforms that don't give you the window size you asked for. */
SDL_RenderSetLogicalSize(screen, SCREEN_WIDTH, SCREEN_HEIGHT);
/* Print info about the joystick we are watching */
name = SDL_JoystickName(joystick);
SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick),
name ? name : "Unknown Joystick");
SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
SDL_Log("\n\n\
====================================================================================\n\
Press the buttons on your controller when indicated\n\
(Your controller may look different than the picture)\n\
If you want to correct a mistake, press backspace or the back button on your device\n\
To skip a button, press SPACE or click/touch the screen\n\
To exit, press ESC\n\
====================================================================================\n");
412
413
nJoystickID = SDL_JoystickInstanceID(joystick);
414
415
s_nNumAxes = SDL_JoystickNumAxes(joystick);
416
s_arrAxisState = (AxisState *)SDL_calloc(s_nNumAxes, sizeof(*s_arrAxisState));
417
418
419
420
421
422
/* Skip any spurious events at start */
while (SDL_PollEvent(&event) > 0) {
continue;
}
423
/* Loop, getting joystick events! */
424
425
426
427
while (!done && !s_bBindingComplete) {
int iElement = s_arrBindingOrder[s_iCurrentBinding];
switch (s_arrBindingDisplay[iElement].marker) {
428
429
430
431
432
433
434
435
436
437
case MARKER_AXIS:
marker = axis;
break;
case MARKER_BUTTON:
marker = button;
break;
default:
break;
}
438
439
dst.x = s_arrBindingDisplay[iElement].x;
dst.y = s_arrBindingDisplay[iElement].y;
440
441
SDL_QueryTexture(marker, NULL, NULL, &dst.w, &dst.h);
442
443
444
445
446
if (SDL_GetTicks() - alpha_ticks > 5) {
alpha_ticks = SDL_GetTicks();
alpha += alpha_step;
if (alpha == 255) {
alpha_step = -1;
447
}
448
449
450
451
452
453
454
455
456
457
458
459
if (alpha < 128) {
alpha_step = 1;
}
}
SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE);
SDL_RenderClear(screen);
SDL_RenderCopy(screen, background, NULL, NULL);
SDL_SetTextureAlphaMod(marker, alpha);
SDL_SetTextureColorMod(marker, 10, 255, 21);
SDL_RenderCopyEx(screen, marker, NULL, &dst, s_arrBindingDisplay[iElement].angle, NULL, SDL_FLIP_NONE);
SDL_RenderPresent(screen);
460
461
462
463
464
465
466
467
468
469
while (SDL_PollEvent(&event) > 0) {
switch (event.type) {
case SDL_JOYDEVICEREMOVED:
if (event.jaxis.which == nJoystickID) {
done = SDL_TRUE;
}
break;
case SDL_JOYAXISMOTION:
if (event.jaxis.which == nJoystickID) {
470
const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 controller needed 96 */
471
472
473
474
AxisState *pAxisState = &s_arrAxisState[event.jaxis.axis];
int nValue = event.jaxis.value;
int nCurrentDistance, nFarthestDistance;
if (!pAxisState->m_bMoving) {
475
476
Sint16 nInitialValue;
pAxisState->m_bMoving = SDL_JoystickGetAxisInitialState(joystick, event.jaxis.axis, &nInitialValue);
477
pAxisState->m_nLastValue = nInitialValue;
478
479
pAxisState->m_nStartingValue = nInitialValue;
pAxisState->m_nFarthestValue = nInitialValue;
480
481
482
483
} else if (SDL_abs(nValue - pAxisState->m_nLastValue) <= MAX_ALLOWED_JITTER) {
break;
} else {
pAxisState->m_nLastValue = nValue;
484
485
486
487
488
}
nCurrentDistance = SDL_abs(nValue - pAxisState->m_nStartingValue);
nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
if (nCurrentDistance > nFarthestDistance) {
pAxisState->m_nFarthestValue = nValue;
489
nFarthestDistance = SDL_abs(pAxisState->m_nFarthestValue - pAxisState->m_nStartingValue);
490
}
491
492
493
494
495
496
497
#ifdef DEBUG_CONTROLLERMAP
SDL_Log("AXIS %d nValue %d nCurrentDistance %d nFarthestDistance %d\n", event.jaxis.axis, nValue, nCurrentDistance, nFarthestDistance);
#endif
if (nFarthestDistance >= 16000) {
/* If we've gone out far enough and started to come back, let's bind this axis */
SDL_bool bCommitBinding = (nCurrentDistance <= 10000) ? SDL_TRUE : SDL_FALSE;
498
SDL_GameControllerExtendedBind binding;
499
500
SDL_zero(binding);
binding.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
501
502
503
binding.value.axis.axis = event.jaxis.axis;
binding.value.axis.axis_min = StandardizeAxisValue(pAxisState->m_nStartingValue);
binding.value.axis.axis_max = StandardizeAxisValue(pAxisState->m_nFarthestValue);
504
binding.committed = bCommitBinding;
505
ConfigureBinding(&binding);
506
}
507
508
509
510
511
}
break;
case SDL_JOYHATMOTION:
if (event.jhat.which == nJoystickID) {
if (event.jhat.value != SDL_HAT_CENTERED) {
512
SDL_GameControllerExtendedBind binding;
513
514
515
516
#ifdef DEBUG_CONTROLLERMAP
SDL_Log("HAT %d %d\n", event.jhat.hat, event.jhat.value);
#endif
517
518
519
520
SDL_zero(binding);
binding.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
binding.value.hat.hat = event.jhat.hat;
binding.value.hat.hat_mask = event.jhat.value;
521
binding.committed = SDL_TRUE;
522
ConfigureBinding(&binding);
523
}
524
525
526
527
528
529
}
break;
case SDL_JOYBALLMOTION:
break;
case SDL_JOYBUTTONDOWN:
if (event.jbutton.which == nJoystickID) {
530
SDL_GameControllerExtendedBind binding;
531
532
533
534
#ifdef DEBUG_CONTROLLERMAP
SDL_Log("BUTTON %d\n", event.jbutton.button);
#endif
535
536
537
SDL_zero(binding);
binding.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
binding.value.button = event.jbutton.button;
538
binding.committed = SDL_TRUE;
539
540
541
542
543
544
545
546
547
548
549
ConfigureBinding(&binding);
}
break;
case SDL_FINGERDOWN:
case SDL_MOUSEBUTTONDOWN:
/* Skip this step */
SetCurrentBinding(s_iCurrentBinding + 1);
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_BACKSPACE || event.key.keysym.sym == SDLK_AC_BACK) {
SetCurrentBinding(s_iCurrentBinding - 1);
550
break;
551
552
553
}
if (event.key.keysym.sym == SDLK_SPACE) {
SetCurrentBinding(s_iCurrentBinding + 1);
554
break;
555
556
557
}
if ((event.key.keysym.sym != SDLK_ESCAPE)) {
558
559
break;
}
560
561
562
563
564
565
/* Fall through to signal quit */
case SDL_QUIT:
done = SDL_TRUE;
break;
default:
break;
566
567
568
}
}
569
570
571
572
573
574
575
576
SDL_Delay(15);
/* Wait 100 ms for joystick events to stop coming in,
in case a controller sends multiple events for a single control (e.g. axis and button for trigger)
*/
if (s_unPendingAdvanceTime && SDL_GetTicks() - s_unPendingAdvanceTime >= 100) {
SetCurrentBinding(s_iCurrentBinding + 1);
}
577
578
}
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
if (s_bBindingComplete) {
char mapping[1024];
char trimmed_name[128];
char *spot;
int iIndex;
char pszElement[12];
SDL_strlcpy(trimmed_name, name, SDL_arraysize(trimmed_name));
while (SDL_isspace(trimmed_name[0])) {
SDL_memmove(&trimmed_name[0], &trimmed_name[1], SDL_strlen(trimmed_name));
}
while (trimmed_name[0] && SDL_isspace(trimmed_name[SDL_strlen(trimmed_name) - 1])) {
trimmed_name[SDL_strlen(trimmed_name) - 1] = '\0';
}
while ((spot = SDL_strchr(trimmed_name, ',')) != NULL) {
SDL_memmove(spot, spot + 1, SDL_strlen(spot));
}
/* Initialize mapping with GUID and name */
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), mapping, SDL_arraysize(mapping));
SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
SDL_strlcat(mapping, trimmed_name, SDL_arraysize(mapping));
SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
SDL_strlcat(mapping, "platform:", SDL_arraysize(mapping));
SDL_strlcat(mapping, SDL_GetPlatform(), SDL_arraysize(mapping));
SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
for (iIndex = 0; iIndex < SDL_arraysize(s_arrBindings); ++iIndex) {
607
SDL_GameControllerExtendedBind *pBinding = &s_arrBindings[iIndex];
608
609
610
611
612
613
614
615
if (pBinding->bindType == SDL_CONTROLLER_BINDTYPE_NONE) {
continue;
}
if (iIndex < SDL_CONTROLLER_BUTTON_MAX) {
SDL_GameControllerButton eButton = (SDL_GameControllerButton)iIndex;
SDL_strlcat(mapping, SDL_GameControllerGetStringForButton(eButton), SDL_arraysize(mapping));
} else {
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
const char *pszAxisName;
switch (iIndex - SDL_CONTROLLER_BUTTON_MAX) {
case SDL_CONTROLLER_BINDING_AXIS_LEFTX_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_LEFTX_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_LEFTY_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_LEFTY_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_LEFTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTX_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTX);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_NEGATIVE:
if (!BMergeAxisBindings(iIndex)) {
SDL_strlcat(mapping, "-", SDL_arraysize(mapping));
}
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_RIGHTY_POSITIVE:
SDL_strlcat(mapping, "+", SDL_arraysize(mapping));
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_RIGHTY);
break;
case SDL_CONTROLLER_BINDING_AXIS_TRIGGERLEFT:
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT);
break;
case SDL_CONTROLLER_BINDING_AXIS_TRIGGERRIGHT:
pszAxisName = SDL_GameControllerGetStringForAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
break;
}
SDL_strlcat(mapping, pszAxisName, SDL_arraysize(mapping));
666
667
668
669
670
671
672
673
674
}
SDL_strlcat(mapping, ":", SDL_arraysize(mapping));
pszElement[0] = '\0';
switch (pBinding->bindType) {
case SDL_CONTROLLER_BINDTYPE_BUTTON:
SDL_snprintf(pszElement, sizeof(pszElement), "b%d", pBinding->value.button);
break;
case SDL_CONTROLLER_BINDTYPE_AXIS:
675
676
677
678
679
680
681
682
683
684
685
686
687
if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MIN) {
/* The negative half axis */
SDL_snprintf(pszElement, sizeof(pszElement), "-a%d", pBinding->value.axis.axis);
} else if (pBinding->value.axis.axis_min == 0 && pBinding->value.axis.axis_max == SDL_JOYSTICK_AXIS_MAX) {
/* The positive half axis */
SDL_snprintf(pszElement, sizeof(pszElement), "+a%d", pBinding->value.axis.axis);
} else {
SDL_snprintf(pszElement, sizeof(pszElement), "a%d", pBinding->value.axis.axis);
if (pBinding->value.axis.axis_min > pBinding->value.axis.axis_max) {
/* Invert the axis */
SDL_strlcat(pszElement, "~", SDL_arraysize(pszElement));
}
}
688
689
690
691
692
693
694
695
696
697
698
699
break;
case SDL_CONTROLLER_BINDTYPE_HAT:
SDL_snprintf(pszElement, sizeof(pszElement), "h%d.%d", pBinding->value.hat.hat, pBinding->value.hat.hat_mask);
break;
default:
SDL_assert(!"Unknown bind type");
break;
}
SDL_strlcat(mapping, pszElement, SDL_arraysize(mapping));
SDL_strlcat(mapping, ",", SDL_arraysize(mapping));
}
700
701
702
703
SDL_Log("Mapping:\n\n%s\n\n", mapping);
/* Print to stdout as well so the user can cat the output somewhere */
printf("%s\n", mapping);
}
704
705
706
SDL_free(s_arrAxisState);
s_arrAxisState = NULL;
707
708
709
710
711
712
713
714
715
716
717
718
719
SDL_DestroyRenderer(screen);
SDL_DestroyWindow(window);
}
int
main(int argc, char *argv[])
{
const char *name;
int i;
SDL_Joystick *joystick;
/* Enable standard application logging */
720
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
/* Initialize SDL (Note: video is required to start event loop) */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
/* Print information about the joysticks */
SDL_Log("There are %d joysticks attached\n", SDL_NumJoysticks());
for (i = 0; i < SDL_NumJoysticks(); ++i) {
name = SDL_JoystickNameForIndex(i);
SDL_Log("Joystick %d: %s\n", i, name ? name : "Unknown Joystick");
joystick = SDL_JoystickOpen(i);
if (joystick == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_JoystickOpen(%d) failed: %s\n", i,
SDL_GetError());
} else {
char guid[64];
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
guid, sizeof (guid));
SDL_Log(" axes: %d\n", SDL_JoystickNumAxes(joystick));
SDL_Log(" balls: %d\n", SDL_JoystickNumBalls(joystick));
SDL_Log(" hats: %d\n", SDL_JoystickNumHats(joystick));
SDL_Log(" buttons: %d\n", SDL_JoystickNumButtons(joystick));
SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick));
SDL_Log(" guid: %s\n", guid);
747
SDL_Log(" VID/PID: 0x%.4x/0x%.4x\n", SDL_JoystickGetVendor(joystick), SDL_JoystickGetProduct(joystick));
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
SDL_JoystickClose(joystick);
}
}
#ifdef __ANDROID__
if (SDL_NumJoysticks() > 0) {
#else
if (argv[1]) {
#endif
int device;
#ifdef __ANDROID__
device = 0;
#else
device = atoi(argv[1]);
#endif
joystick = SDL_JoystickOpen(device);
764
765
766
767
768
if (joystick == NULL) {
SDL_Log("Couldn't open joystick %d: %s\n", device, SDL_GetError());
} else {
WatchJoystick(joystick);
SDL_JoystickClose(joystick);
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
}
}
else {
SDL_Log("\n\nUsage: ./controllermap number\nFor example: ./controllermap 0\nOr: ./controllermap 0 >> gamecontrollerdb.txt");
}
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
return 0;
}
#else
int
main(int argc, char *argv[])
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL compiled without Joystick support.\n");
785
return 1;
786
787
788
}
#endif
789
790
/* vi: set ts=4 sw=4 expandtab: */