From 809f5cd6e53d055f3b30cb4c9b42cdfb33238a07 Mon Sep 17 00:00:00 2001 From: Boulay Mathias Date: Sun, 21 May 2023 12:50:06 +0200 Subject: [PATCH] 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 --- app_pojavlauncher/build.gradle | 1 + .../kdt/pojavlaunch/MinecraftGLSurface.java | 26 +- .../customcontrols/gamepad/Gamepad.java | 318 +++++++++--------- .../gamepad/GamepadJoystick.java | 60 ++-- .../prefs/GamepadRemapPreference.java | 34 ++ .../prefs/LauncherPreferences.java | 2 + .../LauncherPreferenceControlFragment.java | 6 + .../src/main/res/values/strings.xml | 6 + .../src/main/res/xml/pref_control.xml | 16 + 9 files changed, 277 insertions(+), 192 deletions(-) create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/GamepadRemapPreference.java diff --git a/app_pojavlauncher/build.gradle b/app_pojavlauncher/build.gradle index fdb7a1254..4bc5ca66b 100644 --- a/app_pojavlauncher/build.gradle +++ b/app_pojavlauncher/build.gradle @@ -157,6 +157,7 @@ dependencies { implementation 'com.github.PojavLauncherTeam:portrait-sdp:ed33e89cbc' implementation 'com.github.PojavLauncherTeam:portrait-ssp:6c02fd739b' 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' diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java index 25049b921..acd65d4c7 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java @@ -39,12 +39,32 @@ import net.kdt.pojavlaunch.utils.MathUtils; 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 */ -public class MinecraftGLSurface extends View implements GrabListener{ +public class MinecraftGLSurface extends View implements GrabListener { /* Gamepad object for gamepad inputs, instantiated on need */ 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 */ private final float mScaleFactor = LauncherPreferences.PREF_SCALE_FACTOR/100f; /* Sensitivity, adjusted according to screen size */ @@ -385,7 +405,7 @@ public class MinecraftGLSurface extends View implements GrabListener{ mGamepad = new Gamepad(this, event.getDevice()); } - mGamepad.update(event); + mInputManager.handleMotionEventInput(getContext(), event, mGamepad); return true; } @@ -479,7 +499,7 @@ public class MinecraftGLSurface extends View implements GrabListener{ mGamepad = new Gamepad(this, event.getDevice()); } - mGamepad.update(event); + mInputManager.handleKeyEventInput(getContext(), event, mGamepad); return true; } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java index 13b1df213..8b7b96ea6 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/Gamepad.java @@ -1,6 +1,15 @@ 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.view.Choreographer; 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.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 */ 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 */ private final double mSensitivityFactor = (1.4 * (1080f/ currentDisplayMetrics.heightPixels)); private final ImageView mPointerImageView; - private final GamepadDpad mGamepadDpad = new GamepadDpad(); - private final GamepadJoystick mLeftJoystick; private int mCurrentJoystickDirection = DIRECTION_NONE; @@ -70,9 +78,7 @@ public class Gamepad implements GrabListener { // The negation is to force trigger the onGrabState 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 */ private final Choreographer mScreenChoreographer; @@ -97,25 +103,9 @@ public class Gamepad implements GrabListener { /* Add the listener for the cross hair */ MCOptionUtils.addMCOptionListener(mGuiScaleListener); - Toast.makeText(contextView.getContext(),"GAMEPAD CREATED", Toast.LENGTH_LONG).show(); - for(InputDevice.MotionRange range : inputDevice.getMotionRanges()){ - 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(AXIS_X, AXIS_Y, inputDevice); + mRightJoystick = new GamepadJoystick(AXIS_Z, AXIS_RZ, inputDevice); - 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(); mPointerImageView = new ImageView(contextView.getContext()); @@ -125,28 +115,20 @@ public class Gamepad implements GrabListener { int size = (int) ((22 * getMcScale()) / mScaleFactor); mPointerImageView.setLayoutParams(new FrameLayout.LayoutParams(size, size)); - mMouse_x = CallbackBridge.windowWidth/2f; - mMouse_y = CallbackBridge.windowHeight/2f; - CallbackBridge.sendCursorPos(mMouse_x, mMouse_y); - placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2); - + CallbackBridge.sendCursorPos(CallbackBridge.windowWidth/2f, CallbackBridge.windowHeight/2f); ((ViewGroup)contextView.getParent()).addView(mPointerImageView); + placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2); + 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); - sendButton(dpadEvent[0], dpadEvent[1]); + public void updateJoysticks(){ + updateDirectionalJoystick(); + updateMouseJoystick(); } 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){ for(int keycode : keycodes){ @@ -281,6 +183,7 @@ public class Gamepad implements GrabListener { */ private void tick(long frameTimeNanos){ //update mouse position + long newFrameTime = System.nanoTime(); if(mLastHorizontalValue != 0 || mLastVerticalValue != 0){ GamepadJoystick currentJoystick = isGrabbing ? mLeftJoystick : mRightJoystick; @@ -291,7 +194,8 @@ public class Gamepad implements GrabListener { // Compute delta since last tick time float deltaX = (float) (Math.cos(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; deltaY *= deltaTimeScale; @@ -304,27 +208,24 @@ public class Gamepad implements GrabListener { placePointerView((int) (CallbackBridge.mouseX / mScaleFactor), (int) (CallbackBridge.mouseY/ mScaleFactor)); } - mMouse_x = CallbackBridge.mouseX; - mMouse_y = CallbackBridge.mouseY; - //Send the mouse to the game CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY); } // Update last nano time - mLastFrameTime = frameTimeNanos; + mLastFrameTime = newFrameTime; } - private void updateMouseJoystick(MotionEvent event){ + private void updateMouseJoystick(){ GamepadJoystick currentJoystick = isGrabbing ? mRightJoystick : mLeftJoystick; - float horizontalValue = currentJoystick.getHorizontalAxis(event); - float verticalValue = currentJoystick.getVerticalAxis(event); + float horizontalValue = currentJoystick.getHorizontalAxis(); + float verticalValue = currentJoystick.getVerticalAxis(); if(horizontalValue != mLastHorizontalValue || verticalValue != mLastVerticalValue){ mLastHorizontalValue = horizontalValue; mLastVerticalValue = verticalValue; - mMouseMagnitude = currentJoystick.getMagnitude(event); - mMouseAngle = currentJoystick.getAngleRadian(event); + mMouseMagnitude = currentJoystick.getMagnitude(); + mMouseAngle = currentJoystick.getAngleRadian(); tick(System.nanoTime()); return; @@ -332,16 +233,16 @@ public class Gamepad implements GrabListener { mLastHorizontalValue = horizontalValue; mLastVerticalValue = verticalValue; - mMouseMagnitude = currentJoystick.getMagnitude(event); - mMouseAngle = currentJoystick.getAngleRadian(event); + mMouseMagnitude = currentJoystick.getMagnitude(); + mMouseAngle = currentJoystick.getAngleRadian(); } - private void updateDirectionalJoystick(MotionEvent event){ + private void updateDirectionalJoystick(){ GamepadJoystick currentJoystick = isGrabbing ? mLeftJoystick : mRightJoystick; int lastJoystickDirection = mCurrentJoystickDirection; - mCurrentJoystickDirection = currentJoystick.getHeightDirection(event); + mCurrentJoystickDirection = currentJoystick.getHeightDirection(); if(mCurrentJoystickDirection == lastJoystickDirection) return; @@ -349,37 +250,6 @@ public class Gamepad implements GrabListener { 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(){ 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){ mPointerImageView.setX(x - mPointerImageView.getWidth()/2f); mPointerImageView.setY(y - mPointerImageView.getHeight()/2f); @@ -442,12 +313,123 @@ public class Gamepad implements GrabListener { mCurrentMap = mMenuMap; sendDirectionalKeycode(mCurrentJoystickDirection, false, mGameMap); // removing what we were doing - mMouse_x = CallbackBridge.windowWidth/2f; - mMouse_y = CallbackBridge.windowHeight/2f; - CallbackBridge.sendCursorPos(mMouse_x, mMouse_y); + CallbackBridge.sendCursorPos(CallbackBridge.windowWidth/2f, CallbackBridge.windowHeight/2f); placePointerView(CallbackBridge.physicalWidth/2, CallbackBridge.physicalHeight/2); mPointerImageView.setVisibility(View.VISIBLE); // Sensitivity in menu is MC and HARDWARE resolution dependent 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; + } + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadJoystick.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadJoystick.java index b419ec5c8..8f1edc1d2 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadJoystick.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/gamepad/GamepadJoystick.java @@ -1,5 +1,8 @@ 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.MotionEvent; @@ -21,42 +24,46 @@ public class GamepadJoystick { public static final int DIRECTION_SOUTH_EAST = 7; private final InputDevice mInputDevice; - private final int mVerticalAxis; + private final int mHorizontalAxis; + private final int mVerticalAxis; + private float mVerticalAxisValue = 0; + private float mHorizontalAxisValue = 0; public GamepadJoystick(int horizontalAxis, int verticalAxis, InputDevice device){ - this.mVerticalAxis = verticalAxis; - this.mHorizontalAxis = horizontalAxis; + mHorizontalAxis = horizontalAxis; + mVerticalAxis = verticalAxis; this.mInputDevice = device; } - public double getAngleRadian(MotionEvent event){ + public double getAngleRadian(){ //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 - double result = Math.toDegrees(getAngleRadian(event)); + double result = Math.toDegrees(getAngleRadian()); if(result < 0) result += 360; return result; } - public double getMagnitude(MotionEvent event){ - float x = Math.abs(event.getAxisValue(mHorizontalAxis)); - float y = Math.abs(event.getAxisValue(mVerticalAxis)); + public double getMagnitude(){ + float x = Math.abs(mHorizontalAxisValue); + float y = Math.abs(mVerticalAxisValue); return MathUtils.dist(0,0, x, y); } - public float getVerticalAxis(MotionEvent event){ - return applyDeadzone(event, mVerticalAxis); + public float getVerticalAxis(){ + return applyDeadzone(mVerticalAxisValue); } - public float getHorizontalAxis(MotionEvent event){ - return applyDeadzone(event, mHorizontalAxis); + public float getHorizontalAxis(){ + return applyDeadzone(mHorizontalAxisValue); } public static boolean isJoystickEvent(MotionEvent event){ @@ -65,9 +72,9 @@ public class GamepadJoystick { } - public int getHeightDirection(MotionEvent event){ - if(getMagnitude(event) <= getDeadzone()) return DIRECTION_NONE; - return ((int) ((getAngleDegree(event)+22.5)/45)) % 8; + public int getHeightDirection(){ + if(getMagnitude() <= getDeadzone()) return DIRECTION_NONE; + return ((int) ((getAngleDegree()+22.5)/45)) % 8; } /** @@ -77,20 +84,31 @@ public class GamepadJoystick { */ public float getDeadzone() { try{ - return Math.max(mInputDevice.getMotionRange(mHorizontalAxis).getFlat() * 1.9f, 0.2f); + return mInputDevice.getMotionRange(mHorizontalAxis).getFlat() * PREF_DEADZONE_SCALE; }catch (Exception e){ + Log.e(GamepadJoystick.class.toString(), "Dynamic Deadzone is not supported "); return 0.2f; } } - private float applyDeadzone(MotionEvent event, int axis){ + private float applyDeadzone(float value){ //This piece of code also modifies the value //to make it seem like there was no deadzone in the first place - double magnitude = getMagnitude(event); + double magnitude = getMagnitude(); float deadzone = getDeadzone(); 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; } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/GamepadRemapPreference.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/GamepadRemapPreference.java new file mode 100644 index 000000000..d56589e4c --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/GamepadRemapPreference.java @@ -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; + }); + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java index 7176dd097..899238020 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java @@ -57,6 +57,7 @@ public class LauncherPreferences { public static boolean PREF_BUTTON_ALL_CAPS = true; public static boolean PREF_DUMP_SHADERS = false; + public static float PREF_DEADZONE_SCALE = 1f; public static void loadPreferences(Context ctx) { @@ -96,6 +97,7 @@ public class LauncherPreferences { PREF_FORCE_VSYNC = DEFAULT_PREF.getBoolean("force_vsync", false); PREF_BUTTON_ALL_CAPS = DEFAULT_PREF.getBoolean("buttonAllCaps", true); 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="; for (String arg : JREUtils.parseJavaArguments(PREF_CUSTOM_JAVA_ARGS)) { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java index 3df4919aa..ed11ec071 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceControlFragment.java @@ -23,6 +23,7 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen int gyroSampleRate = LauncherPreferences.PREF_GYRO_SAMPLE_RATE; float mouseSpeed = LauncherPreferences.PREF_MOUSESPEED; float gyroSpeed = LauncherPreferences.PREF_GYRO_SENSITIVITY; + float joystickDeadzone = LauncherPreferences.PREF_DEADZONE_SCALE; //Triggers a write for some reason which resets the value addPreferencesFromResource(R.xml.pref_control); @@ -47,6 +48,11 @@ public class LauncherPreferenceControlFragment extends LauncherPreferenceFragmen seek6.setValue((int)(mouseSpeed *100f)); seek6.setSuffix(" %"); + CustomSeekBarPreference deadzoneSeek = findPreference("gamepad_deadzone_scale"); + deadzoneSeek.setRange(50, 200); + deadzoneSeek.setValue((int) joystickDeadzone * 100); + deadzoneSeek.setSuffix(" %"); + Context context = getContext(); if(context != null) { mGyroAvailable = ((SensorManager)context.getSystemService(Context.SENSOR_SERVICE)).getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null; diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index f6114030e..7a0eb7225 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -364,4 +364,10 @@ Save and exit Yes No + The controller config has been wiped + Controller settings + Reset controller mapping + Allow you to remap the controller buttons + Joystick deadzone scale + Increase it if the joystick drifts diff --git a/app_pojavlauncher/src/main/res/xml/pref_control.xml b/app_pojavlauncher/src/main/res/xml/pref_control.xml index 273212676..73e26380d 100644 --- a/app_pojavlauncher/src/main/res/xml/pref_control.xml +++ b/app_pojavlauncher/src/main/res/xml/pref_control.xml @@ -123,6 +123,22 @@ + + + + +