src/joystick/SDL_gamecontroller.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 25 Jan 2013 14:25:19 -0800
changeset 6823 e9d312d26979
parent 6738 b408d5a406a3
child 6841 90bba8d8e42a
permissions -rw-r--r--
Fixed crash when the game controller mapping hint is set - the hint was duplicated and not null terminated.
slouken@6690
     1
/*
slouken@6690
     2
  Simple DirectMedia Layer
slouken@6690
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@6690
     4
slouken@6690
     5
  This software is provided 'as-is', without any express or implied
slouken@6690
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@6690
     7
  arising from the use of this software.
slouken@6690
     8
slouken@6690
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@6690
    10
  including commercial applications, and to alter it and redistribute it
slouken@6690
    11
  freely, subject to the following restrictions:
slouken@6690
    12
slouken@6690
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@6690
    14
     claim that you wrote the original software. If you use this software
slouken@6690
    15
     in a product, an acknowledgment in the product documentation would be
slouken@6690
    16
     appreciated but is not required.
slouken@6690
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@6690
    18
     misrepresented as being the original software.
slouken@6690
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@6690
    20
*/
slouken@6690
    21
#include "SDL_config.h"
slouken@6690
    22
slouken@6690
    23
/* This is the game controller API for Simple DirectMedia Layer */
slouken@6690
    24
slouken@6690
    25
#include "SDL_events.h"
slouken@6690
    26
#include "SDL_assert.h"
slouken@6690
    27
#include "SDL_sysjoystick.h"
slouken@6690
    28
#include "SDL_hints.h"
slouken@6690
    29
slouken@6690
    30
#if !SDL_EVENTS_DISABLED
slouken@6690
    31
#include "../events/SDL_events_c.h"
slouken@6690
    32
#endif
slouken@6690
    33
#define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
slouken@6690
    34
slouken@6690
    35
slouken@6690
    36
/* a list of currently opened game controllers */
slouken@6690
    37
static SDL_GameController *SDL_gamecontrollers = NULL;
slouken@6690
    38
slouken@6690
    39
/* keep track of the hat and mask value that transforms this hat movement into a button press */
slouken@6690
    40
struct _SDL_HatAsButton
slouken@6690
    41
{
slouken@6690
    42
	int hat;
slouken@6690
    43
	Uint8 mask;
slouken@6690
    44
};
slouken@6690
    45
slouken@6690
    46
#define k_nMaxReverseEntries 20
slouken@6690
    47
slouken@6690
    48
/* our in memory mapping db between joystick objects and controller mappings*/
slouken@6690
    49
struct _SDL_ControllerMapping
slouken@6690
    50
{
slouken@6738
    51
	SDL_JoystickGUID guid;
slouken@6690
    52
	const char *name;
slouken@6690
    53
slouken@6690
    54
	// mapping of axis/button id to controller version
slouken@6690
    55
	int axes[SDL_CONTROLLER_AXIS_MAX];
slouken@6690
    56
	int buttons[SDL_CONTROLLER_BUTTON_MAX];
slouken@6690
    57
slouken@6690
    58
	int axesasbutton[SDL_CONTROLLER_BUTTON_MAX];
slouken@6690
    59
	struct _SDL_HatAsButton hatasbutton[SDL_CONTROLLER_BUTTON_MAX];
slouken@6690
    60
	int buttonasaxis[SDL_CONTROLLER_AXIS_MAX];
slouken@6690
    61
slouken@6690
    62
	// reverse mapping, joystick indices to buttons
slouken@6690
    63
	SDL_CONTROLLER_AXIS raxes[k_nMaxReverseEntries];
slouken@6690
    64
	SDL_CONTROLLER_BUTTON rbuttons[k_nMaxReverseEntries];
slouken@6690
    65
	SDL_CONTROLLER_BUTTON raxesasbutton[k_nMaxReverseEntries];
slouken@6690
    66
	struct _SDL_HatAsButton rhatasbutton[k_nMaxReverseEntries];
slouken@6690
    67
	SDL_CONTROLLER_AXIS rbuttonasaxis[k_nMaxReverseEntries];
slouken@6690
    68
};
slouken@6690
    69
slouken@6690
    70
slouken@6690
    71
/* our hard coded list of mapping support */
slouken@6690
    72
typedef struct _ControllerMapping_t
slouken@6690
    73
{
slouken@6738
    74
	SDL_JoystickGUID guid;
slouken@6690
    75
	char *name;
slouken@6690
    76
	const char *mapping;
slouken@6690
    77
	struct _ControllerMapping_t *next;
slouken@6690
    78
} ControllerMapping_t;
slouken@6690
    79
slouken@6690
    80
slouken@6690
    81
/* default mappings we support */
slouken@6690
    82
const char *s_ControllerMappings [] =
slouken@6690
    83
{
slouken@6701
    84
#ifdef SDL_JOYSTICK_DINPUT
slouken@6690
    85
	"xinput,X360 Controller,a:b10,b:b11,y:b13,x:b12,start:b4,guide:b14,back:b5,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftshoulder:b8,rightshoulder:b9,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5",
slouken@6690
    86
	"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7",
slouken@6690
    87
	"88880803000000000000504944564944,PS3,a:b2,b:b1,x:b0,y:b3,start:b11,back:b8,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.4,dpdown:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,guide:b12",
slouken@6690
    88
	"25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,x:b0,y:b3,start:b8,guide:,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.4,dpdown:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5",
slouken@6690
    89
#elif defined(__MACOSX__)
slouken@6690
    90
	"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftshoulder:b4,rightshoulder:b5,leftstick:b6,rightstick:b7,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5",
slouken@6690
    91
	"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,x:b12,y:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b6,dpdown:b7,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9",
slouken@6690
    92
#elif defined(__LINUX__)
slouken@6690
    93
	
slouken@6690
    94
#endif
slouken@6690
    95
	NULL
slouken@6690
    96
};
slouken@6690
    97
slouken@6690
    98
static ControllerMapping_t *s_pSupportedControllers = NULL;
slouken@6708
    99
#ifdef SDL_JOYSTICK_DINPUT
slouken@6690
   100
static ControllerMapping_t *s_pXInputMapping = NULL;
slouken@6708
   101
#endif
slouken@6690
   102
slouken@6690
   103
/* The SDL game controller structure */
slouken@6690
   104
struct _SDL_GameController
slouken@6690
   105
{
slouken@6690
   106
	SDL_Joystick *joystick;	/* underlying joystick device */
slouken@6690
   107
	int ref_count;
slouken@6690
   108
	struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */
slouken@6690
   109
	struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
slouken@6690
   110
};
slouken@6690
   111
slouken@6690
   112
slouken@6690
   113
int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis, Sint16 value);
slouken@6690
   114
int	SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button, Uint8 state);
slouken@6690
   115
slouken@6690
   116
/*
slouken@6690
   117
 * Event filter to fire controller events from joystick ones
slouken@6690
   118
 */
slouken@6690
   119
