Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 44871626cf | |||
| f661522b5d | |||
| a454b0ab78 | |||
| 75bf84d0d9 | |||
| c248994ed4 | |||
| a7a34ec629 | |||
| 8d469c5d0a | |||
| e6979d50b5 | |||
| 6e25b135a3 | |||
| 04e093a2c2 | |||
| 813f2edd95 | |||
| 337d753a33 | |||
| 1137c74f76 | |||
| 0c1451f757 | |||
| 5ab9ea48fd | |||
| ffcb623040 | |||
| bfe6929642 | |||
| 50d45011a8 | |||
| 2f7087d6d3 | |||
| 92b71588d0 | |||
| 4f3d018764 | |||
| a22e33eeb9 | |||
| 6a939e7495 | |||
| f8ba7cf190 |
+2
-2
@@ -8,8 +8,8 @@ android {
|
|||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
|
|
||||||
versionName "6.2"
|
versionName "7.2"
|
||||||
versionCode = 186
|
versionCode = 191
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions "root"
|
flavorDimensions "root"
|
||||||
|
|||||||
Vendored
+1
@@ -25,3 +25,4 @@
|
|||||||
|
|
||||||
# jMDNS
|
# jMDNS
|
||||||
-dontwarn javax.jmdns.impl.DNSCache
|
-dontwarn javax.jmdns.impl.DNSCache
|
||||||
|
-dontwarn org.slf4j.**
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
|||||||
@@ -66,12 +66,14 @@ import android.view.Window;
|
|||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
|
||||||
public class Game extends Activity implements SurfaceHolder.Callback,
|
public class Game extends Activity implements SurfaceHolder.Callback,
|
||||||
@@ -110,6 +112,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
private boolean grabbedInput = true;
|
private boolean grabbedInput = true;
|
||||||
private boolean grabComboDown = false;
|
private boolean grabComboDown = false;
|
||||||
private StreamView streamView;
|
private StreamView streamView;
|
||||||
|
private TextView notificationOverlayView;
|
||||||
|
|
||||||
private ShortcutHelper shortcutHelper;
|
private ShortcutHelper shortcutHelper;
|
||||||
|
|
||||||
@@ -201,6 +204,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
streamView.setOnTouchListener(this);
|
streamView.setOnTouchListener(this);
|
||||||
streamView.setInputCallbacks(this);
|
streamView.setInputCallbacks(this);
|
||||||
|
|
||||||
|
notificationOverlayView = findViewById(R.id.notificationOverlay);
|
||||||
|
|
||||||
inputCaptureProvider = InputCaptureManager.getInputCaptureProvider(this, this);
|
inputCaptureProvider = InputCaptureManager.getInputCaptureProvider(this, this);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@@ -424,7 +429,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
|
|
||||||
if (prefConfig.onscreenController) {
|
if (prefConfig.onscreenController) {
|
||||||
// create virtual onscreen controller
|
// create virtual onscreen controller
|
||||||
virtualController = new VirtualController(conn,
|
virtualController = new VirtualController(controllerHandler,
|
||||||
(FrameLayout)streamView.getParent(),
|
(FrameLayout)streamView.getParent(),
|
||||||
this);
|
this);
|
||||||
virtualController.refreshLayout();
|
virtualController.refreshLayout();
|
||||||
@@ -1267,6 +1272,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
if (connecting || connected) {
|
if (connecting || connected) {
|
||||||
connecting = connected = false;
|
connecting = connected = false;
|
||||||
|
|
||||||
|
controllerHandler.stop();
|
||||||
|
|
||||||
// Stop may take a few hundred ms to do some network I/O to tell
|
// Stop may take a few hundred ms to do some network I/O to tell
|
||||||
// the server we're going away and clean up. Let it run in a separate
|
// the server we're going away and clean up. Let it run in a separate
|
||||||
// thread to keep things smooth for the UI. Inside moonlight-common,
|
// thread to keep things smooth for the UI. Inside moonlight-common,
|
||||||
@@ -1322,8 +1329,41 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
LimeLog.severe("Connection terminated: " + errorCode);
|
LimeLog.severe("Connection terminated: " + errorCode);
|
||||||
stopConnection();
|
stopConnection();
|
||||||
|
|
||||||
Dialog.displayDialog(Game.this, getResources().getString(R.string.conn_terminated_title),
|
// Display the error dialog if it was an unexpected termination.
|
||||||
getResources().getString(R.string.conn_terminated_msg), true);
|
// Otherwise, just finish the activity immediately.
|
||||||
|
if (errorCode != 0) {
|
||||||
|
Dialog.displayDialog(Game.this, getResources().getString(R.string.conn_terminated_title),
|
||||||
|
getResources().getString(R.string.conn_terminated_msg), true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connectionStatusUpdate(final int connectionStatus) {
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (prefConfig.disableWarnings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectionStatus == MoonBridge.CONN_STATUS_POOR) {
|
||||||
|
if (prefConfig.bitrate > 5000) {
|
||||||
|
notificationOverlayView.setText(getResources().getString(R.string.slow_connection_msg));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
notificationOverlayView.setText(getResources().getString(R.string.poor_connection_msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationOverlayView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
else if (connectionStatus == MoonBridge.CONN_STATUS_OKAY) {
|
||||||
|
notificationOverlayView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1377,6 +1417,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) {
|
||||||
|
LimeLog.info(String.format((Locale)null, "Rumble on gamepad %d: %04x %04x", controllerNumber, lowFreqMotor, highFreqMotor));
|
||||||
|
|
||||||
|
controllerHandler.handleRumble(controllerNumber, lowFreqMotor, highFreqMotor);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||||
if (!surfaceCreated) {
|
if (!surfaceCreated) {
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ 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.media.AudioAttributes;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.os.VibrationEffect;
|
||||||
|
import android.os.Vibrator;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.InputEvent;
|
import android.view.InputEvent;
|
||||||
@@ -14,6 +17,7 @@ import android.view.MotionEvent;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.limelight.LimeLog;
|
import com.limelight.LimeLog;
|
||||||
|
import com.limelight.binding.input.driver.AbstractController;
|
||||||
import com.limelight.binding.input.driver.UsbDriverListener;
|
import com.limelight.binding.input.driver.UsbDriverListener;
|
||||||
import com.limelight.binding.input.driver.UsbDriverService;
|
import com.limelight.binding.input.driver.UsbDriverService;
|
||||||
import com.limelight.nvstream.NvConnection;
|
import com.limelight.nvstream.NvConnection;
|
||||||
@@ -51,6 +55,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
private final double stickDeadzone;
|
private final double stickDeadzone;
|
||||||
private final InputDeviceContext defaultContext = new InputDeviceContext();
|
private final InputDeviceContext defaultContext = new InputDeviceContext();
|
||||||
private final GameGestures gestures;
|
private final GameGestures gestures;
|
||||||
|
private final Vibrator deviceVibrator;
|
||||||
private boolean hasGameController;
|
private boolean hasGameController;
|
||||||
|
|
||||||
private final PreferenceConfiguration prefConfig;
|
private final PreferenceConfiguration prefConfig;
|
||||||
@@ -61,10 +66,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
this.conn = conn;
|
this.conn = conn;
|
||||||
this.gestures = gestures;
|
this.gestures = gestures;
|
||||||
this.prefConfig = prefConfig;
|
this.prefConfig = prefConfig;
|
||||||
|
this.deviceVibrator = (Vibrator) activityContext.getSystemService(Context.VIBRATOR_SERVICE);
|
||||||
|
|
||||||
// HACK: For now we're hardcoding a 10% deadzone. Some deadzone
|
// HACK: For now we're hardcoding a 7% deadzone. Some deadzone
|
||||||
// is required for controller batching support to work.
|
// is required for controller batching support to work.
|
||||||
int deadzonePercentage = 10;
|
int deadzonePercentage = 7;
|
||||||
|
|
||||||
int[] ids = InputDevice.getDeviceIds();
|
int[] ids = InputDevice.getDeviceIds();
|
||||||
for (int id : ids) {
|
for (int id : ids) {
|
||||||
@@ -151,6 +157,18 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
onInputDeviceAdded(deviceId);
|
onInputDeviceAdded(deviceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
|
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
||||||
|
|
||||||
|
if (deviceContext.vibrator != null) {
|
||||||
|
deviceContext.vibrator.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceVibrator.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean hasJoystickAxes(InputDevice device) {
|
private static boolean hasJoystickAxes(InputDevice device) {
|
||||||
return (device.getSources() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK &&
|
return (device.getSources() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK &&
|
||||||
getMotionRangeForJoystickAxis(device, MotionEvent.AXIS_X) != null &&
|
getMotionRangeForJoystickAxis(device, MotionEvent.AXIS_X) != null &&
|
||||||
@@ -206,6 +224,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PreferenceConfiguration.readPreferences(context).onscreenController) {
|
||||||
|
LimeLog.info("Counting OSC gamepad");
|
||||||
|
mask |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
LimeLog.info("Enumerated "+count+" gamepads");
|
LimeLog.info("Enumerated "+count+" gamepads");
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
@@ -298,10 +321,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.assignedControllerNumber = true;
|
context.assignedControllerNumber = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UsbDeviceContext createUsbDeviceContextForDevice(int deviceId) {
|
private UsbDeviceContext createUsbDeviceContextForDevice(AbstractController device) {
|
||||||
UsbDeviceContext context = new UsbDeviceContext();
|
UsbDeviceContext context = new UsbDeviceContext();
|
||||||
|
|
||||||
context.id = deviceId;
|
context.id = device.getControllerId();
|
||||||
|
context.device = device;
|
||||||
|
|
||||||
context.leftStickDeadzoneRadius = (float) stickDeadzone;
|
context.leftStickDeadzoneRadius = (float) stickDeadzone;
|
||||||
context.rightStickDeadzoneRadius = (float) stickDeadzone;
|
context.rightStickDeadzoneRadius = (float) stickDeadzone;
|
||||||
@@ -393,6 +417,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
context.name = devName;
|
context.name = devName;
|
||||||
context.id = dev.getId();
|
context.id = dev.getId();
|
||||||
|
|
||||||
|
if (dev.getVibrator().hasVibrator()) {
|
||||||
|
context.vibrator = dev.getVibrator();
|
||||||
|
}
|
||||||
|
|
||||||
context.leftStickXAxis = MotionEvent.AXIS_X;
|
context.leftStickXAxis = MotionEvent.AXIS_X;
|
||||||
context.leftStickYAxis = MotionEvent.AXIS_Y;
|
context.leftStickYAxis = MotionEvent.AXIS_Y;
|
||||||
if (getMotionRangeForJoystickAxis(dev, context.leftStickXAxis) != null &&
|
if (getMotionRangeForJoystickAxis(dev, context.leftStickXAxis) != null &&
|
||||||
@@ -614,7 +642,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
private short getActiveControllerMask() {
|
private short getActiveControllerMask() {
|
||||||
if (prefConfig.multiController) {
|
if (prefConfig.multiController) {
|
||||||
return (short)(currentControllers | initialControllers);
|
return (short)(currentControllers | initialControllers | (prefConfig.onscreenController ? 1 : 0));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Only Player 1 is active with multi-controller disabled
|
// Only Player 1 is active with multi-controller disabled
|
||||||
@@ -1043,6 +1071,94 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void rumbleVibrator(Vibrator vibrator, short lowFreqMotor, short highFreqMotor) {
|
||||||
|
// Since we can only use a single amplitude value, compute the desired amplitude
|
||||||
|
// by taking 80% of the big motor and 33% of the small motor, then capping to 255.
|
||||||
|
// NB: This value is now 0-255 as required by VibrationEffect.
|
||||||
|
short lowFreqMotorMSB = (short)((lowFreqMotor >> 8) & 0xFF);
|
||||||
|
short highFreqMotorMSB = (short)((highFreqMotor >> 8) & 0xFF);
|
||||||
|
int simulatedAmplitude = Math.min(255, (int)((lowFreqMotorMSB * 0.80) + (highFreqMotorMSB * 0.33)));
|
||||||
|
|
||||||
|
if (simulatedAmplitude == 0) {
|
||||||
|
// This case is easy - just cancel the current effect and get out.
|
||||||
|
// NB: We cannot simply check lowFreqMotor == highFreqMotor == 0
|
||||||
|
// because our simulatedAmplitude could be 0 even though our inputs
|
||||||
|
// are not (ex: lowFreqMotor == 0 && highFreqMotor == 1).
|
||||||
|
vibrator.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to use amplitude-based control if we're on Oreo and the device
|
||||||
|
// supports amplitude-based vibration control.
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
if (vibrator.hasAmplitudeControl()) {
|
||||||
|
VibrationEffect effect = VibrationEffect.createOneShot(60000, simulatedAmplitude);
|
||||||
|
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||||
|
.setUsage(AudioAttributes.USAGE_GAME)
|
||||||
|
.build();
|
||||||
|
vibrator.vibrate(effect, audioAttributes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach this point, we don't have amplitude controls available, so
|
||||||
|
// we must emulate it by PWMing the vibration. Ick.
|
||||||
|
long pwmPeriod = 20;
|
||||||
|
long onTime = (long)((simulatedAmplitude / 255.0) * pwmPeriod);
|
||||||
|
long offTime = pwmPeriod - onTime;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
AudioAttributes audioAttributes = new AudioAttributes.Builder()
|
||||||
|
.setUsage(AudioAttributes.USAGE_GAME)
|
||||||
|
.build();
|
||||||
|
vibrator.vibrate(new long[]{0, onTime, offTime}, 0, audioAttributes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vibrator.vibrate(new long[]{0, onTime, offTime}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleRumble(short controllerNumber, short lowFreqMotor, short highFreqMotor) {
|
||||||
|
boolean foundMatchingDevice = false;
|
||||||
|
boolean vibrated = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < inputDeviceContexts.size(); i++) {
|
||||||
|
InputDeviceContext deviceContext = inputDeviceContexts.valueAt(i);
|
||||||
|
|
||||||
|
if (deviceContext.controllerNumber == controllerNumber) {
|
||||||
|
foundMatchingDevice = true;
|
||||||
|
|
||||||
|
if (deviceContext.vibrator != null) {
|
||||||
|
vibrated = true;
|
||||||
|
rumbleVibrator(deviceContext.vibrator, lowFreqMotor, highFreqMotor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < usbDeviceContexts.size(); i++) {
|
||||||
|
UsbDeviceContext deviceContext = usbDeviceContexts.valueAt(i);
|
||||||
|
|
||||||
|
if (deviceContext.controllerNumber == controllerNumber) {
|
||||||
|
foundMatchingDevice = vibrated = true;
|
||||||
|
deviceContext.device.rumble((short)lowFreqMotor, (short)highFreqMotor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We may decide to rumble the device for player 1
|
||||||
|
if (controllerNumber == 0) {
|
||||||
|
// If we didn't find a matching device, it must be the on-screen
|
||||||
|
// controls that triggered the rumble. Vibrate the device if
|
||||||
|
// the user has requested that behavior.
|
||||||
|
if (!foundMatchingDevice && prefConfig.onscreenController && !prefConfig.onlyL3R3 && prefConfig.vibrateOsc) {
|
||||||
|
rumbleVibrator(deviceVibrator, lowFreqMotor, highFreqMotor);
|
||||||
|
}
|
||||||
|
else if (foundMatchingDevice && !vibrated && prefConfig.vibrateFallbackToDevice) {
|
||||||
|
// We found a device to vibrate but it didn't have rumble support. The user
|
||||||
|
// has requested us to vibrate the device in this case.
|
||||||
|
rumbleVibrator(deviceVibrator, lowFreqMotor, highFreqMotor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean handleButtonUp(KeyEvent event) {
|
public boolean handleButtonUp(KeyEvent event) {
|
||||||
InputDeviceContext context = getContextForEvent(event);
|
InputDeviceContext context = getContextForEvent(event);
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
@@ -1294,12 +1410,30 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reportOscState(short buttonFlags,
|
||||||
|
short leftStickX, short leftStickY,
|
||||||
|
short rightStickX, short rightStickY,
|
||||||
|
byte leftTrigger, byte rightTrigger) {
|
||||||
|
defaultContext.leftStickX = leftStickX;
|
||||||
|
defaultContext.leftStickY = leftStickY;
|
||||||
|
|
||||||
|
defaultContext.rightStickX = rightStickX;
|
||||||
|
defaultContext.rightStickY = rightStickY;
|
||||||
|
|
||||||
|
defaultContext.leftTrigger = leftTrigger;
|
||||||
|
defaultContext.rightTrigger = rightTrigger;
|
||||||
|
|
||||||
|
defaultContext.inputMap = buttonFlags;
|
||||||
|
|
||||||
|
sendControllerInputPacket(defaultContext);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportControllerState(int controllerId, short buttonFlags,
|
public void reportControllerState(int controllerId, short buttonFlags,
|
||||||
float leftStickX, float leftStickY,
|
float leftStickX, float leftStickY,
|
||||||
float rightStickX, float rightStickY,
|
float rightStickX, float rightStickY,
|
||||||
float leftTrigger, float rightTrigger) {
|
float leftTrigger, float rightTrigger) {
|
||||||
UsbDeviceContext context = usbDeviceContexts.get(controllerId);
|
GenericControllerContext context = usbDeviceContexts.get(controllerId);
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1334,19 +1468,19 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deviceRemoved(int controllerId) {
|
public void deviceRemoved(AbstractController controller) {
|
||||||
UsbDeviceContext context = usbDeviceContexts.get(controllerId);
|
UsbDeviceContext context = usbDeviceContexts.get(controller.getControllerId());
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
LimeLog.info("Removed controller: "+controllerId);
|
LimeLog.info("Removed controller: "+controller.getControllerId());
|
||||||
releaseControllerNumber(context);
|
releaseControllerNumber(context);
|
||||||
usbDeviceContexts.remove(controllerId);
|
usbDeviceContexts.remove(controller.getControllerId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deviceAdded(int controllerId) {
|
public void deviceAdded(AbstractController controller) {
|
||||||
UsbDeviceContext context = createUsbDeviceContextForDevice(controllerId);
|
UsbDeviceContext context = createUsbDeviceContextForDevice(controller);
|
||||||
usbDeviceContexts.put(controllerId, context);
|
usbDeviceContexts.put(controller.getControllerId(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
class GenericControllerContext {
|
class GenericControllerContext {
|
||||||
@@ -1375,6 +1509,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
|
|
||||||
class InputDeviceContext extends GenericControllerContext {
|
class InputDeviceContext extends GenericControllerContext {
|
||||||
public String name;
|
public String name;
|
||||||
|
public Vibrator vibrator;
|
||||||
|
|
||||||
public int leftStickXAxis = -1;
|
public int leftStickXAxis = -1;
|
||||||
public int leftStickYAxis = -1;
|
public int leftStickYAxis = -1;
|
||||||
@@ -1412,5 +1547,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
|
|||||||
public long startDownTime = 0;
|
public long startDownTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UsbDeviceContext extends GenericControllerContext {}
|
class UsbDeviceContext extends GenericControllerContext {
|
||||||
|
public AbstractController device;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,11 +37,13 @@ public abstract class AbstractController {
|
|||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void rumble(short lowFreqMotor, short highFreqMotor);
|
||||||
|
|
||||||
protected void notifyDeviceRemoved() {
|
protected void notifyDeviceRemoved() {
|
||||||
listener.deviceRemoved(deviceId);
|
listener.deviceRemoved(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notifyDeviceAdded() {
|
protected void notifyDeviceAdded() {
|
||||||
listener.deviceAdded(deviceId);
|
listener.deviceAdded(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,9 @@ public abstract class AbstractXboxController extends AbstractController {
|
|||||||
|
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
|
||||||
|
// Cancel any rumble effects
|
||||||
|
rumble((short)0, (short)0);
|
||||||
|
|
||||||
// Stop the input thread
|
// Stop the input thread
|
||||||
if (inputThread != null) {
|
if (inputThread != null) {
|
||||||
inputThread.interrupt();
|
inputThread.interrupt();
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ public interface UsbDriverListener {
|
|||||||
float rightStickX, float rightStickY,
|
float rightStickX, float rightStickY,
|
||||||
float leftTrigger, float rightTrigger);
|
float leftTrigger, float rightTrigger);
|
||||||
|
|
||||||
void deviceRemoved(int controllerId);
|
void deviceRemoved(AbstractController controller);
|
||||||
void deviceAdded(int controllerId);
|
void deviceAdded(AbstractController controller);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,26 +47,21 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deviceRemoved(int controllerId) {
|
public void deviceRemoved(AbstractController controller) {
|
||||||
// Remove the the controller from our list (if not removed already)
|
// Remove the the controller from our list (if not removed already)
|
||||||
for (AbstractController controller : controllers) {
|
controllers.remove(controller);
|
||||||
if (controller.getControllerId() == controllerId) {
|
|
||||||
controllers.remove(controller);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call through to the client's listener
|
// Call through to the client's listener
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.deviceRemoved(controllerId);
|
listener.deviceRemoved(controller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deviceAdded(int controllerId) {
|
public void deviceAdded(AbstractController controller) {
|
||||||
// Call through to the client's listener
|
// Call through to the client's listener
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.deviceAdded(controllerId);
|
listener.deviceAdded(controller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +108,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
|||||||
// Report all controllerMap that already exist
|
// Report all controllerMap that already exist
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
for (AbstractController controller : controllers) {
|
for (AbstractController controller : controllers) {
|
||||||
listener.deviceAdded(controller.getControllerId());
|
listener.deviceAdded(controller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,4 +139,17 @@ public class Xbox360Controller extends AbstractXboxController {
|
|||||||
// No need to fail init if the LED command fails
|
// No need to fail init if the LED command fails
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rumble(short lowFreqMotor, short highFreqMotor) {
|
||||||
|
byte[] data = {
|
||||||
|
0x00, 0x08, 0x00,
|
||||||
|
(byte)(lowFreqMotor >> 8), (byte)(highFreqMotor >> 8),
|
||||||
|
0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
int res = connection.bulkTransfer(outEndpt, data, data.length, 100);
|
||||||
|
if (res != data.length) {
|
||||||
|
LimeLog.warning("Rumble transfer failed: "+res);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class XboxOneController extends AbstractXboxController {
|
|||||||
new InitPacket(0x24c6, 0x543a, RUMBLE_INIT2),
|
new InitPacket(0x24c6, 0x543a, RUMBLE_INIT2),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private byte seqNum = 0;
|
||||||
|
|
||||||
public XboxOneController(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
|
public XboxOneController(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
|
||||||
super(device, connection, deviceId, listener);
|
super(device, connection, deviceId, listener);
|
||||||
@@ -134,8 +135,6 @@ public class XboxOneController extends AbstractXboxController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doInit() {
|
protected boolean doInit() {
|
||||||
byte seqNum = 0;
|
|
||||||
|
|
||||||
// Send all applicable init packets
|
// Send all applicable init packets
|
||||||
for (InitPacket pkt : INIT_PKTS) {
|
for (InitPacket pkt : INIT_PKTS) {
|
||||||
if (pkt.vendorId != 0 && device.getVendorId() != pkt.vendorId) {
|
if (pkt.vendorId != 0 && device.getVendorId() != pkt.vendorId) {
|
||||||
@@ -162,6 +161,20 @@ public class XboxOneController extends AbstractXboxController {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rumble(short lowFreqMotor, short highFreqMotor) {
|
||||||
|
byte[] data = {
|
||||||
|
0x09, 0x00, seqNum++, 0x09, 0x00,
|
||||||
|
0x0F, 0x00, 0x00,
|
||||||
|
(byte)(lowFreqMotor >> 9), (byte)(highFreqMotor >> 9),
|
||||||
|
(byte)0xFF, 0x00, (byte)0xFF
|
||||||
|
};
|
||||||
|
int res = connection.bulkTransfer(outEndpt, data, data.length, 100);
|
||||||
|
if (res != data.length) {
|
||||||
|
LimeLog.warning("Rumble transfer failed: "+res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class InitPacket {
|
private static class InitPacket {
|
||||||
final int vendorId;
|
final int vendorId;
|
||||||
final int productId;
|
final int productId;
|
||||||
|
|||||||
+9
-8
@@ -13,6 +13,7 @@ import android.widget.RelativeLayout;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.limelight.R;
|
import com.limelight.R;
|
||||||
|
import com.limelight.binding.input.ControllerHandler;
|
||||||
import com.limelight.nvstream.NvConnection;
|
import com.limelight.nvstream.NvConnection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -38,7 +39,7 @@ public class VirtualController {
|
|||||||
|
|
||||||
private static final boolean _PRINT_DEBUG_INFORMATION = false;
|
private static final boolean _PRINT_DEBUG_INFORMATION = false;
|
||||||
|
|
||||||
private NvConnection connection = null;
|
private ControllerHandler controllerHandler;
|
||||||
private Context context = null;
|
private Context context = null;
|
||||||
|
|
||||||
private FrameLayout frame_layout = null;
|
private FrameLayout frame_layout = null;
|
||||||
@@ -53,8 +54,8 @@ public class VirtualController {
|
|||||||
|
|
||||||
private List<VirtualControllerElement> elements = new ArrayList<>();
|
private List<VirtualControllerElement> elements = new ArrayList<>();
|
||||||
|
|
||||||
public VirtualController(final NvConnection conn, FrameLayout layout, final Context context) {
|
public VirtualController(final ControllerHandler controllerHandler, FrameLayout layout, final Context context) {
|
||||||
this.connection = conn;
|
this.controllerHandler = controllerHandler;
|
||||||
this.frame_layout = layout;
|
this.frame_layout = layout;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
@@ -173,15 +174,15 @@ public class VirtualController {
|
|||||||
_DBG("LEFT STICK X: " + inputContext.leftStickX + " Y: " + inputContext.leftStickY);
|
_DBG("LEFT STICK X: " + inputContext.leftStickX + " Y: " + inputContext.leftStickY);
|
||||||
_DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY);
|
_DBG("RIGHT STICK X: " + inputContext.rightStickX + " Y: " + inputContext.rightStickY);
|
||||||
|
|
||||||
if (connection != null) {
|
if (controllerHandler != null) {
|
||||||
connection.sendControllerInput(
|
controllerHandler.reportOscState(
|
||||||
inputContext.inputMap,
|
inputContext.inputMap,
|
||||||
inputContext.leftTrigger,
|
|
||||||
inputContext.rightTrigger,
|
|
||||||
inputContext.leftStickX,
|
inputContext.leftStickX,
|
||||||
inputContext.leftStickY,
|
inputContext.leftStickY,
|
||||||
inputContext.rightStickX,
|
inputContext.rightStickX,
|
||||||
inputContext.rightStickY
|
inputContext.rightStickY,
|
||||||
|
inputContext.leftTrigger,
|
||||||
|
inputContext.rightTrigger
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ public class PreferenceConfiguration {
|
|||||||
private static final String MOUSE_EMULATION_STRING = "checkbox_mouse_emulation";
|
private static final String MOUSE_EMULATION_STRING = "checkbox_mouse_emulation";
|
||||||
private static final String MOUSE_NAV_BUTTONS_STRING = "checkbox_mouse_nav_buttons";
|
private static final String MOUSE_NAV_BUTTONS_STRING = "checkbox_mouse_nav_buttons";
|
||||||
static final String UNLOCK_FPS_STRING = "checkbox_unlock_fps";
|
static final String UNLOCK_FPS_STRING = "checkbox_unlock_fps";
|
||||||
|
private static final String VIBRATE_OSC_PREF_STRING = "checkbox_vibrate_osc";
|
||||||
|
private static final String VIBRATE_FALLBACK_PREF_STRING = "checkbox_vibrate_fallback";
|
||||||
|
|
||||||
static final String DEFAULT_RESOLUTION = "720p";
|
static final String DEFAULT_RESOLUTION = "720p";
|
||||||
static final String DEFAULT_FPS = "60";
|
static final String DEFAULT_FPS = "60";
|
||||||
@@ -58,6 +60,8 @@ public class PreferenceConfiguration {
|
|||||||
private static final boolean DEFAULT_MOUSE_EMULATION = true;
|
private static final boolean DEFAULT_MOUSE_EMULATION = true;
|
||||||
private static final boolean DEFAULT_MOUSE_NAV_BUTTONS = false;
|
private static final boolean DEFAULT_MOUSE_NAV_BUTTONS = false;
|
||||||
private static final boolean DEFAULT_UNLOCK_FPS = false;
|
private static final boolean DEFAULT_UNLOCK_FPS = false;
|
||||||
|
private static final boolean DEFAULT_VIBRATE_OSC = true;
|
||||||
|
private static final boolean DEFAULT_VIBRATE_FALLBACK = false;
|
||||||
|
|
||||||
public static final int FORCE_H265_ON = -1;
|
public static final int FORCE_H265_ON = -1;
|
||||||
public static final int AUTOSELECT_H265 = 0;
|
public static final int AUTOSELECT_H265 = 0;
|
||||||
@@ -79,6 +83,8 @@ public class PreferenceConfiguration {
|
|||||||
public boolean mouseEmulation;
|
public boolean mouseEmulation;
|
||||||
public boolean mouseNavButtons;
|
public boolean mouseNavButtons;
|
||||||
public boolean unlockFps;
|
public boolean unlockFps;
|
||||||
|
public boolean vibrateOsc;
|
||||||
|
public boolean vibrateFallbackToDevice;
|
||||||
|
|
||||||
private static int getHeightFromResolutionString(String resString) {
|
private static int getHeightFromResolutionString(String resString) {
|
||||||
if (resString.equalsIgnoreCase("360p")) {
|
if (resString.equalsIgnoreCase("360p")) {
|
||||||
@@ -329,6 +335,8 @@ public class PreferenceConfiguration {
|
|||||||
config.mouseEmulation = prefs.getBoolean(MOUSE_EMULATION_STRING, DEFAULT_MOUSE_EMULATION);
|
config.mouseEmulation = prefs.getBoolean(MOUSE_EMULATION_STRING, DEFAULT_MOUSE_EMULATION);
|
||||||
config.mouseNavButtons = prefs.getBoolean(MOUSE_NAV_BUTTONS_STRING, DEFAULT_MOUSE_NAV_BUTTONS);
|
config.mouseNavButtons = prefs.getBoolean(MOUSE_NAV_BUTTONS_STRING, DEFAULT_MOUSE_NAV_BUTTONS);
|
||||||
config.unlockFps = prefs.getBoolean(UNLOCK_FPS_STRING, DEFAULT_UNLOCK_FPS);
|
config.unlockFps = prefs.getBoolean(UNLOCK_FPS_STRING, DEFAULT_UNLOCK_FPS);
|
||||||
|
config.vibrateOsc = prefs.getBoolean(VIBRATE_OSC_PREF_STRING, DEFAULT_VIBRATE_OSC);
|
||||||
|
config.vibrateFallbackToDevice = prefs.getBoolean(VIBRATE_FALLBACK_PREF_STRING, DEFAULT_VIBRATE_FALLBACK);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:width="128dp"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:height="128dp"
|
||||||
<path android:fillColor="#FF000000" android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"
|
||||||
|
android:fillColor="#FFFFFF"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -10,4 +10,16 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/notificationOverlay"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_gravity="right"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:gravity="right"
|
||||||
|
android:background="#80000000"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!-- Shortcut strings -->
|
<!-- Shortcut strings -->
|
||||||
<string name="scut_deleted_pc">PC supprimé</string>
|
<string name="scut_deleted_pc">PC supprimé</string>
|
||||||
<string name="scut_not_paired">PC non appairé</string>
|
<string name="scut_not_paired">PC non appairé</string>
|
||||||
@@ -133,6 +134,8 @@
|
|||||||
<string name="category_input_settings">Paramètres d\'entrée</string>
|
<string name="category_input_settings">Paramètres d\'entrée</string>
|
||||||
<string name="title_checkbox_multi_controller">Prise en charge de plusieurs contrôleurs</string>
|
<string name="title_checkbox_multi_controller">Prise en charge de plusieurs contrôleurs</string>
|
||||||
<string name="summary_checkbox_multi_controller">Lorsqu\'elle n\'est pas cochée, tous les contrôleurs sont regroupés</string>
|
<string name="summary_checkbox_multi_controller">Lorsqu\'elle n\'est pas cochée, tous les contrôleurs sont regroupés</string>
|
||||||
|
<string name="title_checkbox_vibrate_fallback">Emuler le support vibration</string>
|
||||||
|
<string name="summary_checkbox_vibrate_fallback">Vibre votre appareil pour émuler une vibration si votre manette ne le prend pas en charge</string>
|
||||||
<string name="title_seekbar_deadzone">Régler la zone morte du stick analogique</string>
|
<string name="title_seekbar_deadzone">Régler la zone morte du stick analogique</string>
|
||||||
<string name="suffix_seekbar_deadzone">%</string>
|
<string name="suffix_seekbar_deadzone">%</string>
|
||||||
<string name="title_checkbox_xb1_driver">Pilote de contrôleur Xbox 360/One</string>
|
<string name="title_checkbox_xb1_driver">Pilote de contrôleur Xbox 360/One</string>
|
||||||
@@ -147,6 +150,8 @@
|
|||||||
<string name="category_on_screen_controls_settings">Paramètres des contrôles à l\'écran</string>
|
<string name="category_on_screen_controls_settings">Paramètres des contrôles à l\'écran</string>
|
||||||
<string name="title_checkbox_show_onscreen_controls">Afficher les commandes à l\'écran</string>
|
<string name="title_checkbox_show_onscreen_controls">Afficher les commandes à l\'écran</string>
|
||||||
<string name="summary_checkbox_show_onscreen_controls">Afficher la superposition du contrôleur virtuel sur l\'écran tactile</string>
|
<string name="summary_checkbox_show_onscreen_controls">Afficher la superposition du contrôleur virtuel sur l\'écran tactile</string>
|
||||||
|
<string name="title_checkbox_vibrate_osc">Activer les vibrations</string>
|
||||||
|
<string name="summary_checkbox_vibrate_osc">Vibre votre appareil pour émuler les vibrations des commandes à l\'écran</string>
|
||||||
<string name="title_only_l3r3">Montre seulement L3 et R3</string>
|
<string name="title_only_l3r3">Montre seulement L3 et R3</string>
|
||||||
<string name="summary_only_l3r3">Cacher tout sauf L3 et R3</string>
|
<string name="summary_only_l3r3">Cacher tout sauf L3 et R3</string>
|
||||||
<string name="title_reset_osc">Effacer la disposition des commandes à l\'écran sauvegardée</string>
|
<string name="title_reset_osc">Effacer la disposition des commandes à l\'écran sauvegardée</string>
|
||||||
|
|||||||
@@ -84,6 +84,8 @@
|
|||||||
<string name="title_details">Details</string>
|
<string name="title_details">Details</string>
|
||||||
<string name="help">Help</string>
|
<string name="help">Help</string>
|
||||||
<string name="delete_pc_msg">Are you sure you want to delete this PC?</string>
|
<string name="delete_pc_msg">Are you sure you want to delete this PC?</string>
|
||||||
|
<string name="slow_connection_msg">Slow connection to PC\nReduce your bitrate</string>
|
||||||
|
<string name="poor_connection_msg">Poor connection to PC</string>
|
||||||
|
|
||||||
<!-- AppList activity -->
|
<!-- AppList activity -->
|
||||||
<string name="applist_connect_msg">Connecting to PC…</string>
|
<string name="applist_connect_msg">Connecting to PC…</string>
|
||||||
@@ -136,6 +138,8 @@
|
|||||||
<string name="category_input_settings">Input Settings</string>
|
<string name="category_input_settings">Input Settings</string>
|
||||||
<string name="title_checkbox_multi_controller">Automatic gamepad presence detection</string>
|
<string name="title_checkbox_multi_controller">Automatic gamepad presence detection</string>
|
||||||
<string name="summary_checkbox_multi_controller">Unchecking this option forces a gamepad to always be present</string>
|
<string name="summary_checkbox_multi_controller">Unchecking this option forces a gamepad to always be present</string>
|
||||||
|
<string name="title_checkbox_vibrate_fallback">Emulate rumble support with vibration</string>
|
||||||
|
<string name="summary_checkbox_vibrate_fallback">Vibrates your device to emulate rumble if your gamepad does not support it</string>
|
||||||
<string name="title_seekbar_deadzone">Adjust analog stick deadzone</string>
|
<string name="title_seekbar_deadzone">Adjust analog stick deadzone</string>
|
||||||
<string name="suffix_seekbar_deadzone">%</string>
|
<string name="suffix_seekbar_deadzone">%</string>
|
||||||
<string name="title_checkbox_xb1_driver">Xbox 360/One controller driver</string>
|
<string name="title_checkbox_xb1_driver">Xbox 360/One controller driver</string>
|
||||||
@@ -150,6 +154,8 @@
|
|||||||
<string name="category_on_screen_controls_settings">On-screen Controls Settings</string>
|
<string name="category_on_screen_controls_settings">On-screen Controls Settings</string>
|
||||||
<string name="title_checkbox_show_onscreen_controls">Show on-screen controls</string>
|
<string name="title_checkbox_show_onscreen_controls">Show on-screen controls</string>
|
||||||
<string name="summary_checkbox_show_onscreen_controls">Show virtual controller overlay on touchscreen</string>
|
<string name="summary_checkbox_show_onscreen_controls">Show virtual controller overlay on touchscreen</string>
|
||||||
|
<string name="title_checkbox_vibrate_osc">Enable vibration</string>
|
||||||
|
<string name="summary_checkbox_vibrate_osc">Vibrates your device to emulate rumble for the on-screen controls</string>
|
||||||
<string name="title_only_l3r3">Only show L3 and R3</string>
|
<string name="title_only_l3r3">Only show L3 and R3</string>
|
||||||
<string name="summary_only_l3r3">Hide all virtual buttons except L3 and R3</string>
|
<string name="summary_only_l3r3">Hide all virtual buttons except L3 and R3</string>
|
||||||
<string name="title_reset_osc">Clear saved on-screen controls layout</string>
|
<string name="title_reset_osc">Clear saved on-screen controls layout</string>
|
||||||
|
|||||||
@@ -82,6 +82,11 @@
|
|||||||
android:title="@string/title_checkbox_mouse_emulation"
|
android:title="@string/title_checkbox_mouse_emulation"
|
||||||
android:summary="@string/summary_checkbox_mouse_emulation"
|
android:summary="@string/summary_checkbox_mouse_emulation"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="checkbox_vibrate_fallback"
|
||||||
|
android:title="@string/title_checkbox_vibrate_fallback"
|
||||||
|
android:summary="@string/summary_checkbox_vibrate_fallback"
|
||||||
|
android:defaultValue="false" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/category_on_screen_controls_settings"
|
<PreferenceCategory android:title="@string/category_on_screen_controls_settings"
|
||||||
android:key="category_onscreen_controls">
|
android:key="category_onscreen_controls">
|
||||||
@@ -90,6 +95,12 @@
|
|||||||
android:key="checkbox_show_onscreen_controls"
|
android:key="checkbox_show_onscreen_controls"
|
||||||
android:summary="@string/summary_checkbox_show_onscreen_controls"
|
android:summary="@string/summary_checkbox_show_onscreen_controls"
|
||||||
android:title="@string/title_checkbox_show_onscreen_controls" />
|
android:title="@string/title_checkbox_show_onscreen_controls" />
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="checkbox_vibrate_osc"
|
||||||
|
android:dependency="checkbox_show_onscreen_controls"
|
||||||
|
android:title="@string/title_checkbox_vibrate_osc"
|
||||||
|
android:summary="@string/summary_checkbox_vibrate_osc"
|
||||||
|
android:defaultValue="true" />
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:dependency="checkbox_show_onscreen_controls"
|
android:dependency="checkbox_show_onscreen_controls"
|
||||||
@@ -138,6 +149,11 @@
|
|||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory android:title="@string/category_advanced_settings"
|
<PreferenceCategory android:title="@string/category_advanced_settings"
|
||||||
android:key="category_advanced_settings">
|
android:key="category_advanced_settings">
|
||||||
|
<CheckBoxPreference
|
||||||
|
android:key="checkbox_disable_warnings"
|
||||||
|
android:title="@string/title_checkbox_disable_warnings"
|
||||||
|
android:summary="@string/summary_checkbox_disable_warnings"
|
||||||
|
android:defaultValue="false" />
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="video_format"
|
android:key="video_format"
|
||||||
android:title="@string/title_video_format"
|
android:title="@string/title_video_format"
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.3.1'
|
classpath 'com.android.tools.build:gradle:3.4.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
#Tue Feb 05 20:54:22 PST 2019
|
#Fri Apr 26 18:29:34 PDT 2019
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||||
|
|||||||
+1
-1
Submodule moonlight-common updated: 4e4a8f2c4e...238fb4bd77
Reference in New Issue
Block a user