mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-14 07:05:40 -04:00
Feat[gyro]: improve calibration and smoothing (#4229)
* Feat[gyro]: Reduce jitter with moving average * Cleanup: Remove logging * Feat[gyro]: Add dampering window * Feat[gyro]: Use extremely low pass filter Technically, it doesn't entirely filter out the input, only stores it * Tweak[Gyro]: Lower hyro threshold even more * Feat: Simplify smoothing, better calibration * Feat[gyro]: Add dampering window # Conflicts: # app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java # app_pojavlauncher/src/main/res/values/strings.xml * Cleanup[gyro]: Don't use import * Refactor[gyro]: reduce JNI calls * Fix[Gyro]: Adjust low pass treshold to sensitivity * Feat[Gyro]: Handle single/multi axis deplacement * Tweak[gyro]: Raise single axis threshold
This commit is contained in:
parent
2a27439887
commit
a7444aa99e
@ -7,13 +7,20 @@ import android.hardware.SensorEvent;
|
|||||||
import android.hardware.SensorEventListener;
|
import android.hardware.SensorEventListener;
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.view.OrientationEventListener;
|
import android.view.OrientationEventListener;
|
||||||
|
import android.view.Surface;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
|
||||||
|
|
||||||
import org.lwjgl.glfw.CallbackBridge;
|
import org.lwjgl.glfw.CallbackBridge;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class GyroControl implements SensorEventListener, GrabListener {
|
public class GyroControl implements SensorEventListener, GrabListener {
|
||||||
|
/* How much distance has to be moved before taking into account the gyro */
|
||||||
|
private static final float SINGLE_AXIS_LOW_PASS_THRESHOLD = 1.13F;
|
||||||
|
private static final float MULTI_AXIS_LOW_PASS_THRESHOLD = 1.3F;
|
||||||
|
|
||||||
private final WindowManager mWindowManager;
|
private final WindowManager mWindowManager;
|
||||||
private int mSurfaceRotation;
|
private int mSurfaceRotation;
|
||||||
private final SensorManager mSensorManager;
|
private final SensorManager mSensorManager;
|
||||||
@ -29,12 +36,29 @@ public class GyroControl implements SensorEventListener, GrabListener{
|
|||||||
private final float[] mCurrentRotation = new float[16];
|
private final float[] mCurrentRotation = new float[16];
|
||||||
private final float[] mAngleDifference = new float[3];
|
private final float[] mAngleDifference = new float[3];
|
||||||
|
|
||||||
|
|
||||||
|
/* Used to average the last values, if smoothing is enabled */
|
||||||
|
private final float[][] mAngleBuffer = new float[
|
||||||
|
LauncherPreferences.PREF_GYRO_SMOOTHING ? 2 : 1
|
||||||
|
][3];
|
||||||
|
private float xTotal = 0;
|
||||||
|
private float yTotal = 0;
|
||||||
|
|
||||||
|
private float xAverage = 0;
|
||||||
|
private float yAverage = 0;
|
||||||
|
private int mHistoryIndex = -1;
|
||||||
|
|
||||||
|
/* Store the gyro movement under the threshold */
|
||||||
|
private float mStoredX = 0;
|
||||||
|
private float mStoredY = 0;
|
||||||
|
|
||||||
public GyroControl(Activity activity) {
|
public GyroControl(Activity activity) {
|
||||||
mWindowManager = activity.getWindowManager();
|
mWindowManager = activity.getWindowManager();
|
||||||
mSurfaceRotation = -10;
|
mSurfaceRotation = -10;
|
||||||
mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
|
mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
|
||||||
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
|
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);
|
||||||
mCorrectionListener = new OrientationCorrectionListener(activity);
|
mCorrectionListener = new OrientationCorrectionListener(activity);
|
||||||
|
updateOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enable() {
|
public void enable() {
|
||||||
@ -50,8 +74,10 @@ public class GyroControl implements SensorEventListener, GrabListener{
|
|||||||
if(mSensor == null) return;
|
if(mSensor == null) return;
|
||||||
mSensorManager.unregisterListener(this);
|
mSensorManager.unregisterListener(this);
|
||||||
mCorrectionListener.disable();
|
mCorrectionListener.disable();
|
||||||
|
resetDamper();
|
||||||
CallbackBridge.removeGrabListener(this);
|
CallbackBridge.removeGrabListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSensorChanged(SensorEvent sensorEvent) {
|
public void onSensorChanged(SensorEvent sensorEvent) {
|
||||||
if (!mShouldHandleEvents) return;
|
if (!mShouldHandleEvents) return;
|
||||||
@ -59,21 +85,78 @@ public class GyroControl implements SensorEventListener, GrabListener{
|
|||||||
System.arraycopy(mCurrentRotation, 0, mPreviousRotation, 0, 16);
|
System.arraycopy(mCurrentRotation, 0, mPreviousRotation, 0, 16);
|
||||||
SensorManager.getRotationMatrixFromVector(mCurrentRotation, sensorEvent.values);
|
SensorManager.getRotationMatrixFromVector(mCurrentRotation, sensorEvent.values);
|
||||||
|
|
||||||
|
|
||||||
if(mFirstPass){ // Setup initial position
|
if(mFirstPass){ // Setup initial position
|
||||||
mFirstPass = false;
|
mFirstPass = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SensorManager.getAngleChange(mAngleDifference, mCurrentRotation, mPreviousRotation);
|
SensorManager.getAngleChange(mAngleDifference, mCurrentRotation, mPreviousRotation);
|
||||||
|
damperValue(mAngleDifference);
|
||||||
|
mStoredX += xAverage * 1000 * LauncherPreferences.PREF_GYRO_SENSITIVITY;
|
||||||
|
mStoredY += yAverage * 1000 * LauncherPreferences.PREF_GYRO_SENSITIVITY;
|
||||||
|
|
||||||
CallbackBridge.mouseX -= (mAngleDifference[mSwapXY ? 2 : 1] * 1000 * LauncherPreferences.PREF_GYRO_SENSITIVITY * xFactor);
|
boolean updatePosition = false;
|
||||||
CallbackBridge.mouseY += (mAngleDifference[mSwapXY ? 1 : 2] * 1000 * LauncherPreferences.PREF_GYRO_SENSITIVITY * yFactor);
|
float absX = Math.abs(mStoredX);
|
||||||
|
float absY = Math.abs(mStoredY);
|
||||||
|
|
||||||
|
if(absX + absY > MULTI_AXIS_LOW_PASS_THRESHOLD) {
|
||||||
|
CallbackBridge.mouseX -= ((mSwapXY ? mStoredY : mStoredX) * xFactor);
|
||||||
|
CallbackBridge.mouseY += ((mSwapXY ? mStoredX : mStoredY) * yFactor);
|
||||||
|
mStoredX = 0;
|
||||||
|
mStoredY = 0;
|
||||||
|
updatePosition = true;
|
||||||
|
} else {
|
||||||
|
if(Math.abs(mStoredX) > SINGLE_AXIS_LOW_PASS_THRESHOLD){
|
||||||
|
CallbackBridge.mouseX -= ((mSwapXY ? mStoredY : mStoredX) * xFactor);
|
||||||
|
mStoredX = 0;
|
||||||
|
updatePosition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Math.abs(mStoredY) > SINGLE_AXIS_LOW_PASS_THRESHOLD) {
|
||||||
|
CallbackBridge.mouseY += ((mSwapXY ? mStoredX : mStoredY) * yFactor);
|
||||||
|
mStoredY = 0;
|
||||||
|
updatePosition = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(updatePosition){
|
||||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update the axis mapping in accordance to activity rotation, used for initial rotation */
|
||||||
|
public void updateOrientation(){
|
||||||
|
int rotation = mWindowManager.getDefaultDisplay().getRotation();
|
||||||
|
mSurfaceRotation = rotation;
|
||||||
|
switch (rotation){
|
||||||
|
case Surface.ROTATION_0:
|
||||||
|
mSwapXY = true;
|
||||||
|
xFactor = 1;
|
||||||
|
yFactor = 1;
|
||||||
|
break;
|
||||||
|
case Surface.ROTATION_90:
|
||||||
|
mSwapXY = false;
|
||||||
|
xFactor = -1;
|
||||||
|
yFactor = 1;
|
||||||
|
break;
|
||||||
|
case Surface.ROTATION_180:
|
||||||
|
mSwapXY = true;
|
||||||
|
xFactor = -1;
|
||||||
|
yFactor = -1;
|
||||||
|
break;
|
||||||
|
case Surface.ROTATION_270:
|
||||||
|
mSwapXY = false;
|
||||||
|
xFactor = 1;
|
||||||
|
yFactor = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LauncherPreferences.PREF_GYRO_INVERT_X) xFactor *= -1;
|
||||||
|
if(LauncherPreferences.PREF_GYRO_INVERT_Y) yFactor *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAccuracyChanged(Sensor sensor, int i) {
|
public void onAccuracyChanged(Sensor sensor, int i) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGrabState(boolean isGrabbing) {
|
public void onGrabState(boolean isGrabbing) {
|
||||||
@ -81,6 +164,40 @@ public class GyroControl implements SensorEventListener, GrabListener{
|
|||||||
mShouldHandleEvents = isGrabbing;
|
mShouldHandleEvents = isGrabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the moving average of the gyroscope to reduce jitter
|
||||||
|
* @param newAngleDifference The new angle difference
|
||||||
|
*/
|
||||||
|
private void damperValue(float[] newAngleDifference){
|
||||||
|
mHistoryIndex ++;
|
||||||
|
if(mHistoryIndex >= mAngleBuffer.length) mHistoryIndex = 0;
|
||||||
|
|
||||||
|
xTotal -= mAngleBuffer[mHistoryIndex][1];
|
||||||
|
yTotal -= mAngleBuffer[mHistoryIndex][2];
|
||||||
|
|
||||||
|
System.arraycopy(newAngleDifference, 0, mAngleBuffer[mHistoryIndex], 0, 3);
|
||||||
|
|
||||||
|
xTotal += mAngleBuffer[mHistoryIndex][1];
|
||||||
|
yTotal += mAngleBuffer[mHistoryIndex][2];
|
||||||
|
|
||||||
|
// compute the moving average
|
||||||
|
xAverage = xTotal / mAngleBuffer.length;
|
||||||
|
yAverage = yTotal / mAngleBuffer.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reset the moving average data */
|
||||||
|
private void resetDamper(){
|
||||||
|
mHistoryIndex = -1;
|
||||||
|
xTotal = 0;
|
||||||
|
yTotal = 0;
|
||||||
|
xAverage = 0;
|
||||||
|
yAverage = 0;
|
||||||
|
for(float[] oldAngle : mAngleBuffer){
|
||||||
|
Arrays.fill(oldAngle, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class OrientationCorrectionListener extends OrientationEventListener {
|
class OrientationCorrectionListener extends OrientationEventListener {
|
||||||
|
|
||||||
public OrientationCorrectionListener(Context context) {
|
public OrientationCorrectionListener(Context context) {
|
||||||
@ -92,31 +209,39 @@ public class GyroControl implements SensorEventListener, GrabListener{
|
|||||||
// Force to wait to be in game before setting factors
|
// Force to wait to be in game before setting factors
|
||||||
// Theoretically, one could use the whole interface in portrait...
|
// Theoretically, one could use the whole interface in portrait...
|
||||||
if(!mShouldHandleEvents) return;
|
if(!mShouldHandleEvents) return;
|
||||||
int surfaceRotation = mWindowManager.getDefaultDisplay().getRotation();
|
|
||||||
if(surfaceRotation == mSurfaceRotation) return;
|
|
||||||
|
|
||||||
if(i == OrientationEventListener.ORIENTATION_UNKNOWN) {
|
if(i == OrientationEventListener.ORIENTATION_UNKNOWN) {
|
||||||
return; //change nothing
|
return; //change nothing
|
||||||
}
|
}
|
||||||
mSurfaceRotation = surfaceRotation;
|
|
||||||
|
|
||||||
if((315 < i && i <= 360) || (i < 45) ) {
|
|
||||||
mSwapXY = true;
|
|
||||||
xFactor = 1;
|
switch (mSurfaceRotation){
|
||||||
|
case Surface.ROTATION_90:
|
||||||
|
case Surface.ROTATION_270:
|
||||||
|
mSwapXY = false;
|
||||||
|
if(225 < i && i < 315) {
|
||||||
|
xFactor = -1;
|
||||||
yFactor = 1;
|
yFactor = 1;
|
||||||
}else if(45 < i && i < 135) {
|
}else if(45 < i && i < 135) {
|
||||||
mSwapXY = false;
|
|
||||||
xFactor = 1;
|
xFactor = 1;
|
||||||
yFactor = -1;
|
yFactor = -1;
|
||||||
}else if(135 < i && i < 225) {
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Surface.ROTATION_0:
|
||||||
|
case Surface.ROTATION_180:
|
||||||
mSwapXY = true;
|
mSwapXY = true;
|
||||||
|
if((315 < i && i <= 360) || (i < 45) ) {
|
||||||
|
xFactor = 1;
|
||||||
|
yFactor = 1;
|
||||||
|
}else if(135 < i && i < 225) {
|
||||||
xFactor = -1;
|
xFactor = -1;
|
||||||
yFactor = -1;
|
yFactor = -1;
|
||||||
}else if(225 < i && i < 315) {
|
|
||||||
mSwapXY = false;
|
|
||||||
xFactor = -1;
|
|
||||||
yFactor = 1;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if(LauncherPreferences.PREF_GYRO_INVERT_X) xFactor *= -1;
|
if(LauncherPreferences.PREF_GYRO_INVERT_X) xFactor *= -1;
|
||||||
if(LauncherPreferences.PREF_GYRO_INVERT_Y) yFactor *= -1;
|
if(LauncherPreferences.PREF_GYRO_INVERT_Y) yFactor *= -1;
|
||||||
}
|
}
|
||||||
|
@ -279,6 +279,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
|
|||||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
|
|
||||||
|
if(mGyroControl != null) mGyroControl.updateOrientation();
|
||||||
Tools.updateWindowSize(this);
|
Tools.updateWindowSize(this);
|
||||||
minecraftGLView.refreshSize();
|
minecraftGLView.refreshSize();
|
||||||
runOnUiThread(() -> mControlLayout.refreshControlButtonPositions());
|
runOnUiThread(() -> mControlLayout.refreshControlButtonPositions());
|
||||||
|
@ -49,6 +49,7 @@ public class LauncherPreferences {
|
|||||||
public static boolean PREF_ENABLE_GYRO = false;
|
public static boolean PREF_ENABLE_GYRO = false;
|
||||||
public static float PREF_GYRO_SENSITIVITY = 1f;
|
public static float PREF_GYRO_SENSITIVITY = 1f;
|
||||||
public static int PREF_GYRO_SAMPLE_RATE = 16;
|
public static int PREF_GYRO_SAMPLE_RATE = 16;
|
||||||
|
public static boolean PREF_GYRO_SMOOTHING = true;
|
||||||
|
|
||||||
public static boolean PREF_GYRO_INVERT_X = false;
|
public static boolean PREF_GYRO_INVERT_X = false;
|
||||||
|
|
||||||
@ -61,6 +62,7 @@ public class LauncherPreferences {
|
|||||||
public static boolean PREF_BIG_CORE_AFFINITY = false;
|
public static boolean PREF_BIG_CORE_AFFINITY = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void loadPreferences(Context ctx) {
|
public static void loadPreferences(Context ctx) {
|
||||||
//Required for the data folder.
|
//Required for the data folder.
|
||||||
Tools.initContextConstants(ctx);
|
Tools.initContextConstants(ctx);
|
||||||
@ -93,6 +95,7 @@ public class LauncherPreferences {
|
|||||||
PREF_ENABLE_GYRO = DEFAULT_PREF.getBoolean("enableGyro", false);
|
PREF_ENABLE_GYRO = DEFAULT_PREF.getBoolean("enableGyro", false);
|
||||||
PREF_GYRO_SENSITIVITY = ((float)DEFAULT_PREF.getInt("gyroSensitivity", 100))/100f;
|
PREF_GYRO_SENSITIVITY = ((float)DEFAULT_PREF.getInt("gyroSensitivity", 100))/100f;
|
||||||
PREF_GYRO_SAMPLE_RATE = DEFAULT_PREF.getInt("gyroSampleRate", 16);
|
PREF_GYRO_SAMPLE_RATE = DEFAULT_PREF.getInt("gyroSampleRate", 16);
|
||||||
|
PREF_GYRO_SMOOTHING = DEFAULT_PREF.getBoolean("gyroSmoothing", true);
|
||||||
PREF_GYRO_INVERT_X = DEFAULT_PREF.getBoolean("gyroInvertX", false);
|
PREF_GYRO_INVERT_X = DEFAULT_PREF.getBoolean("gyroInvertX", false);
|
||||||
PREF_GYRO_INVERT_Y = DEFAULT_PREF.getBoolean("gyroInvertY", false);
|
PREF_GYRO_INVERT_Y = DEFAULT_PREF.getBoolean("gyroInvertY", false);
|
||||||
PREF_FORCE_VSYNC = DEFAULT_PREF.getBoolean("force_vsync", false);
|
PREF_FORCE_VSYNC = DEFAULT_PREF.getBoolean("force_vsync", false);
|
||||||
|
@ -25,6 +25,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
|
|||||||
float gyroSpeed = LauncherPreferences.PREF_GYRO_SENSITIVITY;
|
float gyroSpeed = LauncherPreferences.PREF_GYRO_SENSITIVITY;
|
||||||
float joystickDeadzone = LauncherPreferences.PREF_DEADZONE_SCALE;
|
float joystickDeadzone = LauncherPreferences.PREF_DEADZONE_SCALE;
|
||||||
|
|
||||||
|
|
||||||
//Triggers a write for some reason which resets the value
|
//Triggers a write for some reason which resets the value
|
||||||
addPreferencesFromResource(R.xml.pref_control);
|
addPreferencesFromResource(R.xml.pref_control);
|
||||||
|
|
||||||
@ -53,6 +54,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
|
|||||||
deadzoneSeek.setValue((int) joystickDeadzone * 100);
|
deadzoneSeek.setValue((int) joystickDeadzone * 100);
|
||||||
deadzoneSeek.setSuffix(" %");
|
deadzoneSeek.setSuffix(" %");
|
||||||
|
|
||||||
|
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
if(context != null) {
|
if(context != null) {
|
||||||
mGyroAvailable = ((SensorManager)context.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null;
|
mGyroAvailable = ((SensorManager)context.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null;
|
||||||
@ -83,6 +85,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
|
|||||||
findPreference("gyroSampleRate").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
|
findPreference("gyroSampleRate").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
|
||||||
findPreference("gyroInvertX").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
|
findPreference("gyroInvertX").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
|
||||||
findPreference("gyroInvertY").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
|
findPreference("gyroInvertY").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
|
||||||
|
findPreference("gyroSmoothing").setVisible(LauncherPreferences.PREF_ENABLE_GYRO);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -302,6 +302,8 @@
|
|||||||
<string name="preference_gyro_invert_y_axis">Invert Y axis</string>
|
<string name="preference_gyro_invert_y_axis">Invert Y axis</string>
|
||||||
<string name="preference_gyro_invert_x_axis_description">Invert the horizontal axis</string>
|
<string name="preference_gyro_invert_x_axis_description">Invert the horizontal axis</string>
|
||||||
<string name="preference_gyro_invert_y_axis_description">Invert the vertical axis</string>
|
<string name="preference_gyro_invert_y_axis_description">Invert the vertical axis</string>
|
||||||
|
<string name="preference_gyro_smoothing_title">Enable gyro smoothing</string>
|
||||||
|
<string name="preference_gyro_smoothing_description">Reduce jitter in exchange of latency.</string>
|
||||||
|
|
||||||
<string name="preference_back_title">Back to the last screen</string>
|
<string name="preference_back_title">Back to the last screen</string>
|
||||||
<string name="gles_hack_none">Don\'t shrink textures</string>
|
<string name="gles_hack_none">Don\'t shrink textures</string>
|
||||||
@ -367,12 +369,15 @@
|
|||||||
<string name="global_save_and_exit">Save and exit</string>
|
<string name="global_save_and_exit">Save and exit</string>
|
||||||
<string name="global_yes">Yes</string>
|
<string name="global_yes">Yes</string>
|
||||||
<string name="global_no">No</string>
|
<string name="global_no">No</string>
|
||||||
|
|
||||||
<string name="preference_controller_map_wiped">The controller config has been wiped</string>
|
<string name="preference_controller_map_wiped">The controller config has been wiped</string>
|
||||||
<string name="preference_category_controller_settings">Controller settings</string>
|
<string name="preference_category_controller_settings">Controller settings</string>
|
||||||
<string name="preference_wipe_controller_title">Reset controller mapping</string>
|
<string name="preference_wipe_controller_title">Reset controller mapping</string>
|
||||||
<string name="preference_wipe_controller_description">Allow you to remap the controller buttons</string>
|
<string name="preference_wipe_controller_description">Allow you to remap the controller buttons</string>
|
||||||
<string name="preference_deadzone_scale_title">Joystick deadzone scale</string>
|
<string name="preference_deadzone_scale_title">Joystick deadzone scale</string>
|
||||||
<string name="preference_deadzone_scale_description">Increase it if the joystick drifts</string>
|
<string name="preference_deadzone_scale_description">Increase it if the joystick drifts</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="preference_force_big_core_title">Force renderer to run on the big core</string>
|
<string name="preference_force_big_core_title">Force renderer to run on the big core</string>
|
||||||
<string name="preference_force_big_core_desc">Forces the Minecraft render thread to run on the core with the highest max frequency</string>
|
<string name="preference_force_big_core_desc">Forces the Minecraft render thread to run on the core with the highest max frequency</string>
|
||||||
<string name="version_select_hint">Select a version</string>
|
<string name="version_select_hint">Select a version</string>
|
||||||
@ -395,4 +400,10 @@
|
|||||||
<string name="of_dl_failed_to_scrape">Failed to collect data for OptiFine installation</string>
|
<string name="of_dl_failed_to_scrape">Failed to collect data for OptiFine installation</string>
|
||||||
<string name="of_dl_progress">Downloading %s</string>
|
<string name="of_dl_progress">Downloading %s</string>
|
||||||
<string name="create_profile_optifine">Create OptiFine profile</string>
|
<string name="create_profile_optifine">Create OptiFine profile</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="preference_gyro_damper_window_title">Smoothing time</string>
|
||||||
|
<string name="preference_gyro_damper_window_description">Reduce jitter in exchange of latency. 0 to disable it</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -112,6 +112,12 @@
|
|||||||
android:summary="@string/preference_gyro_sample_rate_description"
|
android:summary="@string/preference_gyro_sample_rate_description"
|
||||||
app2:selectable="false"
|
app2:selectable="false"
|
||||||
app2:showSeekBarValue="true"/>
|
app2:showSeekBarValue="true"/>
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="gyroSmoothing"
|
||||||
|
android:title="@string/preference_gyro_smoothing_title"
|
||||||
|
android:summary="@string/preference_gyro_smoothing_description"
|
||||||
|
android:defaultValue="true"
|
||||||
|
/>
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="gyroInvertX"
|
android:key="gyroInvertX"
|
||||||
android:title="@string/preference_gyro_invert_x_axis"
|
android:title="@string/preference_gyro_invert_x_axis"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user