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