int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
slouken@6690
   120
{
slouken@6690
   121
	switch( event->type )
slouken@6690
   122
	{
slouken@6690
   123
	case SDL_JOYAXISMOTION:
slouken@6690
   124
		{
slouken@6690
   125
			SDL_GameController *controllerlist = SDL_gamecontrollers;
slouken@6690
   126
			while ( controllerlist )
slouken@6690
   127
			{
slouken@6690
   128
				if ( controllerlist->joystick->instance_id == event->jaxis.which )
slouken@6690
   129
				{
slouken@6690
   130
					if ( controllerlist->mapping.raxes[event->jaxis.axis] >= 0 ) // simple axis to axis, send it through
slouken@6690
   131
					{
slouken@6690
   132
						SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.raxes[event->jaxis.axis], event->jaxis.value );
slouken@6690
   133
					}
slouken@6690
   134
					else if ( controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0 ) // simlate an axis as a button
slouken@6690
   135
					{
slouken@6690
   136
						SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? 1 : 0 );
slouken@6690
   137
					}
slouken@6690
   138
					break;
slouken@6690
   139
				}
slouken@6690
   140
				controllerlist = controllerlist->next;
slouken@6690
   141
			}
slouken@6690
   142
		}
slouken@6690
   143
		break;
slouken@6690
   144
	case SDL_JOYBUTTONDOWN:
slouken@6690
   145
	case SDL_JOYBUTTONUP:
slouken@6690
   146
		{
slouken@6690
   147
			SDL_GameController *controllerlist = SDL_gamecontrollers;
slouken@6690
   148
			while ( controllerlist )
slouken@6690
   149
			{
slouken@6690
   150
				if ( controllerlist->joystick->instance_id == event->jbutton.which )
slouken@6690
   151
				{
slouken@6690
   152
					if ( controllerlist->mapping.rbuttons[event->jbutton.button] >= 0 ) // simple button as button
slouken@6690
   153
					{
slouken@6690
   154
						SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state );
slouken@6690
   155
					}
slouken@6690
   156
					else if ( controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0 ) // an button pretending to be an axis
slouken@6690
   157
					{
slouken@6690
   158
						SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32768 : 0 );
slouken@6690
   159
					}
slouken@6690
   160
					break;
slouken@6690
   161
				}
slouken@6690
   162
				controllerlist = controllerlist->next;
slouken@6690
   163
			}
slouken@6690
   164
		}
slouken@6690
   165
		break;
slouken@6690
   166
	case SDL_JOYHATMOTION:
slouken@6690
   167
		{
slouken@6690
   168
			if ( event->jhat.hat == 0 ) // BUGBUG - multiple hat support??
slouken@6690
   169
			{
slouken@6690
   170
				SDL_GameController *controllerlist = SDL_gamecontrollers;
slouken@6690
   171
				while ( controllerlist )
slouken@6690
   172
				{
slouken@6690
   173
					if ( controllerlist->joystick->instance_id == event->jhat.which )
slouken@6690
   174
					{
slouken@6690
   175
						static Uint8 bHatsDown = 0;
slouken@6690
   176
						if ( event->jhat.value == 0 )
slouken@6690
   177
						{
slouken@6690
   178
							if ( bHatsDown & SDL_HAT_DOWN )
slouken@6690
   179
								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_DOWN, 0 );
slouken@6690
   180
							if ( bHatsDown & SDL_HAT_UP )
slouken@6690
   181
								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_UP, 0 );
slouken@6690
   182
							if ( bHatsDown & SDL_HAT_LEFT )
slouken@6690
   183
								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_LEFT, 0 );
slouken@6690
   184
							if ( bHatsDown & SDL_HAT_RIGHT )
slouken@6690
   185
								SDL_PrivateGameControllerButton( controllerlist, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, 0 );
slouken@6690
   186
							bHatsDown = 0;
slouken@6690
   187
						}
slouken@6690
   188
						else if ( controllerlist->mapping.rhatasbutton[event->jhat.value].hat >= 0 )
slouken@6690
   189
						{
slouken@6690
   190
							bHatsDown |= event->jhat.value;
slouken@6690
   191
							SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[event->jhat.value].hat, (event->jhat.value & controllerlist->mapping.rhatasbutton[event->jhat.value].mask) > 0 ? 1 : 0 );
slouken@6690
   192
						}
slouken@6690
   193
						break;
slouken@6690
   194
					}
slouken@6690
   195
					controllerlist = controllerlist->next;
slouken@6690
   196
				}
slouken@6690
   197
			}
slouken@6690
   198
		}
slouken@6690
   199
		break;
slouken@6690
   200
	case SDL_JOYDEVICEADDED:
slouken@6690
   201
		{
slouken@6690
   202
			if ( SDL_IsGameController(event->jdevice.which ) )
slouken@6690
   203
			{
slouken@6690
   204
				SDL_Event deviceevent;
slouken@6690
   205
				deviceevent.type = SDL_CONTROLLERDEVICEADDED;
slouken@6690
   206
				deviceevent.cdevice.which = event->jdevice.which;
slouken@6690
   207
				SDL_PushEvent(&deviceevent);
slouken@6690
   208
			}
slouken@6690
   209
		}
slouken@6690
   210
		break;
slouken@6690
   211
	case SDL_JOYDEVICEREMOVED:
slouken@6690
   212
		{
slouken@6690
   213
			SDL_GameController *controllerlist = SDL_gamecontrollers;
slouken@6690
   214
			while ( controllerlist )
slouken@6690
   215
			{
slouken@6690
   216
				if ( controllerlist->joystick->instance_id == event->jdevice.which )
slouken@6690
   217
				{
slouken@6690
   218
					SDL_Event deviceevent;
slouken@6690
   219
					deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
slouken@6690
   220
					deviceevent.cdevice.which = event->jdevice.which;
slouken@6690
   221
					SDL_PushEvent(&deviceevent);
slouken@6690
   222
					break;
slouken@6690
   223
				}
slouken@6690
   224
				controllerlist = controllerlist->next;
slouken@6690
   225
			}
slouken@6690
   226
		}
slouken@6690
   227
		break;
slouken@6690
   228
	default:
slouken@6690
   229
		break;
slouken@6690
   230
	}
slouken@6690
   231
slouken@6690
   232
	return 1;
slouken@6690
   233
}
slouken@6690
   234
slouken@6690
   235
/*
slouken@6690
   236
 * Helper function to determine pre-caclulated offset to certain joystick mappings
slouken@6690
   237
 */
slouken@6690
   238
ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
slouken@6690
   239
{
slouken@6701
   240
#ifdef SDL_JOYSTICK_DINPUT
slouken@6690
   241
	if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping )
slouken@6690
   242
	{
slouken@6690
   243
		return s_pXInputMapping;
slouken@6690
   244
	}
slouken@6690
   245
#endif
slouken@6690
   246
	return NULL;
slouken@6690
   247
}
slouken@6690
   248
slouken@6690
   249
slouken@6690
   250
/*
slouken@6690
   251
 * convert a string to its enum equivalent
slouken@6690
   252
 */
slouken@6690
   253
