mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-18 18:42:46 +00:00
Add dynamic method for allowing back buttons for navigation
This commit is contained in:
parent
2cd9e31684
commit
eb6f15c2b7
@ -4,6 +4,7 @@ import android.content.Context;
|
|||||||
import android.hardware.input.InputManager;
|
import android.hardware.input.InputManager;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
@ -22,6 +23,7 @@ import com.limelight.preferences.PreferenceConfiguration;
|
|||||||
import com.limelight.ui.GameGestures;
|
import com.limelight.ui.GameGestures;
|
||||||
import com.limelight.utils.Vector2d;
|
import com.limelight.utils.Vector2d;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
@ -308,6 +310,79 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isExternal(InputDevice dev) {
|
||||||
|
try {
|
||||||
|
// Landroid/view/InputDevice;->isExternal()Z is on the light graylist in Android P
|
||||||
|
return (Boolean)dev.getClass().getMethod("isExternal").invoke(dev);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Answer true if we don't know
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldIgnoreBack(InputDevice dev) {
|
||||||
|
String devName = dev.getName();
|
||||||
|
|
||||||
|
// The Serval has a Select button but the framework doesn't
|
||||||
|
// know about that because it uses a non-standard scancode.
|
||||||
|
if (devName.contains("Razer Serval")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classify this device as a remote by name if it has no joystick axes
|
||||||
|
if (getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_X) == null &&
|
||||||
|
getMotionRangeForJoystickAxis(dev, MotionEvent.AXIS_Y) == null &&
|
||||||
|
devName.toLowerCase().contains("remote")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, dynamically try to determine whether we should allow this
|
||||||
|
// back button to function for navigation.
|
||||||
|
//
|
||||||
|
// First, check if this is an internal device we're being called on.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !isExternal(dev)) {
|
||||||
|
InputManager im = (InputManager) activityContext.getSystemService(Context.INPUT_SERVICE);
|
||||||
|
|
||||||
|
boolean foundInternalGamepad = false;
|
||||||
|
boolean foundInternalSelect = false;
|
||||||
|
for (int id : im.getInputDeviceIds()) {
|
||||||
|
InputDevice currentDev = im.getInputDevice(id);
|
||||||
|
|
||||||
|
// Ignore external devices
|
||||||
|
if (currentDev == null || isExternal(currentDev)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we are explicitly NOT excluding the current device we're examining here,
|
||||||
|
// since the other gamepad buttons may be on our current device and that's fine.
|
||||||
|
boolean[] keys = currentDev.hasKeys(KeyEvent.KEYCODE_BUTTON_SELECT, KeyEvent.KEYCODE_BUTTON_A);
|
||||||
|
if (keys[0]) {
|
||||||
|
foundInternalSelect = true;
|
||||||
|
}
|
||||||
|
if (keys[1]) {
|
||||||
|
foundInternalGamepad = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the back button to function for navigation if we either:
|
||||||
|
// a) have no internal gamepad (most phones)
|
||||||
|
// b) have an internal gamepad but also have an internal select button (GPD XD)
|
||||||
|
// but not:
|
||||||
|
// c) have an internal gamepad but no internal select button (NVIDIA SHIELD Portable)
|
||||||
|
return !foundInternalGamepad || foundInternalSelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private InputDeviceContext createInputDeviceContextForDevice(InputDevice dev) {
|
private InputDeviceContext createInputDeviceContextForDevice(InputDevice dev) {
|
||||||
InputDeviceContext context = new InputDeviceContext();
|
InputDeviceContext context = new InputDeviceContext();
|
||||||
String devName = dev.getName();
|
String devName = dev.getName();
|
||||||
@ -440,6 +515,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.ignoreBack = shouldIgnoreBack(dev);
|
||||||
|
|
||||||
if (devName != null) {
|
if (devName != null) {
|
||||||
// For the Nexus Player (and probably other ATV devices), we should
|
// For the Nexus Player (and probably other ATV devices), we should
|
||||||
// use the back button as start since it doesn't have a start/menu button
|
// use the back button as start since it doesn't have a start/menu button
|
||||||
@ -459,30 +536,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
// so we increase the deadzone on them to minimize this
|
// so we increase the deadzone on them to minimize this
|
||||||
context.triggerDeadzone = 0.30f;
|
context.triggerDeadzone = 0.30f;
|
||||||
}
|
}
|
||||||
// Classify this device as a remote by name
|
|
||||||
else if (devName.toLowerCase().contains("remote")) {
|
|
||||||
// It's only a remote if it doesn't any sticks
|
|
||||||
if (!context.hasJoystickAxes) {
|
|
||||||
context.ignoreBack = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// SHIELD controllers will use small stick deadzones
|
// SHIELD controllers will use small stick deadzones
|
||||||
else if (devName.contains("SHIELD")) {
|
else if (devName.contains("SHIELD")) {
|
||||||
context.leftStickDeadzoneRadius = 0.07f;
|
context.leftStickDeadzoneRadius = 0.07f;
|
||||||
context.rightStickDeadzoneRadius = 0.07f;
|
context.rightStickDeadzoneRadius = 0.07f;
|
||||||
}
|
}
|
||||||
// Samsung's face buttons appear as a non-virtual button so we'll explicitly ignore
|
|
||||||
// back presses on this device. The Goodix buttons on the Nokia 6 also appear
|
|
||||||
// non-virtual so we'll ignore those too.
|
|
||||||
else if (devName.equals("sec_touchscreen") || devName.equals("sec_touchkey") ||
|
|
||||||
devName.equals("goodix_fp")) {
|
|
||||||
context.ignoreBack = true;
|
|
||||||
}
|
|
||||||
// The Serval has a couple of unknown buttons that are start and select. It also has
|
// The Serval has a couple of unknown buttons that are start and select. It also has
|
||||||
// a back button which we want to ignore since there's already a select button.
|
// a back button which we want to ignore since there's already a select button.
|
||||||
else if (devName.contains("Razer Serval")) {
|
else if (devName.contains("Razer Serval")) {
|
||||||
context.isServal = true;
|
context.isServal = true;
|
||||||
context.ignoreBack = true;
|
|
||||||
}
|
}
|
||||||
// The Xbox One S Bluetooth controller has some mappings that need fixing up.
|
// The Xbox One S Bluetooth controller has some mappings that need fixing up.
|
||||||
// However, Microsoft released a firmware update with no change to VID/PID
|
// However, Microsoft released a firmware update with no change to VID/PID
|
||||||
|
Loading…
x
Reference in New Issue
Block a user