Send the initial number of connected gamepads during launch to fix some games like L4D2

This commit is contained in:
Cameron Gutman 2018-01-20 01:13:56 -08:00
parent 8d4c86e113
commit fb54bd5c78
3 changed files with 72 additions and 11 deletions

View File

@ -295,6 +295,16 @@ public class Game extends Activity implements SurfaceHolder.Callback,
Toast.makeText(this, "No H.265 decoder found.\nFalling back to H.264.", Toast.LENGTH_LONG).show(); Toast.makeText(this, "No H.265 decoder found.\nFalling back to H.264.", Toast.LENGTH_LONG).show();
} }
int gamepadMask = ControllerHandler.getAttachedControllerMask(this);
if (!prefConfig.multiController && gamepadMask != 0) {
// If any gamepads are present in non-MC mode, set only gamepad 1.
gamepadMask = 1;
}
if (prefConfig.onscreenController) {
// If we're using OSC, always set at least gamepad 1.
gamepadMask |= 1;
}
StreamConfiguration config = new StreamConfiguration.Builder() StreamConfiguration config = new StreamConfiguration.Builder()
.setResolution(prefConfig.width, prefConfig.height) .setResolution(prefConfig.width, prefConfig.height)
.setRefreshRate(prefConfig.fps) .setRefreshRate(prefConfig.fps)
@ -307,6 +317,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
.setHevcBitratePercentageMultiplier(75) .setHevcBitratePercentageMultiplier(75)
.setHevcSupported(decoderRenderer.isHevcSupported()) .setHevcSupported(decoderRenderer.isHevcSupported())
.setEnableHdr(willStreamHdr) .setEnableHdr(willStreamHdr)
.setAttachedGamepadMask(gamepadMask)
.setAudioConfiguration(prefConfig.enable51Surround ? .setAudioConfiguration(prefConfig.enable51Surround ?
MoonBridge.AUDIO_CONFIGURATION_51_SURROUND : MoonBridge.AUDIO_CONFIGURATION_51_SURROUND :
MoonBridge.AUDIO_CONFIGURATION_STEREO) MoonBridge.AUDIO_CONFIGURATION_STEREO)

View File