SDL_CONTROLLER_AXIS SDL_GameControllerGetAxisFromString( const char *pchString )
slouken@6690
   254
{
slouken@6690
   255
	if ( !pchString || !pchString[0] )
slouken@6690
   256
		return SDL_CONTROLLER_AXIS_INVALID;
slouken@6690
   257
slouken@6690
   258
	if ( !SDL_strcasecmp( pchString, "leftx" ) )
slouken@6690
   259
		return SDL_CONTROLLER_AXIS_LEFTX;
slouken@6690
   260
	else if ( !SDL_strcasecmp( pchString, "lefty" ) )
slouken@6690
   261
		return SDL_CONTROLLER_AXIS_LEFTY;
slouken@6690
   262
	else if ( !SDL_strcasecmp( pchString, "rightx" ) )
slouken@6690
   263
		return SDL_CONTROLLER_AXIS_RIGHTX;
slouken@6690
   264
	else if ( !SDL_strcasecmp( pchString, "righty" ) )
slouken@6690
   265
		return SDL_CONTROLLER_AXIS_RIGHTY;
slouken@6690
   266
	else if ( !SDL_strcasecmp( pchString, "lefttrigger" ) )
slouken@6690
   267
		return SDL_CONTROLLER_AXIS_TRIGGERLEFT;
slouken@6690
   268
	else if ( !SDL_strcasecmp( pchString, "righttrigger" ) )
slouken@6690
   269
		return SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
slouken@6690
   270
	else
slouken@6690
   271
		return SDL_CONTROLLER_AXIS_INVALID;
slouken@6690
   272
}
slouken@6690
   273
slouken@6690
   274
slouken@6690
   275
/*
slouken@6690
   276
 * convert a string to its enum equivalent
slouken@6690
   277
 */
slouken@6690
   278
SDL_CONTROLLER_BUTTON SDL_GameControllerGetButtonFromString( const char *pchString )
slouken@6690
   279
{
slouken@6690
   280
	if ( !pchString || !pchString[0] )
slouken@6690
   281
		return SDL_CONTROLLER_BUTTON_INVALID;
slouken@6690
   282
slouken@6690
   283
	if ( !SDL_strcasecmp( pchString, "a" ) )
slouken@6690
   284
		return SDL_CONTROLLER_BUTTON_A;
slouken@6690
   285
	else if ( !SDL_strcasecmp( pchString, "b" ) )
slouken@6690
   286
		return SDL_CONTROLLER_BUTTON_B;
slouken@6690
   287
	else if ( !SDL_strcasecmp( pchString, "x" ) )
slouken@6690
   288
		return SDL_CONTROLLER_BUTTON_X;
slouken@6690
   289
	else if ( !SDL_strcasecmp( pchString, "y" ) )
slouken@6690
   290
		return SDL_CONTROLLER_BUTTON_Y;
slouken@6690
   291
	else if ( !SDL_strcasecmp( pchString, "start" ) )
slouken@6690
   292
		return SDL_CONTROLLER_BUTTON_START;
slouken@6690
   293
	else if ( !SDL_strcasecmp( pchString, "guide" ) )
slouken@6690
   294
		return SDL_CONTROLLER_BUTTON_GUIDE;
slouken@6690
   295
	else if ( !SDL_strcasecmp( pchString, "back" ) )
slouken@6690
   296
		return SDL_CONTROLLER_BUTTON_BACK;
slouken@6690
   297
	else if ( !SDL_strcasecmp( pchString, "dpup" ) )
slouken@6690
   298
		return SDL_CONTROLLER_BUTTON_DPAD_UP;
slouken@6690
   299
	else if ( !SDL_strcasecmp( pchString, "dpdown" ) )
slouken@6690
   300
		return SDL_CONTROLLER_BUTTON_DPAD_DOWN;
slouken@6690
   301
	else if ( !SDL_strcasecmp( pchString, "dpleft" ) )
slouken@6690
   302
		return SDL_CONTROLLER_BUTTON_DPAD_LEFT;
slouken@6690
   303
	else if ( !SDL_strcasecmp( pchString, "dpright" ) )
slouken@6690
   304
		return SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
slouken@6690
   305
	else if ( !SDL_strcasecmp( pchString, "leftshoulder" ) )
slouken@6690
   306
		return SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
slouken@6690
   307
	else if ( !SDL_strcasecmp( pchString, "rightshoulder" ) )
slouken@6690
   308
		return SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
slouken@6690
   309
	else if ( !SDL_strcasecmp( pchString, "leftstick" ) )
slouken@6690
   310
		return SDL_CONTROLLER_BUTTON_LEFTSTICK;
slouken@6690
   311
	else if ( !SDL_strcasecmp( pchString, "rightstick" ) )
slouken@6690
   312
		return SDL_CONTROLLER_BUTTON_RIGHTSTICK;
slouken@6690
   313
	else
slouken@6690
   314
		return SDL_CONTROLLER_BUTTON_INVALID;
slouken@6690
   315
}
slouken@6690
   316
slouken@6690
   317
slouken@6690
   318
/*
slouken@6690
   319
 * given a controller button name and a joystick name update our mapping structure with it
slouken@6690
   320
 */
slouken@6690
   321
void SDL_PrivateGameControllerParseButton( const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping )
slouken@6690
   322
{
slouken@6690
   323
	int iSDLButton = 0;
slouken@6690
   324
	SDL_CONTROLLER_BUTTON button;
slouken@6690
   325
	SDL_CONTROLLER_AXIS axis;
slouken@6690
   326
	button = SDL_GameControllerGetButtonFromString( szGameButton );
slouken@6690
   327
	axis = SDL_GameControllerGetAxisFromString( szGameButton );
slouken@6690
   328
	iSDLButton = SDL_atoi( &szJoystickButton[1] );
slouken@6690
   329
slouken@6690
   330
	if ( iSDLButton >= k_nMaxReverseEntries )
slouken@6690
   331
	{
slouken@6690
   332
		SDL_SetError("Button index too large: %d", iSDLButton );
slouken@6690
   333
		return;
slouken@6690
   334
	}
slouken@6690
   335
slouken@6690
   336
	if ( szJoystickButton[0] == 'a' )
slouken@6690
   337
	{
slouken@6690
   338
		if ( axis != SDL_CONTROLLER_AXIS_INVALID )
slouken@6690
   339
		{
slouken@6690
   340
			pMapping->axes[ axis ] = iSDLButton;
slouken@6690
   341
			pMapping->raxes[ iSDLButton ] = axis;
slouken@6690
   342
		}
slouken@6690
   343
		else if ( button != SDL_CONTROLLER_BUTTON_INVALID )
slouken@6690
   344
		{
slouken@6690
   345
			pMapping->buttonasaxis[ button ] = iSDLButton;
slouken@6690
   346
			pMapping->rbuttonasaxis[ iSDLButton ] = button;
slouken@6690
   347
		}
slouken@6690
   348
		else
slouken@6690
   349
		{
slouken@6690
   350
			SDL_assert( !"How did we get here?" );
slouken@6690
   351
		}
slouken@6690
   352
slouken@6690
   353
	}
slouken@6690
   354
	else if ( szJoystickButton[0] == 'b' )
slouken@6690
   355
	{
slouken@6690
   356
		if ( button != SDL_CONTROLLER_BUTTON_INVALID )
slouken@6690
   357
		{
slouken@6690
   358
			pMapping->buttons[ button ] = iSDLButton;
slouken@6690
   359
			pMapping->rbuttons[ iSDLButton ] = button;
slouken@6690
   360
		}
slouken@6690
   361
		else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
slouken@6690
   362
		{
slouken@6690
   363
			pMapping->buttonasaxis[ axis ] = iSDLButton;
slouken@6690
   364
			pMapping->rbuttonasaxis[ iSDLButton ] = axis;
slouken@6690
   365
		}
slouken@6690
   366
		else
slouken@6690
   367
		{
slouken@6690
   368
			SDL_assert( !"How did we get here?" );
slouken@6690
   369
		}
slouken@6690
   370
	}
slouken@6690
   371
	else if ( szJoystickButton[0] == 'h' )
slouken@6690
   372
	{
slouken@6690
   373
		int hat = SDL_atoi( &szJoystickButton[1] );
slouken@6690
   374
		int mask = SDL_atoi( &szJoystickButton[3] );
slouken@6690
   375
slouken@6690
   376
		if ( button != SDL_CONTROLLER_BUTTON_INVALID )
slouken@6690
   377
		{
slouken@6690
   378
			pMapping->hatasbutton[ button ].hat = hat;
slouken@6690
   379
			pMapping->hatasbutton[ button ].mask = mask;
slouken@6690
   380
			pMapping->rhatasbutton[ mask ].hat = button;
slouken@6690
   381
			pMapping->rhatasbutton[ mask ].mask = mask;
slouken@6690
   382
		}
slouken@6690
   383
		else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
slouken@6690
   384
		{
slouken@6690
   385
			SDL_assert( !"Support hat as axis" );
slouken@6690
   386
		}
slouken@6690
   387
		else
slouken@6690
   388
		{
slouken@6690
   389
			SDL_assert( !"How did we get here?" );
slouken@6690
   390
		}
slouken@6690
   391
	}
slouken@6690
   392
slouken@6690
   393
}
slouken@6690
   394
