SDL: Removed balls from the joystick API

From fcafe40948fe308cc9552df5a3d625ee2725de5a Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 5 Dec 2022 12:47:48 -0800
Subject: [PATCH] Removed balls from the joystick API

They were only used by one joystick decades ago, so removing them for SDL3

Fixes https://github.com/libsdl-org/SDL/issues/6766
---
 .../org/libsdl/app/SDLControllerManager.java  |  4 +-
 include/SDL3/SDL_events.h                     | 20 +----
 include/SDL3/SDL_joystick.h                   | 40 ---------
 src/core/android/SDL_android.c                |  6 +-
 src/dynapi/SDL_dynapi.sym                     |  2 -
 src/dynapi/SDL_dynapi_overrides.h             |  2 -
 src/dynapi/SDL_dynapi_procs.h                 |  2 -
 src/events/SDL_events.c                       |  6 --
 src/joystick/SDL_joystick.c                   | 83 +------------------
 src/joystick/SDL_joystick_c.h                 |  2 -
 src/joystick/SDL_sysjoystick.h                |  7 --
 src/joystick/android/SDL_sysjoystick.c        |  6 +-
 src/joystick/android/SDL_sysjoystick_c.h      |  4 +-
 src/joystick/apple/SDL_mfijoystick.m          |  1 -
 src/joystick/darwin/SDL_iokitjoystick.c       |  1 -
 src/joystick/emscripten/SDL_sysjoystick.c     |  1 -
 src/joystick/linux/SDL_sysjoystick.c          | 59 -------------
 src/joystick/linux/SDL_sysjoystick_c.h        |  5 --
 src/test/SDL_test_common.c                    |  5 --
 test/controllermap.c                          |  8 +-
 test/testautomation_joystick.c                |  1 -
 test/testjoystick.c                           |  6 --
 22 files changed, 14 insertions(+), 257 deletions(-)

diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
index 82373d9d6fd6..1486f4ed1ec9 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
@@ -24,7 +24,7 @@
     public static native int nativeAddJoystick(int device_id, String name, String desc,
                                                int vendor_id, int product_id,
                                                boolean is_accelerometer, int button_mask,
-                                               int naxes, int nhats, int nballs);
+                                               int naxes, int nhats);
     public static native int nativeRemoveJoystick(int device_id);
     public static native int nativeAddHaptic(int device_id, String name);
     public static native int nativeRemoveHaptic(int device_id);
@@ -210,7 +210,7 @@ public void pollInputDevices() {
                     mJoysticks.add(joystick);
                     SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
                             getVendorId(joystickDevice), getProductId(joystickDevice), false,
-                            getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
+                            getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2);
                 }
             }
         }
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index 6ce016db3407..a666c2d0d23f 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -112,8 +112,7 @@ typedef enum
 
     /* Joystick events */
     SDL_JOYAXISMOTION  = 0x600, /**< Joystick axis motion */
-    SDL_JOYBALLMOTION,          /**< Joystick trackball motion */
-    SDL_JOYHATMOTION,           /**< Joystick hat position change */
+    SDL_JOYHATMOTION   = 0x602, /**< Joystick hat position change */
     SDL_JOYBUTTONDOWN,          /**< Joystick button pressed */
     SDL_JOYBUTTONUP,            /**< Joystick button released */
     SDL_JOYDEVICEADDED,         /**< A new joystick has been inserted into the system */
@@ -338,22 +337,6 @@ typedef struct SDL_JoyAxisEvent
     Uint16 padding4;
 } SDL_JoyAxisEvent;
 
-/**
- *  \brief Joystick trackball motion event structure (event.jball.*)
- */
-typedef struct SDL_JoyBallEvent
-{
-    Uint32 type;        /**< ::SDL_JOYBALLMOTION */
-    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
-    SDL_JoystickID which; /**< The joystick instance id */
-    Uint8 ball;         /**< The joystick trackball index */
-    Uint8 padding1;
-    Uint8 padding2;
-    Uint8 padding3;
-    Sint16 xrel;        /**< The relative motion in the X direction */
-    Sint16 yrel;        /**< The relative motion in the Y direction */
-} SDL_JoyBallEvent;
-
 /**
  *  \brief Joystick hat position change event structure (event.jhat.*)
  */
