src/joystick/SDL_gamecontroller.c
author Sam Lantinga
Tue, 11 Dec 2012 12:16:28 -0800
changeset 6744 4ac2bb6dc80c
parent 6738 b408d5a406a3
child 6823 e9d312d26979
permissions -rw-r--r--
Fixed joystick GUID renaming for other platforms
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@6690
   521
	const char *pFirstComma = SDL_strchr( pMapping, ',' );
slouken@6690
   522
	const char *pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
slouken@6690
   523
	if ( pFirstComma && pSecondComma )
slouken@6690
   524
	{
slouken@6690
   525
		char *pchName = SDL_malloc( pSecondComma - pFirstComma );
slouken@6690
   526
		if ( !pchName )
slouken@6690
   527
		{
slouken@6690
   528
			SDL_OutOfMemory();
slouken@6690
   529
			return NULL;
slouken@6690
   530
		}
slouken@6690
   531
		SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma );
slouken@6690
   532
		pchName[ pSecondComma - pFirstComma - 1 ] = 0;
slouken@6690
   533
		return pchName;
slouken@6690
   534
	}
slouken@6690
   535
	return NULL;
slouken@6690
   536
}
slouken@6690
   537
slouken@6690
   538
slouken@6690
   539
/*
slouken@6690
   540
 * grab the button mapping string from a mapping string
slouken@6690
   541
 */
slouken@6690
   542
const char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
slouken@6690
   543
{
slouken@6690
   544
	const char *pFirstComma = SDL_strchr( pMapping, ',' );
slouken@6690
   545
	const char *pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
slouken@6690
   546
	if ( pSecondComma )
slouken@6690
   547
		return pSecondComma + 1; // mapping is everything after the 3rd comma, no need to malloc it
slouken@6690
   548
	else
slouken@6690
   549
		return NULL;
slouken@6690
   550
}
slouken@6690
   551
slouken@6690
   552
slouken@6690
   553
/*
slouken@6690
   554
 * Initialize the game controller system, mostly load our DB of controller config mappings
slouken@6690
   555
 */
slouken@6690
   556
int
slouken@6690
   557
SDL_GameControllerInit(void)
slouken@6690
   558
{
slouken@6690
   559
	int i = 0;
slouken@6690
   560
	const char *pMappingString = NULL;
slouken@6690
   561
	s_pSupportedControllers = NULL;
slouken@6690
   562
	pMappingString = s_ControllerMappings[i];
slouken@6690
   563
	while ( pMappingString )
slouken@6690
   564
	{
slouken@6690
   565
		ControllerMapping_t *pControllerMapping;
slouken@6690
   566
		char *pchGUID;
slouken@6690
   567
		char *pchName;
slouken@6690
   568
		const char *pchMapping;
slouken@6690
   569
		pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
slouken@6690
   570
		if ( !pControllerMapping )
slouken@6690
   571
		{
slouken@6690
   572
			SDL_OutOfMemory();
slouken@6690
   573
			return -1;
slouken@6690
   574
		}
slouken@6690
   575
slouken@6690
   576
		pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pMappingString );
slouken@6690
   577
		pchName = SDL_PrivateGetControllerNameFromMappingString( pMappingString );
slouken@6690
   578
		pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pMappingString );
slouken@6690
   579
		if ( pchGUID && pchName )
slouken@6690
   580
		{
slouken@6701
   581
#ifdef SDL_JOYSTICK_DINPUT
slouken@6690
   582
			if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
slouken@6690
   583
			{
slouken@6690
   584
				s_pXInputMapping = pControllerMapping;
slouken@6690
   585
			}
slouken@6690
   586
#endif
slouken@6690
   587
			pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
slouken@6690
   588
			pControllerMapping->name = pchName;
slouken@6690
   589
			pControllerMapping->mapping = pchMapping;
slouken@6690
   590
			pControllerMapping->next = s_pSupportedControllers;
slouken@6690
   591
			s_pSupportedControllers = pControllerMapping;
slouken@6690
   592
slouken@6690
   593
			SDL_free( pchGUID );
slouken@6690
   594
		}
slouken@6690
   595
slouken@6690
   596
		i++;
slouken@6690
   597
		pMappingString = s_ControllerMappings[i];
slouken@6690
   598
	}
slouken@6690
   599
