| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | #include "../events/SDL_events_c.h" |
| | | #endif |
| | | #include "../video/SDL_sysvideo.h" |
| | | #include "hidapi/SDL_hidapijoystick_c.h" |
| | | |
| | | /* This is included in only one place because it has a large static list of controllers */ |
| | | #include "controller_type.h" |
| | |
| | | static SDL_bool SDL_updating_joystick = SDL_FALSE; |
| | | static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */ |
| | | static SDL_atomic_t SDL_next_joystick_instance_id; |
| | | static int SDL_joystick_player_count = 0; |
| | | static SDL_JoystickID *SDL_joystick_players = NULL; |
| | | |
| | | void |
| | | SDL_LockJoysticks(void) |
| | |
| | | } |
| | | } |
| | | |
| | | static int |
| | | SDL_FindFreePlayerIndex() |
| | | { |
| | | int player_index; |
| | | |
| | | for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) { |
| | | if (SDL_joystick_players[player_index] == -1) { |
| | | return player_index; |
| | | } |
| | | } |
| | | return player_index; |
| | | } |
| | | |
| | | static int |
| | | SDL_GetPlayerIndexForJoystickID(SDL_JoystickID instance_id) |
| | | { |
| | | int player_index; |
| | | |
| | | for (player_index = 0; player_index < SDL_joystick_player_count; ++player_index) { |
| | | if (instance_id == SDL_joystick_players[player_index]) { |
| | | break; |
| | | } |
| | | } |
| | | if (player_index == SDL_joystick_player_count) { |
| | | player_index = -1; |
| | | } |
| | | return player_index; |
| | | } |
| | | |
| | | static SDL_JoystickID |
| | | SDL_GetJoystickIDForPlayerIndex(int player_index) |
| | | { |
| | | if (player_index < 0 || player_index >= SDL_joystick_player_count) { |
| | | return -1; |
| | | } |
| | | return SDL_joystick_players[player_index]; |
| | | } |
| | | |
| | | static SDL_bool |
| | | SDL_SetJoystickIDForPlayerIndex(int player_index, SDL_JoystickID instance_id) |
| | | { |
| | | SDL_JoystickID existing_instance = SDL_GetJoystickIDForPlayerIndex(player_index); |
| | | SDL_JoystickDriver *driver; |
| | | int device_index; |
| | | int existing_player_index; |
| | | |
| | | if (player_index < 0) { |
| | | return SDL_FALSE; |
| | | } |
| | | if (player_index >= SDL_joystick_player_count) { |
| | | SDL_JoystickID *new_players = (SDL_JoystickID *)SDL_realloc(SDL_joystick_players, (player_index + 1)*sizeof(*SDL_joystick_players)); |
| | | if (!new_players) { |
| | | SDL_OutOfMemory(); |
| | | return SDL_FALSE; |
| | | } |
| | | |
| | | SDL_joystick_players = new_players; |
| | | SDL_memset(&SDL_joystick_players[SDL_joystick_player_count], 0xFF, (player_index - SDL_joystick_player_count + 1) * sizeof(SDL_joystick_players[0])); |
| | | SDL_joystick_player_count = player_index + 1; |
| | | } else if (SDL_joystick_players[player_index] == instance_id) { |
| | | /* Joystick is already assigned the requested player index */ |
| | | return SDL_TRUE; |
| | | } |
| | | |
| | | /* Clear the old player index */ |
| | | existing_player_index = SDL_GetPlayerIndexForJoystickID(instance_id); |
| | | if (existing_player_index >= 0) { |
| | | SDL_joystick_players[existing_player_index] = -1; |
| | | } |
| | | |
| | | SDL_joystick_players[player_index] = instance_id; |
| | | |
| | | /* Update the driver with the new index */ |
| | | device_index = SDL_JoystickGetDeviceIndexFromInstanceID(instance_id); |
| | | if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) { |
| | | driver->SetDevicePlayerIndex(device_index, player_index); |
| | | } |
| | | |
| | | /* Move any existing joystick to another slot */ |
| | | if (existing_instance >= 0) { |
| | | SDL_SetJoystickIDForPlayerIndex(SDL_FindFreePlayerIndex(), existing_instance); |
| | | } |
| | | return SDL_TRUE; |
| | | } |
| | | |
| | | static void SDLCALL |
| | | SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) |
| | |
| | | return name; |
| | | } |
| | | |
| | | /* |
| | | * Get the player index of a joystick, or -1 if it's not available |
| | | */ |
| | | int |
| | | SDL_JoystickGetDevicePlayerIndex(int device_index) |
| | | { |
| | | SDL_JoystickDriver *driver; |
| | | int player_index = -1; |
| | | int player_index; |
| | | |
| | | SDL_LockJoysticks(); |
| | | if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) { |
| | | player_index = driver->GetDevicePlayerIndex(device_index); |
| | | } |
| | | player_index = SDL_GetPlayerIndexForJoystickID(SDL_JoystickGetDeviceInstanceID(device_index)); |
| | | SDL_UnlockJoysticks(); |
| | | |
| | | return player_index; |
| | |
| | | joystick->driver = driver; |
| | | joystick->instance_id = instance_id; |
| | | joystick->attached = SDL_TRUE; |
| | | joystick->player_index = -1; |
| | | joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; |
| | | |
| | | if (driver->Open(joystick, device_index) < 0) { |
| | | SDL_free(joystick); |
| | |
| | | SDL_UnlockJoysticks(); |
| | | return NULL; |
| | | } |
| | | joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; |
| | | |
| | | /* If this joystick is known to have all zero centered axes, skip the auto-centering code */ |
| | | if (SDL_JoystickAxesCenteredAtZero(joystick)) { |
| | |
| | | /* |
| | | * Checks to make sure the joystick is valid. |
| | | */ |
| | | int |
| | | SDL_bool |
| | | SDL_PrivateJoystickValid(SDL_Joystick * joystick) |
| | | { |
| | | int valid; |
| | | SDL_bool valid; |
| | | |
| | | if (joystick == NULL) { |
| | | SDL_SetError("Joystick hasn't been opened yet"); |
| | | valid = 0; |
| | | valid = SDL_FALSE; |
| | | } else { |
| | | valid = 1; |
| | | valid = SDL_TRUE; |
| | | } |
| | | |
| | | return valid; |
| | |
| | | } |
| | | |
| | | /* |
| | | * Find the SDL_Joystick that owns this instance id |
| | | * Return the SDL_Joystick associated with an instance id. |
| | | */ |
| | | SDL_Joystick * |
| | | SDL_JoystickFromInstanceID(SDL_JoystickID joyid) |
| | | SDL_JoystickFromInstanceID(SDL_JoystickID instance_id) |
| | | { |
| | | SDL_Joystick *joystick; |
| | | |
| | | SDL_LockJoysticks(); |
| | | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
| | | if (joystick->instance_id == joyid) { |
| | | if (joystick->instance_id == instance_id) { |
| | | break; |
| | | } |
| | | } |
| | | SDL_UnlockJoysticks(); |
| | | return joystick; |
| | | } |
| | | |
| | | /** |
| | | * Return the SDL_Joystick associated with a player index. |
| | | */ |
| | | SDL_Joystick * |
| | | SDL_JoystickFromPlayerIndex(int player_index) |
| | | { |
| | | SDL_JoystickID instance_id; |
| | | SDL_Joystick *joystick; |
| | | |
| | | SDL_LockJoysticks(); |
| | | instance_id = SDL_GetJoystickIDForPlayerIndex(player_index); |
| | | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
| | | if (joystick->instance_id == instance_id) { |
| | | break; |
| | | } |
| | | } |
| | |
| | | return SDL_FixupJoystickName(joystick->name); |
| | | } |
| | | |
| | | /** |
| | | * Get the player index of an opened joystick, or -1 if it's not available |
| | | */ |
| | | int |
| | | SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick) |
| | | { |
| | | int player_index; |
| | | |
| | | if (!SDL_PrivateJoystickValid(joystick)) { |
| | | return -1; |
| | | } |
| | | return joystick->player_index; |
| | | |
| | | SDL_LockJoysticks(); |
| | | player_index = SDL_GetPlayerIndexForJoystickID(joystick->instance_id); |
| | | SDL_UnlockJoysticks(); |
| | | |
| | | return player_index; |
| | | } |
| | | |
| | | /** |
| | | * Set the player index of an opened joystick |
| | | */ |
| | | void |
| | | SDL_JoystickSetPlayerIndex(SDL_Joystick * joystick, int player_index) |
| | | { |
| | | if (!SDL_PrivateJoystickValid(joystick)) { |
| | | return; |
| | | } |
| | | |
| | | SDL_LockJoysticks(); |
| | | SDL_SetJoystickIDForPlayerIndex(player_index, joystick->instance_id); |
| | | SDL_UnlockJoysticks(); |
| | | } |
| | | |
| | | int |
| | | SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) |
| | | { |
| | | int result; |
| | | |
| | | if (!SDL_PrivateJoystickValid(joystick)) { |
| | | return -1; |
| | | } |
| | | return joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms); |
| | | |
| | | SDL_LockJoysticks(); |
| | | if (low_frequency_rumble == joystick->low_frequency_rumble && |
| | | high_frequency_rumble == joystick->high_frequency_rumble) { |
| | | /* Just update the expiration */ |
| | | result = 0; |
| | | } else { |
| | | result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble); |
| | | } |
| | | |
| | | /* Save the rumble value regardless of success, so we don't spam the driver */ |
| | | joystick->low_frequency_rumble = low_frequency_rumble; |
| | | joystick->high_frequency_rumble = high_frequency_rumble; |
| | | |
| | | if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) { |
| | | joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); |
| | | if (!joystick->rumble_expiration) { |
| | | joystick->rumble_expiration = 1; |
| | | } |
| | | } else { |
| | | joystick->rumble_expiration = 0; |
| | | } |
| | | SDL_UnlockJoysticks(); |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /* |
| | |
| | | if (SDL_updating_joystick) { |
| | | SDL_UnlockJoysticks(); |
| | | return; |
| | | } |
| | | |
| | | if (joystick->rumble_expiration) { |
| | | SDL_JoystickRumble(joystick, 0, 0, 0); |
| | | } |
| | | |
| | | joystick->driver->Close(joystick); |
| | |
| | | int i; |
| | | |
| | | /* Make sure we're not getting called in the middle of updating joysticks */ |
| | | SDL_assert(!SDL_updating_joystick); |
| | | |
| | | SDL_LockJoysticks(); |
| | | while (SDL_updating_joystick) { |
| | | SDL_UnlockJoysticks(); |
| | | SDL_Delay(1); |
| | | SDL_LockJoysticks(); |
| | | } |
| | | |
| | | /* Stop the event polling */ |
| | | while (SDL_joysticks) { |
| | |
| | | SDL_joystick_drivers[i]->Quit(); |
| | | } |
| | | |
| | | if (SDL_joystick_players) { |
| | | SDL_free(SDL_joystick_players); |
| | | SDL_joystick_players = NULL; |
| | | SDL_joystick_player_count = 0; |
| | | } |
| | | SDL_UnlockJoysticks(); |
| | | |
| | | #if !SDL_EVENTS_DISABLED |
| | |
| | | SDL_JoystickAllowBackgroundEventsChanged, NULL); |
| | | |
| | | if (SDL_joystick_lock) { |
| | | SDL_DestroyMutex(SDL_joystick_lock); |
| | | SDL_mutex *mutex = SDL_joystick_lock; |
| | | SDL_joystick_lock = NULL; |
| | | SDL_DestroyMutex(mutex); |
| | | } |
| | | |
| | | SDL_GameControllerQuitMappings(); |
| | |
| | | |
| | | void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance) |
| | | { |
| | | #if !SDL_EVENTS_DISABLED |
| | | SDL_Event event; |
| | | int device_index; |
| | | |
| | | device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance); |
| | | SDL_JoystickDriver *driver; |
| | | int driver_device_index; |
| | | int player_index = -1; |
| | | int device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance); |
| | | if (device_index < 0) { |
| | | return; |
| | | } |
| | | |
| | | event.type = SDL_JOYDEVICEADDED; |
| | | SDL_LockJoysticks(); |
| | | if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) { |
| | | player_index = driver->GetDevicePlayerIndex(driver_device_index); |
| | | } |
| | | if (player_index < 0 && SDL_IsGameController(device_index)) { |
| | | player_index = SDL_FindFreePlayerIndex(); |
| | | } |
| | | if (player_index >= 0) { |
| | | SDL_SetJoystickIDForPlayerIndex(player_index, device_instance); |
| | | } |
| | | SDL_UnlockJoysticks(); |
| | | |
| | | if (SDL_GetEventState(event.type) == SDL_ENABLE) { |
| | | event.jdevice.which = device_index; |
| | | SDL_PushEvent(&event); |
| | | #if !SDL_EVENTS_DISABLED |
| | | { |
| | | SDL_Event event; |
| | | |
| | | event.type = SDL_JOYDEVICEADDED; |
| | | |
| | | if (SDL_GetEventState(event.type) == SDL_ENABLE) { |
| | | event.jdevice.which = device_index; |
| | | SDL_PushEvent(&event); |
| | | } |
| | | } |
| | | #endif /* !SDL_EVENTS_DISABLED */ |
| | | } |
| | |
| | | { |
| | | int i, num_events; |
| | | SDL_Event *events; |
| | | SDL_bool isstack; |
| | | |
| | | num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED); |
| | | if (num_events <= 0) { |
| | | return; |
| | | } |
| | | |
| | | events = SDL_stack_alloc(SDL_Event, num_events); |
| | | events = SDL_small_alloc(SDL_Event, num_events, &isstack); |
| | | if (!events) { |
| | | return; |
| | | } |
| | |
| | | } |
| | | SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0); |
| | | |
| | | SDL_stack_free(events); |
| | | SDL_small_free(events, isstack); |
| | | } |
| | | |
| | | void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance) |
| | | { |
| | | SDL_Joystick *joystick; |
| | | int player_index; |
| | | |
| | | #if !SDL_EVENTS_DISABLED |
| | | SDL_Event event; |
| | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | SDL_LockJoysticks(); |
| | | player_index = SDL_GetPlayerIndexForJoystickID(device_instance); |
| | | if (player_index >= 0) { |
| | | SDL_joystick_players[player_index] = -1; |
| | | } |
| | | SDL_UnlockJoysticks(); |
| | | } |
| | | |
| | | int |
| | | SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value) |
| | | { |
| | | int posted; |
| | | SDL_JoystickAxisInfo *info; |
| | | |
| | | /* Make sure we're not getting garbage or duplicate events */ |
| | | if (axis >= joystick->naxes) { |
| | | return 0; |
| | | } |
| | | if (!joystick->axes[axis].has_initial_value) { |
| | | joystick->axes[axis].initial_value = value; |
| | | joystick->axes[axis].value = value; |
| | | joystick->axes[axis].zero = value; |
| | | joystick->axes[axis].has_initial_value = SDL_TRUE; |
| | | |
| | | info = &joystick->axes[axis]; |
| | | if (!info->has_initial_value || |
| | | (!info->has_second_value && (info->initial_value == -32768 || info->initial_value == 32767) && SDL_abs(value) < (SDL_JOYSTICK_AXIS_MAX / 4))) { |
| | | info->initial_value = value; |
| | | info->value = value; |
| | | info->zero = value; |
| | | info->has_initial_value = SDL_TRUE; |
| | | } else { |
| | | info->has_second_value = SDL_TRUE; |
| | | } |
| | | if (value == joystick->axes[axis].value) { |
| | | if (value == info->value) { |
| | | return 0; |
| | | } |
| | | if (!joystick->axes[axis].sent_initial_value) { |
| | | if (!info->sent_initial_value) { |
| | | /* Make sure we don't send motion until there's real activity on this axis */ |
| | | const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80; /* ShanWan PS3 controller needed 96 */ |
| | | if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) { |
| | | if (SDL_abs(value - info->value) <= MAX_ALLOWED_JITTER) { |
| | | return 0; |
| | | } |
| | | joystick->axes[axis].sent_initial_value = SDL_TRUE; |
| | | joystick->axes[axis].value = value; /* Just so we pass the check above */ |
| | | SDL_PrivateJoystickAxis(joystick, axis, joystick->axes[axis].initial_value); |
| | | info->sent_initial_value = SDL_TRUE; |
| | | info->value = value; /* Just so we pass the check above */ |
| | | SDL_PrivateJoystickAxis(joystick, axis, info->initial_value); |
| | | } |
| | | |
| | | /* We ignore events if we don't have keyboard focus, except for centering |
| | | * events. |
| | | */ |
| | | if (SDL_PrivateJoystickShouldIgnoreEvent()) { |
| | | if ((value > joystick->axes[axis].zero && value >= joystick->axes[axis].value) || |
| | | (value < joystick->axes[axis].zero && value <= joystick->axes[axis].value)) { |
| | | if ((value > info->zero && value >= info->value) || |
| | | (value < info->zero && value <= info->value)) { |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | /* Update internal joystick state */ |
| | | joystick->axes[axis].value = value; |
| | | info->value = value; |
| | | |
| | | /* Post the event, if desired */ |
| | | posted = 0; |
| | |
| | | SDL_JoystickUpdate(void) |
| | | { |
| | | int i; |
| | | SDL_Joystick *joystick; |
| | | SDL_Joystick *joystick, *next; |
| | | |
| | | if (!SDL_WasInit(SDL_INIT_JOYSTICK)) { |
| | | return; |
| | | } |
| | | |
| | | SDL_LockJoysticks(); |
| | | |
| | |
| | | /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */ |
| | | SDL_UnlockJoysticks(); |
| | | |
| | | #ifdef SDL_JOYSTICK_HIDAPI |
| | | /* Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks */ |
| | | HIDAPI_UpdateDevices(); |
| | | #endif /* SDL_JOYSTICK_HIDAPI */ |
| | | |
| | | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
| | | if (joystick->attached) { |
| | | joystick->driver->Update(joystick); |
| | | /* This should always be true, but seeing a crash in the wild...? */ |
| | | if (joystick->driver) { |
| | | joystick->driver->Update(joystick); |
| | | } |
| | | |
| | | if (joystick->delayed_guide_button) { |
| | | SDL_GameControllerHandleDelayedGuideButton(joystick); |
| | | } |
| | | } |
| | | |
| | | if (joystick->rumble_expiration) { |
| | | SDL_LockJoysticks(); |
| | | /* Double check now that the lock is held */ |
| | | if (joystick->rumble_expiration && |
| | | SDL_TICKS_PASSED(SDL_GetTicks(), joystick->rumble_expiration)) { |
| | | SDL_JoystickRumble(joystick, 0, 0, 0); |
| | | } |
| | | SDL_UnlockJoysticks(); |
| | | } |
| | | |
| | | if (joystick->force_recentering) { |
| | |
| | | SDL_updating_joystick = SDL_FALSE; |
| | | |
| | | /* If any joysticks were closed while updating, free them here */ |
| | | for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { |
| | | for (joystick = SDL_joysticks; joystick; joystick = next) { |
| | | next = joystick->next; |
| | | if (joystick->ref_count <= 0) { |
| | | SDL_JoystickClose(joystick); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | SDL_bool |
| | | SDL_IsJoystickPS4(Uint16 vendor, Uint16 product) |
| | | const char * |
| | | SDL_GetCustomJoystickManufacturer(const char *manufacturer) |
| | | { |
| | | return (GuessControllerType(vendor, product) == k_eControllerType_PS4Controller); |
| | | if (manufacturer) { |
| | | if (SDL_strcmp(manufacturer, "Performance Designed Products") == 0) { |
| | | return "PDP"; |
| | | } else if (SDL_strcmp(manufacturer, "HORI CO.,LTD") == 0) { |
| | | return "HORI"; |
| | | } |
| | | } |
| | | return manufacturer; |
| | | } |
| | | |
| | | const char * |
| | | SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product) |
| | | { |
| | | return GuessControllerName(vendor, product); |
| | | } |
| | | |
| | | SDL_GameControllerType |
| | | SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name) |
| | | { |
| | | SDL_GameControllerType type; |
| | | Uint16 vendor, product; |
| | | |
| | | SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); |
| | | type = SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0); |
| | | if (type == SDL_CONTROLLER_TYPE_UNKNOWN) { |
| | | if (SDL_IsJoystickXInput(guid)) { |
| | | /* This is probably an Xbox One controller */ |
| | | return SDL_CONTROLLER_TYPE_XBOXONE; |
| | | } |
| | | } |
| | | return type; |
| | | } |
| | | |
| | | SDL_GameControllerType |
| | | SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol) |
| | | { |
| | | static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF; |
| | | static const int XB360_IFACE_SUBCLASS = 93; |
| | | static const int XB360_IFACE_PROTOCOL = 1; /* Wired */ |
| | | static const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */ |
| | | static const int XBONE_IFACE_SUBCLASS = 71; |
| | | static const int XBONE_IFACE_PROTOCOL = 208; |
| | | |
| | | SDL_GameControllerType type = SDL_CONTROLLER_TYPE_UNKNOWN; |
| | | |
| | | /* This code should match the checks in libusb/hid.c and HIDDeviceManager.java */ |
| | | if (interface_class == LIBUSB_CLASS_VENDOR_SPEC && |
| | | interface_subclass == XB360_IFACE_SUBCLASS && |
| | | (interface_protocol == XB360_IFACE_PROTOCOL || |
| | | interface_protocol == XB360W_IFACE_PROTOCOL)) { |
| | | |
| | | static const int SUPPORTED_VENDORS[] = { |
| | | 0x0079, /* GPD Win 2 */ |
| | | 0x044f, /* Thrustmaster */ |
| | | 0x045e, /* Microsoft */ |
| | | 0x046d, /* Logitech */ |
| | | 0x056e, /* Elecom */ |
| | | 0x06a3, /* Saitek */ |
| | | 0x0738, /* Mad Catz */ |
| | | 0x07ff, /* Mad Catz */ |
| | | 0x0e6f, /* PDP */ |
| | | 0x0f0d, /* Hori */ |
| | | 0x1038, /* SteelSeries */ |
| | | 0x11c9, /* Nacon */ |
| | | 0x12ab, /* Unknown */ |
| | | 0x1430, /* RedOctane */ |
| | | 0x146b, /* BigBen */ |
| | | 0x1532, /* Razer Sabertooth */ |
| | | 0x15e4, /* Numark */ |
| | | 0x162e, /* Joytech */ |
| | | 0x1689, /* Razer Onza */ |
| | | 0x1bad, /* Harmonix */ |
| | | 0x24c6, /* PowerA */ |
| | | }; |
| | | |
| | | int i; |
| | | for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) { |
| | | if (vendor == SUPPORTED_VENDORS[i]) { |
| | | type = SDL_CONTROLLER_TYPE_XBOX360; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (interface_number == 0 && |
| | | interface_class == LIBUSB_CLASS_VENDOR_SPEC && |
| | | interface_subclass == XBONE_IFACE_SUBCLASS && |
| | | interface_protocol == XBONE_IFACE_PROTOCOL) { |
| | | |
| | | static const int SUPPORTED_VENDORS[] = { |
| | | 0x045e, /* Microsoft */ |
| | | 0x0738, /* Mad Catz */ |
| | | 0x0e6f, /* PDP */ |
| | | 0x0f0d, /* Hori */ |
| | | 0x1532, /* Razer Wildcat */ |
| | | 0x24c6, /* PowerA */ |
| | | 0x2e24, /* Hyperkin */ |
| | | }; |
| | | |
| | | int i; |
| | | for (i = 0; i < SDL_arraysize(SUPPORTED_VENDORS); ++i) { |
| | | if (vendor == SUPPORTED_VENDORS[i]) { |
| | | type = SDL_CONTROLLER_TYPE_XBOXONE; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (type == SDL_CONTROLLER_TYPE_UNKNOWN) { |
| | | if (vendor == 0x0000 && product == 0x0000) { |
| | | /* Some devices are only identifiable by their name */ |
| | | if (SDL_strcmp(name, "Lic Pro Controller") == 0 || |
| | | SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 || |
| | | SDL_strcmp(name, "Wireless Gamepad") == 0) { |
| | | /* HORI or PowerA Switch Pro Controller clone */ |
| | | type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO; |
| | | } else { |
| | | type = SDL_CONTROLLER_TYPE_UNKNOWN; |
| | | } |
| | | |
| | | } else if (vendor == 0x0001 && product == 0x0001) { |
| | | type = SDL_CONTROLLER_TYPE_UNKNOWN; |
| | | |
| | | } else { |
| | | switch (GuessControllerType(vendor, product)) { |
| | | case k_eControllerType_XBox360Controller: |
| | | type = SDL_CONTROLLER_TYPE_XBOX360; |
| | | break; |
| | | case k_eControllerType_XBoxOneController: |
| | | type = SDL_CONTROLLER_TYPE_XBOXONE; |
| | | break; |
| | | case k_eControllerType_PS3Controller: |
| | | type = SDL_CONTROLLER_TYPE_PS3; |
| | | break; |
| | | case k_eControllerType_PS4Controller: |
| | | type = SDL_CONTROLLER_TYPE_PS4; |
| | | break; |
| | | case k_eControllerType_SwitchProController: |
| | | case k_eControllerType_SwitchInputOnlyController: |
| | | type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO; |
| | | break; |
| | | default: |
| | | type = SDL_CONTROLLER_TYPE_UNKNOWN; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return type; |
| | | } |
| | | |
| | | SDL_bool |
| | | SDL_IsJoystickNintendoSwitchPro(Uint16 vendor, Uint16 product) |
| | | SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor, Uint16 product) |
| | | { |
| | | return (GuessControllerType(vendor, product) == k_eControllerType_SwitchProController); |
| | | EControllerType eType = GuessControllerType(vendor, product); |
| | | return (eType == k_eControllerType_SwitchInputOnlyController); |
| | | } |
| | | |
| | | SDL_bool |
| | | SDL_IsJoystickSteamController(Uint16 vendor, Uint16 product) |
| | | { |
| | | return BIsSteamController(GuessControllerType(vendor, product)); |
| | | } |
| | | |
| | | SDL_bool |
| | | SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product) |
| | | { |
| | | /* Filter out some bogus values here */ |
| | | if (vendor == 0x0000 && product == 0x0000) { |
| | | return SDL_FALSE; |
| | | } |
| | | if (vendor == 0x0001 && product == 0x0001) { |
| | | return SDL_FALSE; |
| | | } |
| | | return (GuessControllerType(vendor, product) == k_eControllerType_XBox360Controller); |
| | | } |
| | | |
| | | SDL_bool |
| | | SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product) |
| | | { |
| | | return (GuessControllerType(vendor, product) == k_eControllerType_XBoxOneController); |
| | | EControllerType eType = GuessControllerType(vendor, product); |
| | | return (eType == k_eControllerType_SteamController || |
| | | eType == k_eControllerType_SteamControllerV2); |
| | | } |
| | | |
| | | SDL_bool |
| | |
| | | |
| | | SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid) |
| | | { |
| | | /* This list is taken from: |
| | | https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py |
| | | */ |
| | | static Uint32 joystick_blacklist[] = { |
| | | /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */ |
| | | /* Microsoft Wireless Desktop - Comfort Edition */ |
| | | MAKE_VIDPID(0x045e, 0x009d), |
| | | |
| | | /* Microsoft Microsoft® Digital Media Pro Keyboard */ |
| | | /* Microsoft Corp. Digital Media Pro Keyboard */ |
| | | MAKE_VIDPID(0x045e, 0x00b0), |
| | | |
| | | /* Microsoft Microsoft® Digital Media Keyboard */ |
| | | /* Microsoft Corp. Digital Media Keyboard 1.0A */ |
| | | MAKE_VIDPID(0x045e, 0x00b4), |
| | | |
| | | /* Microsoft Microsoft® Digital Media Keyboard 3000 */ |
| | | MAKE_VIDPID(0x045e, 0x0730), |
| | | |
| | | /* Microsoft Microsoft® 2.4GHz Transceiver v6.0 */ |
| | | /* Microsoft Microsoft® 2.4GHz Transceiver v8.0 */ |
| | | /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */ |
| | | /* Microsoft Wireless Mobile Mouse 1000 */ |
| | | /* Microsoft Wireless Desktop 3000 */ |
| | | MAKE_VIDPID(0x045e, 0x0745), |
| | | |
| | | /* Microsoft® SideWinder(TM) 2.4GHz Transceiver */ |
| | | MAKE_VIDPID(0x045e, 0x0748), |
| | | |
| | | /* Microsoft Corp. Wired Keyboard 600 */ |
| | | MAKE_VIDPID(0x045e, 0x0750), |
| | | |
| | | /* Microsoft Corp. Sidewinder X4 keyboard */ |
| | | MAKE_VIDPID(0x045e, 0x0768), |
| | | |
| | | /* Microsoft Corp. Arc Touch Mouse Transceiver */ |
| | | MAKE_VIDPID(0x045e, 0x0773), |
| | | |
| | | /* Microsoft® 2.4GHz Transceiver v9.0 */ |
| | | /* Microsoft® Nano Transceiver v2.1 */ |
| | | /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */ |
| | | MAKE_VIDPID(0x045e, 0x07a5), |
| | | |
| | | /* Microsoft® Nano Transceiver v1.0 */ |
| | | /* Microsoft Wireless Keyboard 800 */ |
| | | MAKE_VIDPID(0x045e, 0x07b2), |
| | | |
| | | /* Microsoft® Nano Transceiver v2.0 */ |
| | | MAKE_VIDPID(0x045e, 0x0800), |
| | | |
| | | MAKE_VIDPID(0x046d, 0xc30a), /* Logitech, Inc. iTouch Composite keboard */ |
| | | |
| | | MAKE_VIDPID(0x04d9, 0xa0df), /* Tek Syndicate Mouse (E-Signal USB Gaming Mouse) */ |
| | | |
| | | /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */ |
| | | MAKE_VIDPID(0x056a, 0x0010), /* Wacom ET-0405 Graphire */ |
| | | MAKE_VIDPID(0x056a, 0x0011), /* Wacom ET-0405A Graphire2 (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0012), /* Wacom ET-0507A Graphire2 (5x7) */ |
| | | MAKE_VIDPID(0x056a, 0x0013), /* Wacom CTE-430 Graphire3 (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0014), /* Wacom CTE-630 Graphire3 (6x8) */ |
| | | MAKE_VIDPID(0x056a, 0x0015), /* Wacom CTE-440 Graphire4 (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire4 (6x8) */ |
| | | MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0018), /* Wacom CTE-650 Bamboo Fun 6x8 */ |
| | | MAKE_VIDPID(0x056a, 0x0019), /* Wacom CTE-631 Bamboo One */ |
| | | MAKE_VIDPID(0x056a, 0x00d1), /* Wacom Bamboo Pen and Touch CTH-460 */ |
| | | MAKE_VIDPID(0x056a, 0x030e), /* Wacom Intuos Pen (S) CTL-480 */ |
| | | |
| | | MAKE_VIDPID(0x09da, 0x054f), /* A4 Tech Co., G7 750 mouse */ |
| | | MAKE_VIDPID(0x09da, 0x1410), /* A4 Tech Co., Ltd Bloody AL9 mouse */ |
| | | MAKE_VIDPID(0x09da, 0x3043), /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x31b5), /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x3997), /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */ |
| | | MAKE_VIDPID(0x09da, 0x3f8b), /* A4 Tech Co., Ltd Bloody V8 mouse */ |
| | | MAKE_VIDPID(0x09da, 0x51f4), /* Modecom MC-5006 Keyboard */ |
| | | MAKE_VIDPID(0x09da, 0x5589), /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x7b22), /* A4 Tech Co., Ltd Bloody V5 */ |
| | | MAKE_VIDPID(0x09da, 0x7f2d), /* A4 Tech Co., Ltd Bloody R3 mouse */ |
| | | MAKE_VIDPID(0x09da, 0x8090), /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x9033), /* A4 Tech Co., X7 X-705K */ |
| | | MAKE_VIDPID(0x09da, 0x9066), /* A4 Tech Co., Sharkoon Fireglider Optical */ |
| | | MAKE_VIDPID(0x09da, 0x9090), /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x90c0), /* A4 Tech Co., Ltd X7 G800V keyboard */ |
| | | MAKE_VIDPID(0x09da, 0xf012), /* A4 Tech Co., Ltd Bloody V7 mouse */ |
| | | MAKE_VIDPID(0x09da, 0xf32a), /* A4 Tech Co., Ltd Bloody B540 keyboard */ |
| | | MAKE_VIDPID(0x09da, 0xf613), /* A4 Tech Co., Ltd Bloody V2 mouse */ |
| | | MAKE_VIDPID(0x09da, 0xf624), /* A4 Tech Co., Ltd Bloody B120 Keyboard */ |
| | | |
| | | MAKE_VIDPID(0x1b1c, 0x1b3c), /* Corsair Harpoon RGB gaming mouse */ |
| | | |
| | | MAKE_VIDPID(0x1d57, 0xad03), /* [T3] 2.4GHz and IR Air Mouse Remote Control */ |
| | | |
| | | MAKE_VIDPID(0x1e7d, 0x2e4a), /* Roccat Tyon Mouse */ |
| | | |
| | | MAKE_VIDPID(0x20a0, 0x422d), /* Winkeyless.kr Keyboards */ |
| | | |
| | | MAKE_VIDPID(0x2516, 0x001f), /* Cooler Master Storm Mizar Mouse */ |
| | | MAKE_VIDPID(0x2516, 0x0028), /* Cooler Master Storm Alcor Mouse */ |
| | | }; |
| | | |
| | | unsigned int i; |
| | | Uint32 id; |
| | | Uint16 vendor; |
| | | Uint16 product; |
| | | |
| | | SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL); |
| | | |
| | | if (SDL_IsJoystickPS4(vendor, product) && SDL_IsPS4RemapperRunning()) { |
| | | /* Check the joystick blacklist */ |
| | | id = MAKE_VIDPID(vendor, product); |
| | | for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) { |
| | | if (id == joystick_blacklist[i]) { |
| | | return SDL_TRUE; |
| | | } |
| | | } |
| | | |
| | | if (SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0) == SDL_CONTROLLER_TYPE_PS4 && SDL_IsPS4RemapperRunning()) { |
| | | return SDL_TRUE; |
| | | } |
| | | |