@@ -636,7 +619,6 @@ typedef union SDL_Event
     SDL_MouseButtonEvent button;            /**< Mouse button event data */
     SDL_MouseWheelEvent wheel;              /**< Mouse wheel event data */
     SDL_JoyAxisEvent jaxis;                 /**< Joystick axis event data */
-    SDL_JoyBallEvent jball;                 /**< Joystick ball event data */
     SDL_JoyHatEvent jhat;                   /**< Joystick hat event data */
     SDL_JoyButtonEvent jbutton;             /**< Joystick button event data */
     SDL_JoyDeviceEvent jdevice;             /**< Joystick device change event data */
diff --git a/include/SDL3/SDL_joystick.h b/include/SDL3/SDL_joystick.h
index 418b833fd7b9..5fa2e754ee02 100644
--- a/include/SDL3/SDL_joystick.h
+++ b/include/SDL3/SDL_joystick.h
@@ -717,24 +717,6 @@ extern DECLSPEC SDL_JoystickID SDLCALL SDL_JoystickInstanceID(SDL_Joystick *joys
  */
 extern DECLSPEC int SDLCALL SDL_JoystickNumAxes(SDL_Joystick *joystick);
 
-/**
- * Get the number of trackballs on a joystick.
- *
- * Joystick trackballs have only relative motion events associated with them
- * and their state cannot be polled.
- *
- * Most joysticks do not have trackballs.
- *
- * \param joystick an SDL_Joystick structure containing joystick information
- * \returns the number of trackballs on success or a negative error code on
- *          failure; call SDL_GetError() for more information.
- *
- * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_JoystickGetBall
- */
-extern DECLSPEC int SDLCALL SDL_JoystickNumBalls(SDL_Joystick *joystick);
-
 /**
  * Get the number of POV hats on a joystick.
  *
@@ -886,28 +868,6 @@ extern DECLSPEC SDL_bool SDLCALL SDL_JoystickGetAxisInitialState(SDL_Joystick *j
 extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetHat(SDL_Joystick *joystick,
                                                  int hat);
 
-/**
- * Get the ball axis change since the last poll.
- *
- * Trackballs can only return relative motion since the last call to
- * SDL_JoystickGetBall(), these motion deltas are placed into `dx` and `dy`.
- *
- * Most joysticks do not have trackballs.
- *
- * \param joystick the SDL_Joystick to query
- * \param ball the ball index to query; ball indices start at index 0
- * \param dx stores the difference in the x axis position since the last poll
- * \param dy stores the difference in the y axis position since the last poll
- * \returns 0 on success or a negative error code on failure; call
- *          SDL_GetError() for more information.
- *
- * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_JoystickNumBalls
- */
-extern DECLSPEC int SDLCALL SDL_JoystickGetBall(SDL_Joystick *joystick,
-                                                int ball, int *dx, int *dy);
-
 /**
  * Get the current state of a button on a joystick.
  *
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index caa2ea18f9a7..fbec5a8971e5 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -240,7 +240,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
     JNIEnv *env, jclass jcls,
     jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
-    jboolean is_accelerometer, jint button_mask, jint naxes, jint nhats, jint nballs);
+    jboolean is_accelerometer, jint button_mask, jint naxes, jint nhats);
 
 JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
     JNIEnv *env, jclass jcls,
@@ -939,13 +939,13 @@ JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
     JNIEnv *env, jclass jcls,
     jint device_id, jstring device_name, jstring device_desc,
     jint vendor_id, jint product_id, jboolean is_accelerometer,
-    jint button_mask, jint naxes, jint nhats, jint nballs)
+    jint button_mask, jint naxes, jint nhats)
 {
     int retval;
     const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
     const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
 
-    retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer ? SDL_TRUE : SDL_FALSE, button_mask, naxes, nhats, nballs);
+    retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer ? SDL_TRUE : SDL_FALSE, button_mask, naxes, nhats);
 
     (*env)->ReleaseStringUTFChars(env, device_name, name);
     (*env)->ReleaseStringUTFChars(env, device_desc, desc);
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index d8514dd18a80..948c6168f9b5 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -746,7 +746,6 @@ SDL3_0.0.0 {
     SDL_JoystickGetAttached;
     SDL_JoystickInstanceID;
     SDL_JoystickNumAxes;
-    SDL_JoystickNumBalls;
     SDL_JoystickNumHats;
     SDL_JoystickNumButtons;
     SDL_JoystickUpdate;
@@ -754,7 +753,6 @@ SDL3_0.0.0 {
     SDL_JoystickGetAxis;
     SDL_JoystickGetAxisInitialState;
     SDL_JoystickGetHat;
-    SDL_JoystickGetBall;
     SDL_JoystickGetButton;
     SDL_JoystickRumble;
     SDL_JoystickRumbleTriggers;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 0984586e638a..d8249bb187c0 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -202,14 +202,12 @@
 #define SDL_JoystickGetAttached SDL_JoystickGetAttached_REAL
 #define SDL_JoystickInstanceID SDL_JoystickInstanceID_REAL
 #define SDL_JoystickNumAxes SDL_JoystickNumAxes_REAL
-#define SDL_JoystickNumBalls SDL_JoystickNumBalls_REAL
 #define SDL_JoystickNumHats SDL_JoystickNumHats_REAL
 #define SDL_JoystickNumButtons SDL_JoystickNumButtons_REAL
 #define SDL_JoystickUpdate SDL_JoystickUpdate_REAL
 #define SDL_JoystickEventState SDL_JoystickEventState_REAL
 #define SDL_JoystickGetAxis SDL_JoystickGetAxis_REAL
 #define SDL_JoystickGetHat SDL_JoystickGetHat_REAL
-#define SDL_JoystickGetBall SDL_JoystickGetBall_REAL
 #define SDL_JoystickGetButton SDL_JoystickGetButton_REAL
 #define SDL_JoystickClose SDL_JoystickClose_REAL
 #define SDL_GetKeyboardFocus SDL_GetKeyboardFocus_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 0f6b8a2e31ed..53dede94f57f 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -229,14 +229,12 @@ SDL_DYNAPI_PROC(SDL_JoystickGUID,SDL_JoystickGetGUIDFromString,(const char *a),(
 SDL_DYNAPI_PROC(SDL_bool,SDL_JoystickGetAttached,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(SDL_JoystickID,SDL_JoystickInstanceID,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_JoystickNumAxes,(SDL_Joystick *a),(a),return)
-SDL_DYNAPI_PROC(int,SDL_JoystickNumBalls,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_JoystickNumHats,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_JoystickNumButtons,(SDL_Joystick *a),(a),return)
 SDL_DYNAPI_PROC(void,SDL_JoystickUpdate,(void),(),)
 SDL_DYNAPI_PROC(int,SDL_JoystickEventState,(int a),(a),return)
 SDL_DYNAPI_PROC(Sint16,SDL_JoystickGetAxis,(SDL_Joystick *a, int b),(a,b),return)
 SDL_DYNAPI_PROC(Uint8,SDL_JoystickGetHat,(SDL_Joystick *a, int b),(a,b),return)
-SDL_DYNAPI_PROC(int,SDL_JoystickGetBall,(SDL_Joystick *a, int b, int *c, int *d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(Uint8,SDL_JoystickGetButton,(SDL_Joystick *a, int b),(a,b),return)
 SDL_DYNAPI_PROC(void,SDL_JoystickClose,(SDL_Joystick *a),(a),)
 SDL_DYNAPI_PROC(SDL_Window*,SDL_GetKeyboardFocus,(void),(),return)
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index f0b7022fadbc..07adf42c9dc8 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -360,12 +360,6 @@ static void SDL_LogEvent(const SDL_Event *event)
                            (uint)event->jaxis.axis, (int)event->jaxis.value);
         break;
 
-        SDL_EVENT_CASE(SDL_JOYBALLMOTION)
-        (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d ball=%u xrel=%d yrel=%d)",
-                           (uint)event->jball.timestamp, (int)event->jball.which,
-                           (uint)event->jball.ball, (int)event->jball.xrel, (int)event->jball.yrel);
-        break;
-
         SDL_EVENT_CASE(SDL_JOYHATMOTION)
         (void)SDL_snprintf(details, sizeof(details), " (timestamp=%u which=%d hat=%u value=%u)",
                            (uint)event->jhat.timestamp, (int)event->jhat.which,
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index fe452f8dd881..9ebdb7e160e5 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -528,13 +528,10 @@ SDL_JoystickOpen(int device_index)
     if (joystick->nhats > 0) {
         joystick->hats = (Uint8 *)SDL_calloc(joystick->nhats, sizeof(Uint8));
     }
-    if (joystick->nballs > 0) {
-        joystick->balls = (struct balldelta *)SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
-    }
     if (joystick->nbuttons > 0) {
         joystick->buttons = (Uint8 *)SDL_calloc(joystick->nbuttons, sizeof(Uint8));
     }
-    if (((joystick->naxes > 0) && !joystick->axes) || ((joystick->nhats > 0) && !joystick->hats) || ((joystick->nballs > 0) && !joystick->balls) || ((joystick->nbuttons > 0) && !joystick->buttons)) {
+    if (((joystick->naxes > 0) && !joystick->axes) || ((joystick->nhats > 0) && !joystick->hats) || ((joystick->nbuttons > 0) && !joystick->buttons)) {
         SDL_OutOfMemory();
         SDL_JoystickClose(joystick);
         SDL_UnlockJoysticks();
@@ -719,16 +716,6 @@ int SDL_JoystickNumHats(SDL_Joystick *joystick)
     return joystick->nhats;
 }
 
-/*
- * Get the number of trackballs on a joystick
- */
-int SDL_JoystickNumBalls(SDL_Joystick *joystick)
-{
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
-
-    return joystick->nballs;
-}
-
 /*
  * Get the number of buttons on a joystick
  */
@@ -794,31 +781,6 @@ Uint8 SDL_JoystickGetHat(SDL_Joystick *joystick, int hat)
     return state;
 }
 