slouken@6690
   600
	// load in any user supplied config
slouken@6690
   601
	{
slouken@6690
   602
		const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
slouken@6690
   603
		if ( hint && hint[0] )
slouken@6690
   604
		{
slouken@6690
   605
			int nchHints = SDL_strlen( hint );
slouken@6690
   606
			char *pUserMappings = SDL_malloc( nchHints + 1 );
slouken@6690
   607
			SDL_memcpy( pUserMappings, hint, nchHints );
slouken@6690
   608
			while ( pUserMappings )
slouken@6690
   609
			{
slouken@6690
   610
				char *pchGUID;
slouken@6690
   611
				char *pchName;
slouken@6690
   612
				const char *pchMapping;
slouken@6690
   613
				char *pchNewLine = NULL;
slouken@6690
   614
				ControllerMapping_t *pControllerMapping;
slouken@6690
   615
slouken@6690
   616
				pchNewLine = SDL_strchr( pUserMappings, '\n' );
slouken@6690
   617
				if ( pchNewLine )
slouken@6690
   618
					*pchNewLine = '\0';
slouken@6690
   619
slouken@6690
   620
				pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
slouken@6690
   621
				if ( !pControllerMapping )
slouken@6690
   622
				{
slouken@6690
   623
					SDL_OutOfMemory();
slouken@6690
   624
					return -1;
slouken@6690
   625
				}
slouken@6690
   626
slouken@6690
   627
				pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( pUserMappings );
slouken@6690
   628
				pchName = SDL_PrivateGetControllerNameFromMappingString( pUserMappings );
slouken@6690
   629
				pchMapping = SDL_PrivateGetControllerMappingFromMappingString( pUserMappings );
slouken@6690
   630
slouken@6690
   631
				if ( pchGUID && pchName )
slouken@6690
   632
				{
slouken@6701
   633
#ifdef SDL_JOYSTICK_DINPUT
slouken@6690
   634
					if ( !SDL_strcasecmp( pchGUID, "xinput" ) )
slouken@6690
   635
					{
slouken@6690
   636
						s_pXInputMapping = pControllerMapping;
slouken@6690
   637
					}
slouken@6690
   638
#endif
slouken@6690
   639
slouken@6690
   640
					pControllerMapping->guid = SDL_JoystickGetGUIDFromString( pchGUID );
slouken@6690
   641
					pControllerMapping->name = pchName;
slouken@6690
   642
					pControllerMapping->mapping = pchMapping;
slouken@6690
   643
					pControllerMapping->next = s_pSupportedControllers;
slouken@6690
   644
					s_pSupportedControllers = pControllerMapping;
slouken@6690
   645
slouken@6690
   646
					SDL_free( pchGUID );
slouken@6690
   647
				}
slouken@6690
   648
slouken@6690
   649
				if ( pchNewLine )
slouken@6690
   650
					pUserMappings = pchNewLine + 1;
slouken@6690
   651
				else
slouken@6690
   652
					pUserMappings = NULL;
slouken@6690
   653
			}
slouken@6690
   654
		}
slouken@6690
   655
	}
slouken@6690
   656
slouken@6690
   657
	/* watch for joy events and fire controller ones if needed */
slouken@6690
   658
	SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL );
slouken@6690
   659
	return (0);
slouken@6690
   660
}
slouken@6690
   661
slouken@6690
   662
slouken@6690
   663
/*
slouken@6690
   664
 * Get the implementation dependent name of a controller
slouken@6690
   665
 */
slouken@6690
   666
const char *
slouken@6690
   667
SDL_GameControllerNameForIndex(int device_index)
slouken@6690
   668
{
slouken@6690
   669
	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
slouken@6690
   670
	if ( pSupportedController )
slouken@6690
   671
	{
slouken@6690
   672
		return pSupportedController->name;
slouken@6690
   673
	}
slouken@6690
   674
	else
slouken@6690
   675
	{
slouken@6738
   676
		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
slouken@6690
   677
		pSupportedController = s_pSupportedControllers;
slouken@6690
   678
		while ( pSupportedController )
slouken@6690
   679
		{
slouken@6690
   680
			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
slouken@6690
   681
			{
slouken@6690
   682
				return pSupportedController->name;
slouken@6690
   683
			}
slouken@6690
   684
			pSupportedController = pSupportedController->next;
slouken@6690
   685
		}
slouken@6690
   686
	}
slouken@6690
   687
    return NULL;
slouken@6690
   688
}
slouken@6690
   689
