Bladeren bron

android: Add RGB LED support for joysticks.

MAJigsaw77 3 maanden geleden
bovenliggende
commit
cb04dcd6f8

+ 59 - 4
android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java

@@ -6,6 +6,11 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.List;
 
 
 import android.content.Context;
 import android.content.Context;
+import android.hardware.lights.Light;
+import android.hardware.lights.LightsRequest;
+import android.hardware.lights.LightsManager;
+import android.hardware.lights.LightState;
+import android.graphics.Color;
 import android.os.Build;
 import android.os.Build;
 import android.os.VibrationEffect;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.os.Vibrator;
@@ -25,7 +30,7 @@ public class SDLControllerManager
     static native void nativeAddJoystick(int device_id, String name, String desc,
     static native void nativeAddJoystick(int device_id, String name, String desc,
                                                 int vendor_id, int product_id,
                                                 int vendor_id, int product_id,
                                                 int button_mask,
                                                 int button_mask,
-                                                int naxes, int axis_mask, int nhats, boolean can_rumble);
+                                                int naxes, int axis_mask, int nhats, boolean can_rumble, boolean has_rgb_led);
     static native void nativeRemoveJoystick(int device_id);
     static native void nativeRemoveJoystick(int device_id);
     static native void nativeAddHaptic(int device_id, String name);
     static native void nativeAddHaptic(int device_id, String name);
     static native void nativeRemoveHaptic(int device_id);
     static native void nativeRemoveHaptic(int device_id);
@@ -69,6 +74,13 @@ public class SDLControllerManager
         mJoystickHandler.pollInputDevices();
         mJoystickHandler.pollInputDevices();
     }
     }
 
 
+    /**
+     * This method is called by SDL using JNI.
+     */
+    static void joystickSetLED(int device_id, int red, int green, int blue) {
+        mJoystickHandler.setLED(device_id, red, green, blue);
+    }
+
     /**
     /**
      * This method is called by SDL using JNI.
      * This method is called by SDL using JNI.
      */
      */
@@ -139,6 +151,8 @@ class SDLJoystickHandler {
         String desc;
         String desc;
         ArrayList<InputDevice.MotionRange> axes;
         ArrayList<InputDevice.MotionRange> axes;
         ArrayList<InputDevice.MotionRange> hats;
         ArrayList<InputDevice.MotionRange> hats;
+        ArrayList<Light> lights;
+        LightsManager.LightsSession lightsSession;
     }
     }
     static class RangeComparator implements Comparator<InputDevice.MotionRange> {
     static class RangeComparator implements Comparator<InputDevice.MotionRange> {
         @Override
         @Override
@@ -211,6 +225,7 @@ class SDLJoystickHandler {
                     joystick.desc = getJoystickDescriptor(joystickDevice);
                     joystick.desc = getJoystickDescriptor(joystickDevice);
                     joystick.axes = new ArrayList<InputDevice.MotionRange>();
                     joystick.axes = new ArrayList<InputDevice.MotionRange>();
                     joystick.hats = new ArrayList<InputDevice.MotionRange>();
                     joystick.hats = new ArrayList<InputDevice.MotionRange>();
+                    joystick.lights = new ArrayList<Light>();
 
 
                     List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
                     List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
                     Collections.sort(ranges, new RangeComparator());
                     Collections.sort(ranges, new RangeComparator());
@@ -225,18 +240,30 @@ class SDLJoystickHandler {
                     }
                     }
 
 
                     boolean can_rumble = false;
                     boolean can_rumble = false;
+                    boolean has_rgb_led = false;
                     if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
                     if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
-                        VibratorManager manager = joystickDevice.getVibratorManager();
-                        int[] vibrators = manager.getVibratorIds();
+                        VibratorManager vibratorManager = joystickDevice.getVibratorManager();
+                        int[] vibrators = vibratorManager.getVibratorIds();
                         if (vibrators.length > 0) {
                         if (vibrators.length > 0) {
                             can_rumble = true;
                             can_rumble = true;
                         }
                         }
+                        LightsManager lightsManager = joystickDevice.getLightsManager();
+                        List<Light> lights = lightsManager.getLights();
+                        for (Light light : lights) {
+                            if (light.hasRgbControl()) {
+                                joystick.lights.add(light);
+                            }
+                        }
+                        if (!joystick.lights.isEmpty()) {
+                            joystick.lightsSession = lightsManager.openSession();
+                            has_rgb_led = true;
+                        }
                     }
                     }
 
 
                     mJoysticks.add(joystick);
                     mJoysticks.add(joystick);
                     SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
                     SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
                             getVendorId(joystickDevice), getProductId(joystickDevice),
                             getVendorId(joystickDevice), getProductId(joystickDevice),
