77#include <stdio.h>
88#include <string.h>
99
10+ /*
11+ * Stores the SDL game controller bindings associated with a mapping action.
12+ *
13+ * Unlike mapping_element, which describes a generic joystick input in terms of
14+ * this project's JOYSTICK_ELEMENT_* representation, controller_mapping keeps
15+ * the SDL_GameController-derived binding information returned by SDL for each
16+ * action so it can be translated into the internal mapping format.
17+ */
18+ typedef struct {
19+ /* Action that the listed controller bindings should trigger. */
20+ mapping_action action ;
21+ struct {
22+ /* SDL binding kind for this entry (button, axis, hat, etc.). */
23+ SDL_GameControllerBindType type ;
24+ /* SDL identifier for the bound control, such as axis/button index. */
25+ int id ;
26+ /* Direction or position associated with the binding when applicable. */
27+ int position ;
28+ } element [JOYSTICK_MAPPING_ELEMENTS_MAX ];
29+ } controller_mapping ;
30+
1031#ifdef __vita__
1132#include "platform/vita/pad.h"
1233
@@ -98,48 +119,165 @@ static mapping_element default_mapping[] = {
98119};
99120#endif
100121
122+ static controller_mapping controller_mappings [] = {
123+ {MAPPING_ACTION_MOUSE_CURSOR_UP , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_LEFTY , JOYSTICK_AXIS_NEGATIVE }}},
124+ {MAPPING_ACTION_MOUSE_CURSOR_LEFT , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_LEFTX , JOYSTICK_AXIS_NEGATIVE }}},
125+ {MAPPING_ACTION_MOUSE_CURSOR_DOWN , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_LEFTY , JOYSTICK_AXIS_POSITIVE }}},
126+ {MAPPING_ACTION_MOUSE_CURSOR_RIGHT , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_LEFTX , JOYSTICK_AXIS_POSITIVE }}},
127+ {MAPPING_ACTION_FASTER_MOUSE_CURSOR_SPEED , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_TRIGGERLEFT , JOYSTICK_AXIS_POSITIVE }}},
128+ {MAPPING_ACTION_SLOWER_MOUSE_CURSOR_SPEED , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_TRIGGERRIGHT , JOYSTICK_AXIS_POSITIVE }}},
129+ {MAPPING_ACTION_LEFT_MOUSE_BUTTON , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_A }}},
130+ {MAPPING_ACTION_RIGHT_MOUSE_BUTTON , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_B }}},
131+ {MAPPING_ACTION_SCROLL_WINDOW_UP , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_RIGHTY , JOYSTICK_AXIS_NEGATIVE }}},
132+ {MAPPING_ACTION_SCROLL_WINDOW_DOWN , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_RIGHTY , JOYSTICK_AXIS_POSITIVE }}},
133+ {MAPPING_ACTION_SCROLL_MAP_UP , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_RIGHTY , JOYSTICK_AXIS_NEGATIVE }}},
134+ {MAPPING_ACTION_SCROLL_MAP_LEFT , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_RIGHTX , JOYSTICK_AXIS_NEGATIVE }}},
135+ {MAPPING_ACTION_SCROLL_MAP_DOWN , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_RIGHTY , JOYSTICK_AXIS_POSITIVE }}},
136+ {MAPPING_ACTION_SCROLL_MAP_RIGHT , {{SDL_CONTROLLER_BINDTYPE_AXIS , SDL_CONTROLLER_AXIS_RIGHTX , JOYSTICK_AXIS_POSITIVE }}},
137+ {MAPPING_ACTION_ROTATE_MAP_LEFT , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_LEFTSHOULDER }}},
138+ {MAPPING_ACTION_ROTATE_MAP_RIGHT , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_RIGHTSHOULDER }}},
139+ {MAPPING_ACTION_INCREASE_GAME_SPEED , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_Y }}},
140+ {MAPPING_ACTION_DECREASE_GAME_SPEED , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_X }}},
141+ {MAPPING_ACTION_MOUSE_CURSOR_UP , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_DPAD_UP }}},
142+ {MAPPING_ACTION_MOUSE_CURSOR_LEFT , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_DPAD_LEFT }}},
143+ {MAPPING_ACTION_MOUSE_CURSOR_DOWN , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_DPAD_DOWN }}},
144+ {MAPPING_ACTION_MOUSE_CURSOR_RIGHT , {{SDL_CONTROLLER_BINDTYPE_BUTTON , SDL_CONTROLLER_BUTTON_DPAD_RIGHT }}}
145+ };
146+
147+ #define NUM_CONTROLLER_MAPPINGS (sizeof(controller_mappings) / sizeof(controller_mapping))
148+
101149static int use_joystick (void )
102150{
103- #if defined(__vita__ ) || defined(__SWITCH__ )
151+ #if defined(__vita__ ) || defined(__SWITCH__ ) || defined( __ANDROID__ )
104152 return 1 ;
105153#else
106154 return 0 ;
107155#endif
108156}
109157
110- static void create_new_model (const char * guid , const char * name , int instance_id )
158+ static joystick_hat_position convert_hat_position (int value )
159+ {
160+ joystick_hat_position position = JOYSTICK_HAT_CENTERED ;
161+ if (value & SDL_HAT_UP ) {
162+ position |= JOYSTICK_HAT_UP ;
163+ }
164+ if (value & SDL_HAT_DOWN ) {
165+ position |= JOYSTICK_HAT_DOWN ;
166+ }
167+ if (value & SDL_HAT_LEFT ) {
168+ position |= JOYSTICK_HAT_LEFT ;
169+ }
170+ if (value & SDL_HAT_RIGHT ) {
171+ position |= JOYSTICK_HAT_RIGHT ;
172+ }
173+ return position ;
174+ }
175+
176+ static void set_default_controller_mapping (joystick_model * model , SDL_GameController * controller )
177+ {
178+ for (int i = 0 ; i < NUM_CONTROLLER_MAPPINGS ; i ++ ) {
179+ const controller_mapping * mapping = & controller_mappings [i ];
180+ SDL_GameControllerButtonBind binds [JOYSTICK_MAPPING_ELEMENTS_MAX ] = { 0 };
181+ int bind_failed = 0 ;
182+ for (int j = 0 ; j < JOYSTICK_MAPPING_ELEMENTS_MAX ; j ++ ) {
183+ int has_bind = 0 ;
184+ if (mapping -> element [j ].type == SDL_CONTROLLER_BINDTYPE_AXIS ) {
185+ has_bind = 1 ;
186+ binds [j ] = SDL_GameControllerGetBindForAxis (controller , mapping -> element [j ].id );
187+ } else if (mapping -> element [j ].type == SDL_CONTROLLER_BINDTYPE_BUTTON ) {
188+ has_bind = 1 ;
189+ binds [j ] = SDL_GameControllerGetBindForButton (controller , mapping -> element [j ].id );
190+ }
191+ if (has_bind && binds [j ].bindType == SDL_CONTROLLER_BINDTYPE_NONE ) {
192+ bind_failed = 1 ;
193+ break ;
194+ }
195+ }
196+ if (bind_failed ) {
197+ continue ;
198+ }
199+ mapping_element * action = & model -> mapping [model -> num_mappings ];
200+ action -> action = mapping -> action ;
201+ for (int j = 0 ; j < JOYSTICK_MAPPING_ELEMENTS_MAX ; j ++ ) {
202+ switch (binds [j ].bindType ) {
203+ case SDL_CONTROLLER_BINDTYPE_AXIS :
204+ action -> element [j ].type = JOYSTICK_ELEMENT_AXIS ;
205+ action -> element [j ].id = binds [j ].value .axis ;
206+ action -> element [j ].position = mapping -> element [j ].position ;
207+ break ;
208+ case SDL_CONTROLLER_BINDTYPE_BUTTON :
209+ action -> element [j ].type = JOYSTICK_ELEMENT_BUTTON ;
210+ action -> element [j ].id = binds [j ].value .button ;
211+ break ;
212+ case SDL_CONTROLLER_BINDTYPE_HAT :
213+ action -> element [j ].type = JOYSTICK_ELEMENT_HAT ;
214+ action -> element [j ].id = binds [j ].value .hat .hat ;
215+ action -> element [j ].position = convert_hat_position (binds [j ].value .hat .hat_mask );
216+ break ;
217+ default :
218+ break ;
219+ }
220+ }
221+ model -> num_mappings ++ ;
222+ }
223+ }
224+
225+ static void create_new_model (const char * guid , const char * name , int instance_id , SDL_GameController * controller )
111226{
112227 joystick_model model ;
113228 memset (& model , 0 , sizeof (model ));
114- strncpy (model .guid , guid , JOYSTICK_MAX_GUID );
229+ snprintf (model .guid , JOYSTICK_MAX_GUID , "%s" , guid );
115230 if (!name ) {
116231 snprintf (model .name , JOYSTICK_MAX_NAME , "Joystick %d" , instance_id );
117232 } else {
118- strncpy (model .name , name , JOYSTICK_MAX_NAME - 1 );
233+ snprintf (model .name , JOYSTICK_MAX_NAME , "Joystick %s" , name );
119234 }
120- int size = sizeof (default_mapping );
121- if (size > sizeof (model .mapping )) {
122- size = sizeof (model .mapping );
235+ if (controller ) {
236+ set_default_controller_mapping (& model , controller );
237+ } else {
238+ size_t size = sizeof (default_mapping );
239+ if (size > sizeof (model .mapping )) {
240+ size = sizeof (model .mapping );
241+ }
242+ memcpy (model .mapping , default_mapping , size );
243+ model .num_mappings = (int ) (size / sizeof (mapping_element ));
123244 }
124- memcpy (model .mapping , default_mapping , size );
125- model .num_mappings = size / sizeof (mapping_element );
126245 joystick_add_model (& model );
127246}
128247
129248static void add_joystick (int index )
130249{
131- SDL_Joystick * joystick = SDL_JoystickOpen (index );
250+ SDL_GameController * controller = 0 ;
251+ SDL_Joystick * joystick = 0 ;
252+
253+ if (SDL_IsGameController (index )) {
254+ controller = SDL_GameControllerOpen (index );
255+ joystick = SDL_GameControllerGetJoystick (controller );
256+ SDL_Log ("Game controller found. Setting default gamepad mapping." );
257+ } else {
258+ joystick = SDL_JoystickOpen (index );
259+ }
132260 int instance_id = SDL_JoystickInstanceID (joystick );
133261 if (joystick_is_active (instance_id )) {
262+ if (controller ) {
263+ SDL_GameControllerClose (controller );
264+ } else {
265+ SDL_JoystickClose (joystick );
266+ }
134267 return ;
135268 }
269+
136270 static char guid [JOYSTICK_MAX_GUID ];
137271 SDL_JoystickGetGUIDString (SDL_JoystickGetGUID (joystick ), guid , JOYSTICK_MAX_GUID );
138272 if (!joystick_has_model (guid )) {
139- create_new_model (guid , SDL_JoystickName (joystick ), instance_id );
273+ create_new_model (guid , SDL_JoystickName (joystick ), instance_id , controller );
140274 }
141275 if (!joystick_add (instance_id , guid )) {
142- SDL_JoystickClose (joystick );
276+ if (controller ) {
277+ SDL_GameControllerClose (controller );
278+ } else {
279+ SDL_JoystickClose (joystick );
280+ }
143281 }
144282}
145283
@@ -148,23 +286,40 @@ static void remove_joystick(int instance_id)
148286 if (!joystick_is_active (instance_id )) {
149287 return ;
150288 }
289+ SDL_GameController * controller = 0 ;
151290 SDL_Joystick * joystick = 0 ;
152291#if SDL_VERSION_ATLEAST (2 , 0 , 4 )
153292 if (platform_sdl_version_at_least (2 , 0 , 4 )) {
154- joystick = SDL_JoystickFromInstanceID (instance_id );
293+ controller = SDL_GameControllerFromInstanceID (instance_id );
294+ if (!controller ) {
295+ joystick = SDL_JoystickFromInstanceID (instance_id );
296+ }
155297 } else {
156298#endif
157299 for (int i = 0 ; i < SDL_NumJoysticks (); ++ i ) {
158- SDL_Joystick * current_joystick = SDL_JoystickOpen (i );
159- if (SDL_JoystickInstanceID (current_joystick ) == instance_id ) {
160- joystick = current_joystick ;
161- break ;
300+ if (SDL_IsGameController (i )) {
301+ SDL_GameController * current_controller = SDL_GameControllerOpen (i );
302+ SDL_Joystick * current_joystick = SDL_GameControllerGetJoystick (current_controller );
303+ if (SDL_JoystickInstanceID (current_joystick ) == instance_id ) {
304+ controller = current_controller ;
305+ break ;
306+ }
307+ SDL_GameControllerClose (current_controller );
308+ } else {
309+ SDL_Joystick * current_joystick = SDL_JoystickOpen (i );
310+ if (SDL_JoystickInstanceID (current_joystick ) == instance_id ) {
311+ joystick = current_joystick ;
312+ break ;
313+ }
314+ SDL_JoystickClose (current_joystick );
162315 }
163316 }
164317#if SDL_VERSION_ATLEAST (2 , 0 , 4 )
165318 }
166319#endif
167- if (joystick ) {
320+ if (controller ) {
321+ SDL_GameControllerClose (controller );
322+ } else if (joystick ) {
168323 SDL_JoystickClose (joystick );
169324 }
170325 joystick_remove (instance_id );
@@ -216,20 +371,7 @@ void platform_joystick_handle_hat(SDL_JoyHatEvent *event)
216371 if (!use_joystick ()) {
217372 return ;
218373 }
219- joystick_hat_position position = JOYSTICK_HAT_CENTERED ;
220- if (event -> value & SDL_HAT_UP ) {
221- position |= JOYSTICK_HAT_UP ;
222- }
223- if (event -> value & SDL_HAT_DOWN ) {
224- position |= JOYSTICK_HAT_DOWN ;
225- }
226- if (event -> value & SDL_HAT_LEFT ) {
227- position |= JOYSTICK_HAT_LEFT ;
228- }
229- if (event -> value & SDL_HAT_RIGHT ) {
230- position |= JOYSTICK_HAT_RIGHT ;
231- }
232- joystick_update_element (event -> which , JOYSTICK_ELEMENT_HAT , event -> hat , position , 0 );
374+ joystick_update_element (event -> which , JOYSTICK_ELEMENT_HAT , event -> hat , convert_hat_position (event -> value ), 0 );
233375}
234376
235377void platform_joystick_handle_button (SDL_JoyButtonEvent * event , int is_down )
0 commit comments