mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-13 06:39:54 -04:00
Feat[V 2.Gamepad]: Merge #4179
* Feat: gamepad remapping, with custom deazone * Fix[gamepad]: wrong starting pointer offset * cleanup[gamepad]: Remove useless variables * Fix[gamepad]: Reduce jitter Turns out the argument was a bit off when there are cpu constraints * Chore: bump up remapper library version * Build: bump up library version
This commit is contained in:
parent
7916166795
commit
809f5cd6e5
@ -157,6 +157,7 @@ dependencies {
|
|||||||
implementation 'com.github.PojavLauncherTeam:portrait-sdp:ed33e89cbc'
|
implementation 'com.github.PojavLauncherTeam:portrait-sdp:ed33e89cbc'
|
||||||
implementation 'com.github.PojavLauncherTeam:portrait-ssp:6c02fd739b'
|
implementation 'com.github.PojavLauncherTeam:portrait-ssp:6c02fd739b'
|
||||||
implementation 'com.github.Mathias-Boulay:ExtendedView:1.0.0'
|
implementation 'com.github.Mathias-Boulay:ExtendedView:1.0.0'
|
||||||
|
implementation 'com.github.Mathias-Boulay:android_gamepad_remapper:71397676b5'
|
||||||
|
|
||||||
|
|
||||||
// implementation 'com.intuit.sdp:sdp-android:1.0.5'
|
// implementation 'com.intuit.sdp:sdp-android:1.0.5'
|
||||||
|
@ -39,12 +39,32 @@ import net.kdt.pojavlaunch.utils.MathUtils;
|
|||||||
|
|
||||||
import org.lwjgl.glfw.CallbackBridge;
|
import org.lwjgl.glfw.CallbackBridge;
|
||||||
|
|
||||||
|
import fr.spse.gamepad_remapper.RemapperManager;
|
||||||
|
import fr.spse.gamepad_remapper.RemapperView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
|
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
|
||||||
*/
|
*/
|
||||||
public class MinecraftGLSurface extends View implements GrabListener{
|
public class MinecraftGLSurface extends View implements GrabListener {
|
||||||
/* Gamepad object for gamepad inputs, instantiated on need */
|
/* Gamepad object for gamepad inputs, instantiated on need */
|
||||||
private Gamepad mGamepad = null;
|
private Gamepad mGamepad = null;
|
||||||
|
/* The RemapperView.Builder object allows you to set which buttons to remap */
|
||||||
|
private final RemapperManager mInputManager = new RemapperManager(getContext(), new RemapperView.Builder(null)
|
||||||
|
.remapA(true)
|
||||||
|
.remapB(true)
|
||||||
|
.remapX(true)
|
||||||
|
.remapY(true)
|
||||||
|
|
||||||
|
.remapDpad(true)
|
||||||
|
.remapLeftJoystick(true)
|
||||||
|
.remapRightJoystick(true)
|
||||||
|
.remapStart(true)
|
||||||
|
.remapSelect(true)
|
||||||
|
.remapLeftShoulder(true)
|
||||||
|
.remapRightShoulder(true)
|
||||||
|
.remapLeftTrigger(true)
|
||||||
|
.remapRightTrigger(true));
|
||||||
|
|
||||||
/* Resolution scaler option, allow downsizing a window */
|
/* Resolution scaler option, allow downsizing a window */
|
||||||
private final float mScaleFactor = LauncherPreferences.PREF_SCALE_FACTOR/100f;
|
private final float mScaleFactor = LauncherPreferences.PREF_SCALE_FACTOR/100f;
|
||||||
/* Sensitivity, adjusted according to screen size */
|
/* Sensitivity, adjusted according to screen size */
|
||||||
@ -385,7 +405,7 @@ public class MinecraftGLSurface extends View implements GrabListener{
|
|||||||
mGamepad = new Gamepad(this, event.getDevice());
|
mGamepad = new Gamepad(this, event.getDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
mGamepad.update(event);
|
mInputManager.handleMotionEventInput(getContext(), event, mGamepad);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +499,7 @@ public class MinecraftGLSurface extends View implements GrabListener{
|
|||||||
mGamepad = new Gamepad(this, event.getDevice());
|
mGamepad = new Gamepad(this, event.getDevice());
|
||||||
}
|
}
|
||||||
|
|
||||||
mGamepad.update(event);
|
mInputManager.handleKeyEventInput(getContext(), event, mGamepad);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
||||||
|
|
||||||
|
|
||||||
|
import static android.view.MotionEvent.AXIS_HAT_X;
|
||||||
|
import static android.view.MotionEvent.AXIS_HAT_Y;
|
||||||
|
import static android.view.MotionEvent.AXIS_LTRIGGER;
|
||||||
|
import static android.view.MotionEvent.AXIS_RTRIGGER;
|
||||||
|
import static android.view.MotionEvent.AXIS_RZ;
|
||||||
|
import static android.view.MotionEvent.AXIS_X;
|
||||||
|
import static android.view.MotionEvent.AXIS_Y;
|
||||||
|
import static android.view.MotionEvent.AXIS_Z;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
@ -38,19 +47,18 @@ import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
|
|||||||
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||||
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
|
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
|
||||||
|
|
||||||
public class Gamepad implements GrabListener {
|
import fr.spse.gamepad_remapper.GamepadHandler;
|
||||||
|
|
||||||
|
public class Gamepad implements GrabListener, GamepadHandler {
|
||||||
|
|
||||||
/* Resolution scaler option, allow downsizing a window */
|
/* Resolution scaler option, allow downsizing a window */
|
||||||
private final float mScaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
private final float mScaleFactor = LauncherPreferences.DEFAULT_PREF.getInt("resolutionRatio",100)/100f;
|
||||||
/* Mouse positions, scaled by the scaleFactor */
|
|
||||||
private float mMouse_x, mMouse_y;
|
|
||||||
/* Sensitivity, adjusted according to screen size */
|
/* Sensitivity, adjusted according to screen size */
|
||||||
private final double mSensitivityFactor = (1.4 * (1080f/ currentDisplayMetrics.heightPixels));
|
private final double mSensitivityFactor = (1.4 * (1080f/ currentDisplayMetrics.heightPixels));
|
||||||
|
|
||||||
private final ImageView mPointerImageView;
|
private final ImageView mPointerImageView;
|
||||||
|
|
||||||
private final GamepadDpad mGamepadDpad = new GamepadDpad();
|
|
||||||
|
|
||||||
private final GamepadJoystick mLeftJoystick;
|
private final GamepadJoystick mLeftJoystick;
|
||||||
private int mCurrentJoystickDirection = DIRECTION_NONE;
|
private int mCurrentJoystickDirection = DIRECTION_NONE;
|
||||||
|
|
||||||
@ -70,9 +78,7 @@ public class Gamepad implements GrabListener {
|
|||||||
|
|
||||||
// The negation is to force trigger the onGrabState
|
// The negation is to force trigger the onGrabState
|
||||||
private boolean isGrabbing = !CallbackBridge.isGrabbing();
|
private boolean isGrabbing = !CallbackBridge.isGrabbing();
|
||||||
//private final boolean mModifierDigitalTriggers;
|
|
||||||
private final boolean mModifierAnalogTriggers;
|
|
||||||
private boolean mModifierSwappedAxis = true; //Triggers and right stick axis are swapped.
|
|
||||||
|
|
||||||
/* Choreographer with time to compute delta on ticking */
|
/* Choreographer with time to compute delta on ticking */
|
||||||
private final Choreographer mScreenChoreographer;
|
private final Choreographer mScreenChoreographer;
|
||||||
@ -97,25 +103,9 @@ public class Gamepad implements GrabListener {
|
|||||||
/* Add the listener for the cross hair */
|
/* Add the listener for the cross hair */
|
||||||
MCOptionUtils.addMCOptionListener(mGuiScaleListener);
|
MCOptionUtils.addMCOptionListener(mGuiScaleListener);
|
||||||
|
|
||||||
Toast.makeText(contextView.getContext(),"GAMEPAD CREATED", Toast.LENGTH_LONG).show();
|
mLeftJoystick = new GamepadJoystick(AXIS_X, AXIS_Y, inputDevice);
|
||||||
for(InputDevice.MotionRange range : inputDevice.getMotionRanges()){
|
mRightJoystick = new GamepadJoystick(AXIS_Z, AXIS_RZ, inputDevice);
|
||||||
if(range.getAxis() == MotionEvent.AXIS_RTRIGGER
|
|
||||||
|| range.getAxis() == MotionEvent.AXIS_LTRIGGER
|
|
||||||
|| range.getAxis() == MotionEvent.AXIS_GAS
|
|
||||||
|| range.getAxis() == MotionEvent.AXIS_BRAKE){
|
|
||||||
mModifierSwappedAxis = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mLeftJoystick = new GamepadJoystick(MotionEvent.AXIS_X, MotionEvent.AXIS_Y, inputDevice);
|
|
||||||
if(!mModifierSwappedAxis)
|
|
||||||
mRightJoystick = new GamepadJoystick(MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ, inputDevice);
|
|
||||||
else
|
|
||||||
mRightJoystick = new GamepadJoystick(MotionEvent.AXIS_RX, MotionEvent.AXIS_RY, inputDevice);
|
|
||||||
|
|
||||||
//mModifierDigitalTriggers = inputDevice.hasKeys(KeyEvent.KEYCODE_BUTTON_R2)[0];
|
|
||||||
mModifierAnalogTriggers = supportAnalogTriggers(inputDevice);
|
|
||||||
|
|
||||||
Context ctx = contextView.getContext();
|
Context ctx = contextView.getContext();
|
||||||
mPointerImageView = new ImageView(contextView.getContext());
|
mPointerImageView = new ImageView(contextView.getContext());
|
||||||
@ -125,28 +115,20 @@ public class Gamepad implements GrabListener {
|
|||||||
int size = (int) ((22 * getMcScale()) / mScaleFactor);
|
int size = (int) ((22 * getMcScale()) / mScaleFactor);
|
||||||
mPointerImageView.setLayoutParams(new FrameLayout.LayoutParams(size, size));
|
mPointerImageView.setLayoutParams(new FrameLayout.LayoutParams(size, size));
|
||||||
|
|
||||||
mMouse_x = CallbackBridge.windowWidth/2f;
|
CallbackBridge.sendCursorPos(CallbackBridge.windowWidth/2f, CallbackBridge.windowHeight/2f);
|
||||||
mMouse_y = CallbackBridge.windowHeight/2f;
|
|
||||||
CallbackBridge.sendCursorPos(mMouse_x, mMouse_y);
|
|
||||||
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
|
|
||||||
|
|
||||||
((ViewGroup)contextView.getParent()).addView(mPointerImageView);
|
((ViewGroup)contextView.getParent()).addView(mPointerImageView);
|
||||||
|
|
||||||
|
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
|
||||||
|
|
||||||
CallbackBridge.addGrabListener(this);
|
CallbackBridge.addGrabListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void update(KeyEvent event){
|
|
||||||
sendButton(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update(MotionEvent event){
|
|
||||||
updateDirectionalJoystick(event);
|
|
||||||
updateMouseJoystick(event);
|
|
||||||
updateAnalogTriggers(event);
|
|
||||||
|
|
||||||
int[] dpadEvent = mGamepadDpad.convertEvent(event);
|
public void updateJoysticks(){
|
||||||
sendButton(dpadEvent[0], dpadEvent[1]);
|
updateDirectionalJoystick();
|
||||||
|
updateMouseJoystick();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyGUISizeChange(int newSize){
|
public void notifyGUISizeChange(int newSize){
|
||||||
@ -156,86 +138,6 @@ public class Gamepad implements GrabListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendButton(KeyEvent event){
|
|
||||||
sendButton(event.getKeyCode(), event.getAction());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendButton(int keycode, int action){
|
|
||||||
boolean isDown = action == KeyEvent.ACTION_DOWN;
|
|
||||||
switch (keycode){
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_A:
|
|
||||||
getCurrentMap().BUTTON_A.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_B:
|
|
||||||
getCurrentMap().BUTTON_B.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_X:
|
|
||||||
getCurrentMap().BUTTON_X.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_Y:
|
|
||||||
getCurrentMap().BUTTON_Y.update(isDown);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Shoulders
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_L1:
|
|
||||||
getCurrentMap().SHOULDER_LEFT.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_R1:
|
|
||||||
getCurrentMap().SHOULDER_RIGHT.update(isDown);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Triggers
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_L2:
|
|
||||||
if(mModifierAnalogTriggers) break;
|
|
||||||
getCurrentMap().TRIGGER_LEFT.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_R2:
|
|
||||||
if(mModifierAnalogTriggers) break;
|
|
||||||
getCurrentMap().TRIGGER_RIGHT.update(isDown);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//L3 || R3
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_THUMBL:
|
|
||||||
getCurrentMap().THUMBSTICK_LEFT.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_THUMBR:
|
|
||||||
getCurrentMap().THUMBSTICK_RIGHT.update(isDown);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//DPAD
|
|
||||||
case KeyEvent.KEYCODE_DPAD_UP:
|
|
||||||
getCurrentMap().DPAD_UP.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_DPAD_DOWN:
|
|
||||||
getCurrentMap().DPAD_DOWN.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_DPAD_LEFT:
|
|
||||||
getCurrentMap().DPAD_LEFT.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
|
||||||
getCurrentMap().DPAD_RIGHT.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_DPAD_CENTER:
|
|
||||||
getCurrentMap().DPAD_RIGHT.update(false);
|
|
||||||
getCurrentMap().DPAD_LEFT.update(false);
|
|
||||||
getCurrentMap().DPAD_UP.update(false);
|
|
||||||
getCurrentMap().DPAD_DOWN.update(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Start/select
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_START:
|
|
||||||
getCurrentMap().BUTTON_START.update(isDown);
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_BUTTON_SELECT:
|
|
||||||
getCurrentMap().BUTTON_SELECT.update(isDown);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
|
||||||
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_SPACE, CallbackBridge.getCurrentMods(), isDown);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendInput(int[] keycodes, boolean isDown){
|
public static void sendInput(int[] keycodes, boolean isDown){
|
||||||
for(int keycode : keycodes){
|
for(int keycode : keycodes){
|
||||||
@ -281,6 +183,7 @@ public class Gamepad implements GrabListener {
|
|||||||
*/
|
*/
|
||||||
private void tick(long frameTimeNanos){
|
private void tick(long frameTimeNanos){
|
||||||
//update mouse position
|
//update mouse position
|
||||||
|
long newFrameTime = System.nanoTime();
|
||||||
if(mLastHorizontalValue != 0 || mLastVerticalValue != 0){
|
if(mLastHorizontalValue != 0 || mLastVerticalValue != 0){
|
||||||
GamepadJoystick currentJoystick = isGrabbing ? mLeftJoystick : mRightJoystick;
|
GamepadJoystick currentJoystick = isGrabbing ? mLeftJoystick : mRightJoystick;
|
||||||
|
|
||||||
@ -291,7 +194,8 @@ public class Gamepad implements GrabListener {
|
|||||||
// Compute delta since last tick time
|
// Compute delta since last tick time
|
||||||
float deltaX = (float) (Math.cos(mMouseAngle) * acceleration * mMouseSensitivity);
|
float deltaX = (float) (Math.cos(mMouseAngle) * acceleration * mMouseSensitivity);
|
||||||
float deltaY = (float) (Math.sin(mMouseAngle) * acceleration * mMouseSensitivity);
|
float deltaY = (float) (Math.sin(mMouseAngle) * acceleration * mMouseSensitivity);
|
||||||
float deltaTimeScale = ((frameTimeNanos - mLastFrameTime) / 16666666f); // Scale of 1 = 60Hz
|
newFrameTime = System.nanoTime(); // More accurate delta
|
||||||
|
float deltaTimeScale = ((newFrameTime - mLastFrameTime) / 16666666f); // Scale of 1 = 60Hz
|
||||||
deltaX *= deltaTimeScale;
|
deltaX *= deltaTimeScale;
|
||||||
deltaY *= deltaTimeScale;
|
deltaY *= deltaTimeScale;
|
||||||
|
|
||||||
@ -304,27 +208,24 @@ public class Gamepad implements GrabListener {
|
|||||||
placePointerView((int) (CallbackBridge.mouseX / mScaleFactor), (int) (CallbackBridge.mouseY/ mScaleFactor));
|
placePointerView((int) (CallbackBridge.mouseX / mScaleFactor), (int) (CallbackBridge.mouseY/ mScaleFactor));
|
||||||
}
|
}
|
||||||
|
|
||||||
mMouse_x = CallbackBridge.mouseX;
|
|
||||||
mMouse_y = CallbackBridge.mouseY;
|
|
||||||
|
|
||||||
//Send the mouse to the game
|
//Send the mouse to the game
|
||||||
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update last nano time
|
// Update last nano time
|
||||||
mLastFrameTime = frameTimeNanos;
|
mLastFrameTime = newFrameTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMouseJoystick(MotionEvent event){
|
private void updateMouseJoystick(){
|
||||||
GamepadJoystick currentJoystick = isGrabbing ? mRightJoystick : mLeftJoystick;
|
GamepadJoystick currentJoystick = isGrabbing ? mRightJoystick : mLeftJoystick;
|
||||||
float horizontalValue = currentJoystick.getHorizontalAxis(event);
|
float horizontalValue = currentJoystick.getHorizontalAxis();
|
||||||
float verticalValue = currentJoystick.getVerticalAxis(event);
|
float verticalValue = currentJoystick.getVerticalAxis();
|
||||||
if(horizontalValue != mLastHorizontalValue || verticalValue != mLastVerticalValue){
|
if(horizontalValue != mLastHorizontalValue || verticalValue != mLastVerticalValue){
|
||||||
mLastHorizontalValue = horizontalValue;
|
mLastHorizontalValue = horizontalValue;
|
||||||
mLastVerticalValue = verticalValue;
|
mLastVerticalValue = verticalValue;
|
||||||
|
|
||||||
mMouseMagnitude = currentJoystick.getMagnitude(event);
|
mMouseMagnitude = currentJoystick.getMagnitude();
|
||||||
mMouseAngle = currentJoystick.getAngleRadian(event);
|
mMouseAngle = currentJoystick.getAngleRadian();
|
||||||
|
|
||||||
tick(System.nanoTime());
|
tick(System.nanoTime());
|
||||||
return;
|
return;
|
||||||
@ -332,16 +233,16 @@ public class Gamepad implements GrabListener {
|
|||||||
mLastHorizontalValue = horizontalValue;
|
mLastHorizontalValue = horizontalValue;
|
||||||
mLastVerticalValue = verticalValue;
|
mLastVerticalValue = verticalValue;
|
||||||
|
|
||||||
mMouseMagnitude = currentJoystick.getMagnitude(event);
|
mMouseMagnitude = currentJoystick.getMagnitude();
|
||||||
mMouseAngle = currentJoystick.getAngleRadian(event);
|
mMouseAngle = currentJoystick.getAngleRadian();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDirectionalJoystick(MotionEvent event){
|
private void updateDirectionalJoystick(){
|
||||||
GamepadJoystick currentJoystick = isGrabbing ? mLeftJoystick : mRightJoystick;
|
GamepadJoystick currentJoystick = isGrabbing ? mLeftJoystick : mRightJoystick;
|
||||||
|
|
||||||
int lastJoystickDirection = mCurrentJoystickDirection;
|
int lastJoystickDirection = mCurrentJoystickDirection;
|
||||||
mCurrentJoystickDirection = currentJoystick.getHeightDirection(event);
|
mCurrentJoystickDirection = currentJoystick.getHeightDirection();
|
||||||
|
|
||||||
if(mCurrentJoystickDirection == lastJoystickDirection) return;
|
if(mCurrentJoystickDirection == lastJoystickDirection) return;
|
||||||
|
|
||||||
@ -349,37 +250,6 @@ public class Gamepad implements GrabListener {
|
|||||||
sendDirectionalKeycode(mCurrentJoystickDirection, true, getCurrentMap());
|
sendDirectionalKeycode(mCurrentJoystickDirection, true, getCurrentMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAnalogTriggers(MotionEvent event){
|
|
||||||
if(mModifierAnalogTriggers){
|
|
||||||
getCurrentMap().TRIGGER_LEFT.update(
|
|
||||||
(event.getAxisValue(MotionEvent.AXIS_LTRIGGER) > 0.5)
|
|
||||||
|| (event.getAxisValue(MotionEvent.AXIS_BRAKE) > 0.5)
|
|
||||||
|| (mModifierSwappedAxis &&(event.getAxisValue(MotionEvent.AXIS_Z) > 0.5)) );
|
|
||||||
getCurrentMap().TRIGGER_RIGHT.update(
|
|
||||||
(event.getAxisValue( MotionEvent.AXIS_RTRIGGER) > 0.5)
|
|
||||||
|| (event.getAxisValue(MotionEvent.AXIS_GAS) > 0.5)
|
|
||||||
|| (mModifierSwappedAxis && event.getAxisValue(MotionEvent.AXIS_RZ) > 0.5) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect if a gamepad supports analog triggers
|
|
||||||
* @param inputDevice The input device with all the MotionRange
|
|
||||||
* @return Whether the gamepad supports analog triggers
|
|
||||||
*/
|
|
||||||
private boolean supportAnalogTriggers(InputDevice inputDevice){
|
|
||||||
for(InputDevice.MotionRange motionRange : inputDevice.getMotionRanges()){
|
|
||||||
int axis = motionRange.getAxis();
|
|
||||||
|
|
||||||
if( axis == MotionEvent.AXIS_BRAKE || axis == MotionEvent.AXIS_GAS ||
|
|
||||||
axis == MotionEvent.AXIS_LTRIGGER || axis == MotionEvent.AXIS_RTRIGGER ||
|
|
||||||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_Z) ||
|
|
||||||
(mModifierSwappedAxis && axis == MotionEvent.AXIS_RZ)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private GamepadMap getCurrentMap(){
|
private GamepadMap getCurrentMap(){
|
||||||
return mCurrentMap;
|
return mCurrentMap;
|
||||||
@ -418,6 +288,7 @@ public class Gamepad implements GrabListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Place the pointer on the screen, offsetting the image size */
|
||||||
private void placePointerView(int x, int y){
|
private void placePointerView(int x, int y){
|
||||||
mPointerImageView.setX(x - mPointerImageView.getWidth()/2f);
|
mPointerImageView.setX(x - mPointerImageView.getWidth()/2f);
|
||||||
mPointerImageView.setY(y - mPointerImageView.getHeight()/2f);
|
mPointerImageView.setY(y - mPointerImageView.getHeight()/2f);
|
||||||
@ -442,12 +313,123 @@ public class Gamepad implements GrabListener {
|
|||||||
mCurrentMap = mMenuMap;
|
mCurrentMap = mMenuMap;
|
||||||
sendDirectionalKeycode(mCurrentJoystickDirection, false, mGameMap); // removing what we were doing
|
sendDirectionalKeycode(mCurrentJoystickDirection, false, mGameMap); // removing what we were doing
|
||||||
|
|
||||||
mMouse_x = CallbackBridge.windowWidth/2f;
|
CallbackBridge.sendCursorPos(CallbackBridge.windowWidth/2f, CallbackBridge.windowHeight/2f);
|
||||||
mMouse_y = CallbackBridge.windowHeight/2f;
|
|
||||||
CallbackBridge.sendCursorPos(mMouse_x, mMouse_y);
|
|
||||||
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
|
placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2);
|
||||||
mPointerImageView.setVisibility(View.VISIBLE);
|
mPointerImageView.setVisibility(View.VISIBLE);
|
||||||
// Sensitivity in menu is MC and HARDWARE resolution dependent
|
// Sensitivity in menu is MC and HARDWARE resolution dependent
|
||||||
mMouseSensitivity = 19 * mScaleFactor / mSensitivityFactor;
|
mMouseSensitivity = 19 * mScaleFactor / mSensitivityFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleGamepadInput(int keycode, float value) {
|
||||||
|
boolean isKeyEventDown = value == 1f;
|
||||||
|
switch (keycode){
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_A:
|
||||||
|
getCurrentMap().BUTTON_A.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_B:
|
||||||
|
getCurrentMap().BUTTON_B.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_X:
|
||||||
|
getCurrentMap().BUTTON_X.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_Y:
|
||||||
|
getCurrentMap().BUTTON_Y.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Shoulders
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_L1:
|
||||||
|
getCurrentMap().SHOULDER_LEFT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_R1:
|
||||||
|
getCurrentMap().SHOULDER_RIGHT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Triggers
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_L2:
|
||||||
|
getCurrentMap().TRIGGER_LEFT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_R2:
|
||||||
|
getCurrentMap().TRIGGER_RIGHT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//L3 || R3
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_THUMBL:
|
||||||
|
getCurrentMap().THUMBSTICK_LEFT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_THUMBR:
|
||||||
|
getCurrentMap().THUMBSTICK_RIGHT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//DPAD
|
||||||
|
case KeyEvent.KEYCODE_DPAD_UP:
|
||||||
|
getCurrentMap().DPAD_UP.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_DPAD_DOWN:
|
||||||
|
getCurrentMap().DPAD_DOWN.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_DPAD_LEFT:
|
||||||
|
getCurrentMap().DPAD_LEFT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_DPAD_RIGHT:
|
||||||
|
getCurrentMap().DPAD_RIGHT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||||
|
getCurrentMap().DPAD_RIGHT.update(false);
|
||||||
|
getCurrentMap().DPAD_LEFT.update(false);
|
||||||
|
getCurrentMap().DPAD_UP.update(false);
|
||||||
|
getCurrentMap().DPAD_DOWN.update(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Start/select
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_START:
|
||||||
|
getCurrentMap().BUTTON_START.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
case KeyEvent.KEYCODE_BUTTON_SELECT:
|
||||||
|
getCurrentMap().BUTTON_SELECT.update(isKeyEventDown);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Now, it is time for motionEvents */
|
||||||
|
case AXIS_HAT_X:
|
||||||
|
getCurrentMap().DPAD_RIGHT.update(value > 0.85);
|
||||||
|
getCurrentMap().DPAD_LEFT.update(value < -0.85);
|
||||||
|
break;
|
||||||
|
case AXIS_HAT_Y:
|
||||||
|
getCurrentMap().DPAD_DOWN.update(value > 0.85);
|
||||||
|
getCurrentMap().DPAD_UP.update(value < -0.85);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Left joystick
|
||||||
|
case AXIS_X:
|
||||||
|
mLeftJoystick.setXAxisValue(value);
|
||||||
|
updateJoysticks();
|
||||||
|
break;
|
||||||
|
case AXIS_Y:
|
||||||
|
mLeftJoystick.setYAxisValue(value);
|
||||||
|
updateJoysticks();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Right joystick
|
||||||
|
case AXIS_Z:
|
||||||
|
mRightJoystick.setXAxisValue(value);
|
||||||
|
updateJoysticks();
|
||||||
|
break;
|
||||||
|
case AXIS_RZ:
|
||||||
|
mRightJoystick.setYAxisValue(value);
|
||||||
|
updateJoysticks();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Triggers
|
||||||
|
case AXIS_RTRIGGER:
|
||||||
|
getCurrentMap().TRIGGER_RIGHT.update(value > 0.5);
|
||||||
|
break;
|
||||||
|
case AXIS_LTRIGGER:
|
||||||
|
getCurrentMap().TRIGGER_LEFT.update(value > 0.5);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
sendKeyPress(LwjglGlfwKeycode.GLFW_KEY_SPACE, CallbackBridge.getCurrentMods(), isKeyEventDown);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
||||||
|
|
||||||
|
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_DEADZONE_SCALE;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
@ -21,42 +24,46 @@ public class GamepadJoystick {
|
|||||||
public static final int DIRECTION_SOUTH_EAST = 7;
|
public static final int DIRECTION_SOUTH_EAST = 7;
|
||||||
|
|
||||||
private final InputDevice mInputDevice;
|
private final InputDevice mInputDevice;
|
||||||
private final int mVerticalAxis;
|
|
||||||
private final int mHorizontalAxis;
|
private final int mHorizontalAxis;
|
||||||
|
private final int mVerticalAxis;
|
||||||
|
private float mVerticalAxisValue = 0;
|
||||||
|
private float mHorizontalAxisValue = 0;
|
||||||
|
|
||||||
public GamepadJoystick(int horizontalAxis, int verticalAxis, InputDevice device){
|
public GamepadJoystick(int horizontalAxis, int verticalAxis, InputDevice device){
|
||||||
this.mVerticalAxis = verticalAxis;
|
mHorizontalAxis = horizontalAxis;
|
||||||
this.mHorizontalAxis = horizontalAxis;
|
mVerticalAxis = verticalAxis;
|
||||||
this.mInputDevice = device;
|
this.mInputDevice = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getAngleRadian(MotionEvent event){
|
public double getAngleRadian(){
|
||||||
//From -PI to PI
|
//From -PI to PI
|
||||||
return -Math.atan2(getVerticalAxis(event), getHorizontalAxis(event));
|
// TODO misuse of the deadzone here !
|
||||||
|
return -Math.atan2(getVerticalAxis(), getHorizontalAxis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public double getAngleDegree(MotionEvent event){
|
public double getAngleDegree(){
|
||||||
//From 0 to 360 degrees
|
//From 0 to 360 degrees
|
||||||
double result = Math.toDegrees(getAngleRadian(event));
|
double result = Math.toDegrees(getAngleRadian());
|
||||||
if(result < 0) result += 360;
|
if(result < 0) result += 360;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getMagnitude(MotionEvent event){
|
public double getMagnitude(){
|
||||||
float x = Math.abs(event.getAxisValue(mHorizontalAxis));
|
float x = Math.abs(mHorizontalAxisValue);
|
||||||
float y = Math.abs(event.getAxisValue(mVerticalAxis));
|
float y = Math.abs(mVerticalAxisValue);
|
||||||
|
|
||||||
return MathUtils.dist(0,0, x, y);
|
return MathUtils.dist(0,0, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getVerticalAxis(MotionEvent event){
|
public float getVerticalAxis(){
|
||||||
return applyDeadzone(event, mVerticalAxis);
|
return applyDeadzone(mVerticalAxisValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getHorizontalAxis(MotionEvent event){
|
public float getHorizontalAxis(){
|
||||||
return applyDeadzone(event, mHorizontalAxis);
|
return applyDeadzone(mHorizontalAxisValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isJoystickEvent(MotionEvent event){
|
public static boolean isJoystickEvent(MotionEvent event){
|
||||||
@ -65,9 +72,9 @@ public class GamepadJoystick {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getHeightDirection(MotionEvent event){
|
public int getHeightDirection(){
|
||||||
if(getMagnitude(event) <= getDeadzone()) return DIRECTION_NONE;
|
if(getMagnitude() <= getDeadzone()) return DIRECTION_NONE;
|
||||||
return ((int) ((getAngleDegree(event)+22.5)/45)) % 8;
|
return ((int) ((getAngleDegree()+22.5)/45)) % 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,20 +84,31 @@ public class GamepadJoystick {
|
|||||||
*/
|
*/
|
||||||
public float getDeadzone() {
|
public float getDeadzone() {
|
||||||
try{
|
try{
|
||||||
return Math.max(mInputDevice.getMotionRange(mHorizontalAxis).getFlat() * 1.9f, 0.2f);
|
return mInputDevice.getMotionRange(mHorizontalAxis).getFlat() * PREF_DEADZONE_SCALE;
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
|
Log.e(GamepadJoystick.class.toString(), "Dynamic Deadzone is not supported ");
|
||||||
return 0.2f;
|
return 0.2f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float applyDeadzone(MotionEvent event, int axis){
|
private float applyDeadzone(float value){
|
||||||
//This piece of code also modifies the value
|
//This piece of code also modifies the value
|
||||||
//to make it seem like there was no deadzone in the first place
|
//to make it seem like there was no deadzone in the first place
|
||||||
|
|
||||||
double magnitude = getMagnitude(event);
|
double magnitude = getMagnitude();
|
||||||
float deadzone = getDeadzone();
|
float deadzone = getDeadzone();
|
||||||
if (magnitude < deadzone) return 0;
|
if (magnitude < deadzone) return 0;
|
||||||
|
|
||||||
return (float) ( (event.getAxisValue(axis) / magnitude) * ((magnitude - deadzone) / (1 - deadzone)) );
|
return (float) ( (value / magnitude) * ((magnitude - deadzone) / (1 - deadzone)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Setters */
|
||||||
|
public void setXAxisValue(float value){
|
||||||
|
this.mHorizontalAxisValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYAxisValue(float value){
|
||||||
|
this.mVerticalAxisValue = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.kdt.pojavlaunch.prefs;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
|
import net.kdt.pojavlaunch.R;
|
||||||
|
|
||||||
|
import fr.spse.gamepad_remapper.Remapper;
|
||||||
|
|
||||||
|
public class GamepadRemapPreference extends Preference {
|
||||||
|
|
||||||
|
public GamepadRemapPreference(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadRemapPreference(@NonNull Context context) {
|
||||||
|
super(context);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(){
|
||||||
|
setOnPreferenceClickListener(preference -> {
|
||||||
|
Remapper.wipePreferences(getContext());
|
||||||
|
Toast.makeText(getContext(), R.string.preference_controller_map_wiped, Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,7 @@ public class LauncherPreferences {
|
|||||||
|
|
||||||
public static boolean PREF_BUTTON_ALL_CAPS = true;
|
public static boolean PREF_BUTTON_ALL_CAPS = true;
|
||||||
public static boolean PREF_DUMP_SHADERS = false;
|
public static boolean PREF_DUMP_SHADERS = false;
|
||||||
|
public static float PREF_DEADZONE_SCALE = 1f;
|
||||||
|
|
||||||
|
|
||||||
public static void loadPreferences(Context ctx) {
|
public static void loadPreferences(Context ctx) {
|
||||||
@ -96,6 +97,7 @@ public class LauncherPreferences {
|
|||||||
PREF_FORCE_VSYNC = DEFAULT_PREF.getBoolean("force_vsync", false);
|
PREF_FORCE_VSYNC = DEFAULT_PREF.getBoolean("force_vsync", false);
|
||||||
PREF_BUTTON_ALL_CAPS = DEFAULT_PREF.getBoolean("buttonAllCaps", true);
|
PREF_BUTTON_ALL_CAPS = DEFAULT_PREF.getBoolean("buttonAllCaps", true);
|
||||||
PREF_DUMP_SHADERS = DEFAULT_PREF.getBoolean("dump_shaders", false);
|
PREF_DUMP_SHADERS = DEFAULT_PREF.getBoolean("dump_shaders", false);
|
||||||
|
PREF_DEADZONE_SCALE = DEFAULT_PREF.getInt("gamepad_deadzone_scale", 100)/100f;
|
||||||
|
|
||||||
String argLwjglLibname = "-Dorg.lwjgl.opengl.libname=";
|
String argLwjglLibname = "-Dorg.lwjgl.opengl.libname=";
|
||||||
for (String arg : JREUtils.parseJavaArguments(PREF_CUSTOM_JAVA_ARGS)) {
|
for (String arg : JREUtils.parseJavaArguments(PREF_CUSTOM_JAVA_ARGS)) {
|
||||||
|
@ -23,6 +23,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
|
|||||||
int gyroSampleRate = LauncherPreferences.PREF_GYRO_SAMPLE_RATE;
|
int gyroSampleRate = LauncherPreferences.PREF_GYRO_SAMPLE_RATE;
|
||||||
float mouseSpeed = LauncherPreferences.PREF_MOUSESPEED;
|
float mouseSpeed = LauncherPreferences.PREF_MOUSESPEED;
|
||||||
float gyroSpeed = LauncherPreferences.PREF_GYRO_SENSITIVITY;
|
float gyroSpeed = LauncherPreferences.PREF_GYRO_SENSITIVITY;
|
||||||
|
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);
|
||||||
@ -47,6 +48,11 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen
|
|||||||
seek6.setValue((int)(mouseSpeed *100f));
|
seek6.setValue((int)(mouseSpeed *100f));
|
||||||
seek6.setSuffix(" %");
|
seek6.setSuffix(" %");
|
||||||
|
|
||||||
|
CustomSeekBarPreference deadzoneSeek = findPreference("gamepad_deadzone_scale");
|
||||||
|
deadzoneSeek.setRange(50, 200);
|
||||||
|
deadzoneSeek.setValue((int) joystickDeadzone * 100);
|
||||||
|
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;
|
||||||
|
@ -364,4 +364,10 @@
|
|||||||
<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_category_controller_settings">Controller settings</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_deadzone_scale_title">Joystick deadzone scale</string>
|
||||||
|
<string name="preference_deadzone_scale_description">Increase it if the joystick drifts</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -123,6 +123,22 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="@string/preference_category_controller_settings"
|
||||||
|
>
|
||||||
|
<net.kdt.pojavlaunch.prefs.GamepadRemapPreference
|
||||||
|
android:title="@string/preference_wipe_controller_title"
|
||||||
|
android:summary="@string/preference_wipe_controller_description"
|
||||||
|
/>
|
||||||
|
<net.kdt.pojavlaunch.prefs.CustomSeekBarPreference
|
||||||
|
android:key="gamepad_deadzone_scale"
|
||||||
|
android:title="@string/preference_deadzone_scale_title"
|
||||||
|
android:summary="@string/preference_deadzone_scale_description"
|
||||||
|
app2:showSeekBarValue="true"
|
||||||
|
app2:seekBarIncrement="5"
|
||||||
|
/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user