-                            getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble);
+                            getButtonMask(joystickDevice), joystick.axes.size(), getAxisMask(joystick.axes), joystick.hats.size()/2, can_rumble, has_rgb_led);
                 }
                 }
             }
             }
         }
         }
@@ -262,6 +289,16 @@ class SDLJoystickHandler {
                 SDLControllerManager.nativeRemoveJoystick(device_id);
                 SDLControllerManager.nativeRemoveJoystick(device_id);
                 for (int i = 0; i < mJoysticks.size(); i++) {
                 for (int i = 0; i < mJoysticks.size(); i++) {
                     if (mJoysticks.get(i).device_id == device_id) {
                     if (mJoysticks.get(i).device_id == device_id) {
+                        if (Build.VERSION.SDK_INT >= 31 /* Android 12.0 (S) */) {
+                            if (mJoysticks.get(i).lightsSession != null) {
+                                try {
+                                    mJoysticks.get(i).lightsSession.close();
+                                } catch (Exception e) {
+                                    // Session may already be unregistered when device disconnects
+                                }
+                                mJoysticks.get(i).lightsSession = null;
+                            }
+                        }
                         mJoysticks.remove(i);
                         mJoysticks.remove(i);
                         break;
                         break;
                     }
                     }
@@ -453,6 +490,24 @@ class SDLJoystickHandler {
         }
         }
         return button_mask;
         return button_mask;
     }
     }
+
+    void setLED(int device_id, int red, int green, int blue) {
+        if (Build.VERSION.SDK_INT < 31 /* Android 12.0 (S) */) {
+            return;
+        }
+        SDLJoystick joystick = getJoystick(device_id);
+        if (joystick == null || joystick.lights.isEmpty()) {
+            return;
+        }
+        LightsRequest.Builder lightsRequest = new LightsRequest.Builder();
+        LightState lightState = new LightState.Builder().setColor(Color.rgb(red, green, blue)).build();
+        for (Light light : joystick.lights) {
+            if (light.hasRgbControl()) {
+                lightsRequest.addLight(light, lightState);
+            }
+        }
+        joystick.lightsSession.requestLights(lightsRequest.build());
+    }
 }
 }
 
 
 class SDLHapticHandler_API31 extends SDLHapticHandler {
 class SDLHapticHandler_API31 extends SDLHapticHandler {

+ 14 - 5
src/core/android/SDL_android.c

@@ -314,7 +314,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
 JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
 JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
     JNIEnv *env, jclass jcls,
     JNIEnv *env, jclass jcls,
     jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
     jint device_id, jstring device_name, jstring device_desc, jint vendor_id, jint product_id,
-    jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble);
+    jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble, jboolean has_rgb_led);
 
 
 JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
 JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
     JNIEnv *env, jclass jcls,
     JNIEnv *env, jclass jcls,
