diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h index de0815913a..cf80b5d5b7 100644 --- a/include/SDL3/SDL_events.h +++ b/include/SDL3/SDL_events.h @@ -151,6 +151,7 @@ typedef enum SDL_EVENT_JOYSTICK_ADDED, /**< A new joystick has been inserted into the system */ SDL_EVENT_JOYSTICK_REMOVED, /**< An opened joystick has been removed */ SDL_EVENT_JOYSTICK_BATTERY_UPDATED, /**< Joystick battery level change */ + SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, /**< Joystick update is complete (disabled by default) */ /* Gamepad events */ SDL_EVENT_GAMEPAD_AXIS_MOTION = 0x650, /**< Gamepad axis motion */ @@ -163,6 +164,7 @@ typedef enum SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION, /**< Gamepad touchpad finger was moved */ SDL_EVENT_GAMEPAD_TOUCHPAD_UP, /**< Gamepad touchpad finger was lifted */ SDL_EVENT_GAMEPAD_SENSOR_UPDATE, /**< Gamepad sensor was updated */ + SDL_EVENT_GAMEPAD_UPDATE_COMPLETE, /**< Gamepad update is complete (disabled by default) */ /* Touch events */ SDL_EVENT_FINGER_DOWN = 0x700, @@ -398,7 +400,7 @@ typedef struct SDL_JoyButtonEvent */ typedef struct SDL_JoyDeviceEvent { - Uint32 type; /**< ::SDL_EVENT_JOYSTICK_ADDED or ::SDL_EVENT_JOYSTICK_REMOVED */ + Uint32 type; /**< ::SDL_EVENT_JOYSTICK_ADDED or ::SDL_EVENT_JOYSTICK_REMOVED or ::SDL_EVENT_JOYSTICK_UPDATE_COMPLETE */ Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ SDL_JoystickID which; /**< The joystick instance id */ } SDL_JoyDeviceEvent; @@ -451,7 +453,7 @@ typedef struct SDL_GamepadButtonEvent */ typedef struct SDL_GamepadDeviceEvent { - Uint32 type; /**< ::SDL_EVENT_GAMEPAD_ADDED, ::SDL_EVENT_GAMEPAD_REMOVED, or ::SDL_EVENT_GAMEPAD_REMAPPED */ + Uint32 type; /**< ::SDL_EVENT_GAMEPAD_ADDED, ::SDL_EVENT_GAMEPAD_REMOVED, or ::SDL_EVENT_GAMEPAD_REMAPPED or ::SDL_EVENT_GAMEPAD_UPDATE_COMPLETE */ Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */ SDL_JoystickID which; /**< The joystick instance id */ } SDL_GamepadDeviceEvent; diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 7e1130b0cf..865a9b063a 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -579,6 +579,8 @@ int SDL_StartEventLoop(void) SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, SDL_FALSE); SDL_SetEventEnabled(SDL_EVENT_DROP_TEXT, SDL_FALSE); #endif + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, SDL_FALSE); + SDL_SetEventEnabled(SDL_EVENT_GAMEPAD_UPDATE_COMPLETE, SDL_FALSE); SDL_EventQ.active = SDL_TRUE; SDL_UnlockMutex(SDL_EventQ.lock); @@ -1264,6 +1266,29 @@ void SDL_SetEventEnabled(Uint32 type, SDL_bool enabled) if (enabled != current_state) { if (enabled) { SDL_disabled_events[hi]->bits[lo / 32] &= ~(1 << (lo & 31)); + + /* Gamepad events depend on joystick events */ + switch (type) { + case SDL_EVENT_GAMEPAD_ADDED: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_ADDED, SDL_TRUE); + break; + case SDL_EVENT_GAMEPAD_REMOVED: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_REMOVED, SDL_TRUE); + break; + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_AXIS_MOTION, SDL_TRUE); + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_HAT_MOTION, SDL_TRUE); + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_DOWN, SDL_TRUE); + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_BUTTON_UP, SDL_TRUE); + break; + case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE: + SDL_SetEventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE, SDL_TRUE); + break; + default: + break; + } } else { /* Disable this event type and discard pending events */ if (!SDL_disabled_events[hi]) { diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index 2df24a6336..5e9dee5ea4 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -392,6 +392,22 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event) SDL_PushEvent(&deviceevent); } } break; + case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE: + { + SDL_AssertJoysticksLocked(); + + for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) { + if (gamepad->joystick->instance_id == event->jdevice.which) { + SDL_Event deviceevent; + + deviceevent.type = SDL_EVENT_GAMEPAD_UPDATE_COMPLETE; + deviceevent.common.timestamp = event->jdevice.timestamp; + deviceevent.gdevice.which = event->jdevice.which; + SDL_PushEvent(&deviceevent); + break; + } + } + } break; default: break; } diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index a4f8939ee4..463569ae12 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -1753,6 +1753,7 @@ int SDL_SendJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick, Uint8 axis, S /* Update internal joystick state */ info->value = value; + joystick->update_complete = timestamp; /* Post the event, if desired */ posted = 0; @@ -1795,6 +1796,7 @@ int SDL_SendJoystickHat(Uint64 timestamp, SDL_Joystick *joystick, Uint8 hat, Uin /* Update internal joystick state */ joystick->hats[hat] = value; + joystick->update_complete = timestamp; /* Post the event, if desired */ posted = 0; @@ -1853,6 +1855,7 @@ int SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 butto /* Update internal joystick state */ joystick->buttons[button] = state; + joystick->update_complete = timestamp; /* Post the event, if desired */ posted = 0; @@ -1913,6 +1916,21 @@ void SDL_UpdateJoysticks(void) } } + if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_UPDATE_COMPLETE)) { + for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { + if (joystick->update_complete) { + SDL_Event event; + + event.type = SDL_EVENT_JOYSTICK_UPDATE_COMPLETE; + event.common.timestamp = joystick->update_complete; + event.gdevice.which = joystick->instance_id; + SDL_PushEvent(&event); + + joystick->update_complete = 0; + } + } + } + /* this needs to happen AFTER walking the joystick list above, so that any dangling hardware data from removed devices can be free'd */ @@ -3178,6 +3196,7 @@ int SDL_SendJoystickTouchpad(Uint64 timestamp, SDL_Joystick *joystick, int touch finger_info->x = x; finger_info->y = y; finger_info->pressure = pressure; + joystick->update_complete = timestamp; /* Post the event, if desired */ posted = 0; @@ -3219,6 +3238,7 @@ int SDL_SendJoystickSensor(Uint64 timestamp, SDL_Joystick *joystick, SDL_SensorT /* Update internal sensor state */ SDL_memcpy(sensor->data, data, num_values * sizeof(*data)); + joystick->update_complete = timestamp; /* Post the event, if desired */ #ifndef SDL_EVENTS_DISABLED diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 99784dcf21..f0f547e10d 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -119,6 +119,8 @@ struct SDL_Joystick SDL_Sensor *gyro _guarded; float sensor_transform[3][3] _guarded; + Uint64 update_complete _guarded; + struct SDL_JoystickDriver *driver _guarded; struct joystick_hwdata *hwdata _guarded; /* Driver dependent information */