slouken@6690
   690
slouken@6690
   691
/*
slouken@6690
   692
 * Return 1 if the joystick at this device index is a supported controller
slouken@6690
   693
 */
slouken@6690
   694
int SDL_IsGameController(int device_index)
slouken@6690
   695
{
slouken@6690
   696
	ControllerMapping_t *pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
slouken@6690
   697
	if ( pSupportedController )
slouken@6690
   698
	{
slouken@6690
   699
		return 1;
slouken@6690
   700
	}
slouken@6690
   701
	else
slouken@6690
   702
	{
slouken@6738
   703
		SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
slouken@6690
   704
		pSupportedController = s_pSupportedControllers;
slouken@6690
   705
		// debug code to help get the guid string for a new joystick
slouken@6738
   706
		/* char szGUID[33];
slouken@6738
   707
		SDL_JoystickGetGUIDString( jGUID, szGUID, sizeof(szGUID) );
slouken@6690
   708
		printf( "%s\n", pchGUID );
slouken@6690
   709
		SDL_free( pchGUID );*/
slouken@6690
   710
		while ( pSupportedController )
slouken@6690
   711
		{
slouken@6690
   712
			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
slouken@6690
   713
			{
slouken@6690
   714
				return 1;
slouken@6690
   715
			}
slouken@6690
   716
			pSupportedController = pSupportedController->next;
slouken@6690
   717
		}
slouken@6690
   718
	}
slouken@6690
   719
	return 0;
slouken@6690
   720
}
slouken@6690
   721
slouken@6690
   722
/*
slouken@6690
   723
 * Open a controller for use - the index passed as an argument refers to
slouken@6690
   724
 * the N'th controller on the system.  This index is the value which will
slouken@6690
   725
 * identify this controller in future controller events.
slouken@6690
   726
 *
slouken@6690
   727
 * This function returns a controller identifier, or NULL if an error occurred.
slouken@6690
   728
 */
slouken@6690
   729
SDL_GameController *
slouken@6690
   730
SDL_GameControllerOpen(int device_index)
slouken@6690
   731
{
slouken@6690
   732
    SDL_GameController *gamecontroller;
slouken@6690
   733
	SDL_GameController *gamecontrollerlist;
slouken@6690
   734
	ControllerMapping_t *pSupportedController = NULL;
slouken@6690
   735
slouken@6690
   736
    if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
slouken@6690
   737
        SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
slouken@6690
   738
        return (NULL);
slouken@6690
   739
    }
slouken@6690
   740
slouken@6690
   741
	gamecontrollerlist = SDL_gamecontrollers;
slouken@6690
   742
    // If the controller is already open, return it 
slouken@6690
   743
	while ( gamecontrollerlist )
slouken@6690
   744
	{
slouken@6690
   745
		if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) {
slouken@6690
   746
				gamecontroller = gamecontrollerlist;
slouken@6690
   747
				++gamecontroller->ref_count;
slouken@6690
   748
				return (gamecontroller);
slouken@6690
   749
		}
slouken@6690
   750
		gamecontrollerlist = gamecontrollerlist->next;
slouken@6690
   751
    }
slouken@6690
   752
slouken@6690
   753
    // Create and initialize the joystick 
slouken@6690
   754
    gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
slouken@6690
   755
    if (gamecontroller == NULL) {
slouken@6690
   756
        SDL_OutOfMemory();
slouken@6690
   757
        return NULL;
slouken@6690
   758
    }
slouken@6690
   759
slouken@6690
   760
	pSupportedController =  SDL_PrivateGetControllerMapping(device_index);
slouken@6690
   761
	if ( !pSupportedController )
slouken@6690
   762
	{
slouken@6738
   763
		SDL_JoystickGUID jGUID;
slouken@6690
   764
slouken@6690
   765
		jGUID = SDL_JoystickGetDeviceGUID( device_index );
slouken@6690
   766
		pSupportedController = s_pSupportedControllers;
slouken@6690
   767
		while ( pSupportedController )
slouken@6690
   768
		{
slouken@6690
   769
			if ( !SDL_memcmp( &jGUID, &pSupportedController->guid, sizeof(jGUID) ) )
slouken@6690
   770
			{
slouken@6690
   771
				break;
slouken@6690
   772
			}
slouken@6690
   773
slouken@6690
   774
			pSupportedController = pSupportedController->next;
slouken@6690
   775
		}
slouken@6690
   776
	}
