|
|
|
@ -231,6 +231,78 @@ static BOOL IsControllerBackboneOne(GCController *controller)
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
static BOOL IsControllerSiriRemote(GCController *controller)
|
|
|
|
|
{
|
|
|
|
|
if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
|
|
|
|
|
if ([controller.productCategory hasPrefix:@"Siri Remote"]) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL ElementAlreadyHandled(NSString *element, NSDictionary<NSString *, GCControllerElement *> *elements)
|
|
|
|
|
{
|
|
|
|
|
if ([element isEqualToString:@"Left Thumbstick Left"] ||
|
|
|
|
|
[element isEqualToString:@"Left Thumbstick Right"]) {
|
|
|
|
|
if (elements[@"Left Thumbstick X Axis"]) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ([element isEqualToString:@"Left Thumbstick Up"] ||
|
|
|
|
|
[element isEqualToString:@"Left Thumbstick Down"]) {
|
|
|
|
|
if (elements[@"Left Thumbstick Y Axis"]) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ([element isEqualToString:@"Right Thumbstick Left"] ||
|
|
|
|
|
[element isEqualToString:@"Right Thumbstick Right"]) {
|
|
|
|
|
if (elements[@"Right Thumbstick X Axis"]) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ([element isEqualToString:@"Right Thumbstick Up"] ||
|
|
|
|
|
[element isEqualToString:@"Right Thumbstick Down"]) {
|
|
|
|
|
if (elements[@"Right Thumbstick Y Axis"]) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ([element isEqualToString:@"Direction Pad X Axis"]) {
|
|
|
|
|
if (elements[@"Direction Pad Left"] &&
|
|
|
|
|
elements[@"Direction Pad Right"]) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ([element isEqualToString:@"Direction Pad Y Axis"]) {
|
|
|
|
|
if (elements[@"Direction Pad Up"] &&
|
|
|
|
|
elements[@"Direction Pad Down"]) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ([element isEqualToString:@"Touchpad 1 X Axis"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 1 Y Axis"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 1 Left"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 1 Right"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 1 Up"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 1 Down"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 2 X Axis"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 2 Y Axis"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 2 Left"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 2 Right"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 2 Up"] ||
|
|
|
|
|
[element isEqualToString:@"Touchpad 2 Down"]) {
|
|
|
|
|
/* The touchpad is handled separately */
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
#if TARGET_OS_TV
|
|
|
|
|
if ([element isEqualToString:GCInputButtonHome]) {
|
|
|
|
|
/* The OS uses the home button, it's not available to apps */
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
|
|
|
|
|
{
|
|
|
|
|
Uint16 vendor = 0;
|
|
|
|
@ -259,13 +331,20 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
device->name = SDL_CreateJoystickName(0, 0, NULL, name);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_CONTROLLER_PROFILE
|
|
|
|
|
NSLog(@"Product name: %@\n", controller.vendorName);
|
|
|
|
|
NSLog(@"Product category: %@\n", controller.productCategory);
|
|
|
|
|
NSLog(@"Elements available:\n");
|
|
|
|
|
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
|
|
|
|
if (controller.physicalInputProfile) {
|
|
|
|
|
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
|
|
|
|
for (id key in controller.physicalInputProfile.buttons) {
|
|
|
|
|
NSLog(@"Button %@ available\n", key);
|
|
|
|
|
NSLog(@"\tButton: %@ (%s)\n", key, elements[key].analog ? "analog" : "digital");
|
|
|
|
|
}
|
|
|
|
|
for (id key in controller.physicalInputProfile.axes) {
|
|
|
|
|
NSLog(@"Axis %@ available\n", key);
|
|
|
|
|
NSLog(@"\tAxis: %@\n", key);
|
|
|
|
|
}
|
|
|
|
|
for (id key in controller.physicalInputProfile.dpads) {
|
|
|
|
|
NSLog(@"\tHat: %@\n", key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -297,6 +376,21 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
(void)is_switch_joyconL;
|
|
|
|
|
(void)is_switch_joyconR;
|
|
|
|
|
#endif
|
|
|
|
|
device->is_siri_remote = IsControllerSiriRemote(controller);
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
|
|
|
|
|
if (controller.physicalInputProfile.buttons[GCInputDualShockTouchpadButton] != nil) {
|
|
|
|
|
device->has_dualshock_touchpad = SDL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (controller.physicalInputProfile.buttons[GCInputXboxPaddleOne] != nil) {
|
|
|
|
|
device->has_xbox_paddles = SDL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (controller.physicalInputProfile.buttons[GCInputXboxShareButton] != nil) {
|
|
|
|
|
device->has_xbox_share_button = SDL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif // ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
|
|
|
|
|
if (is_backbone_one) {
|
|
|
|
|
vendor = USB_VENDOR_BACKBONE;
|
|
|
|
@ -305,21 +399,17 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
} else {
|
|
|
|
|
product = USB_PRODUCT_BACKBONE_ONE_IOS;
|
|
|
|
|
}
|
|
|
|
|
subtype = 0;
|
|
|
|
|
} else if (is_xbox) {
|
|
|
|
|
vendor = USB_VENDOR_MICROSOFT;
|
|
|
|
|
if (device->has_xbox_paddles) {
|
|
|
|
|
/* Assume Xbox One Elite Series 2 Controller unless/until GCController flows VID/PID */
|
|
|
|
|
product = USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH;
|
|
|
|
|
subtype = 1;
|
|
|
|
|
} else if (device->has_xbox_share_button) {
|
|
|
|
|
/* Assume Xbox Series X Controller unless/until GCController flows VID/PID */
|
|
|
|
|
product = USB_PRODUCT_XBOX_SERIES_X_BLE;
|
|
|
|
|
subtype = 1;
|
|
|
|
|
} else {
|
|
|
|
|
/* Assume Xbox One S Bluetooth Controller unless/until GCController flows VID/PID */
|
|
|
|
|
product = USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH;
|
|
|
|
|
subtype = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (is_ps4) {
|
|
|
|
|
/* Assume DS4 Slim unless/until GCController flows VID/PID */
|
|
|
|
@ -327,29 +417,32 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
product = USB_PRODUCT_SONY_DS4_SLIM;
|
|
|
|
|
if (device->has_dualshock_touchpad) {
|
|
|
|
|
subtype = 1;
|
|
|
|
|
} else {
|
|
|
|
|
subtype = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (is_ps5) {
|
|
|
|
|
vendor = USB_VENDOR_SONY;
|
|
|
|
|
product = USB_PRODUCT_SONY_DS5;
|
|
|
|
|
subtype = 0;
|
|
|
|
|
} else if (is_switch_pro) {
|
|
|
|
|
vendor = USB_VENDOR_NINTENDO;
|
|
|
|
|
product = USB_PRODUCT_NINTENDO_SWITCH_PRO;
|
|
|
|
|
subtype = 0;
|
|
|
|
|
device->has_nintendo_buttons = SDL_TRUE;
|
|
|
|
|
} else if (is_switch_joycon_pair) {
|
|
|
|
|
vendor = USB_VENDOR_NINTENDO;
|
|
|
|
|
product = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
|
|
|
|
|
subtype = 0;
|
|
|
|
|
device->has_nintendo_buttons = SDL_TRUE;
|
|
|
|
|
} else if (is_switch_joyconL) {
|
|
|
|
|
vendor = USB_VENDOR_NINTENDO;
|
|
|
|
|
product = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT;
|
|
|
|
|
subtype = 0;
|
|
|
|
|
device->is_single_joycon = SDL_TRUE;
|
|
|
|
|
} else if (is_switch_joyconR) {
|
|
|
|
|
vendor = USB_VENDOR_NINTENDO;
|
|
|
|
|
product = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT;
|
|
|
|
|
subtype = 0;
|
|
|
|
|
device->is_single_joycon = SDL_TRUE;
|
|
|
|
|
#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
} else if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
|
|
|
|
|
vendor = USB_VENDOR_APPLE;
|
|
|
|
|
product = 4;
|
|
|
|
|
subtype = 4;
|
|
|
|
|
#endif
|
|
|
|
|
} else if (controller.extendedGamepad) {
|
|
|
|
|
vendor = USB_VENDOR_APPLE;
|
|
|
|
|
product = 1;
|
|
|
|
@ -363,12 +456,6 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
vendor = USB_VENDOR_APPLE;
|
|
|
|
|
product = 3;
|
|
|
|
|
subtype = 3;
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
} else if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
|
|
|
|
|
vendor = USB_VENDOR_APPLE;
|
|
|
|
|
product = 4;
|
|
|
|
|
subtype = 4;
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
vendor = USB_VENDOR_APPLE;
|
|
|
|
@ -376,6 +463,61 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
subtype = 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
|
|
|
|
|
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
|
|
|
|
|
|
|
|
|
/* Provide both axes and analog buttons as SDL axes */
|
|
|
|
|
device->use_physical_profile = SDL_TRUE;
|
|
|
|
|
device->axes = [[[elements allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
|
|
|
|
|
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
|
|
|
|
|
if (ElementAlreadyHandled((NSString *)object, elements)) {
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GCControllerElement *element = elements[object];
|
|
|
|
|
if (element.analog) {
|
|
|
|
|
if ([element isKindOfClass:[GCControllerAxisInput class]] ||
|
|
|
|
|
[element isKindOfClass:[GCControllerButtonInput class]]) {
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}]];
|
|
|
|
|
device->naxes = device->axes.count;
|
|
|
|
|
device->buttons = [[[elements allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]
|
|
|
|
|
filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
|
|
|
|
|
if (ElementAlreadyHandled((NSString *)object, elements)) {
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GCControllerElement *element = elements[object];
|
|
|
|
|
if ([element isKindOfClass:[GCControllerButtonInput class]]) {
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}]];
|
|
|
|
|
device->nbuttons = device->buttons.count;
|
|
|
|
|
subtype = 4;
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_CONTROLLER_PROFILE
|
|
|
|
|
NSLog(@"Elements used:\n", controller.vendorName);
|
|
|
|
|
for (id key in device->buttons) {
|
|
|
|
|
NSLog(@"\tButton: %@ (%s)\n", key, elements[key].analog ? "analog" : "digital");
|
|
|
|
|
}
|
|
|
|
|
for (id key in device->axes) {
|
|
|
|
|
NSLog(@"\tAxis: %@\n", key);
|
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG_CONTROLLER_PROFILE */
|
|
|
|
|
|
|
|
|
|
#if TARGET_OS_TV
|
|
|
|
|
/* tvOS turns the menu button into a system gesture, so we grab it here instead */
|
|
|
|
|
if (elements[GCInputButtonMenu] && !elements[GCInputButtonHome]) {
|
|
|
|
|
device->pause_button_index = [device->buttons indexOfObject:GCInputButtonMenu];
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
} else
|
|
|
|
|
#endif
|
|
|
|
|
if (controller.extendedGamepad) {
|
|
|
|
|
GCExtendedGamepad *gamepad = controller.extendedGamepad;
|
|
|
|
|
int nbuttons = 0;
|
|
|
|
@ -415,12 +557,12 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
|
|
|
|
|
has_direct_menu = [gamepad respondsToSelector:@selector(buttonMenu)] && gamepad.buttonMenu;
|
|
|
|
|
if (!has_direct_menu) {
|
|
|
|
|
device->uses_pause_handler = SDL_TRUE;
|
|
|
|
|
device->pause_button_index = (nbuttons - 1);
|
|
|
|
|
}
|
|
|
|
|
#if TARGET_OS_TV
|
|
|
|
|
/* The single menu button isn't very reliable, at least as of tvOS 16.1 */
|
|
|
|
|
if ((device->button_mask & (1 << SDL_GAMEPAD_BUTTON_BACK)) == 0) {
|
|
|
|
|
device->uses_pause_handler = SDL_TRUE;
|
|
|
|
|
device->pause_button_index = (nbuttons - 1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
@ -437,15 +579,13 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
++nbuttons;
|
|
|
|
|
}
|
|
|
|
|
if (controller.physicalInputProfile.buttons[GCInputXboxPaddleTwo] != nil) {
|
|
|
|
|
/* TODO: Is this right? SDL_gamepad.h says P2 is the lower right */
|
|
|
|
|
device->has_xbox_paddles = SDL_TRUE;
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_LEFT_PADDLE1);
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2);
|
|
|
|
|
++nbuttons;
|
|
|
|
|
}
|
|
|
|
|
if (controller.physicalInputProfile.buttons[GCInputXboxPaddleThree] != nil) {
|
|
|
|
|
/* TODO: Is this right? SDL_gamepad.h says P3 is the upper left */
|
|
|
|
|
device->has_xbox_paddles = SDL_TRUE;
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2);
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_LEFT_PADDLE1);
|
|
|
|
|
++nbuttons;
|
|
|
|
|
}
|
|
|
|
|
if (controller.physicalInputProfile.buttons[GCInputXboxPaddleFour] != nil) {
|
|
|
|
@ -485,14 +625,9 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_NORTH);
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_LEFT_SHOULDER);
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER);
|
|
|
|
|
#if TARGET_OS_TV
|
|
|
|
|
/* The menu button is used by the OS and not available to applications */
|
|
|
|
|
nbuttons += 6;
|
|
|
|
|
#else
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_START);
|
|
|
|
|
nbuttons += 7;
|
|
|
|
|
device->uses_pause_handler = SDL_TRUE;
|
|
|
|
|
#endif
|
|
|
|
|
device->pause_button_index = (nbuttons - 1);
|
|
|
|
|
|
|
|
|
|
device->naxes = 0; /* no traditional analog inputs */
|
|
|
|
|
device->nhats = 1; /* d-pad */
|
|
|
|
@ -504,11 +639,9 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_SOUTH);
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_EAST); /* Button X on microGamepad */
|
|
|
|
|
nbuttons += 2;
|
|
|
|
|
|
|
|
|
|
device->button_mask |= (1 << SDL_GAMEPAD_BUTTON_START);
|
|
|
|
|
++nbuttons;
|
|
|
|
|
device->uses_pause_handler = SDL_TRUE;
|
|
|
|
|
nbuttons += 3;
|
|
|
|
|
device->pause_button_index = (nbuttons - 1);
|
|
|
|
|
|
|
|
|
|
device->naxes = 2; /* treat the touch surface as two axes */
|
|
|
|
|
device->nhats = 0; /* apparently the touch surface-as-dpad is buggy */
|
|
|
|
@ -516,35 +649,32 @@ static BOOL IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
|
|
|
|
|
|
|
|
|
controller.microGamepad.allowsRotation = SDL_GetHintBoolean(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, SDL_FALSE);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
else if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
|
|
|
|
|
device->use_physical_profile = SDL_TRUE;
|
|
|
|
|
device->axes = [controller.physicalInputProfile.axes allKeys];
|
|
|
|
|
device->naxes = controller.physicalInputProfile.axes.count;
|
|
|
|
|
device->dpads = [controller.physicalInputProfile.dpads allKeys];
|
|
|
|
|
device->nhats = controller.physicalInputProfile.dpads.count;
|
|
|
|
|
device->buttons = [controller.physicalInputProfile.buttons allKeys];
|
|
|
|
|
device->nbuttons = controller.physicalInputProfile.buttons.count;
|
|
|
|
|
subtype = 4;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
else {
|
|
|
|
|
/* We can't detect any inputs on this */
|
|
|
|
|
return SDL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Uint16 signature;
|
|
|
|
|
if (device->use_physical_profile) {
|
|
|
|
|
signature = 0;
|
|
|
|
|
signature = SDL_crc16(signature, device->name, SDL_strlen(device->name));
|
|
|
|
|
for (id key in device->axes) {
|
|
|
|
|
const char *string = ((NSString *)key).UTF8String;
|
|
|
|
|
signature = SDL_crc16(signature, string, SDL_strlen(string));
|
|
|
|
|
}
|
|
|
|
|
for (id key in device->buttons) {
|
|
|
|
|
const char *string = ((NSString *)key).UTF8String;
|
|
|
|
|
signature = SDL_crc16(signature, string, SDL_strlen(string));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
signature = device->button_mask;
|
|
|
|
|
}
|
|
|
|
|
if (vendor == USB_VENDOR_APPLE) {
|
|
|
|
|
/* Note that this is an MFI controller and what subtype it is */
|
|
|
|
|
device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, 0, name, 'm', subtype);
|
|
|
|
|
device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, signature, name, 'm', subtype);
|
|
|
|
|
} else {
|
|
|
|
|
device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, 0, name, 0, subtype);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Update the GUID with capability bits */
|
|
|
|
|
{
|
|
|
|
|
Uint16 *guid16 = (Uint16 *)device->guid.data;
|
|
|
|
|
guid16[6] = SDL_SwapLE16(device->button_mask);
|
|
|
|
|
device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, signature, name, 0, subtype);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This will be set when the first button press of the controller is
|
|
|
|
@ -582,6 +712,7 @@ static void IOS_AddJoystickDevice(GCController *controller, SDL_bool acceleromet
|
|
|
|
|
|
|
|
|
|
device->accelerometer = accelerometer;
|
|
|
|
|
device->instance_id = SDL_GetNextObjectID();
|
|
|
|
|
device->pause_button_index = -1;
|
|
|
|
|
|
|
|
|
|
if (accelerometer) {
|
|
|
|
|
#ifdef SDL_JOYSTICK_iOS_ACCELEROMETER
|
|
|
|
@ -864,11 +995,11 @@ static int IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
|
|
|
|
#endif
|
|
|
|
|
} else {
|
|
|
|
|
#ifdef SDL_JOYSTICK_MFI
|
|
|
|
|
if (device->uses_pause_handler) {
|
|
|
|
|
if (device->pause_button_index >= 0) {
|
|
|
|
|
GCController *controller = device->controller;
|
|
|
|
|
controller.controllerPausedHandler = ^(GCController *c) {
|
|
|
|
|
if (joystick->hwdata) {
|
|
|
|
|
++joystick->hwdata->num_pause_presses;
|
|
|
|
|
joystick->hwdata->pause_button_pressed = SDL_GetTicks();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
@ -901,7 +1032,7 @@ static int IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
|
|
|
|
#endif /* SDL_JOYSTICK_MFI */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (device->remote) {
|
|
|
|
|
if (device->is_siri_remote) {
|
|
|
|
|
++SDL_AppleTVRemoteOpenedAsJoystick;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -985,9 +1116,9 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
GCController *controller = device->controller;
|
|
|
|
|
Uint8 hatstate = SDL_HAT_CENTERED;
|
|
|
|
|
int i;
|
|
|
|
|
int pause_button_index = 0;
|
|
|
|
|
Uint64 timestamp = SDL_GetTicksNS();
|
|
|
|
|
|
|
|
|
|
#define DEBUG_CONTROLLER_STATE
|
|
|
|
|
#ifdef DEBUG_CONTROLLER_STATE
|
|
|
|
|
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
|
|
|
|
if (controller.physicalInputProfile) {
|
|
|
|
@ -1016,23 +1147,31 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (device->use_physical_profile) {
|
|
|
|
|
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
|
|
|
|
NSDictionary<NSString *, GCControllerButtonInput *> *buttons = controller.physicalInputProfile.buttons;
|
|
|
|
|
|
|
|
|
|
int axis = 0;
|
|
|
|
|
for (id key in device->axes) {
|
|
|
|
|
Sint16 value = (Sint16)(controller.physicalInputProfile.axes[key].value * 32767);
|
|
|
|
|
Sint16 value;
|
|
|
|
|
GCControllerElement *element = elements[key];
|
|
|
|
|
if ([element isKindOfClass:[GCControllerAxisInput class]]) {
|
|
|
|
|
value = (Sint16)([(GCControllerAxisInput *)element value] * 32767);
|
|
|
|
|
} else {
|
|
|
|
|
value = (Sint16)([(GCControllerButtonInput *)element value] * 32767);
|
|
|
|
|
}
|
|
|
|
|
SDL_SendJoystickAxis(timestamp, joystick, axis++, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int button = 0;
|
|
|
|
|
for (id key in device->buttons) {
|
|
|
|
|
Uint8 value = controller.physicalInputProfile.buttons[key].isPressed;
|
|
|
|
|
Uint8 value;
|
|
|
|
|
if (button == device->pause_button_index) {
|
|
|
|
|
value = (device->pause_button_pressed > 0);
|
|
|
|
|
} else {
|
|
|
|
|
value = buttons[key].isPressed;
|
|
|
|
|
}
|
|
|
|
|
SDL_SendJoystickButton(timestamp, joystick, button++, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int hat = 0;
|
|
|
|
|
for (id key in device->dpads) {
|
|
|
|
|
hatstate = IOS_MFIJoystickHatStateForDPad(controller.physicalInputProfile.dpads[key]);
|
|
|
|
|
SDL_SendJoystickHat(timestamp, joystick, hat++, hatstate);
|
|
|
|
|
}
|
|
|
|
|
} else if (controller.extendedGamepad) {
|
|
|
|
|
SDL_bool isstack;
|
|
|
|
|
GCExtendedGamepad *gamepad = controller.extendedGamepad;
|
|
|
|
@ -1079,11 +1218,9 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_GUIDE)) {
|
|
|
|
|
buttons[button_count++] = gamepad.buttonHome.isPressed;
|
|
|
|
|
}
|
|
|
|
|
/* This must be the last button, so we can optionally handle it with pause_button_index below */
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_START)) {
|
|
|
|
|
if (device->uses_pause_handler) {
|
|
|
|
|
pause_button_index = button_count;
|
|
|
|
|
buttons[button_count++] = joystick->delayed_guide_button;
|
|
|
|
|
if (device->pause_button_index >= 0) {
|
|
|
|
|
buttons[button_count++] = (device->pause_button_pressed > 0);
|
|
|
|
|
} else {
|
|
|
|
|
buttons[button_count++] = gamepad.buttonMenu.isPressed;
|
|
|
|
|
}
|
|
|
|
@ -1091,45 +1228,22 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
if (device->has_dualshock_touchpad) {
|
|
|
|
|
GCControllerDirectionPad *dpad;
|
|
|
|
|
buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputDualShockTouchpadButton].isPressed;
|
|
|
|
|
|
|
|
|
|
dpad = controller.physicalInputProfile.dpads[GCInputDualShockTouchpadOne];
|
|
|
|
|
if (dpad.xAxis.value || dpad.yAxis.value) {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, SDL_PRESSED, (1.0f + dpad.xAxis.value) * 0.5f, 1.0f - (1.0f + dpad.yAxis.value) * 0.5f, 1.0f);
|
|
|
|
|
} else {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, SDL_RELEASED, 0.0f, 0.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dpad = controller.physicalInputProfile.dpads[GCInputDualShockTouchpadTwo];
|
|
|
|
|
if (dpad.xAxis.value || dpad.yAxis.value) {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 1, SDL_PRESSED, (1.0f + dpad.xAxis.value) * 0.5f, 1.0f - (1.0f + dpad.yAxis.value) * 0.5f, 1.0f);
|
|
|
|
|
} else {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 1, SDL_RELEASED, 0.0f, 0.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device->has_xbox_paddles) {
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1)) {
|
|
|
|
|
buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleOne].isPressed;
|
|
|
|
|
}
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_PADDLE1)) {
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2)) {
|
|
|
|
|
buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleTwo].isPressed;
|
|
|
|
|
}
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2)) {
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_PADDLE1)) {
|
|
|
|
|
buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleThree].isPressed;
|
|
|
|
|
}
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_LEFT_PADDLE2)) {
|
|
|
|
|
buttons[button_count++] = controller.physicalInputProfile.buttons[GCInputXboxPaddleFour].isPressed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
SDL_Log("Paddles: [%d,%d,%d,%d]",
|
|
|
|
|
controller.physicalInputProfile.buttons[GCInputXboxPaddleOne].isPressed,
|
|
|
|
|
controller.physicalInputProfile.buttons[GCInputXboxPaddleTwo].isPressed,
|
|
|
|
|
controller.physicalInputProfile.buttons[GCInputXboxPaddleThree].isPressed,
|
|
|
|
|
controller.physicalInputProfile.buttons[GCInputXboxPaddleFour].isPressed);
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device->has_xbox_share_button) {
|
|
|
|
@ -1148,30 +1262,6 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
SDL_SendJoystickButton(timestamp, joystick, i, buttons[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_MFI_SENSORS
|
|
|
|
|
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
|
|
|
|
GCMotion *motion = controller.motion;
|
|
|
|
|
if (motion && motion.sensorsActive) {
|
|
|
|
|
float data[3];
|
|
|
|
|
|
|
|
|
|
if (motion.hasRotationRate) {
|
|
|
|
|
GCRotationRate rate = motion.rotationRate;
|
|
|
|
|
data[0] = rate.x;
|
|
|
|
|
data[1] = rate.z;
|
|
|
|
|
data[2] = -rate.y;
|
|
|
|
|
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, timestamp, data, 3);
|
|
|
|
|
}
|
|
|
|
|
if (motion.hasGravityAndUserAcceleration) {
|
|
|
|
|
GCAcceleration accel = motion.acceleration;
|
|
|
|
|
data[0] = -accel.x * SDL_STANDARD_GRAVITY;
|
|
|
|
|
data[1] = -accel.y * SDL_STANDARD_GRAVITY;
|
|
|
|
|
data[2] = -accel.z * SDL_STANDARD_GRAVITY;
|
|
|
|
|
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, data, 3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* ENABLE_MFI_SENSORS */
|
|
|
|
|
|
|
|
|
|
SDL_small_free(buttons, isstack);
|
|
|
|
|
} else if (controller.gamepad) {
|
|
|
|
|
SDL_bool isstack;
|
|
|
|
@ -1192,8 +1282,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
buttons[button_count++] = gamepad.buttonY.isPressed;
|
|
|
|
|
buttons[button_count++] = gamepad.leftShoulder.isPressed;
|
|
|
|
|
buttons[button_count++] = gamepad.rightShoulder.isPressed;
|
|
|
|
|
pause_button_index = button_count;
|
|
|
|
|
buttons[button_count++] = joystick->delayed_guide_button;
|
|
|
|
|
buttons[button_count++] = (device->pause_button_pressed > 0);
|
|
|
|
|
|
|
|
|
|
hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
|
|
|
|
|
|
|
|
|
@ -1220,18 +1309,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
int button_count = 0;
|
|
|
|
|
buttons[button_count++] = gamepad.buttonA.isPressed;
|
|
|
|
|
buttons[button_count++] = gamepad.buttonX.isPressed;
|
|
|
|
|
#pragma clang diagnostic push
|
|
|
|
|
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
|
|
|
|
/* This must be the last button, so we can optionally handle it with pause_button_index below */
|
|
|
|
|
if (device->button_mask & (1 << SDL_GAMEPAD_BUTTON_START)) {
|
|
|
|
|
if (device->uses_pause_handler) {
|
|
|
|
|
pause_button_index = button_count;
|
|
|
|
|
buttons[button_count++] = joystick->delayed_guide_button;
|
|
|
|
|
} else {
|
|
|
|
|
buttons[button_count++] = gamepad.buttonMenu.isPressed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
|
buttons[button_count++] = (device->pause_button_pressed > 0);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < button_count; i++) {
|
|
|
|
|
SDL_SendJoystickButton(timestamp, joystick, i, buttons[i]);
|
|
|
|
@ -1239,18 +1317,62 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
|
|
|
|
}
|
|
|
|
|
#endif /* TARGET_OS_TV */
|
|
|
|
|
|
|
|
|
|
if (joystick->nhats > 0 && !device->use_physical_profile) {
|
|
|
|
|
if (joystick->nhats > 0) {
|
|
|
|
|
SDL_SendJoystickHat(timestamp, joystick, 0, hatstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device->uses_pause_handler) {
|
|
|
|
|
for (i = 0; i < device->num_pause_presses; i++) {
|
|
|
|
|
SDL_SendJoystickButton(timestamp, joystick, pause_button_index, SDL_PRESSED);
|
|
|
|
|
SDL_SendJoystickButton(timestamp, joystick, pause_button_index, SDL_RELEASED);
|
|
|
|
|
if (device->pause_button_pressed) {
|
|
|
|
|
/* The pause callback is instantaneous, so we extend the duration to allow "holding down" by pressing it repeatedly */
|
|
|
|
|
const int PAUSE_BUTTON_PRESS_DURATION_MS = 250;
|
|
|
|
|
if (SDL_GetTicks() >= device->pause_button_pressed + PAUSE_BUTTON_PRESS_DURATION_MS) {
|
|
|
|
|
device->pause_button_pressed = 0;
|
|
|
|
|
}
|
|
|
|
|
device->num_pause_presses = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_PHYSICAL_INPUT_PROFILE
|
|
|
|
|
if (device->has_dualshock_touchpad) {
|
|
|
|
|
GCControllerDirectionPad *dpad;
|
|
|
|
|
|
|
|
|
|
dpad = controller.physicalInputProfile.dpads[GCInputDualShockTouchpadOne];
|
|
|
|
|
if (dpad.xAxis.value || dpad.yAxis.value) {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, SDL_PRESSED, (1.0f + dpad.xAxis.value) * 0.5f, 1.0f - (1.0f + dpad.yAxis.value) * 0.5f, 1.0f);
|
|
|
|
|
} else {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0, SDL_RELEASED, 0.0f, 0.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dpad = controller.physicalInputProfile.dpads[GCInputDualShockTouchpadTwo];
|
|
|
|
|
if (dpad.xAxis.value || dpad.yAxis.value) {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 1, SDL_PRESSED, (1.0f + dpad.xAxis.value) * 0.5f, 1.0f - (1.0f + dpad.yAxis.value) * 0.5f, 1.0f);
|
|
|
|
|
} else {
|
|
|
|
|
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 1, SDL_RELEASED, 0.0f, 0.0f, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* ENABLE_PHYSICAL_INPUT_PROFILE */
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_MFI_SENSORS
|
|
|
|
|
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
|
|
|
|
GCMotion *motion = controller.motion;
|
|
|
|
|
if (motion && motion.sensorsActive) {
|
|
|
|
|
float data[3];
|
|
|
|
|
|
|
|
|
|
if (motion.hasRotationRate) {
|
|
|
|
|
GCRotationRate rate = motion.rotationRate;
|
|
|
|
|
data[0] = rate.x;
|
|
|
|
|
data[1] = rate.z;
|
|
|
|
|
data[2] = -rate.y;
|
|
|
|
|
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, timestamp, data, 3);
|
|
|
|
|
}
|
|
|
|
|
if (motion.hasGravityAndUserAcceleration) {
|
|
|
|
|
GCAcceleration accel = motion.acceleration;
|
|
|
|
|
data[0] = -accel.x * SDL_STANDARD_GRAVITY;
|
|
|
|
|
data[1] = -accel.y * SDL_STANDARD_GRAVITY;
|
|
|
|
|
data[2] = -accel.z * SDL_STANDARD_GRAVITY;
|
|
|
|
|
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, data, 3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* ENABLE_MFI_SENSORS */
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_MFI_BATTERY
|
|
|
|
|
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
|
|
|
|
GCDeviceBattery *battery = controller.battery;
|
|
|
|
@ -1698,7 +1820,7 @@ static void IOS_JoystickClose(SDL_Joystick *joystick)
|
|
|
|
|
#endif /* SDL_JOYSTICK_MFI */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (device->remote) {
|
|
|
|
|
if (device->is_siri_remote) {
|
|
|
|
|
--SDL_AppleTVRemoteOpenedAsJoystick;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1739,7 +1861,138 @@ static void IOS_JoystickQuit(void)
|
|
|
|
|
|
|
|
|
|
static SDL_bool IOS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
|
|
|
|
|
{
|
|
|
|
|
return SDL_FALSE;
|
|
|
|
|
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
|
|
|
|
|
if (device == NULL) {
|
|
|
|
|
return SDL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!device->use_physical_profile) {
|
|
|
|
|
return SDL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int axis = 0;
|
|
|
|
|
for (id key in device->axes) {
|
|
|
|
|
if ([(NSString *)key isEqualToString:@"Left Thumbstick X Axis"]) {
|
|
|
|
|
out->leftx.kind = EMappingKind_Axis;
|
|
|
|
|
out->leftx.target = axis;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Left Thumbstick Y Axis"]) {
|
|
|
|
|
out->lefty.kind = EMappingKind_Axis;
|
|
|
|
|
out->lefty.target = axis;
|
|
|
|
|
out->lefty.axis_reversed = SDL_TRUE;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Right Thumbstick X Axis"]) {
|
|
|
|
|
out->rightx.kind = EMappingKind_Axis;
|
|
|
|
|
out->rightx.target = axis;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Right Thumbstick Y Axis"]) {
|
|
|
|
|
out->righty.kind = EMappingKind_Axis;
|
|
|
|
|
out->righty.target = axis;
|
|
|
|
|
out->righty.axis_reversed = SDL_TRUE;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputLeftTrigger]) {
|
|
|
|
|
out->lefttrigger.kind = EMappingKind_Axis;
|
|
|
|
|
out->lefttrigger.target = axis;
|
|
|
|
|
out->lefttrigger.half_axis_positive = SDL_TRUE;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputRightTrigger]) {
|
|
|
|
|
out->righttrigger.kind = EMappingKind_Axis;
|
|
|
|
|
out->righttrigger.target = axis;
|
|
|
|
|
out->righttrigger.half_axis_positive = SDL_TRUE;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Left"] && device->is_siri_remote) {
|
|
|
|
|
out->dpleft.kind = EMappingKind_Axis;
|
|
|
|
|
out->dpleft.target = axis;
|
|
|
|
|
out->dpleft.half_axis_positive = SDL_TRUE;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Right"] && device->is_siri_remote) {
|
|
|
|
|
out->dpright.kind = EMappingKind_Axis;
|
|
|
|
|
out->dpright.target = axis;
|
|
|
|
|
out->dpright.half_axis_positive = SDL_TRUE;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Up"] && device->is_siri_remote) {
|
|
|
|
|
out->dpup.kind = EMappingKind_Axis;
|
|
|
|
|
out->dpup.target = axis;
|
|
|
|
|
out->dpup.half_axis_positive = SDL_TRUE;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Down"] && device->is_siri_remote) {
|
|
|
|
|
out->dpdown.kind = EMappingKind_Axis;
|
|
|
|
|
out->dpdown.target = axis;
|
|
|
|
|
out->dpdown.half_axis_positive = SDL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
++axis;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int button = 0;
|
|
|
|
|
for (id key in device->buttons) {
|
|
|
|
|
SDL_InputMapping *mapping = NULL;
|
|
|
|
|
|
|
|
|
|
if ([(NSString *)key isEqualToString:GCInputButtonA]) {
|
|
|
|
|
if (device->has_nintendo_buttons) {
|
|
|
|
|
mapping = &out->b;
|
|
|
|
|
} else {
|
|
|
|
|
mapping = &out->a;
|
|
|
|
|
}
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputButtonB]) {
|
|
|
|
|
if (device->has_nintendo_buttons) {
|
|
|
|
|
mapping = &out->a;
|
|
|
|
|
} else if (device->is_single_joycon) {
|
|
|
|
|
mapping = &out->x;
|
|
|
|
|
} else {
|
|
|
|
|
mapping = &out->b;
|
|
|
|
|
}
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputButtonX]) {
|
|
|
|
|
if (device->has_nintendo_buttons) {
|
|
|
|
|
mapping = &out->y;
|
|
|
|
|
} else if (device->is_single_joycon) {
|
|
|
|
|
mapping = &out->b;
|
|
|
|
|
} else {
|
|
|
|
|
mapping = &out->x;
|
|
|
|
|
}
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputButtonY]) {
|
|
|
|
|
if (device->has_nintendo_buttons) {
|
|
|
|
|
mapping = &out->x;
|
|
|
|
|
} else {
|
|
|
|
|
mapping = &out->y;
|
|
|
|
|
}
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Left"] && !device->is_siri_remote) {
|
|
|
|
|
mapping = &out->dpleft;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Right"] && !device->is_siri_remote) {
|
|
|
|
|
mapping = &out->dpright;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Up"] && !device->is_siri_remote) {
|
|
|
|
|
mapping = &out->dpup;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:@"Direction Pad Down"] && !device->is_siri_remote) {
|
|
|
|
|
mapping = &out->dpdown;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputLeftShoulder]) {
|
|
|
|
|
mapping = &out->leftshoulder;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputRightShoulder]) {
|
|
|
|
|
mapping = &out->rightshoulder;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputLeftThumbstickButton]) {
|
|
|
|
|
mapping = &out->leftstick;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputRightThumbstickButton]) {
|
|
|
|
|
mapping = &out->rightstick;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputButtonHome]) {
|
|
|
|
|
mapping = &out->guide;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputButtonMenu]) {
|
|
|
|
|
mapping = &out->start;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputButtonOptions]) {
|
|
|
|
|
mapping = &out->back;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputButtonShare]) {
|
|
|
|
|
mapping = &out->misc1;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputXboxPaddleOne]) {
|
|
|
|
|
mapping = &out->right_paddle1;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputXboxPaddleTwo]) {
|
|
|
|
|
mapping = &out->right_paddle2;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputXboxPaddleThree]) {
|
|
|
|
|
mapping = &out->left_paddle1;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputXboxPaddleFour]) {
|
|
|
|
|
mapping = &out->left_paddle2;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputLeftTrigger]) {
|
|
|
|
|
mapping = &out->lefttrigger;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputRightTrigger]) {
|
|
|
|
|
mapping = &out->righttrigger;
|
|
|
|
|
} else if ([(NSString *)key isEqualToString:GCInputDualShockTouchpadButton]) {
|
|
|
|
|
mapping = &out->touchpad;
|
|
|
|
|
}
|
|
|
|
|
if (mapping && mapping->kind == EMappingKind_None) {
|
|
|
|
|
mapping->kind = EMappingKind_Button;
|
|
|
|
|
mapping->target = button;
|
|
|
|
|
}
|
|
|
|
|
++button;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SDL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if defined(SDL_JOYSTICK_MFI) && defined(__MACOS__)
|
|
|
|
@ -1777,6 +2030,10 @@ static void GetAppleSFSymbolsNameForElement(GCControllerElement *element, char *
|
|
|
|
|
|
|
|
|
|
static GCControllerDirectionPad *GetDirectionalPadForController(GCController *controller)
|
|
|
|
|
{
|
|
|
|
|
if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
|
|
|
|
|
return controller.physicalInputProfile.dpads[GCInputDirectionPad];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (controller.extendedGamepad) {
|
|
|
|
|
return controller.extendedGamepad.dpad;
|
|
|
|
|
}
|
|
|
|
@ -1789,10 +2046,6 @@ static GCControllerDirectionPad *GetDirectionalPadForController(GCController *co
|
|
|
|
|
return controller.microGamepad.dpad;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([controller respondsToSelector:@selector(physicalInputProfile)]) {
|
|
|
|
|
return controller.physicalInputProfile.dpads[GCInputDirectionPad];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
#endif /* SDL_JOYSTICK_MFI && ENABLE_PHYSICAL_INPUT_PROFILE */
|
|
|
|
|