slouken@6690
   395
slouken@6690
   396
/*
slouken@6690
   397
 * given a controller mapping string update our mapping object
slouken@6690
   398
 */
slouken@6690
   399
static void
slouken@6690
   400
SDL_PrivateGameControllerParseControllerConfigString( struct _SDL_ControllerMapping *pMapping, const char *pchString )
slouken@6690
   401
{
slouken@6690
   402
	char szGameButton[20];
slouken@6690
   403
	char szJoystickButton[20];
slouken@6690
   404
	SDL_bool bGameButton = SDL_TRUE;
slouken@6690
   405
	int i = 0;
slouken@6690
   406
	const char *pchPos = pchString;
slouken@6690
   407
slouken@6690
   408
	SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
slouken@6690
   409
	SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
slouken@6690
   410
slouken@6690
   411
	while ( pchPos && *pchPos )
slouken@6690
   412
	{
slouken@6690
   413
		if ( *pchPos == ':' )
slouken@6690
   414
		{
slouken@6690
   415
			i = 0;
slouken@6690
   416
			bGameButton = SDL_FALSE;
slouken@6690
   417
		}
slouken@6690
   418
		else if ( *pchPos == ' ' )
slouken@6690
   419
		{
slouken@6690
   420
slouken@6690
   421
		}
slouken@6690
   422
		else if ( *pchPos == ',' )
slouken@6690
   423
		{
slouken@6690
   424
			i = 0;
slouken@6690
   425
			bGameButton = SDL_TRUE;
slouken@6690
   426
			SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
slouken@6690
   427
			SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
slouken@6690
   428
			SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
slouken@6690
   429
slouken@6690
   430
		}
slouken@6690
   431
		else if ( bGameButton )
slouken@6690
   432
		{
slouken@6690
   433
			if ( i >=  sizeof(szGameButton))
slouken@6690
   434
			{
slouken@6690
   435
				SDL_SetError( "Button name too large: %s", szGameButton );
slouken@6690
   436
				return;
slouken@6690
   437
			}
slouken@6690
   438
			szGameButton[i] = *pchPos;
slouken@6690
   439
			i++;
slouken@6690
   440
		}
slouken@6690
   441
		else
slouken@6690
   442
		{
slouken@6690
   443
			if ( i >=  sizeof(szJoystickButton))
slouken@6690
   444
			{
slouken@6690
   445
				SDL_SetError( "Joystick button name too large: %s", szJoystickButton );
slouken@6690
   446
				return;
slouken@6690
   447
			}
slouken@6690
   448
			szJoystickButton[i] = *pchPos;
slouken@6690
   449
			i++;
slouken@6690
   450
		}
slouken@6690
   451
		pchPos++;
slouken@6690
   452
	}
slouken@6690
   453
slouken@6690
   454
	SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
slouken@6690
   455
slouken@6690
   456
}
slouken@6690
   457
slouken@6690
   458
/*
slouken@6690
   459
 * Make a new button mapping struct
slouken@6690
   460
 */
slouken@6738
   461
void SDL_PrivateLoadButtonMapping( struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping )
slouken@6690
   462
{
slouken@6690
   463
	int j;
slouken@6690
   464
slouken@6690
   465
	pMapping->guid = guid;
slouken@6690
   466
	pMapping->name = pchName;
slouken@6690
   467
slouken@6690
   468
	// set all the button mappings to non defaults
slouken@6690
   469
	for ( j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++ )
slouken@6690
   470
	{
slouken@6690
   471
		pMapping->axes[j] = -1;
slouken@6690
   472
		pMapping->buttonasaxis[j] = -1;
slouken@6690
   473
	}
slouken@6690
   474
	for ( j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++ )
slouken@6690
   475
	{
slouken@6690
   476
		pMapping->buttons[j] = -1;
slouken@6690
   477
		pMapping->axesasbutton[j] = -1;
slouken@6690
   478
		pMapping->hatasbutton[j].hat = -1;
slouken@6690
   479
	}
slouken@6690
   480
slouken@6690
   481
	for ( j = 0; j < k_nMaxReverseEntries; j++ )
slouken@6690
   482
	{
slouken@6690
   483
		pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
slouken@6690
   484
		pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
slouken@6690
   485
		pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
slouken@6690
   486
		pMapping->rhatasbutton[j].hat = -1;
slouken@6690
   487
		pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
slouken@6690
   488
	}
slouken@6690
   489
slouken@6690
   490
	SDL_PrivateGameControllerParseControllerConfigString( pMapping, pchMapping );
slouken@6690
   491
}
slouken@6690
   492
slouken@6690
   493
slouken@6690
   494
/*
slouken@6690
   495
 * grab the guid string from a mapping string
slouken@6690
   496
 */
slouken@6690
   497
char *SDL_PrivateGetControllerGUIDFromMappingString( const char *pMapping )
slouken@6690
   498
{
slouken@6690
   499
	const char *pFirstComma = SDL_strchr( pMapping, ',' );
slouken@6690
   500
	if ( pFirstComma )
slouken@6690
   501
	{
slouken@6690
   502
		char *pchGUID = SDL_malloc( pFirstComma - pMapping + 1 );
slouken@6690
   503
		if ( !pchGUID )
slouken@6690
   504
		{
slouken@6690
   505
			SDL_OutOfMemory();
slouken@6690
   506
			return NULL;
slouken@6690
   507
		}
slouken@6690
   508
		SDL_memcpy( pchGUID, pMapping, pFirstComma - pMapping );
slouken@6690
   509
		pchGUID[ pFirstComma - pMapping ] = 0;
slouken@6690
   510
		return pchGUID;
slouken@6690
   511
	}
slouken@6690
   512
	return NULL;
slouken@6690
   513
}
slouken@6690
   514
slouken@6690
   515
slouken@6690
   516
/*
slouken@6690
   517
 * grab the name string from a mapping string
slouken@6690
   518
 */
