@@ -151,6 +151,7 @@ typedef struct SDL_joylist_item
151
151
SDL_JoystickID device_instance ;
152
152
char * path ; // "/dev/input/event2" or whatever
153
153
char * name ; // "SideWinder 3D Pro" or whatever
154
+ char * driver ; // "xpad" or whatever
154
155
SDL_GUID guid ;
155
156
dev_t devnum ;
156
157
int steam_virtual_gamepad_slot ;
@@ -274,54 +275,54 @@ static bool GuessIsSensor(int fd)
274
275
return false;
275
276
}
276
277
277
- static bool IsJoystick (const char * path , int * fd , char * * name_return , Uint16 * vendor_return , Uint16 * product_return , SDL_GUID * guid )
278
+ static bool IsJoystick (const char * path , int * fd , char * * name_return , Uint16 * vendor_return , Uint16 * product_return , SDL_GUID * guid , char * * driver_return )
278
279
{
279
280
struct input_id inpid ;
280
- char * name ;
281
+ char * name = NULL ;
282
+ char * driver = NULL ;
281
283
char product_string [128 ];
282
284
int class = 0 ;
283
285
284
286
SDL_zero (inpid );
285
287
#ifdef SDL_USE_LIBUDEV
286
288
// Opening input devices can generate synchronous device I/O, so avoid it if we can
287
- if (SDL_UDEV_GetProductInfo (path , & inpid . vendor , & inpid . product , & inpid . version , & class ) &&
289
+ if (SDL_UDEV_GetProductInfo (path , & inpid , & class , & driver ) &&
288
290
!(class & SDL_UDEV_DEVICE_JOYSTICK )) {
289
- return false ;
291
+ goto error ;
290
292
}
291
293
#endif
292
294
293
295
if (fd && * fd < 0 ) {
294
296
* fd = open (path , O_RDONLY | O_CLOEXEC , 0 );
295
297
}
296
298
if (!fd || * fd < 0 ) {
297
- return false ;
299
+ goto error ;
298
300
}
299
301
300
302
if (ioctl (* fd , JSIOCGNAME (sizeof (product_string )), product_string ) <= 0 ) {
301
303
// When udev enumeration or classification, we only got joysticks here, so no need to test
302
304
if (enumeration_method != ENUMERATION_LIBUDEV && !class && !GuessIsJoystick (* fd )) {
303
- return false ;
305
+ goto error ;
304
306
}
305
307
306
308
// Could have vendor and product already from udev, but should agree with evdev
307
309
if (ioctl (* fd , EVIOCGID , & inpid ) < 0 ) {
308
- return false ;
310
+ goto error ;
309
311
}
310
312
311
313
if (ioctl (* fd , EVIOCGNAME (sizeof (product_string )), product_string ) < 0 ) {
312
- return false ;
314
+ goto error ;
313
315
}
314
316
}
315
317
316
318
name = SDL_CreateJoystickName (inpid .vendor , inpid .product , NULL , product_string );
317
319
if (!name ) {
318
- return false ;
320
+ goto error ;
319
321
}
320
322
321
323
if (!IsVirtualJoystick (inpid .vendor , inpid .product , inpid .version , name ) &&
322
324
SDL_JoystickHandledByAnotherDriver (& SDL_LINUX_JoystickDriver , inpid .vendor , inpid .product , inpid .version , name )) {
323
- SDL_free (name );
324
- return false;
325
+ goto error ;
325
326
}
326
327
327
328
FixupDeviceInfoForMapping (* fd , & inpid );
@@ -331,14 +332,23 @@ static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *ve
331
332
#endif
332
333
333
334
if (SDL_ShouldIgnoreJoystick (inpid .vendor , inpid .product , inpid .version , name )) {
334
- SDL_free (name );
335
- return false;
335
+ goto error ;
336
336
}
337
337
* name_return = name ;
338
+ * driver_return = driver ;
338
339
* vendor_return = inpid .vendor ;
339
340
* product_return = inpid .product ;
340
341
* guid = SDL_CreateJoystickGUID (inpid .bustype , inpid .vendor , inpid .product , inpid .version , NULL , product_string , 0 , 0 );
341
342
return true;
343
+
344
+ error :
345
+ if (driver ) {
346
+ SDL_free (driver );
347
+ }
348
+ if (name ) {
349
+ SDL_free (name );
350
+ }
351
+ return false;
342
352
}
343
353
344
354
static bool IsSensor (const char * path , int * fd )
@@ -349,7 +359,7 @@ static bool IsSensor(const char *path, int *fd)
349
359
SDL_zero (inpid );
350
360
#ifdef SDL_USE_LIBUDEV
351
361
// Opening input devices can generate synchronous device I/O, so avoid it if we can
352
- if (SDL_UDEV_GetProductInfo (path , & inpid . vendor , & inpid . product , & inpid . version , & class ) &&
362
+ if (SDL_UDEV_GetProductInfo (path , & inpid , & class , NULL ) &&
353
363
!(class & SDL_UDEV_DEVICE_ACCELEROMETER )) {
354
364
return false;
355
365
}
@@ -422,6 +432,9 @@ static void FreeJoylistItem(SDL_joylist_item *item)
422
432
SDL_free (item -> mapping );
423
433
SDL_free (item -> path );
424
434
SDL_free (item -> name );
435
+ if (item -> driver ) {
436
+ SDL_free (item -> driver );
437
+ }
425
438
SDL_free (item );
426
439
}
427
440
@@ -436,6 +449,7 @@ static void MaybeAddDevice(const char *path)
436
449
struct stat sb ;
437
450
int fd = -1 ;
438
451
char * name = NULL ;
452
+ char * driver = NULL ;
439
453
Uint16 vendor , product ;
440
454
SDL_GUID guid ;
441
455
SDL_joylist_item * item ;
@@ -473,7 +487,7 @@ static void MaybeAddDevice(const char *path)
473
487
SDL_Log ("Checking %s" , path );
474
488
#endif
475
489
476
- if (IsJoystick (path , & fd , & name , & vendor , & product , & guid )) {
490
+ if (IsJoystick (path , & fd , & name , & vendor , & product , & guid , & driver )) {
477
491
#ifdef DEBUG_INPUT_EVENTS
478
492
SDL_Log ("found joystick: %s" , path );
479
493
#endif
@@ -488,6 +502,7 @@ static void MaybeAddDevice(const char *path)
488
502
item -> path = SDL_strdup (path );
489
503
item -> name = name ;
490
504
item -> guid = guid ;
505
+ item -> driver = driver ;
491
506
492
507
if (vendor == USB_VENDOR_VALVE &&
493
508
product == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD ) {
@@ -861,7 +876,7 @@ static void LINUX_ScanSteamVirtualGamepads(void)
861
876
// Opening input devices can generate synchronous device I/O, so avoid it if we can
862
877
class = 0 ;
863
878
SDL_zero (inpid );
864
- if (SDL_UDEV_GetProductInfo (path , & inpid . vendor , & inpid . product , & inpid . version , & class ) &&
879
+ if (SDL_UDEV_GetProductInfo (path , & inpid , & class , NULL ) &&
865
880
(inpid .vendor != USB_VENDOR_VALVE || inpid .product != USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD )) {
866
881
free (entries [i ]); // This should NOT be SDL_free()
867
882
continue ;
@@ -2609,6 +2624,27 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
2609
2624
SDL_Log ("Mapped DPUP+DOWN to axis %d (ABS_HAT0Y)" , out -> dpup .target );
2610
2625
SDL_Log ("Mapped DPLEFT+RIGHT to axis %d (ABS_HAT0X)" , out -> dpleft .target );
2611
2626
#endif
2627
+ } else if (item -> driver && SDL_strcmp (item -> driver , "xpad" ) == 0 ) {
2628
+ // xpad will sometimes map the D-Pad as BTN_TRIGGER_HAPPY1 - BTN_TRIGGER_HAPPY4
2629
+ if (joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY1 ] &&
2630
+ joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY2 ] &&
2631
+ joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY3 ] &&
2632
+ joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY4 ]) {
2633
+ out -> dpleft .kind = EMappingKind_Button ;
2634
+ out -> dpright .kind = EMappingKind_Button ;
2635
+ out -> dpup .kind = EMappingKind_Button ;
2636
+ out -> dpdown .kind = EMappingKind_Button ;
2637
+ out -> dpleft .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY1 ];
2638
+ out -> dpright .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY2 ];
2639
+ out -> dpup .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY3 ];
2640
+ out -> dpdown .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY4 ];
2641
+ #ifdef DEBUG_GAMEPAD_MAPPING
2642
+ SDL_Log ("Mapped DPLEFT to button %d (BTN_TRIGGER_HAPPY1)" , out -> dpleft .target );
2643
+ SDL_Log ("Mapped DPRIGHT to button %d (BTN_TRIGGER_HAPPY2)" , out -> dpright .target );
2644
+ SDL_Log ("Mapped DPUP to button %d (BTN_TRIGGER_HAPPY3)" , out -> dpup .target );
2645
+ SDL_Log ("Mapped DPDOWN to button %d (BTN_TRIGGER_HAPPY4)" , out -> dpdown .target );
2646
+ #endif
2647
+ }
2612
2648
}
2613
2649
}
2614
2650
@@ -2653,7 +2689,7 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
2653
2689
#endif
2654
2690
}
2655
2691
2656
- if (SDL_GetJoystickVendor ( joystick ) == USB_VENDOR_MICROSOFT ) {
2692
+ if (item -> driver && SDL_strcmp ( item -> driver , "xpad" ) == 0 ) {
2657
2693
// The Xbox Elite controllers have the paddles as BTN_TRIGGER_HAPPY5 - BTN_TRIGGER_HAPPY8
2658
2694
if (joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY5 ] &&
2659
2695
joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY6 ] &&
@@ -2674,17 +2710,38 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
2674
2710
SDL_Log ("Mapped LEFT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY8)" , out -> left_paddle2 .target );
2675
2711
#endif
2676
2712
}
2677
-
2678
- // The Xbox Series X controllers have the Share button as KEY_RECORD
2679
- if (joystick -> hwdata -> has_key [KEY_RECORD ]) {
2680
- out -> misc1 .kind = EMappingKind_Button ;
2681
- out -> misc1 .target = joystick -> hwdata -> key_map [KEY_RECORD ];
2713
+ } else if (SDL_GetJoystickVendor (joystick ) == USB_VENDOR_MICROSOFT ) {
2714
+ // The Xbox Elite controllers have the paddles as BTN_TRIGGER_HAPPY1 - BTN_TRIGGER_HAPPY4
2715
+ if (joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY1 ] &&
2716
+ joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY2 ] &&
2717
+ joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY3 ] &&
2718
+ joystick -> hwdata -> has_key [BTN_TRIGGER_HAPPY4 ]) {
2719
+ out -> right_paddle1 .kind = EMappingKind_Button ;
2720
+ out -> right_paddle1 .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY1 ];
2721
+ out -> left_paddle1 .kind = EMappingKind_Button ;
2722
+ out -> left_paddle1 .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY2 ];
2723
+ out -> right_paddle2 .kind = EMappingKind_Button ;
2724
+ out -> right_paddle2 .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY3 ];
2725
+ out -> left_paddle2 .kind = EMappingKind_Button ;
2726
+ out -> left_paddle2 .target = joystick -> hwdata -> key_map [BTN_TRIGGER_HAPPY4 ];
2682
2727
#ifdef DEBUG_GAMEPAD_MAPPING
2683
- SDL_Log ("Mapped MISC1 to button %d (KEY_RECORD)" , out -> misc1 .target );
2728
+ SDL_Log ("Mapped RIGHT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY1)" , out -> right_paddle1 .target );
2729
+ SDL_Log ("Mapped LEFT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY2)" , out -> left_paddle1 .target );
2730
+ SDL_Log ("Mapped RIGHT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY3)" , out -> right_paddle2 .target );
2731
+ SDL_Log ("Mapped LEFT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY4)" , out -> left_paddle2 .target );
2684
2732
#endif
2685
2733
}
2686
2734
}
2687
2735
2736
+ // Xbox Series controllers have the Share button as KEY_RECORD
2737
+ if (joystick -> hwdata -> has_key [KEY_RECORD ]) {
2738
+ out -> misc1 .kind = EMappingKind_Button ;
2739
+ out -> misc1 .target = joystick -> hwdata -> key_map [KEY_RECORD ];
2740
+ #ifdef DEBUG_GAMEPAD_MAPPING
2741
+ SDL_Log ("Mapped MISC1 to button %d (KEY_RECORD)" , out -> misc1 .target );
2742
+ #endif
2743
+ }
2744
+
2688
2745
// Cache the mapping for later
2689
2746
item -> mapping = (SDL_GamepadMapping * )SDL_malloc (sizeof (* item -> mapping ));
2690
2747
if (item -> mapping ) {
0 commit comments