-/*
- * Get the ball axis change since the last poll
- */
-int SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy)
-{
-    int retval;
-
-    CHECK_JOYSTICK_MAGIC(joystick, -1);
-
-    retval = 0;
-    if (ball < joystick->nballs) {
-        if (dx) {
-            *dx = joystick->balls[ball].dx;
-        }
-        if (dy) {
-            *dy = joystick->balls[ball].dy;
-        }
-        joystick->balls[ball].dx = 0;
-        joystick->balls[ball].dy = 0;
-    } else {
-        return SDL_SetError("Joystick only has %d balls", joystick->nballs);
-    }
-    return retval;
-}
-
 /*
  * Get the current state of a button on a joystick
  */
@@ -1160,7 +1122,6 @@ void SDL_JoystickClose(SDL_Joystick *joystick)
     /* Free the data associated with this joystick */
     SDL_free(joystick->axes);
     SDL_free(joystick->hats);
-    SDL_free(joystick->balls);
     SDL_free(joystick->buttons);
     for (i = 0; i < joystick->ntouchpads; i++) {
         SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
@@ -1563,46 +1524,6 @@ int SDL_PrivateJoystickHat(Uint64 timestamp, SDL_Joystick *joystick, Uint8 hat,
     return posted;
 }
 
-int SDL_PrivateJoystickBall(Uint64 timestamp, SDL_Joystick *joystick, Uint8 ball,
-                            Sint16 xrel, Sint16 yrel)
-{
-    int posted;
-
-    SDL_AssertJoysticksLocked();
-
-    CHECK_JOYSTICK_MAGIC(joystick, 0);
-
-    /* Make sure we're not getting garbage events */
-    if (ball >= joystick->nballs) {
-        return 0;
-    }
-
-    /* We ignore events if we don't have keyboard focus. */
-    if (SDL_PrivateJoystickShouldIgnoreEvent()) {
-        return 0;
-    }
-
-    /* Update internal mouse state */
-    joystick->balls[ball].dx += xrel;
-    joystick->balls[ball].dy += yrel;
-
-    /* Post the event, if desired */
-    posted = 0;
-#if !SDL_EVENTS_DISABLED
-    if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
-        SDL_Event event;
-        event.type = SDL_JOYBALLMOTION;
-        event.common.timestamp = timestamp;
-        event.jball.which = joystick->instance_id;
-        event.jball.ball = ball;
-        event.jball.xrel = xrel;
-        event.jball.yrel = yrel;
-        posted = SDL_PushEvent(&event) == 1;
-    }
-#endif /* !SDL_EVENTS_DISABLED */
-    return posted;
-}
-
 int SDL_PrivateJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 button, Uint8 state)
 {
     int posted;
@@ -1720,7 +1641,7 @@ int SDL_JoystickEventState(int state)
     return SDL_DISABLE;
 #else
     const Uint32 event_list[] = {
-        SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
+        SDL_JOYAXISMOTION, SDL_JOYHATMOTION,
         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED,
         SDL_JOYBATTERYUPDATED
     };
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index d3e4076cab19..4c901269c87c 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -153,8 +153,6 @@ extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance);
 extern void SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick);
 extern int SDL_PrivateJoystickAxis(Uint64 timestamp, SDL_Joystick *joystick,
                                    Uint8 axis, Sint16 value);