slouken@6690
   519
char *SDL_PrivateGetControllerNameFromMappingString( const char *pMapping )
slouken@6690
   520
{
slouken@6823
   521
	const char *pFirstComma, *pSecondComma;
slouken@6823
   522
    char *pchName;
slouken@6823
   523
slouken@6823
   524
    pFirstComma = SDL_strchr( pMapping, ',' );
slouken@6823
   525
    if ( !pFirstComma )
slouken@6823
   526
        return NULL;
slouken@6823
   527
slouken@6823
   528
	pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
slouken@6823
   529
    if ( !pSecondComma )
slouken@6823
   530
        return NULL;
slouken@6823
   531
slouken@6823
   532
    pchName = SDL_malloc( pSecondComma - pFirstComma );
slouken@6823
   533
    if ( !pchName )
slouken@6823
   534
    {
slouken@6823
   535
        SDL_OutOfMemory();
slouken@6823
   536
        return NULL;
slouken@6823
   537
    }
slouken@6823
   538
    SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma );
slouken@6823
   539
    pchName[ pSecondComma - pFirstComma - 1 ] = 0;
slouken@6823
   540
    return pchName;
slouken@6690
   541
}
slouken@6690
   542
slouken@6690
   543
slouken@6690
   544
/*
slouken@6690
   545
 * grab the button mapping string from a mapping string
slouken@6690
   546
 */
slouken@6690
   547
const char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
slouken@6690
   548
{
slouken@6823
   549
	const char *pFirstComma, *pSecondComma;
slouken@6823
   550
slouken@6823
   551
    pFirstComma = SDL_strchr( pMapping, ',' );
slouken@6823
   552
    if ( !pFirstComma )
slouken@6823
   553
        return NULL;
slouken@6823
   554
slouken@6823
   555
	pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
slouken@6823
   556
    if ( !pSecondComma )
slouken@6823
   557
        return NULL;
slouken@6823
   558
slouken@6823
   559
    return pSecondComma + 1; /* mapping is everything after the 3rd comma, no need to malloc it */
slouken@6690
   560
}
slouken@6690
   561
slouken@6690
   562
slouken@6690
   563
/*
slouken@6690
   564
 * Initialize the game controller system, mostly load our DB of controller config mappings
slouken@6690
   565
 */
slouken@6690
   566
int
slouken@6690
   567
SDL_GameControllerInit(void)
slouken@6690
   568
{
slouken@6690
   569
	int i = 0;
slouken@6690
   570
	const char *pMappingString = NULL;
slouken@6690
   571
	s_pSupportedControllers = NULL;
slouken@6690
   572
	pMappingString = s_ControllerMappings[i];
slouken@6690
   573
	while ( pMappingString )
slouken@6690
   574
	{
slouken@6690
   575
		ControllerMapping_t *pControllerMapping;
slouken@6690
   576
		char *pchGUID;
slouken@6690
   577
		char *pchName;
slouken@6690
   578
		const char *pchMapping;
slouken@6690
   579
		pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
slouken@6690
   580
		if ( !pControllerMapping )
slouken@6690
   581
		{
slouken@6690
   582
			SDL_OutOfMemory();
slouken@6690
   583
			return -1;
slouken@6690
   584
		}
slouken@6690
   585
slouken@6690
   586
		pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pMappingString );
slouken@6690
   587
		pchName = SDL_PrivateGetControllerNameFromMappingString( pMappingString );
slouken@6690
   588
		pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pMappingString );
slouken@6690
   589
		if ( pchGUID && pchName )
slouken@6690
   590
		{
slouken@6701
   591
#ifdef SDL_JOYSTICK_DINPUT
slouken@6690
   592
			if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
slouken@6690
   593
			{
slouken@6690
   594
				s_pXInputMapping = pControllerMapping;
slouken@6690
   595
			}
slouken@6690
   596
#endif
slouken@6690
   597
			pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
slouken@6690
   598
			pControllerMapping->name = pchName;
slouken@6690
   599
			pControllerMapping->mapping = pchMapping;
slouken@6690
   600
			pControllerMapping->next = s_pSupportedControllers;
slouken@6690
   601
			s_pSupportedControllers = pControllerMapping;
slouken@6690
   602
slouken@6690
   603
			SDL_free( pchGUID );
slouken@6690
   604
		}
slouken@6690
   605
slouken@6690
   606
		i++;
slouken@6690
   607
		pMappingString = s_ControllerMappings[i];
slouken@6690
   608
	}
slouken@6690
   609
slouken@6690
   610
	// load in any user supplied config
slouken@6690
   611
	{
slouken@6690
   612
		const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
slouken@6690
   613
		if ( hint && hint[0] )
slouken@6690
   614
		{
slouken@6690
   615
			int nchHints = SDL_strlen( hint );
slouken@6823
   616
			char *pUserMappings = SDL_malloc( nchHints + 1 ); /* FIXME: memory leak, but we can't free it in this function because pchMapping below points into this memory */
slouken@6823
   617
			SDL_memcpy( pUserMappings, hint, nchHints + 1 );
slouken@6690
   618
			while ( pUserMappings )
slouken@6690
   619
			{
slouken@6690
   620
				char *pchGUID;
slouken@6690
   621
				char *pchName;
slouken@6690
   622
				const char *pchMapping;
slouken@6690
   623
				char *pchNewLine = NULL;
slouken@6690
   624
				ControllerMapping_t *pControllerMapping;
slouken@6690
   625
slouken@6690
   626
				pchNewLine = SDL_strchr( pUserMappings, '\n' );
slouken@6690
   627
				if ( pchNewLine )
slouken@6690
   628
					*pchNewLine = '\0';
slouken@6690
   629
slouken@6690
   630
				pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
slouken@6690
   631
				if ( !pControllerMapping )
slouken@6690
   632
				{
slouken@6690
   633
					SDL_OutOfMemory();
slouken@6690
   634
					return -1;
slouken@6690
   635
				}
slouken@6690
   636
slouken@6690
   637
				pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pUserMappings );
slouken@6690
   638
				pchName = SDL_PrivateGetControllerNameFromMappingString( pUserMappings );
slouken@6690
   639
				pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pUserMappings );
slouken@6690
   640
slouken@6690
   641
				if ( pchGUID && pchName )
slouken@6690
   642
				{
slouken@6701
   643
#ifdef SDL_JOYSTICK_DINPUT
slouken@6690
   644
					if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
slouken@6690
   645
					{
slouken@6690
   646
						s_pXInputMapping = pControllerMapping;
slouken@6690
   647
					}
slouken@6690
   648
#endif
slouken@6690
   649
slouken@6690
   650
					pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
slouken@6690
   651
					pControllerMapping->name = pchName;
slouken@6690
   652
					pControllerMapping->mapping = pchMapping;
slouken@6690
   653
					pControllerMapping->next = s_pSupportedControllers;
slouken@6690
   654
					s_pSupportedControllers = pControllerMapping;
slouken@6690
   655
slouken@6690
   656
					SDL_free( pchGUID );
slouken@6690
   657
				}
slouken@6690
   658
slouken@6690
   659
				if ( pchNewLine )
slouken@6690
   660
					pUserMappings = pchNewLine + 1;
slouken@6690
   661
				else
slouken@6690
   662
					pUserMappings = NULL;
slouken@6690
   663
			}