@ -2,6 +2,8 @@ package com.limelight.binding.input;
import android.content.Context; import android.content.Context;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.InputDevice; import android.view.InputDevice;
@ -12,6 +14,7 @@ import android.widget.Toast;
import com.limelight.LimeLog; import com.limelight.LimeLog;
import com.limelight.binding.input.driver.UsbDriverListener; import com.limelight.binding.input.driver.UsbDriverListener;
import com.limelight.binding.input.driver.UsbDriverService;
import com.limelight.nvstream.NvConnection; import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.ControllerPacket; import com.limelight.nvstream.input.ControllerPacket;
import com.limelight.nvstream.input.MouseButtonPacket; import com.limelight.nvstream.input.MouseButtonPacket;
@ -48,7 +51,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private boolean hasGameController; private boolean hasGameController;
private final boolean multiControllerEnabled; private final boolean multiControllerEnabled;
private short currentControllers; private short currentControllers, initialControllers;
public ControllerHandler(Context activityContext, NvConnection conn, GameGestures gestures, boolean multiControllerEnabled, int deadzonePercentage) { public ControllerHandler(Context activityContext, NvConnection conn, GameGestures gestures, boolean multiControllerEnabled, int deadzonePercentage) {
this.activityContext = activityContext; this.activityContext = activityContext;
@ -102,6 +105,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// consume these. Instead, let's ignore them since that's probably the // consume these. Instead, let's ignore them since that's probably the
// most likely case. // most likely case.
defaultContext.ignoreBack = true; defaultContext.ignoreBack = true;
// Get the initially attached set of gamepads. As each gamepad receives
// its initial InputEvent, we will move these from this set onto the
// currentControllers set which will allow them to properly unplug
// if they are removed.
initialControllers = getAttachedControllerMask(activityContext);
} }
private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) { private static InputDevice.MotionRange getMotionRangeForJoystickAxis(InputDevice dev, int axis) {
@ -139,8 +148,47 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
onInputDeviceAdded(deviceId); onInputDeviceAdded(deviceId);
} }
public static short getAttachedControllerMask(Context context) {
int count = 0;
short mask = 0;
// Count all input devices that are gamepads
InputManager im = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
for (int id : im.getInputDeviceIds()) {
InputDevice dev = im.getInputDevice(id);
if (dev == null) {
continue;
}
if ((dev.getSources() & InputDevice.SOURCE_JOYSTICK) != 0) {
LimeLog.info("Counting InputDevice: "+dev.getName());
mask |= 1 << count++;
}
}
// Count all USB devices that match our drivers
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
for (UsbDevice dev : usbManager.getDeviceList().values()) {
if (UsbDriverService.shouldClaimDevice(dev)) {
LimeLog.info("Counting UsbDevice: "+dev.getDeviceName());
mask |= 1 << count++;
}
}
LimeLog.info("Enumerated "+count+" gamepads");
return mask;
}
private void releaseControllerNumber(GenericControllerContext context) { private void releaseControllerNumber(GenericControllerContext context) {
// If this device sent data as a gamepad, zero the values before removing // If we reserved a controller number, remove that reservation
if (context.reservedControllerNumber) {
LimeLog.info("Controller number "+context.controllerNumber+" is now available");
currentControllers &= ~(1 << context.controllerNumber);
}
// If this device sent data as a gamepad, zero the values before removing.
// We must do this after clearing the currentControllers entry so this
// causes the device to be removed on the server PC.
if (context.assignedControllerNumber) { if (context.assignedControllerNumber) {
conn.sendControllerInput(context.controllerNumber, getActiveControllerMask(), conn.sendControllerInput(context.controllerNumber, getActiveControllerMask(),
(short) 0, (short) 0,
@ -148,12 +196,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
(short) 0, (short) 0, (short) 0, (short) 0,
(short) 0, (short) 0); (short) 0, (short) 0);
} }
// If we reserved a controller number, remove that reservation
if (context.reservedControllerNumber) {
LimeLog.info("Controller number "+context.controllerNumber+" is now available");
currentControllers &= ~(1 << context.controllerNumber);
}
} }
// Called before sending input but after we've determined that this // Called before sending input but after we've determined that this
@ -181,6 +223,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if ((currentControllers & (1 << i)) == 0) { if ((currentControllers & (1 << i)) == 0) {
// Found an unused controller value // Found an unused controller value
currentControllers |= (1 << i); currentControllers |= (1 << i);
// Take this value out of the initial gamepad set
initialControllers &= ~(1 << i);
context.controllerNumber = i; context.controllerNumber = i;
context.reservedControllerNumber = true; context.reservedControllerNumber = true;
break; break;
@ -201,6 +247,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if ((currentControllers & (1 << i)) == 0) { if ((currentControllers & (1 << i)) == 0) {
// Found an unused controller value // Found an unused controller value
currentControllers |= (1 << i); currentControllers |= (1 << i);
// Take this value out of the initial gamepad set
initialControllers &= ~(1 << i);
context.controllerNumber = i; context.controllerNumber = i;
context.reservedControllerNumber = true; context.reservedControllerNumber = true;
break; break;
@ -473,7 +523,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private short getActiveControllerMask() { private short getActiveControllerMask() {
if (multiControllerEnabled) { if (multiControllerEnabled) {
return currentControllers; return (short)(currentControllers | initialControllers);
} }
else { else {
// Only Player 1 is active with multi-controller disabled // Only Player 1 is active with multi-controller disabled

View File

@ -157,7 +157,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
} }
} }
private boolean isRecognizedInputDevice(UsbDevice device) { private static boolean isRecognizedInputDevice(UsbDevice device) {
// On KitKat and later, we can determine if this VID and PID combo // On KitKat and later, we can determine if this VID and PID combo
// matches an existing input device and defer to the built-in controller // matches an existing input device and defer to the built-in controller
// support in that case. Prior to KitKat, we'll always return true to be safe. // support in that case. Prior to KitKat, we'll always return true to be safe.
@ -182,7 +182,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
} }
} }
private boolean shouldClaimDevice(UsbDevice device) { public static boolean shouldClaimDevice(UsbDevice device) {
// We always bind to XB1 controllers but only bind to XB360 controllers // We always bind to XB1 controllers but only bind to XB360 controllers
// if we know the kernel isn't already driving this device. // if we know the kernel isn't already driving this device.
return XboxOneController.canClaimDevice(device) || return XboxOneController.canClaimDevice(device) ||