-extern int SDL_PrivateJoystickBall(Uint64 timestamp, SDL_Joystick *joystick,
-                                   Uint8 ball, Sint16 xrel, Sint16 yrel);
 extern int SDL_PrivateJoystickHat(Uint64 timestamp, SDL_Joystick *joystick,
                                   Uint8 hat, Uint8 value);
 extern int SDL_PrivateJoystickButton(Uint64 timestamp, SDL_Joystick *joystick,
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index f6ada4aa48c4..5c0be7b23d19 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -82,13 +82,6 @@ struct _SDL_Joystick
     int nhats;   /* Number of hats on the joystick */
     Uint8 *hats; /* Current hat states */
 
-    int nballs; /* Number of trackballs on the joystick */
-    struct balldelta
-    {
-        int dx;
-        int dy;
-    } *balls; /* Current ball motion deltas */
-
     int nbuttons;   /* Number of buttons on the joystick */
     Uint8 *buttons; /* Current button states */
 
diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c
index d00d7f05d69b..b28e3385b20f 100644
--- a/src/joystick/android/SDL_sysjoystick.c
+++ b/src/joystick/android/SDL_sysjoystick.c
@@ -297,7 +297,7 @@ int Android_OnHat(int device_id, int hat_id, int x, int y)
     return -1;
 }
 