@@ -334,7 +334,7 @@ static JNINativeMethod SDLControllerManager_tab[] = {
     { "onNativePadUp", "(II)Z", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp) },
     { "onNativePadUp", "(II)Z", SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp) },
     { "onNativeJoy", "(IIF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy) },
     { "onNativeJoy", "(IIF)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy) },
     { "onNativeHat", "(IIII)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat) },
     { "onNativeHat", "(IIII)V", SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat) },
-    { "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIIIIIZ)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
+    { "nativeAddJoystick", "(ILjava/lang/String;Ljava/lang/String;IIIIIIZZ)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick) },
     { "nativeRemoveJoystick", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick) },
     { "nativeRemoveJoystick", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick) },
     { "nativeAddHaptic", "(ILjava/lang/String;)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic) },
     { "nativeAddHaptic", "(ILjava/lang/String;)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic) },
     { "nativeRemoveHaptic", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic) }
     { "nativeRemoveHaptic", "(I)V", SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic) }
@@ -406,6 +406,7 @@ static jclass mControllerManagerClass;
 
 
 // method signatures
 // method signatures
 static jmethodID midPollInputDevices;
 static jmethodID midPollInputDevices;
+static jmethodID midJoystickSetLED;
 static jmethodID midPollHapticDevices;
 static jmethodID midPollHapticDevices;
 static jmethodID midHapticRun;
 static jmethodID midHapticRun;
 static jmethodID midHapticRumble;
 static jmethodID midHapticRumble;
@@ -752,6 +753,8 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
 
 
     midPollInputDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
     midPollInputDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
                                                     "pollInputDevices", "()V");
                                                     "pollInputDevices", "()V");
+    midJoystickSetLED = (*env)->GetStaticMethodID(env, mControllerManagerClass,
+                                              "joystickSetLED", "(IIII)V");
     midPollHapticDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
     midPollHapticDevices = (*env)->GetStaticMethodID(env, mControllerManagerClass,
                                                      "pollHapticDevices", "()V");
                                                      "pollHapticDevices", "()V");
     midHapticRun = (*env)->GetStaticMethodID(env, mControllerManagerClass,
     midHapticRun = (*env)->GetStaticMethodID(env, mControllerManagerClass,
@@ -761,7 +764,7 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv *env
     midHapticStop = (*env)->GetStaticMethodID(env, mControllerManagerClass,
     midHapticStop = (*env)->GetStaticMethodID(env, mControllerManagerClass,
                                               "hapticStop", "(I)V");
                                               "hapticStop", "(I)V");
 
 
-    if (!midPollInputDevices || !midPollHapticDevices || !midHapticRun || !midHapticRumble || !midHapticStop) {
+    if (!midPollInputDevices || !midJoystickSetLED || !midPollHapticDevices || !midHapticRun || !midHapticRumble || !midHapticStop) {
         __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLControllerManager.java?");
         __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLControllerManager.java?");
     }
     }
 
 
@@ -1191,13 +1194,13 @@ JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
     JNIEnv *env, jclass jcls,
     JNIEnv *env, jclass jcls,
     jint device_id, jstring device_name, jstring device_desc,
     jint device_id, jstring device_name, jstring device_desc,
     jint vendor_id, jint product_id,
     jint vendor_id, jint product_id,
-    jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble)
+    jint button_mask, jint naxes, jint axis_mask, jint nhats, jboolean can_rumble, jboolean has_rgb_led)
 {
 {
 #ifdef SDL_JOYSTICK_ANDROID
 #ifdef SDL_JOYSTICK_ANDROID
     const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
     const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
     const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
     const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
 
 
-    Android_AddJoystick(device_id, name, desc, vendor_id, product_id, button_mask, naxes, axis_mask, nhats, can_rumble);
+    Android_AddJoystick(device_id, name, desc, vendor_id, product_id, button_mask, naxes, axis_mask, nhats, can_rumble, has_rgb_led);
 
 
     (*env)->ReleaseStringUTFChars(env, device_name, name);
     (*env)->ReleaseStringUTFChars(env, device_name, name);
     (*env)->ReleaseStringUTFChars(env, device_desc, desc);
     (*env)->ReleaseStringUTFChars(env, device_desc, desc);
@@ -2186,6 +2189,12 @@ void Android_JNI_PollInputDevices(void)
     (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollInputDevices);
     (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollInputDevices);
 }
 }
 
 