slouken@6690
   777
slouken@6690
   778
	if ( !pSupportedController )
slouken@6690
   779
	{
slouken@6690
   780
		SDL_SetError("Couldn't find mapping for device (%d)", device_index );
slouken@6690
   781
		return (NULL);
slouken@6690
   782
	}
slouken@6690
   783
slouken@6690
   784
    SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
slouken@6690
   785
    gamecontroller->joystick = SDL_JoystickOpen(device_index);
slouken@6690
   786
	if ( !gamecontroller->joystick ) {
slouken@6690
   787
        SDL_free(gamecontroller);
slouken@6690
   788
        return NULL;
slouken@6690
   789
    }
slouken@6690
   790
slouken@6690
   791
	SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping );
slouken@6690
   792
slouken@6690
   793
    // Add joystick to list 
slouken@6690
   794
    ++gamecontroller->ref_count;
slouken@6690
   795
	// Link the joystick in the list 
slouken@6690
   796
	gamecontroller->next = SDL_gamecontrollers;
slouken@6690
   797
	SDL_gamecontrollers = gamecontroller;
slouken@6690
   798
slouken@6690
   799
	SDL_SYS_JoystickUpdate( gamecontroller->joystick );
slouken@6690
   800
slouken@6690
   801
    return (gamecontroller);
slouken@6690
   802
}
slouken@6690
   803
slouken@6690
   804
slouken@6690
   805
/*
slouken@6690
   806
 * Get the current state of an axis control on a controller
slouken@6690
   807
 */
slouken@6690
   808
Sint16
slouken@6690
   809
SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis)
slouken@6690
   810
{
slouken@6690
   811
	if ( !gamecontroller )
slouken@6690
   812
		return 0;
slouken@6690
   813
slouken@6690
   814
	if (gamecontroller->mapping.axes[axis] >= 0 )
slouken@6690
   815
	{
slouken@6690
   816
		return ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) );
slouken@6690
   817
	}
slouken@6690
   818
	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
slouken@6690
   819
	{
slouken@6690
   820
		Uint8 value;
slouken@6690
   821
		value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] );
slouken@6690
   822
		if ( value > 0 )
slouken@6690
   823
			return 32767;
slouken@6690
   824
		return 0;
slouken@6690
   825
	}
slouken@6690
   826
	return 0;
slouken@6690
   827
}
slouken@6690
   828
slouken@6690
   829
slouken@6690
   830
/*
slouken@6690
   831
 * Get the current state of a button on a controller
slouken@6690
   832
 */
slouken@6690
   833
Uint8
slouken@6690
   834
SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button)
slouken@6690
   835
{
slouken@6690
   836
	if ( !gamecontroller )
slouken@6690
   837
		return 0;
slouken@6690
   838
slouken@6690
   839
	if ( gamecontroller->mapping.buttons[button] >= 0 )
slouken@6690
   840
	{
slouken@6690
   841
		return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) );
slouken@6690
   842
	}
slouken@6690
   843
	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
slouken@6690
   844
	{
slouken@6690
   845
		Sint16 value;
slouken@6690
   846
		value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] );
slouken@6690
   847
		if ( ABS(value) > 32768/2 )
slouken@6690
   848
			return 1;
slouken@6690
   849
		return 0;
slouken@6690
   850
	}
slouken@6690
   851
	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
slouken@6690
   852
	{
slouken@6690
   853
		Uint8 value;
slouken@6690
   854
		value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat );
slouken@6690
   855
		
slouken@6690
   856
		if ( value & gamecontroller->mapping.hatasbutton[button].mask )
slouken@6690
   857
			return 1;
slouken@6690
   858
		return 0;
slouken@6690
   859
	}
slouken@6690
   860
slouken@6690
   861
	return 0;
slouken@6690
   862
}
slouken@6690
   863
slouken@6690
   864
/*
slouken@6690
   865
 * Return if the joystick in question is currently attached to the system,
slouken@6690
   866
 *  \return 0 if not plugged in, 1 if still present.
slouken@6690
   867
 */