-int Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int nhats, int nballs)
+int Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int nhats)
 {
     SDL_joylist_item *item;
     SDL_JoystickGUID guid;
@@ -389,7 +389,6 @@ int Android_AddJoystick(int device_id, const char *name, const char *desc, int v
     }
     item->naxes = naxes;
     item->nhats = nhats;
-    item->nballs = nballs;
     item->device_instance = SDL_GetNextJoystickInstanceID();
     if (SDL_joylist_tail == NULL) {
         SDL_joylist = SDL_joylist_tail = item;
@@ -478,7 +477,7 @@ static int ANDROID_JoystickInit(void)
 
     if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
         /* Default behavior, accelerometer as joystick */
-        Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, 0, 0, SDL_TRUE, 0, 3, 0, 0);
+        Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, 0, 0, SDL_TRUE, 0, 3, 0);
     }
     return 0;
 }
@@ -588,7 +587,6 @@ static int ANDROID_JoystickOpen(SDL_Joystick *joystick, int device_index)
     joystick->hwdata = (struct joystick_hwdata *)item;
     item->joystick = joystick;
     joystick->nhats = item->nhats;
-    joystick->nballs = item->nballs;
     joystick->nbuttons = item->nbuttons;
     joystick->naxes = item->naxes;
 
diff --git a/src/joystick/android/SDL_sysjoystick_c.h b/src/joystick/android/SDL_sysjoystick_c.h
index b6a9bb05d583..6e0c897a4247 100644
--- a/src/joystick/android/SDL_sysjoystick_c.h
+++ b/src/joystick/android/SDL_sysjoystick_c.h
@@ -32,7 +32,7 @@ extern int Android_OnPadDown(int device_id, int keycode);
 extern int Android_OnPadUp(int device_id, int keycode);
 extern int Android_OnJoy(int device_id, int axisnum, float value);
 extern int Android_OnHat(int device_id, int hat_id, int x, int y);
