Add device vibration and other fixes

This commit is contained in:
Cameron Gutman 2019-02-16 19:13:01 -08:00
parent 2f7087d6d3
commit 50d45011a8
4 changed files with 66 additions and 8 deletions

View File

@ -55,6 +55,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private final double stickDeadzone;
private final InputDeviceContext defaultContext = new InputDeviceContext();
private final GameGestures gestures;
private final Vibrator deviceVibrator;
private boolean hasGameController;
private final PreferenceConfiguration prefConfig;
@ -65,6 +66,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
this.conn = conn;
this.gestures = gestures;
this.prefConfig = prefConfig;
this.deviceVibrator = (Vibrator) activityContext.getSystemService(Context.VIBRATOR_SERVICE);
// HACK: For now we're hardcoding a 10% deadzone. Some deadzone
// is required for controller batching support to work.
@ -163,6 +165,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
deviceContext.vibrator.cancel();
}
}
deviceVibrator.cancel();
}
private static boolean hasJoystickAxes(InputDevice device) {
@ -220,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");
return mask;
}
@ -633,7 +642,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private short getActiveControllerMask() {
if (prefConfig.multiController) {
return (short)(currentControllers | initialControllers);
return (short)(currentControllers | initialControllers | (prefConfig.onscreenController ? 1 : 0));
}
else {
// Only Player 1 is active with multi-controller disabled
@ -1072,13 +1081,15 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// Since we can only use a single amplitude value, compute the desired amplitude
// by taking 75% of the big motor and 25% of the small motor.
// NB: This value is now 0-255 as required by VibrationEffect.
int simulatedAmplitude = (int)(((lowFreqMotor >> 8) * 0.75) + ((highFreqMotor >> 8) * 0.25));
short lowFreqMotorMSB = (short)((lowFreqMotor >> 8) & 0xFF);
short highFreqMotorMSB = (short)((lowFreqMotor >> 8) & 0xFF);
int simulatedAmplitude = (int)((lowFreqMotorMSB * 0.75) + (highFreqMotorMSB * 0.25));
// 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(Long.MAX_VALUE, simulatedAmplitude);
VibrationEffect effect = VibrationEffect.createOneShot(60000, simulatedAmplitude);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.build();
@ -1089,18 +1100,26 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// If we reach this point, we don't have amplitude controls available, so
// we must emulate it by PWMing the vibration. Ick.
long pwmPeriod = 50;
long pwmPeriod = 20;
long onTime = (long)((simulatedAmplitude / 255.0) * pwmPeriod);
long offTime = pwmPeriod - onTime;
vibrator.vibrate(new long[]{offTime, onTime}, 0);
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 && deviceContext.vibrator != null) {
rumbleVibrator(deviceContext.vibrator, lowFreqMotor, highFreqMotor);
if (deviceContext.controllerNumber == controllerNumber) {
foundMatchingDevice = true;
if (deviceContext.vibrator != null) {
vibrated = true;
rumbleVibrator(deviceContext.vibrator, lowFreqMotor, highFreqMotor);
}
}
}
@ -1108,7 +1127,23 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
UsbDeviceContext deviceContext = usbDeviceContexts.valueAt(i);
if (deviceContext.controllerNumber == controllerNumber) {
deviceContext.device.rumble(lowFreqMotor, highFreqMotor);
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);
}
}
}

View File

@ -35,6 +35,8 @@ public class PreferenceConfiguration {
private static final String MOUSE_EMULATION_STRING = "checkbox_mouse_emulation";
private static final String MOUSE_NAV_BUTTONS_STRING = "checkbox_mouse_nav_buttons";
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_FPS = "60";
@ -58,6 +60,8 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_MOUSE_EMULATION = true;
private static final boolean DEFAULT_MOUSE_NAV_BUTTONS = 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 AUTOSELECT_H265 = 0;
@ -79,6 +83,8 @@ public class PreferenceConfiguration {
public boolean mouseEmulation;
public boolean mouseNavButtons;
public boolean unlockFps;
public boolean vibrateOsc;
public boolean vibrateFallbackToDevice;
private static int getHeightFromResolutionString(String resString) {
if (resString.equalsIgnoreCase("360p")) {
@ -329,6 +335,8 @@ public class PreferenceConfiguration {
config.mouseEmulation = prefs.getBoolean(MOUSE_EMULATION_STRING, DEFAULT_MOUSE_EMULATION);
config.mouseNavButtons = prefs.getBoolean(MOUSE_NAV_BUTTONS_STRING, DEFAULT_MOUSE_NAV_BUTTONS);
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;
}

View File

@ -136,6 +136,8 @@
<string name="category_input_settings">Input Settings</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="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="suffix_seekbar_deadzone">%</string>
<string name="title_checkbox_xb1_driver">Xbox 360/One controller driver</string>
@ -150,6 +152,8 @@
<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="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="summary_only_l3r3">Hide all virtual buttons except L3 and R3</string>
<string name="title_reset_osc">Clear saved on-screen controls layout</string>

View File

@ -82,6 +82,11 @@
android:title="@string/title_checkbox_mouse_emulation"
android:summary="@string/summary_checkbox_mouse_emulation"
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 android:title="@string/category_on_screen_controls_settings"
android:key="category_onscreen_controls">
@ -90,6 +95,12 @@
android:key="checkbox_show_onscreen_controls"
android:summary="@string/summary_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
android:defaultValue="false"
android:dependency="checkbox_show_onscreen_controls"