slouken@6690
   868
int
slouken@6690
   869
SDL_GameControllerGetAttached( SDL_GameController * gamecontroller )
slouken@6690
   870
{
slouken@6690
   871
	if ( !gamecontroller )
slouken@6690
   872
		return 0;
slouken@6690
   873
slouken@6690
   874
	return SDL_JoystickGetAttached(gamecontroller->joystick);
slouken@6690
   875
}
slouken@6690
   876
slouken@6690
   877
slouken@6690
   878
/*
slouken@6690
   879
 * Get the number of multi-dimensional axis controls on a joystick
slouken@6690
   880
 */
slouken@6690
   881
const char *
slouken@6690
   882
SDL_GameControllerName(SDL_GameController * gamecontroller)
slouken@6690
   883
{
slouken@6690
   884
	if ( !gamecontroller )
slouken@6690
   885
		return NULL;
slouken@6690
   886
slouken@6690
   887
    return (gamecontroller->mapping.name);
slouken@6690
   888
}
slouken@6690
   889
slouken@6690
   890
slouken@6690
   891
/*
slouken@6690
   892
 * Get the joystick for this controller
slouken@6690
   893
 */
slouken@6690
   894
SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
slouken@6690
   895
{
slouken@6690
   896
	if ( !gamecontroller )
slouken@6690
   897
		return NULL;
slouken@6690
   898
slouken@6690
   899
	return gamecontroller->joystick;
slouken@6690
   900
}
slouken@6690
   901
slouken@6690
   902
/**
slouken@6690
   903
 *  get the sdl joystick layer binding for this controller axi mapping
slouken@6690
   904
 */
slouken@6690
   905
SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis( SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis )
slouken@6690
   906
{
slouken@6690
   907
	SDL_GameControllerButtonBind bind;
slouken@6690
   908
	SDL_memset( &bind, 0x0, sizeof(bind) );
slouken@6690
   909
slouken@6690
   910
	if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID )
slouken@6690
   911
		return bind;
slouken@6690
   912
slouken@6690
   913
	if (gamecontroller->mapping.axes[axis] >= 0 )
slouken@6690
   914
	{
slouken@6690
   915
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
slouken@6690
   916
		bind.button = gamecontroller->mapping.axes[axis];
slouken@6690
   917
	}
slouken@6690
   918
	else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
slouken@6690
   919
	{
slouken@6690
   920
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
slouken@6690
   921
		bind.button = gamecontroller->mapping.buttonasaxis[axis];
slouken@6690
   922
	}
slouken@6690
   923
slouken@6690
   924
	return bind;
slouken@6690
   925
}
slouken@6690
   926
slouken@6690
   927
slouken@6690
   928
/**
slouken@6690
   929
 *  get the sdl joystick layer binding for this controller button mapping
slouken@6690
   930
 */
slouken@6690
   931
SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton( SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button )
slouken@6690
   932
{
slouken@6690
   933
	SDL_GameControllerButtonBind bind;
slouken@6690
   934
	SDL_memset( &bind, 0x0, sizeof(bind) );
slouken@6690
   935
slouken@6690
   936
	if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID )
slouken@6690
   937
		return bind;
slouken@6690
   938
slouken@6690
   939
	if ( gamecontroller->mapping.buttons[button] >= 0 )
slouken@6690
   940
	{
slouken@6690
   941
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
slouken@6690
   942
		bind.button = gamecontroller->mapping.buttons[button];
slouken@6690
   943
	}
slouken@6690
   944
	else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
slouken@6690
   945
	{
slouken@6690
   946
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_AXIS;
slouken@6690
   947
		bind.axis = gamecontroller->mapping.axesasbutton[button];
slouken@6690
   948
	}
slouken@6690
   949
	else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
slouken@6690
   950
	{
slouken@6690
   951
		bind.m_eBindType = SDL_CONTROLLER_BINDTYPE_HAT;
slouken@6690
   952
		bind.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
slouken@6690
   953
		bind.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
slouken@6690
   954
	}
slouken@6690
   955
slouken@6690
   956
	return bind;
slouken@6690
   957
}
slouken@6690
   958
slouken@6690
   959
slouken@6690
   960