slouken@6690
   664
		}
slouken@6690
   665
	}
slouken@6690
   666
slouken@6690
   667
	/* watch for joy events and fire controller ones if needed */
slouken@6690
   668
	SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL );
slouken@6690
   669
	return (0);
slouken@6690
   670
}
slouken@6690
   671
slouken@6690
   672
slouken@6690
   673
/*
slouken@6690
   674
 * Get the implementation dependent name of a controller
slouken@6690
   675
 */
slouken@6690
   676
const char *
slouken@6690
   677
SDL_GameControllerNameForIndex(int device_index)
slouken@6690
   678
{
slouken@6690
   679
	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
slouken@6690
   680
	if ( pSupportedController )
slouken@6690
   681
	{
slouken@6690
   682
		return pSupportedController->name;
slouken@6690
   683
	}
slouken@6690
   684
	else
slouken@6690
   685
	{
slouken@6738
   686
		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
slouken@6690
   687
		pSupportedController = s_pSupportedControllers;
slouken@6690
   688
		while ( pSupportedController )
slouken@6690
   689
		{
slouken@6690
   690
			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
slouken@6690
   691
			{
slouken@6690
   692
				return pSupportedController->name;
slouken@6690
   693
			}
slouken@6690
   694
			pSupportedController = pSupportedController->next;
slouken@6690
   695
		}
slouken@6690
   696
	}
slouken@6690
   697
    return NULL;
slouken@6690
   698
}
slouken@6690
   699
slouken@6690
   700
slouken@6690
   701
/*
slouken@6690
   702
 * Return 1 if the joystick at this device index is a supported controller
slouken@6690
   703
 */
slouken@6690
   704
int SDL_IsGameController(int device_index)
slouken@6690
   705
{
slouken@6690
   706
	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
slouken@6690
   707
	if ( pSupportedController )
slouken@6690
   708
	{
slouken@6690
   709
		return 1;
slouken@6690
   710
	}
slouken@6690
   711
	else
slouken@6690
   712
	{
slouken@6738
   713
		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
slouken@6690
   714
		pSupportedController = s_pSupportedControllers;
slouken@6690
   715
		// debug code to help get the guid string for a new joystick
slouken@6738
   716
		/* char szGUID[33];
slouken@6738
   717
		SDL_JoystickGetGUIDString( jGUID, szGUID, sizeof(szGUID) );
slouken@6690
   718
		printf( "%s\n", pchGUID );
slouken@6690
   719
		SDL_free( pchGUID );*/
slouken@6690
   720
		while ( pSupportedController )
slouken@6690
   721
		{
slouken@6690
   722
			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
slouken@6690
   723
			{
slouken@6690
   724
				return 1;
slouken@6690
   725
			}
slouken@6690
   726
			pSupportedController = pSupportedController->next;
slouken@6690
   727
		}
slouken@6690
   728
	}
slouken@6690
   729
	return 0;
slouken@6690
   730
}
slouken@6690
   731
slouken@6690
   732
/*
slouken@6690
   733
 * Open a controller for use - the index passed as an argument refers to
slouken@6690
   734
 * the N'th controller on the system.  This index is the value which will
slouken@6690
   735
 * identify this controller in future controller events.
slouken@6690
   736
 *
slouken@6690
   737
 * This function returns a controller identifier, or NULL if an error occurred.
slouken@6690
   738
 */
slouken@6690
   739
SDL_GameController *
slouken@6690
   740
SDL_GameControllerOpen(int device_index)
slouken@6690
   741
{
slouken@6690
   742
    SDL_GameController *gamecontroller;
slouken@6690
   743
	SDL_GameController *gamecontrollerlist;
slouken@6690
   744
	ControllerMapping_t *pSupportedController = NULL;
slouken@6690
   745
slouken@6690
   746
    if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
slouken@6690
   747
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@6690
   748
        return (NULL);
slouken@6690
   749
    }
slouken@6690
   750
slouken@6690
   751
	gamecontrollerlist = SDL_gamecontrollers;
slouken@6690
   752
    // If the controller is already open, return it 
slouken@6690
   753
	while ( gamecontrollerlist )
slouken@6690
   754
	{
slouken@6690
   755
		if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) {
slouken@6690
   756
				gamecontroller = gamecontrollerlist;
slouken@6690
   757
				++gamecontroller->ref_count;
slouken@6690
   758
				return (gamecontroller);
slouken@6690
   759
		}
slouken@6690
   760
		gamecontrollerlist = gamecontrollerlist->next;
slouken@6690
   761
    }
slouken@6690
   762
slouken@6690
   763
    // Create and initialize the joystick 
slouken@6690
   764
    gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
slouken@6690
   765
    if (gamecontroller == NULL) {
slouken@6690
   766
        SDL_OutOfMemory();
slouken@6690
   767
        return NULL;
slouken@6690
   768
    }
slouken@6690
   769
slouken@6690
   770
	pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
slouken@6690
   771
	if ( !pSupportedController )
slouken@6690
   772
	{
slouken@6738
   773
		SDL_JoystickGUID jGUID;
slouken@6690
   774
slouken@6690
   775
		jGUID = SDL_JoystickGetDeviceGUID( device_index );
slouken@6690
   776
		pSupportedController = s_pSupportedControllers;
slouken@6690
   777
		while ( pSupportedController )
slouken@6690
   778
		{
slouken@6690
   779
			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
slouken@6690
   780
			{
slouken@6690
   781
				break;
slouken@6690
   782
			}
slouken@6690
   783
slouken@6690
   784
			pSupportedController = pSupportedController->next;
slouken@6690
   785
		}
slouken@6690
   786
	}
slouken@6690
   787
slouken@6690
   788
	if ( !pSupportedController )
slouken@6690
   789
	{
slouken@6690
   790
		SDL_SetError("Couldn't find mapping for device (%d)", device_index );
slouken@6690
   791
		return (NULL);
slouken@6690
   792
	}
slouken@6690
   793
slouken@6690
   794
    SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
slouken@6690
   795
    gamecontroller->joystick = SDL_JoystickOpen(device_index);
slouken@6690
   796
	if ( !gamecontroller->joystick ) {
slouken@6690
   797
        SDL_free(gamecontroller);
slouken@6690
   798
        return NULL;
slouken@6690
   799
    }
slouken@6690
   800
slouken@6690
   801
	SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping );
slouken@6690
   802
slouken@6690
   803
    // Add joystick to list 
slouken@6690
   804
    ++gamecontroller->ref_count;
slouken@6690
   805
	// Link the joystick in the list 
slouken@6690
   806
	gamecontroller->next = SDL_gamecontrollers;
slouken@6690
   807
	SDL_gamecontrollers = gamecontroller;
slouken@6690
   808
slouken@6690
   809
	SDL_SYS_JoystickUpdate( gamecontroller->joystick );
slouken@6690
   810
slouken@6690
   811
    return (gamecontroller);
slouken@6690
   812
}
slouken@6690
   813
slouken@6690
   814
slouken@6690
   815
/*
slouken@6690
   816
 * Get the current state of an axis control on a controller
slouken@6690
   817
 */
slouken@6690
   818
Sint16
slouken@6690
   819
SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis)
slouken@6690
   820
{
slouken@6690
   821
	if ( !gamecontroller )
slouken@6690
   822
		return 0;
slouken@6690
   823
slouken@6690
   824
	if (gamecontroller->mapping.axes[axis] >= 0 )
slouken@6690
   825
	{
slouken@6690
   826
		return ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) );
