SDL: joystick: Fix underflow with 0 delta timestamp

From 687a59f27774b2f4a38027e32bb9158f7aebf73e Mon Sep 17 00:00:00 2001
From: Vicki Pfau <[EMAIL REDACTED]>
Date: Fri, 29 May 2026 20:42:23 -0700
Subject: [PATCH] joystick: Fix underflow with 0 delta timestamp

Some sensors will occasionally report two identical timestamps in a row.
This leads to the timestamp wrapping calculation to underflow, subtracting
0x80000000 from the timestamp whenever it happens. By adjusting the wrap
test, we can just directly add zero to the timestamp, fixing the underflow.
---
 src/joystick/hidapi/SDL_hidapi_8bitdo.c     | 2 +-
 src/joystick/hidapi/SDL_hidapi_ps4.c        | 2 +-
 src/joystick/hidapi/SDL_hidapi_ps5.c        | 2 +-
 src/joystick/hidapi/SDL_hidapi_steam_hori.c | 2 +-
 src/joystick/linux/SDL_sysjoystick.c        | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/joystick/hidapi/SDL_hidapi_8bitdo.c b/src/joystick/hidapi/SDL_hidapi_8bitdo.c
index 8d70f4aaabf4f..6b1dece533ebb 100644
--- a/src/joystick/hidapi/SDL_hidapi_8bitdo.c
+++ b/src/joystick/hidapi/SDL_hidapi_8bitdo.c
@@ -595,7 +595,7 @@ static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
             Uint32 tick = LOAD32(data[27], data[28], data[29], data[30]);
 
             if (ctx->last_tick) {
-                if (ctx->last_tick < tick) {
+                if (ctx->last_tick <= tick) {
                     delta = (tick - ctx->last_tick);
                 } else {
                     delta = (SDL_MAX_UINT32 - ctx->last_tick + tick + 1);
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index 62c9ff6273be3..08f7460f56ff0 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -1150,7 +1150,7 @@ static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
         float data[3];
 
         tick = LOAD16(packet->rgucTimestamp[0], packet->rgucTimestamp[1]);
-        if (ctx->last_tick < tick) {
+        if (ctx->last_tick <= tick) {
             delta = (tick - ctx->last_tick);
         } else {
             delta = (SDL_MAX_UINT16 - ctx->last_tick + tick + 1);
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 473f7fd2122fc..b67fc59f2b076 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -1364,7 +1364,7 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
             Uint32 delta;
             Uint16 tick = LOAD16(packet->rgucSensorTimestamp[0],
                                  packet->rgucSensorTimestamp[1]);
-            if (ctx->last_tick < tick) {
+            if (ctx->last_tick <= tick) {
                 delta = (tick - ctx->last_tick);
             } else {
                 delta = (SDL_MAX_UINT16 - ctx->last_tick + tick + 1);
diff --git a/src/joystick/hidapi/SDL_hidapi_steam_hori.c b/src/joystick/hidapi/SDL_hidapi_steam_hori.c
index c24602f7fe8a2..be93767ce143b 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam_hori.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam_hori.c
@@ -309,7 +309,7 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
         Uint32 delta;
         Uint16 tick = LOAD16(data[10],
                              data[11]);
-        if (ctx->last_tick < tick) {
+        if (ctx->last_tick <= tick) {
             delta = (tick - ctx->last_tick);
         } else {
             delta = (SDL_MAX_UINT16 - ctx->last_tick + tick + 1);
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index 4a924f41a5e24..ede0d5efdc905 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -2086,7 +2086,7 @@ static void HandleInputEvents(SDL_Joystick *joystick)
                     if (code == MSC_TIMESTAMP) {
                         Sint32 tick = event->value;
                         Sint32 delta;
-                        if (joystick->hwdata->last_tick < tick) {
+                        if (joystick->hwdata->last_tick <= tick) {
                             delta = (tick - joystick->hwdata->last_tick);
                         } else {
                             delta = (SDL_MAX_SINT32 - joystick->hwdata->last_tick + tick + 1);