+void Android_JNI_JoystickSetLED(int device_id, int red, int green, int blue)
+{
+    JNIEnv *env = Android_JNI_GetEnv();
+    (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midJoystickSetLED, device_id, red, green, blue);
+}
+
 void Android_JNI_PollHapticDevices(void)
 void Android_JNI_PollHapticDevices(void)
 {
 {
     JNIEnv *env = Android_JNI_GetEnv();
     JNIEnv *env = Android_JNI_GetEnv();

+ 1 - 0
src/core/android/SDL_android.h

@@ -104,6 +104,7 @@ int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seco
 
 
 // Joystick support
 // Joystick support
 void Android_JNI_PollInputDevices(void);
 void Android_JNI_PollInputDevices(void);
+void Android_JNI_JoystickSetLED(int device_id, int red, int green, int blue);
 
 
 // Haptic support
 // Haptic support
 void Android_JNI_PollHapticDevices(void);
 void Android_JNI_PollHapticDevices(void);

+ 15 - 2
src/joystick/android/SDL_sysjoystick.c

@@ -305,7 +305,7 @@ bool Android_OnHat(int device_id, int hat_id, int x, int y)
     return false;
     return false;
 }
 }
 
 
-void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble)
+void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble, bool has_rgb_led)
 {
 {
     SDL_joylist_item *item;
     SDL_joylist_item *item;
     SDL_GUID guid;
     SDL_GUID guid;
@@ -380,6 +380,7 @@ void Android_AddJoystick(int device_id, const char *name, const char *desc, int
     item->naxes = naxes;
     item->naxes = naxes;
     item->nhats = nhats;
     item->nhats = nhats;
     item->can_rumble = can_rumble;
     item->can_rumble = can_rumble;
+    item->has_rgb_led = has_rgb_led;
     item->device_instance = SDL_GetNextObjectID();
     item->device_instance = SDL_GetNextObjectID();
     if (!SDL_joylist_tail) {
     if (!SDL_joylist_tail) {
         SDL_joylist = SDL_joylist_tail = item;
         SDL_joylist = SDL_joylist_tail = item;
@@ -581,6 +582,10 @@ static bool ANDROID_JoystickOpen(SDL_Joystick *joystick, int device_index)
         SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
         SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
     }
     }
 
 
+    if (item->has_rgb_led) {
+        SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, true);
+    }
+
     return true;
     return true;
 }
 }
 
 
@@ -607,7 +612,15 @@ static bool ANDROID_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_r
 
 
 static bool ANDROID_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
 static bool ANDROID_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
 {
 {
-    return SDL_Unsupported();
+    SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
+    if (!item) {
+        return SDL_SetError("SetLED failed, device disconnected");
+    }
+    if (!item->has_rgb_led) {
+        return SDL_Unsupported();
+    }
+    Android_JNI_JoystickSetLED(item->device_id, red, green, blue);
+    return true;
 }
 }
 
 
 static bool ANDROID_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
 static bool ANDROID_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)

+ 2 - 1
src/joystick/android/SDL_sysjoystick_c.h

@@ -32,7 +32,7 @@ extern bool Android_OnPadDown(int device_id, int keycode);
 extern bool Android_OnPadUp(int device_id, int keycode);
 extern bool Android_OnPadUp(int device_id, int keycode);
 extern bool Android_OnJoy(int device_id, int axisnum, float value);
 extern bool Android_OnJoy(int device_id, int axisnum, float value);
 extern bool Android_OnHat(int device_id, int hat_id, int x, int y);
 extern bool Android_OnHat(int device_id, int hat_id, int x, int y);
-extern void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble);
+extern void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble, bool has_rgb_led);
 extern void Android_RemoveJoystick(int device_id);
 extern void Android_RemoveJoystick(int device_id);
 
 
 // A linked list of available joysticks
 // A linked list of available joysticks
@@ -46,6 +46,7 @@ typedef struct SDL_joylist_item
     int nbuttons, naxes, nhats;
     int nbuttons, naxes, nhats;
     int dpad_state;
     int dpad_state;
     bool can_rumble;
     bool can_rumble;
+    bool has_rgb_led;
 
 
     struct SDL_joylist_item *next;
     struct SDL_joylist_item *next;
 } SDL_joylist_item;
 } SDL_joylist_item;