-extern int Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int nhats, int nballs);
+extern int Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int nhats);
 extern int Android_RemoveJoystick(int device_id);
 
 /* A linked list of available joysticks */
@@ -44,7 +44,7 @@ typedef struct SDL_joylist_item
     SDL_JoystickGUID guid;
     SDL_bool is_accelerometer;
     SDL_Joystick *joystick;
-    int nbuttons, naxes, nhats, nballs;
+    int nbuttons, naxes, nhats;
     int dpad_state;
 
     struct SDL_joylist_item *next;
diff --git a/src/joystick/apple/SDL_mfijoystick.m b/src/joystick/apple/SDL_mfijoystick.m
index 926619f84f53..a4bd3ba9b5fc 100644
--- a/src/joystick/apple/SDL_mfijoystick.m
+++ b/src/joystick/apple/SDL_mfijoystick.m
@@ -767,7 +767,6 @@ static int IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
     joystick->naxes = device->naxes;
     joystick->nhats = device->nhats;
     joystick->nbuttons = device->nbuttons;
-    joystick->nballs = 0;
 
     if (device->has_dualshock_touchpad) {
         SDL_PrivateJoystickAddTouchpad(joystick, 2);
diff --git a/src/joystick/darwin/SDL_iokitjoystick.c b/src/joystick/darwin/SDL_iokitjoystick.c
index 0a289e651279..8656c368c1e3 100644
--- a/src/joystick/darwin/SDL_iokitjoystick.c
+++ b/src/joystick/darwin/SDL_iokitjoystick.c
@@ -750,7 +750,6 @@ static int DARWIN_JoystickOpen(SDL_Joystick *joystick, int device_index)
 
     joystick->naxes = device->axes;
     joystick->nhats = device->hats;
-    joystick->nballs = 0;
     joystick->nbuttons = device->buttons;
     return 0;
 }
diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c
index b2951c408faf..67288257fc63 100644
--- a/src/joystick/emscripten/SDL_sysjoystick.c
+++ b/src/joystick/emscripten/SDL_sysjoystick.c
@@ -309,7 +309,6 @@ static int EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
 
     /* HTML5 Gamepad API doesn't say anything about these */
     joystick->nhats = 0;
-    joystick->nballs = 0;
 
     joystick->nbuttons = item->nbuttons;
     joystick->naxes = item->naxes;
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index 21e4937d5b98..8df434b58493 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -861,23 +861,6 @@ static int allocate_hatdata(SDL_Joystick *joystick)
     return 0;
 }
 