/*
slouken@6690
   961
 * Close a joystick previously opened with SDL_JoystickOpen()
slouken@6690
   962
 */
slouken@6690
   963
void
slouken@6690
   964
SDL_GameControllerClose(SDL_GameController * gamecontroller)
slouken@6690
   965
{
slouken@6690
   966
	SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
slouken@6690
   967
slouken@6690
   968
	if ( !gamecontroller )
slouken@6690
   969
		return;
slouken@6690
   970
slouken@6690
   971
	// First decrement ref count 
slouken@6690
   972
    if (--gamecontroller->ref_count > 0) {
slouken@6690
   973
        return;
slouken@6690
   974
    }
slouken@6690
   975
slouken@6690
   976
	SDL_JoystickClose( gamecontroller->joystick );
slouken@6690
   977
	
slouken@6690
   978
	gamecontrollerlist = SDL_gamecontrollers;
slouken@6690
   979
	gamecontrollerlistprev = NULL;
slouken@6690
   980
	while ( gamecontrollerlist )
slouken@6690
   981
	{
slouken@6690
   982
		if (gamecontroller == gamecontrollerlist) 
slouken@6690
   983
		{
slouken@6690
   984
			if ( gamecontrollerlistprev )
slouken@6690
   985
			{
slouken@6690
   986
				// unlink this entry
slouken@6690
   987
				gamecontrollerlistprev->next = gamecontrollerlist->next;
slouken@6690
   988
			}
slouken@6690
   989
			else
slouken@6690
   990
			{
slouken@6690
   991
				SDL_gamecontrollers = gamecontroller->next;
slouken@6690
   992
			}
slouken@6690
   993
slouken@6690
   994
			break;
slouken@6690
   995
		}
slouken@6690
   996
		gamecontrollerlistprev = gamecontrollerlist;
slouken@6690
   997
		gamecontrollerlist = gamecontrollerlist->next;
slouken@6690
   998
	}
slouken@6690
   999
 
slouken@6690
  1000
    SDL_free(gamecontroller);
slouken@6690
  1001
}
slouken@6690
  1002
slouken@6690
  1003
slouken@6690
  1004
/*
slouken@6690
  1005
 * Quit the controller subsystem
slouken@6690
  1006
 */
slouken@6690
  1007
void
slouken@6690
  1008
SDL_GameControllerQuit(void)
slouken@6690
  1009
{
slouken@6690
  1010
	ControllerMapping_t *pControllerMap;
slouken@6690
  1011
	while ( SDL_gamecontrollers )
slouken@6690
  1012
	{
slouken@6690
  1013
		SDL_gamecontrollers->ref_count = 1;
slouken@6690
  1014
        SDL_GameControllerClose(SDL_gamecontrollers);
slouken@6690
  1015
 	}
slouken@6690
  1016
slouken@6690
  1017
	pControllerMap = s_pSupportedControllers;
slouken@6690
  1018
	while ( s_pSupportedControllers )
slouken@6690
  1019
	{
slouken@6690
  1020
		pControllerMap = s_pSupportedControllers;
slouken@6690
  1021
		s_pSupportedControllers = s_pSupportedControllers->next;
slouken@6690
  1022
		SDL_free( pControllerMap->name );
slouken@6690
  1023
		SDL_free( pControllerMap );
slouken@6690
  1024
	}
slouken@6690
  1025
slouken@6690
  1026
	SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL );
slouken@6690
  1027
slouken@6690
  1028
}
slouken@6690
  1029
slouken@6690
  1030
/*
slouken@6690
  1031
 * Event filter to transform joystick events into appropriate game controller ones
slouken@6690
  1032
 */
slouken@6690
  1033
int
slouken@6690
  1034
SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_CONTROLLER_AXIS axis, Sint16 value)
slouken@6690
  1035
{
slouken@6690
  1036
	int posted;
slouken@6690
  1037
slouken@6690
  1038
    /* translate the event, if desired */
slouken@6690
  1039
    posted = 0;
slouken@6690
  1040
#if !SDL_EVENTS_DISABLED
slouken@6690
  1041
    if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
slouken@6690
  1042
        SDL_Event event;
slouken@6690
  1043
        event.type = SDL_CONTROLLERAXISMOTION;
slouken@6690
  1044
        event.caxis.which = gamecontroller->joystick->instance_id;
slouken@6690
  1045
        event.caxis.axis = axis;
slouken@6690
  1046
        event.caxis.value = value;
slouken@6690
  1047
		posted = SDL_PushEvent(&event) == 1;
slouken@6690
  1048
    }