slouken@6690
   827
	}
slouken@6690
   828
	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
slouken@6690
   829
	{
slouken@6690
   830
		Uint8 value;
slouken@6690
   831
		value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] );
slouken@6690
   832
		if ( value > 0 )
slouken@6690
   833
			return 32767;
slouken@6690
   834
		return 0;
slouken@6690
   835
	}
slouken@6690
   836
	return 0;
slouken@6690
   837
}
slouken@6690
   838
slouken@6690
   839
slouken@6690
   840
/*
slouken@6690
   841
 * Get the current state of a button on a controller
slouken@6690
   842
 */
slouken@6690
   843
Uint8
slouken@6690
   844
SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button)
slouken@6690
   845
{
slouken@6690
   846
	if ( !gamecontroller )
slouken@6690
   847
		return 0;
slouken@6690
   848
slouken@6690
   849
	if ( gamecontroller->mapping.buttons[button] >= 0 )
slouken@6690
   850
	{
slouken@6690
   851
		return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) );
slouken@6690
   852
	}
slouken@6690
   853
	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
slouken@6690
   854
	{
slouken@6690
   855
		Sint16 value;
slouken@6690
   856
		value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] );
slouken@6690
   857
		if ( ABS(value) > 32768/2 )
slouken@6690
   858
			return 1;
slouken@6690
   859
		return 0;
slouken@6690
   860
	}
slouken@6690
   861
	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
slouken@6690
   862
	{
slouken@6690
   863
		Uint8 value;
slouken@6690
   864
		value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat );
slouken@6690
   865
		
slouken@6690
   866
		if ( value & gamecontroller->mapping.hatasbutton[button].mask )
slouken@6690
   867
			return 1;
slouken@6690
   868
		return 0;
slouken@6690
   869
	}
slouken@6690
   870
slouken@6690
   871
	return 0;
slouken@6690
   872
}
slouken@6690
   873
slouken@6690
   874
/*
slouken@6690
   875
 * Return if the joystick in question is currently attached to the system,
slouken@6690
   876
 *  \return 0 if not plugged in, 1 if still present.
slouken@6690
   877
 */
slouken@6690
   878
int
slouken@6690
   879
SDL_GameControllerGetAttached( SDL_GameController * gamecontroller )
slouken@6690
   880
{
slouken@6690
   881
	if ( !gamecontroller )
slouken@6690
   882
		return 0;
slouken@6690
   883
slouken@6690
   884
	return SDL_JoystickGetAttached(gamecontroller->joystick);
slouken@6690
   885
}
slouken@6690
   886
slouken@6690
   887
slouken@6690
   888
/*
slouken@6690
   889
 * Get the number of multi-dimensional axis controls on a joystick
slouken@6690
   890
 */
slouken@6690
   891
const char *
slouken@6690
   892
SDL_GameControllerName(SDL_GameController * gamecontroller)
slouken@6690
   893
{
slouken@6690
   894
	if ( !gamecontroller )
slouken@6690
   895
		return NULL;
slouken@6690
   896
slouken@6690
   897
    return (gamecontroller->mapping.name);
slouken@6690
   898
}
slouken@6690
   899
slouken@6690
   900
slouken@6690
   901
/*
slouken@6690
   902
 * Get the joystick for this controller
slouken@6690
   903
 */
slouken@6690
   904
SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
slouken@6690
   905
{
slouken@6690
   906
	if ( !gamecontroller )
slouken@6690
   907
		return NULL;
slouken@6690
   908
slouken@6690
   909
	return gamecontroller->joystick;
slouken@6690
   910
}
slouken@6690
   911
slouken@6690
   912
/**
slouken@6690
   913
 *  get the sdl joystick layer binding for this controller axi mapping
slouken@6690
   914
 */
slouken@6690
   915
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis( SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis )
slouken@6690
   916
{
slouken@6690
   917
	SDL_GameControllerButtonBind bind;
slouken@6690
   918
	SDL_memset( &bind, 0x0, sizeof(bind) );
slouken@6690
   919
slouken@6690
   920
	if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID )
slouken@6690
   921
		return bind;
slouken@6690
   922
slouken@6690
   923
	if (gamecontroller->mapping.axes[axis] >= 0 )
slouken@6690
   924
	{
slouken@6690
   925
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
slouken@6690
   926
		bind.button = gamecontroller->mapping.axes[axis];
slouken@6690
   927
	}
slouken@6690
   928
	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
slouken@6690
   929
	{
slouken@6690
   930
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
slouken@6690
   931
		bind.button = gamecontroller->mapping.buttonasaxis[axis];
slouken@6690
   932
	}
slouken@6690
   933
slouken@6690
   934
	return bind;
slouken@6690
   935
}
slouken@6690
   936
slouken@6690
   937
slouken@6690
   938
/**
slouken@6690
   939
 *  get the sdl joystick layer binding for this controller button mapping
slouken@6690
   940
 */
slouken@6690
   941
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton( SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button )
slouken@6690
   942
{
slouken@6690
   943
	SDL_GameControllerButtonBind bind;
slouken@6690
   944
	SDL_memset( &bind, 0x0, sizeof(bind) );
slouken@6690
   945
slouken@6690
   946
	if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID )
slouken@6690
   947
		return bind;
slouken@6690
   948
slouken@6690
   949
	if ( gamecontroller->mapping.buttons[button] >= 0 )
slouken@6690
   950
	{
slouken@6690
   951
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
slouken@6690
   952
		bind.button = gamecontroller->mapping.buttons[button];
slouken@6690
   953
	}
slouken@6690
   954
	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
slouken@6690
   955
	{
slouken@6690
   956
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
slouken@6690
   957
		bind.axis = gamecontroller->mapping.axesasbutton[button];
slouken@6690
   958
	}
slouken@6690
   959
	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
slouken@6690
   960
	{
slouken@6690
   961
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_HAT;
slouken@6690
   962
		bind.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
slouken@6690
   963
		bind.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
slouken@6690
   964
	}
slouken@6690
   965
slouken@6690
   966
	return bind;
slouken@6690
   967
}
slouken@6690
   968
slouken@6690
   969
slouken@6690
   970
/*
slouken@6690
   971
 * Close a joystick previously opened with SDL_JoystickOpen()
slouken@6690
   972
 */
slouken@6690
   973
void
slouken@6690
   974