-static int allocate_balldata(SDL_Joystick *joystick)
-{
-    int i;
-
-    joystick->hwdata->balls =
-        (struct hwdata_ball *)SDL_malloc(joystick->nballs *
-                                         sizeof(struct hwdata_ball));
-    if (joystick->hwdata->balls == NULL) {
-        return -1;
-    }
-    for (i = 0; i < joystick->nballs; ++i) {
-        joystick->hwdata->balls[i].axis[0] = 0;
-        joystick->hwdata->balls[i].axis[1] = 0;
-    }
-    return 0;
-}
-
 static SDL_bool GuessIfAxesAreDigitalHat(struct input_absinfo *absinfo_x, struct input_absinfo *absinfo_y)
 {
     /* A "hat" is assumed to be a digital input with at most 9 possible states
@@ -1029,9 +1012,6 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd)
                 ++joystick->naxes;
             }
         }
-        if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
-            ++joystick->nballs;
-        }
 
     } else if ((ioctl(fd, JSIOCGBUTTONS, &key_pam_size, sizeof(key_pam_size)) >= 0) &&
                (ioctl(fd, JSIOCGAXES, &abs_pam_size, sizeof(abs_pam_size)) >= 0)) {
@@ -1105,11 +1085,6 @@ static void ConfigJoystick(SDL_Joystick *joystick, int fd)
             joystick->nhats = 0;
         }
     }
-    if (joystick->nballs > 0) {
-        if (allocate_balldata(joystick) < 0) {
-            joystick->nballs = 0;
-        }
-    }
 
     if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
         if (test_bit(FF_RUMBLE, ffbit)) {
@@ -1320,11 +1295,6 @@ static void HandleHat(Uint64 timestamp, SDL_Joystick *stick, int hatidx, int axi
     }
 }
 
-static void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
-{
-    stick->hwdata->balls[ball].axis[axis] += value;
-}
-
 static int AxisCorrect(SDL_Joystick *joystick, int which, int value)
 {
     struct axis_correct *correct;
@@ -1411,8 +1381,6 @@ static void PollAllValues(Uint64 timestamp, SDL_Joystick *joystick)
             }
         }
     }
-
-    /* Joyballs are relative input, so there's no poll state. Events only! */
 }
 
 static void HandleInputEvents(SDL_Joystick *joystick)
@@ -1468,17 +1436,6 @@ static void HandleInputEvents(SDL_Joystick *joystick)
                     break;
                 }
                 break;
-            case EV_REL:
-                switch (code) {
-                case REL_X:
-                case REL_Y:
-                    code -= REL_X;
-                    HandleBall(joystick, code / 2, code % 2, event->value);
-                    break;
-                default:
-                    break;
-                }
-                break;
             case EV_SYN:
                 switch (code) {
                 case SYN_DROPPED:
@@ -1554,8 +1511,6 @@ static void HandleClassicEvents(SDL_Joystick *joystick)
 
 static void LINUX_JoystickUpdate(SDL_Joystick *joystick)
 {
-    int i;
-
     if (joystick->hwdata->m_bSteamController) {
         SDL_UpdateSteamController(joystick);
         return;
@@ -1566,19 +1521,6 @@ static void LINUX_JoystickUpdate(SDL_Joystick *joystick)
     } else {
         HandleInputEvents(joystick);
     }
-
-    /* Deliver ball motion updates */
-    for (i = 0; i < joystick->nballs; ++i) {
-        int xrel, yrel;
-
-        xrel = joystick->hwdata->balls[i].axis[0];
-        yrel = joystick->hwdata->balls[i].axis[1];
-        if (xrel || yrel) {
-            joystick->hwdata->balls[i].axis[0] = 0;
-            joystick->hwdata->balls[i].axis[1] = 0;
-            SDL_PrivateJoystickBall(0, joystick, (Uint8)i, xrel, yrel);
-        }
-    }
 }
 
 /* Function to close a joystick after use */
@@ -1598,7 +1540,6 @@ static void LINUX_JoystickClose(SDL_Joystick *joystick)
         SDL_free(joystick->hwdata->key_pam);
         SDL_free(joystick->hwdata->abs_pam);
         SDL_free(joystick->hwdata->hats);
-        SDL_free(joystick->hwdata->balls);
         SDL_free(joystick->hwdata->fname);
         SDL_free(joystick->hwdata);
     }