slouken@6690
  1049
#endif /* !SDL_EVENTS_DISABLED */
slouken@6690
  1050
    return (posted);
slouken@6690
  1051
}
slouken@6690
  1052
slouken@6690
  1053
slouken@6690
  1054
/*
slouken@6690
  1055
 * Event filter to transform joystick events into appropriate game controller ones
slouken@6690
  1056
 */
slouken@6690
  1057
int
slouken@6690
  1058
SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_CONTROLLER_BUTTON button, Uint8 state)
slouken@6690
  1059
{
slouken@6690
  1060
    int posted;
slouken@6690
  1061
#if !SDL_EVENTS_DISABLED
slouken@6690
  1062
	SDL_Event event;
slouken@6690
  1063
slouken@6690
  1064
    switch (state) {
slouken@6690
  1065
    case SDL_PRESSED:
slouken@6690
  1066
        event.type = SDL_CONTROLLERBUTTONDOWN;
slouken@6690
  1067
        break;
slouken@6690
  1068
    case SDL_RELEASED:
slouken@6690
  1069
        event.type = SDL_CONTROLLERBUTTONUP;
slouken@6690
  1070
        break;
slouken@6690
  1071
    default:
slouken@6690
  1072
        /* Invalid state -- bail */
slouken@6690
  1073
        return (0);
slouken@6690
  1074
    }
slouken@6690
  1075
#endif /* !SDL_EVENTS_DISABLED */
slouken@6690
  1076
slouken@6690
  1077
    /* translate the event, if desired */
slouken@6690
  1078
    posted = 0;
slouken@6690
  1079
#if !SDL_EVENTS_DISABLED
slouken@6690
  1080
    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@6690
  1081
        event.cbutton.which = gamecontroller->joystick->instance_id;
slouken@6690
  1082
        event.cbutton.button = button;
slouken@6690
  1083
        event.cbutton.state = state;
slouken@6690
  1084
		posted = SDL_PushEvent(&event) == 1;
slouken@6690
  1085
    }
slouken@6690
  1086
#endif /* !SDL_EVENTS_DISABLED */
slouken@6690
  1087
    return (posted);
slouken@6690
  1088
}
slouken@6690
  1089
slouken@6690
  1090
/*
slouken@6690
  1091
 * Turn off controller events
slouken@6690
  1092
 */
slouken@6690
  1093
int
slouken@6690
  1094
SDL_GameControllerEventState(int state)
slouken@6690
  1095
{
slouken@6690
  1096
#if SDL_EVENTS_DISABLED
slouken@6690
  1097
    return SDL_IGNORE;
slouken@6690
  1098
#else
slouken@6690
  1099
    const Uint32 event_list[] = {
slouken@6690
  1100
        SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
slouken@6690
  1101
        SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED,
slouken@6690
  1102
    };
slouken@6690
  1103
    unsigned int i;
slouken@6690
  1104
slouken@6690
  1105
    switch (state) {
slouken@6690
  1106
    case SDL_QUERY:
slouken@6690
  1107
        state = SDL_IGNORE;
slouken@6690
  1108
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@6690
  1109
            state = SDL_EventState(event_list[i], SDL_QUERY);
slouken@6690
  1110
            if (state == SDL_ENABLE) {
slouken@6690
  1111
                break;
slouken@6690
  1112
            }
slouken@6690
  1113
        }
slouken@6690
  1114
        break;
slouken@6690
  1115
    default:
slouken@6690
  1116
        for (i = 0; i < SDL_arraysize(event_list); ++i) {
slouken@6690
  1117
            SDL_EventState(event_list[i], state);
slouken@6690
  1118
        }
slouken@6690
  1119
        break;
slouken@6690
  1120
    }
slouken@6690
  1121
    return (state);
slouken@6690
  1122
#endif /* SDL_EVENTS_DISABLED */
slouken@6690
  1123
}
slouken@6690
  1124
slouken@6690
  1125
slouken@6690
  1126
/* vi: set ts=4 sw=4 expandtab: */