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.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseArray;
|
||||
import android.view.InputDevice;
|
||||
@ -22,6 +23,7 @@ import com.limelight.preferences.PreferenceConfiguration;
|
||||
import com.limelight.ui.GameGestures;
|
||||
import com.limelight.utils.Vector2d;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@ -308,6 +310,79 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
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) {
|
||||
InputDeviceContext context = new InputDeviceContext();
|
||||
String devName = dev.getName();
|
||||
@ -440,6 +515,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
}
|
||||
}
|
||||
|
||||
context.ignoreBack = shouldIgnoreBack(dev);
|
||||
|
||||
if (devName != null) {
|
||||
// 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
|
||||
@ -459,30 +536,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
||||
// so we increase the deadzone on them to minimize this
|
||||
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
|
||||
else if (devName.contains("SHIELD")) {
|
||||
context.leftStickDeadzoneRadius = 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
|
||||
// a back button which we want to ignore since there's already a select button.
|
||||
else if (devName.contains("Razer Serval")) {
|
||||
context.isServal = true;
|
||||
context.ignoreBack = true;
|
||||
}
|
||||
// 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user