diff --git a/src/joystick/linux/SDL_sysjoystick_c.h b/src/joystick/linux/SDL_sysjoystick_c.h
index b021f374240f..017beaa1cd6f 100644
--- a/src/joystick/linux/SDL_sysjoystick_c.h
+++ b/src/joystick/linux/SDL_sysjoystick_c.h
@@ -44,11 +44,6 @@ struct joystick_hwdata
     {
         int axis[2];
     } *hats;
-    /* The current Linux joystick driver maps balls to two axes */
-    struct hwdata_ball
-    {
-        int axis[2];
-    } *balls;
 
     /* Support for the Linux 2.4 unified input interface */
     Uint8 key_map[KEY_MAX];
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index cbf1052de339..f13565b29d92 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -1587,11 +1587,6 @@ static void SDLTest_PrintEvent(SDL_Event *event)
         SDL_Log("SDL EVENT: Joystick %" SDL_PRIs32 " removed",
                 event->jdevice.which);
         break;
-    case SDL_JOYBALLMOTION:
-        SDL_Log("SDL EVENT: Joystick %" SDL_PRIs32 ": ball %d moved by %d,%d",
-                event->jball.which, event->jball.ball, event->jball.xrel,
-                event->jball.yrel);
-        break;
     case SDL_JOYHATMOTION:
     {
         const char *position = "UNKNOWN";
diff --git a/test/controllermap.c b/test/controllermap.c
index 22c5715eddd5..86a7c67839a6 100644
--- a/test/controllermap.c
+++ b/test/controllermap.c
@@ -370,9 +370,8 @@ WatchJoystick(SDL_Joystick *joystick)
     name = SDL_JoystickName(joystick);
     SDL_Log("Watching joystick %" SDL_PRIs32 ": (%s)\n", SDL_JoystickInstanceID(joystick),
             name ? name : "Unknown Joystick");
-    SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n",
-            SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick),
-            SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick));
+    SDL_Log("Joystick has %d axes, %d hats, and %d buttons\n",
+            SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick), SDL_JoystickNumButtons(joystick));
 
     SDL_Log("\n\n\
     ====================================================================================\n\
@@ -498,8 +497,6 @@ WatchJoystick(SDL_Joystick *joystick)
                     }
                 }
                 break;
-            case SDL_JOYBALLMOTION:
-                break;
             case SDL_JOYBUTTONDOWN:
                 if (event.jbutton.which == nJoystickID) {
                     SDL_GameControllerExtendedBind binding;
@@ -773,7 +770,6 @@ int main(int argc, char *argv[])
             SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick),
                                       guid, sizeof(guid));
             SDL_Log("       axes: %d\n", SDL_JoystickNumAxes(joystick));
-            SDL_Log("      balls: %d\n", SDL_JoystickNumBalls(joystick));
             SDL_Log("       hats: %d\n", SDL_JoystickNumHats(joystick));
             SDL_Log("    buttons: %d\n", SDL_JoystickNumButtons(joystick));
             SDL_Log("instance id: %" SDL_PRIu32 "\n", SDL_JoystickInstanceID(joystick));
diff --git a/test/testautomation_joystick.c b/test/testautomation_joystick.c
index 56becbfc678a..542708c439e8 100644
--- a/test/testautomation_joystick.c
+++ b/test/testautomation_joystick.c
@@ -47,7 +47,6 @@ TestVirtualJoystick(void *arg)
             SDLTest_AssertCheck(SDL_JoystickGetSerial(joystick) == NULL, "SDL_JoystickGetSerial()");
             SDLTest_AssertCheck(SDL_JoystickGetType(joystick) == desc.type, "SDL_JoystickGetType()");
             SDLTest_AssertCheck(SDL_JoystickNumAxes(joystick) == desc.naxes, "SDL_JoystickNumAxes()");
-            SDLTest_AssertCheck(SDL_JoystickNumBalls(joystick) == 0, "SDL_JoystickNumBalls()");
             SDLTest_AssertCheck(SDL_JoystickNumHats(joystick) == desc.nhats, "SDL_JoystickNumHats()");
             SDLTest_AssertCheck(SDL_JoystickN

(Patch may be truncated, please check the link at the top of this post.)