SDL_GameControllerClose(SDL_GameController * gamecontroller)
slouken@6690
   975
{
slouken@6690
   976
	SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
slouken@6690
   977
slouken@6690
   978
	if ( !gamecontroller )
slouken@6690
   979
		return;
slouken@6690
   980
slouken@6690
   981
	// First decrement ref count 
slouken@6690
   982
    if (--gamecontroller->ref_count > 0) {
slouken@6690
   983
        return;
slouken@6690
   984
    }
slouken@6690
   985
slouken@6690
   986
	SDL_JoystickClose( gamecontroller->joystick );
slouken@6690
   987
	
slouken@6690
   988
	gamecontrollerlist = SDL_gamecontrollers;
slouken@6690
   989
	gamecontrollerlistprev = NULL;
slouken@6690
   990
	while ( gamecontrollerlist )
slouken@6690
   991
	{
slouken@6690
   992
		if (gamecontroller == gamecontrollerlist) 
slouken@6690
   993
		{
slouken@6690
   994
			if ( gamecontrollerlistprev )
slouken@6690
   995
			{
slouken@6690
   996
				// unlink this entry
slouken@6690
   997
				gamecontrollerlistprev->next = gamecontrollerlist->next;
slouken@6690
   998
			}
slouken@6690
   999
			else
slouken@6690
  1000
			{
slouken@6690
  1001
				SDL_gamecontrollers = gamecontroller->next;
slouken@6690
  1002
			}
slouken@6690
  1003
slouken@6690
  1004
			break;
slouken@6690
  1005
		}
slouken@6690
  1006
		gamecontrollerlistprev = gamecontrollerlist;
slouken@6690
  1007
		gamecontrollerlist = gamecontrollerlist->next;
slouken@6690
  1008
	}
slouken@6690
  1009
 
slouken@6690
  1010
    SDL_free(gamecontroller);
slouken@6690
  1011
}
slouken@6690
  1012
slouken@6690
  1013
slouken@6690
  1014
/*
slouken@6690
  1015
 * Quit the controller subsystem
slouken@6690
  1016
 */
slouken@6690
  1017
void
slouken@6690
  1018
SDL_GameControllerQuit(void)
slouken@6690
  1019
{
slouken@6690
  1020
	ControllerMapping_t *pControllerMap;
slouken@6690
  1021
	while ( SDL_gamecontrollers )
slouken@6690
  1022
	{
slouken@6690
  1023
		SDL_gamecontrollers->ref_count = 1;
slouken@6690
  1024
        SDL_GameControllerClose(SDL_gamecontrollers);
slouken@6690
  1025
 	}
slouken@6690
  1026
slouken@6690
  1027
	pControllerMap = s_pSupportedControllers;
slouken@6690
  1028
	while ( s_pSupportedControllers )
slouken@6690
  1029
	{
slouken@6690
  1030
		pControllerMap = s_pSupportedControllers;
slouken@6690
  1031
		s_pSupportedControllers = s_pSupportedControllers->next;
slouken@6690
  1032
		SDL_free( pControllerMap->name );
slouken@6690
  1033
		SDL_free( pControllerMap );
slouken@6690
  1034
	}
slouken@6690
  1035
slouken@6690
  1036
	SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL );
slouken@6690
  1037
slouken@6690
  1038
}
slouken@6690
  1039
slouken@6690
  1040
/*
slouken@6690
  1041
 * Event filter to transform joystick events into appropriate game controller ones
slouken@6690
  1042
 */
slouken@6690
  1043
int
slouken@6690
  1044
SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis, Sint16 value)
slouken@6690
  1045
{
slouken@6690
  1046
	int posted;
slouken@6690
  1047
slouken@6690
  1048
    /* translate the event, if desired */
slouken@6690
  1049
    posted = 0;
slouken@6690
  1050
#if !SDL_EVENTS_DISABLED
slouken@6690
  1051
    if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
slouken@6690
  1052
        SDL_Event event;
slouken@6690
  1053
        event.type = SDL_CONTROLLERAXISMOTION;
slouken@6690
  1054
        event.caxis.which = gamecontroller->joystick->instance_id;
slouken@6690
  1055
        event.caxis.axis = axis;
slouken@6690
  1056
        event.caxis.value = value;
slouken@6690
  1057
		posted = SDL_PushEvent(&event) == 1;
slouken@6690
  1058
    }
slouken@6690
  1059
#endif /* !SDL_EVENTS_DISABLED */
slouken@6690
  1060
    return (posted);
slouken@6690
  1061
}
slouken@6690
  1062
slouken@6690
  1063
slouken@6690
  1064
/*
slouken@6690
  1065
 * Event filter to transform joystick events into appropriate game controller ones
slouken@6690
  1066
 */
slouken@6690
  1067
int
slouken@6690
  1068
SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button, Uint8 state)
slouken@6690
  1069
{
slouken@6690
  1070
    int posted;
slouken@6690
  1071
#if !SDL_EVENTS_DISABLED
slouken@6690
  1072
	SDL_Event event;
slouken@6690
  1073
slouken@6690
  1074
    switch (state) {
slouken@6690
  1075
    case SDL_PRESSED:
slouken@6690
  1076
        event.type = SDL_CONTROLLERBUTTONDOWN;
slouken@6690
  1077
        break;
slouken@6690
  1078
    case SDL_RELEASED:
slouken@6690
  1079
        event.type = SDL_CONTROLLERBUTTONUP;
slouken@6690
  1080
        break;
slouken@6690
  1081
    default:
slouken@6690
  1082
        /* Invalid state -- bail */
slouken@6690
  1083
        return (0);
slouken@6690
  1084
    }
slouken@6690
  1085
#endif /* !SDL_EVENTS_DISABLED */
slouken@6690
  1086
slouken@6690
  1087
    /* translate the event, if desired */
slouken@6690
  1088
    posted = 0;
slouken@6690
  1089
#if !SDL_EVENTS_DISABLED
slouken@6690
  1090
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@6690
  1091
        event.cbutton.which = gamecontroller->joystick->instance_id;
slouken@6690
  1092
        event.cbutton.button = button;
slouken@6690
  1093
        event.cbutton.state = state;
slouken@6690
  1094
		posted = SDL_PushEvent(&event) == 1;
slouken@6690
  1095
    }
slouken@6690
  1096
#endif /* !SDL_EVENTS_DISABLED */
slouken@6690
  1097
    return (posted);
slouken@6690
  1098
}
slouken@6690
  1099
slouken@6690
  1100
/*
slouken@6690
  1101
 * Turn off controller events
slouken@6690
  1102
 */
slouken@6690
  1103
int
slouken@6690
  1104
SDL_GameControllerEventState(int state)
slouken@6690
  1105
{
slouken@6690
  1106
#if SDL_EVENTS_DISABLED
slouken@6690
  1107
    return SDL_IGNORE;
slouken@6690
  1108
#else
slouken@6690
  1109
    const Uint32 event_list[] = {
slouken@6690
  1110
        SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
slouken@6690
  1111
        SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED,
slouken@6690
  1112
    };
slouken@6690
  1113
    unsigned int i;
slouken@6690
  1114
slouken@6690
  1115
    switch (state) {
slouken@6690
  1116
    case SDL_QUERY:
slouken@6690
  1117
        state = SDL_IGNORE;
slouken@6690
  1118
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@6690
  1119
            state = SDL_EventState(event_list[i], SDL_QUERY);
slouken@6690
  1120
            if (state == SDL_ENABLE) {
slouken@6690
  1121
                break;
slouken@6690
  1122
            }
slouken@6690
  1123
        }
slouken@6690
  1124
        break;
slouken@6690
  1125
    default:
slouken@6690
  1126
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@6690
  1127
            SDL_EventState(event_list[i], state);
slouken@6690
  1128
        }
slouken@6690
  1129
        break;
slouken@6690
  1130
    }
slouken@6690
  1131
    return (state);
slouken@6690
  1132
#endif /* SDL_EVENTS_DISABLED */
slouken@6690
  1133
}
slouken@6690
  1134
slouken@6690
  1135
slouken@6690
  1136
/* vi: set ts=4 sw=4 expandtab: */