--- /dev/null
+package org.libsdl.app;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.content.Context;
+import android.os.*;
+import android.view.*;
+import android.util.Log;
+
+
+public class SDLControllerManager
+{
+
+ public static native int nativeSetupJNI();
+
+ 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);
+ 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);
+ public static native int onNativePadDown(int device_id, int keycode);
+ public static native int onNativePadUp(int device_id, int keycode);
+ public static native void onNativeJoy(int device_id, int axis,
+ float value);
+ public static native void onNativeHat(int device_id, int hat_id,
+ int x, int y);
+
+ protected static SDLJoystickHandler mJoystickHandler;
+ protected static SDLHapticHandler mHapticHandler;
+
+ private static final String TAG = "SDLControllerManager";
+
+ public static void initialize() {
+ if (mJoystickHandler == null) {
+ if (Build.VERSION.SDK_INT >= 19) {
+ mJoystickHandler = new SDLJoystickHandler_API19();
+ } else {
+ mJoystickHandler = new SDLJoystickHandler_API16();
+ }
+ }
+
+ if (mHapticHandler == null) {
+ if (Build.VERSION.SDK_INT >= 26) {
+ mHapticHandler = new SDLHapticHandler_API26();
+ } else {
+ mHapticHandler = new SDLHapticHandler();
+ }
+ }
+ }
+
+ // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
+ public static boolean handleJoystickMotionEvent(MotionEvent event) {
+ return mJoystickHandler.handleMotionEvent(event);
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void pollInputDevices() {
+ mJoystickHandler.pollInputDevices();
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void pollHapticDevices() {
+ mHapticHandler.pollHapticDevices();
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void hapticRun(int device_id, float intensity, int length) {
+ mHapticHandler.run(device_id, intensity, length);
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void hapticStop(int device_id)
+ {
+ mHapticHandler.stop(device_id);
+ }
+
+ // Check if a given device is considered a possible SDL joystick
+ public static boolean isDeviceSDLJoystick(int deviceId) {
+ InputDevice device = InputDevice.getDevice(deviceId);
+ // We cannot use InputDevice.isVirtual before API 16, so let's accept
+ // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
+ if ((device == null) || (deviceId < 0)) {
+ return false;
+ }
+ int sources = device.getSources();
+
+ /* This is called for every button press, so let's not spam the logs */
+ /**
+ if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+ Log.v(TAG, "Input device " + device.getName() + " has class joystick.");
+ }
+ if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) {
+ Log.v(TAG, "Input device " + device.getName() + " is a dpad.");
+ }
+ if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
+ Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
+ }
+ **/
+
+ return ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ||
+ ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
+ ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
+ );
+ }
+
+}
+
+class SDLJoystickHandler {
+
+ /**
+ * Handles given MotionEvent.
+ * @param event the event to be handled.
+ * @return if given event was processed.
+ */
+ public boolean handleMotionEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Handles adding and removing of input devices.
+ */
+ public void pollInputDevices() {
+ }
+}
+
+/* Actual joystick functionality available for API >= 12 devices */
+class SDLJoystickHandler_API16 extends SDLJoystickHandler {
+
+ static class SDLJoystick {
+ public int device_id;
+ public String name;
+ public String desc;
+ public ArrayList<InputDevice.MotionRange> axes;
+ public ArrayList<InputDevice.MotionRange> hats;
+ }
+ static class RangeComparator implements Comparator<InputDevice.MotionRange> {
+ @Override
+ public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
+ // Some controllers, like the Moga Pro 2, return AXIS_GAS (22) for right trigger and AXIS_BRAKE (23) for left trigger - swap them so they're sorted in the right order for SDL
+ int arg0Axis = arg0.getAxis();
+ int arg1Axis = arg1.getAxis();
+ if (arg0Axis == MotionEvent.AXIS_GAS) {
+ arg0Axis = MotionEvent.AXIS_BRAKE;
+ } else if (arg0Axis == MotionEvent.AXIS_BRAKE) {
+ arg0Axis = MotionEvent.AXIS_GAS;
+ }
+ if (arg1Axis == MotionEvent.AXIS_GAS) {
+ arg1Axis = MotionEvent.AXIS_BRAKE;
+ } else if (arg1Axis == MotionEvent.AXIS_BRAKE) {
+ arg1Axis = MotionEvent.AXIS_GAS;
+ }
+
+ return arg0Axis - arg1Axis;
+ }
+ }
+
+ private ArrayList<SDLJoystick> mJoysticks;
+
+ public SDLJoystickHandler_API16() {
+
+ mJoysticks = new ArrayList<SDLJoystick>();
+ }
+
+ @Override
+ public void pollInputDevices() {
+ int[] deviceIds = InputDevice.getDeviceIds();
+ for(int i=0; i < deviceIds.length; ++i) {
+ SDLJoystick joystick = getJoystick(deviceIds[i]);
+ if (joystick == null) {
+ joystick = new SDLJoystick();
+ InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
+ if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
+ joystick.device_id = deviceIds[i];
+ joystick.name = joystickDevice.getName();
+ joystick.desc = getJoystickDescriptor(joystickDevice);
+ joystick.axes = new ArrayList<InputDevice.MotionRange>();
+ joystick.hats = new ArrayList<InputDevice.MotionRange>();
+
+ List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
+ Collections.sort(ranges, new RangeComparator());
+ for (InputDevice.MotionRange range : ranges ) {
+ if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+ if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
+ range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+ joystick.hats.add(range);
+ }
+ else {
+ joystick.axes.add(range);
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+ }
+
+ /* Check removed devices */
+ ArrayList<Integer> removedDevices = new ArrayList<Integer>();
+ for(int i=0; i < mJoysticks.size(); i++) {
+ int device_id = mJoysticks.get(i).device_id;
+ int j;
+ for (j=0; j < deviceIds.length; j++) {
+ if (device_id == deviceIds[j]) break;
+ }
+ if (j == deviceIds.length) {
+ removedDevices.add(Integer.valueOf(device_id));
+ }
+ }
+
+ for(int i=0; i < removedDevices.size(); i++) {
+ int device_id = removedDevices.get(i).intValue();
+ SDLControllerManager.nativeRemoveJoystick(device_id);
+ for (int j=0; j < mJoysticks.size(); j++) {
+ if (mJoysticks.get(j).device_id == device_id) {
+ mJoysticks.remove(j);
+ break;
+ }
+ }
+ }
+ }
+
+ protected SDLJoystick getJoystick(int device_id) {
+ for(int i=0; i < mJoysticks.size(); i++) {
+ if (mJoysticks.get(i).device_id == device_id) {
+ return mJoysticks.get(i);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean handleMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
+ int actionPointerIndex = event.getActionIndex();
+ int action = event.getActionMasked();
+ switch(action) {
+ case MotionEvent.ACTION_MOVE:
+ SDLJoystick joystick = getJoystick(event.getDeviceId());
+ if ( joystick != null ) {
+ for (int i = 0; i < joystick.axes.size(); i++) {
+ InputDevice.MotionRange range = joystick.axes.get(i);
+ /* Normalize the value to -1...1 */
+ float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
+ SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
+ }
+ for (int i = 0; i < joystick.hats.size(); i+=2) {
+ int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
+ int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
+ SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+
+ public String getJoystickDescriptor(InputDevice joystickDevice) {
+ String desc = joystickDevice.getDescriptor();
+
+ if (desc != null && !desc.isEmpty()) {
+ return desc;
+ }
+
+ return joystickDevice.getName();
+ }
+ public int getProductId(InputDevice joystickDevice) {
+ return 0;
+ }
+ public int getVendorId(InputDevice joystickDevice) {
+ return 0;
+ }
+ public int getButtonMask(InputDevice joystickDevice) {
+ return -1;
+ }
+}
+
+class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
+
+ @Override
+ public int getProductId(InputDevice joystickDevice) {
+ return joystickDevice.getProductId();
+ }
+
+ @Override
+ public int getVendorId(InputDevice joystickDevice) {
+ return joystickDevice.getVendorId();
+ }
+
+ @Override
+ public int getButtonMask(InputDevice joystickDevice) {
+ int button_mask = 0;
+ int[] keys = new int[] {
+ KeyEvent.KEYCODE_BUTTON_A,
+ KeyEvent.KEYCODE_BUTTON_B,
+ KeyEvent.KEYCODE_BUTTON_X,
+ KeyEvent.KEYCODE_BUTTON_Y,
+ KeyEvent.KEYCODE_BACK,
+ KeyEvent.KEYCODE_BUTTON_MODE,
+ KeyEvent.KEYCODE_BUTTON_START,
+ KeyEvent.KEYCODE_BUTTON_THUMBL,
+ KeyEvent.KEYCODE_BUTTON_THUMBR,
+ KeyEvent.KEYCODE_BUTTON_L1,
+ KeyEvent.KEYCODE_BUTTON_R1,
+ KeyEvent.KEYCODE_DPAD_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN,
+ KeyEvent.KEYCODE_DPAD_LEFT,
+ KeyEvent.KEYCODE_DPAD_RIGHT,
+ KeyEvent.KEYCODE_BUTTON_SELECT,
+ KeyEvent.KEYCODE_DPAD_CENTER,
+
+ // These don't map into any SDL controller buttons directly
+ KeyEvent.KEYCODE_BUTTON_L2,
+ KeyEvent.KEYCODE_BUTTON_R2,
+ KeyEvent.KEYCODE_BUTTON_C,
+ KeyEvent.KEYCODE_BUTTON_Z,
+ KeyEvent.KEYCODE_BUTTON_1,
+ KeyEvent.KEYCODE_BUTTON_2,
+ KeyEvent.KEYCODE_BUTTON_3,
+ KeyEvent.KEYCODE_BUTTON_4,
+ KeyEvent.KEYCODE_BUTTON_5,
+ KeyEvent.KEYCODE_BUTTON_6,
+ KeyEvent.KEYCODE_BUTTON_7,
+ KeyEvent.KEYCODE_BUTTON_8,
+ KeyEvent.KEYCODE_BUTTON_9,
+ KeyEvent.KEYCODE_BUTTON_10,
+ KeyEvent.KEYCODE_BUTTON_11,
+ KeyEvent.KEYCODE_BUTTON_12,
+ KeyEvent.KEYCODE_BUTTON_13,
+ KeyEvent.KEYCODE_BUTTON_14,
+ KeyEvent.KEYCODE_BUTTON_15,
+ KeyEvent.KEYCODE_BUTTON_16,
+ };
+ int[] masks = new int[] {
+ (1 << 0), // A -> A
+ (1 << 1), // B -> B
+ (1 << 2), // X -> X
+ (1 << 3), // Y -> Y
+ (1 << 4), // BACK -> BACK
+ (1 << 5), // MODE -> GUIDE
+ (1 << 6), // START -> START
+ (1 << 7), // THUMBL -> LEFTSTICK
+ (1 << 8), // THUMBR -> RIGHTSTICK
+ (1 << 9), // L1 -> LEFTSHOULDER
+ (1 << 10), // R1 -> RIGHTSHOULDER
+ (1 << 11), // DPAD_UP -> DPAD_UP
+ (1 << 12), // DPAD_DOWN -> DPAD_DOWN
+ (1 << 13), // DPAD_LEFT -> DPAD_LEFT
+ (1 << 14), // DPAD_RIGHT -> DPAD_RIGHT
+ (1 << 4), // SELECT -> BACK
+ (1 << 0), // DPAD_CENTER -> A
+ (1 << 15), // L2 -> ??
+ (1 << 16), // R2 -> ??
+ (1 << 17), // C -> ??
+ (1 << 18), // Z -> ??
+ (1 << 20), // 1 -> ??
+ (1 << 21), // 2 -> ??
+ (1 << 22), // 3 -> ??
+ (1 << 23), // 4 -> ??
+ (1 << 24), // 5 -> ??
+ (1 << 25), // 6 -> ??
+ (1 << 26), // 7 -> ??
+ (1 << 27), // 8 -> ??
+ (1 << 28), // 9 -> ??
+ (1 << 29), // 10 -> ??
+ (1 << 30), // 11 -> ??
+ (1 << 31), // 12 -> ??
+ // We're out of room...
+ 0xFFFFFFFF, // 13 -> ??
+ 0xFFFFFFFF, // 14 -> ??
+ 0xFFFFFFFF, // 15 -> ??
+ 0xFFFFFFFF, // 16 -> ??
+ };
+ boolean[] has_keys = joystickDevice.hasKeys(keys);
+ for (int i = 0; i < keys.length; ++i) {
+ if (has_keys[i]) {
+ button_mask |= masks[i];
+ }
+ }
+ return button_mask;
+ }
+}
+
+class SDLHapticHandler_API26 extends SDLHapticHandler {
+ @Override
+ public void run(int device_id, float intensity, int length) {
+ SDLHaptic haptic = getHaptic(device_id);
+ if (haptic != null) {
+ Log.d("SDL", "Rtest: Vibe with intensity " + intensity + " for " + length);
+ if (intensity == 0.0f) {
+ stop(device_id);
+ return;
+ }
+
+ int vibeValue = Math.round(intensity * 255);
+
+ if (vibeValue > 255) {
+ vibeValue = 255;
+ }
+ if (vibeValue < 1) {
+ stop(device_id);
+ return;
+ }
+ try {
+ haptic.vib.vibrate(VibrationEffect.createOneShot(length, vibeValue));
+ }
+ catch (Exception e) {
+ // Fall back to the generic method, which uses DEFAULT_AMPLITUDE, but works even if
+ // something went horribly wrong with the Android 8.0 APIs.
+ haptic.vib.vibrate(length);
+ }
+ }
+ }
+}
+
+class SDLHapticHandler {
+
+ class SDLHaptic {
+ public int device_id;
+ public String name;
+ public Vibrator vib;
+ }
+
+ private ArrayList<SDLHaptic> mHaptics;
+
+ public SDLHapticHandler() {
+ mHaptics = new ArrayList<SDLHaptic>();
+ }
+
+ public void run(int device_id, float intensity, int length) {
+ SDLHaptic haptic = getHaptic(device_id);
+ if (haptic != null) {
+ haptic.vib.vibrate(length);
+ }
+ }
+
+ public void stop(int device_id) {
+ SDLHaptic haptic = getHaptic(device_id);
+ if (haptic != null) {
+ haptic.vib.cancel();
+ }
+ }
+
+ public void pollHapticDevices() {
+
+ final int deviceId_VIBRATOR_SERVICE = 999999;
+ boolean hasVibratorService = false;
+
+ int[] deviceIds = InputDevice.getDeviceIds();
+ // It helps processing the device ids in reverse order
+ // For example, in the case of the XBox 360 wireless dongle,
+ // so the first controller seen by SDL matches what the receiver
+ // considers to be the first controller
+
+ for (int i = deviceIds.length - 1; i > -1; i--) {
+ SDLHaptic haptic = getHaptic(deviceIds[i]);
+ if (haptic == null) {
+ InputDevice device = InputDevice.getDevice(deviceIds[i]);
+ Vibrator vib = device.getVibrator();
+ if (vib.hasVibrator()) {
+ haptic = new SDLHaptic();
+ haptic.device_id = deviceIds[i];
+ haptic.name = device.getName();
+ haptic.vib = vib;
+ mHaptics.add(haptic);
+ SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
+ }
+ }
+ }
+
+ /* Check VIBRATOR_SERVICE */
+ Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
+ if (vib != null) {
+ hasVibratorService = vib.hasVibrator();
+
+ if (hasVibratorService) {
+ SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
+ if (haptic == null) {
+ haptic = new SDLHaptic();
+ haptic.device_id = deviceId_VIBRATOR_SERVICE;
+ haptic.name = "VIBRATOR_SERVICE";
+ haptic.vib = vib;
+ mHaptics.add(haptic);
+ SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
+ }
+ }
+ }
+
+ /* Check removed devices */
+ ArrayList<Integer> removedDevices = new ArrayList<Integer>();
+ for(int i=0; i < mHaptics.size(); i++) {
+ int device_id = mHaptics.get(i).device_id;
+ int j;
+ for (j=0; j < deviceIds.length; j++) {
+ if (device_id == deviceIds[j]) break;
+ }
+
+ if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
+ // don't remove the vibrator if it is still present
+ } else if (j == deviceIds.length) {
+ removedDevices.add(device_id);
+ }
+ }
+
+ for(int i=0; i < removedDevices.size(); i++) {
+ int device_id = removedDevices.get(i);
+ SDLControllerManager.nativeRemoveHaptic(device_id);
+ for (int j=0; j < mHaptics.size(); j++) {
+ if (mHaptics.get(j).device_id == device_id) {
+ mHaptics.remove(j);
+ break;
+ }
+ }
+ }
+ }
+
+ protected SDLHaptic getHaptic(int device_id) {
+ for(int i=0; i < mHaptics.size(); i++) {
+ if (mHaptics.get(i).device_id == device_id) {
+ return mHaptics.get(i);
+ }
+ }
+ return null;
+ }
+}
+
+class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
+ // Generic Motion (mouse hover, joystick...) events go here
+ @Override
+ public boolean onGenericMotion(View v, MotionEvent event) {
+ float x, y;
+ int action;
+
+ switch ( event.getSource() ) {
+ case InputDevice.SOURCE_JOYSTICK:
+ case InputDevice.SOURCE_GAMEPAD:
+ case InputDevice.SOURCE_DPAD:
+ return SDLControllerManager.handleJoystickMotionEvent(event);
+
+ case InputDevice.SOURCE_MOUSE:
+ action = event.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_SCROLL:
+ x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
+ y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
+ SDLActivity.onNativeMouse(0, action, x, y, false);
+ return true;
+
+ case MotionEvent.ACTION_HOVER_MOVE:
+ x = event.getX(0);
+ y = event.getY(0);
+
+ SDLActivity.onNativeMouse(0, action, x, y, false);
+ return true;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Event was not managed
+ return false;
+ }
+
+ public boolean supportsRelativeMouse() {
+ return false;
+ }
+
+ public boolean inRelativeMode() {
+ return false;
+ }
+
+ public boolean setRelativeMouseEnabled(boolean enabled) {
+ return false;
+ }
+
+ public void reclaimRelativeMouseModeIfNeeded()
+ {
+
+ }
+
+ public float getEventX(MotionEvent event) {
+ return event.getX(0);
+ }
+
+ public float getEventY(MotionEvent event) {
+ return event.getY(0);
+ }
+
+}
+
+class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 {
+ // Generic Motion (mouse hover, joystick...) events go here
+
+ private boolean mRelativeModeEnabled;
+
+ @Override
+ public boolean onGenericMotion(View v, MotionEvent event) {
+
+ // Handle relative mouse mode
+ if (mRelativeModeEnabled) {
+ if (event.getSource() == InputDevice.SOURCE_MOUSE) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_HOVER_MOVE) {
+ float x = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
+ float y = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
+ SDLActivity.onNativeMouse(0, action, x, y, true);
+ return true;
+ }
+ }
+ }
+
+ // Event was not managed, call SDLGenericMotionListener_API12 method
+ return super.onGenericMotion(v, event);
+ }
+
+ @Override
+ public boolean supportsRelativeMouse() {
+ return true;
+ }
+
+ @Override
+ public boolean inRelativeMode() {
+ return mRelativeModeEnabled;
+ }
+
+ @Override
+ public boolean setRelativeMouseEnabled(boolean enabled) {
+ mRelativeModeEnabled = enabled;
+ return true;
+ }
+
+ @Override
+ public float getEventX(MotionEvent event) {
+ if (mRelativeModeEnabled) {
+ return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
+ }
+ else {
+ return event.getX(0);
+ }
+ }
+
+ @Override
+ public float getEventY(MotionEvent event) {
+ if (mRelativeModeEnabled) {
+ return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
+ }
+ else {
+ return event.getY(0);
+ }
+ }
+}
+
+
+class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
+ // Generic Motion (mouse hover, joystick...) events go here
+ private boolean mRelativeModeEnabled;
+
+ @Override
+ public boolean onGenericMotion(View v, MotionEvent event) {
+ float x, y;
+ int action;
+
+ switch ( event.getSource() ) {
+ case InputDevice.SOURCE_JOYSTICK:
+ case InputDevice.SOURCE_GAMEPAD:
+ case InputDevice.SOURCE_DPAD:
+ return SDLControllerManager.handleJoystickMotionEvent(event);
+
+ case InputDevice.SOURCE_MOUSE:
+ // DeX desktop mouse cursor is a separate non-standard input type.
+ case InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN:
+ action = event.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_SCROLL:
+ x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
+ y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
+ SDLActivity.onNativeMouse(0, action, x, y, false);
+ return true;
+
+ case MotionEvent.ACTION_HOVER_MOVE:
+ x = event.getX(0);
+ y = event.getY(0);
+ SDLActivity.onNativeMouse(0, action, x, y, false);
+ return true;
+
+ default:
+ break;
+ }
+ break;
+
+ case InputDevice.SOURCE_MOUSE_RELATIVE:
+ action = event.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_SCROLL:
+ x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
+ y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
+ SDLActivity.onNativeMouse(0, action, x, y, false);
+ return true;
+
+ case MotionEvent.ACTION_HOVER_MOVE:
+ x = event.getX(0);
+ y = event.getY(0);
+ SDLActivity.onNativeMouse(0, action, x, y, true);
+ return true;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Event was not managed
+ return false;
+ }
+
+ @Override
+ public boolean supportsRelativeMouse() {
+ return (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27));
+ }
+
+ @Override
+ public boolean inRelativeMode() {
+ return mRelativeModeEnabled;
+ }
+
+ @Override
+ public boolean setRelativeMouseEnabled(boolean enabled) {
+ if (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27)) {
+ if (enabled) {
+ SDLActivity.getContentView().requestPointerCapture();
+ }
+ else {
+ SDLActivity.getContentView().releasePointerCapture();
+ }
+ mRelativeModeEnabled = enabled;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ @Override
+ public void reclaimRelativeMouseModeIfNeeded()
+ {
+ if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) {
+ SDLActivity.getContentView().requestPointerCapture();
+ }
+ }
+
+ @Override
+ public float getEventX(MotionEvent event) {
+ // Relative mouse in capture mode will only have relative for X/Y
+ return event.getX(0);
+ }
+
+ @Override
+ public float getEventY(MotionEvent event) {
+ // Relative mouse in capture mode will only have relative for X/Y
+ return event.getY(0);
+ }
+}