From aed6c00c40564970f3c2c74d4611c257c218c9fd Mon Sep 17 00:00:00 2001 From: Mathias-Boulay Date: Mon, 15 May 2023 11:31:07 +0200 Subject: [PATCH] Feat[controls]: Input joystick --- app_pojavlauncher/build.gradle | 1 + .../pojavlaunch/CustomControlsActivity.java | 10 +- .../customcontrols/ControlLayout.java | 18 ++ .../customcontrols/CustomControls.java | 8 +- .../buttons/ControlJoystick.java | 180 ++++++++++++++++++ .../handleview/EditControlPopup.java | 2 +- .../src/main/res/values/headings_array.xml | 9 +- .../src/main/res/values/strings.xml | 1 + 8 files changed, 216 insertions(+), 13 deletions(-) create mode 100644 app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlJoystick.java diff --git a/app_pojavlauncher/build.gradle b/app_pojavlauncher/build.gradle index ab5b93bb8..457511fbd 100644 --- a/app_pojavlauncher/build.gradle +++ b/app_pojavlauncher/build.gradle @@ -187,6 +187,7 @@ dependencies { implementation 'com.github.PojavLauncherTeam:portrait-ssp:6c02fd739b' implementation 'com.github.Mathias-Boulay:ExtendedView:1.0.0' implementation 'com.github.Mathias-Boulay:android_gamepad_remapper:eb92e3a5bb' + implementation 'com.github.Mathias-Boulay:virtual-joystick-android:3832b4f94a' // implementation 'com.intuit.sdp:sdp-android:1.0.5' diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java index b8f3e5a4e..690199e5b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/CustomControlsActivity.java @@ -43,11 +43,11 @@ public class CustomControlsActivity extends BaseActivity implements EditorExitab switch(position) { case 0: mControlLayout.addControlButton(new ControlData("New")); break; case 1: mControlLayout.addDrawer(new ControlDrawerData()); break; - //case 2: mControlLayout.addJoystickButton(new ControlData()); break; - case 2: mControlLayout.openLoadDialog(); break; - case 3: mControlLayout.openSaveDialog(this); break; - case 4: mControlLayout.openSetDefaultDialog(); break; - case 5: // Saving the currently shown control + case 2: mControlLayout.addJoystickButton(new ControlData()); break; + case 3: mControlLayout.openLoadDialog(); break; + case 4: mControlLayout.openSaveDialog(this); break; + case 5: mControlLayout.openSetDefaultDialog(); break; + case 6: // Saving the currently shown control try { Uri contentUri = DocumentsContract.buildDocumentUri(getString(R.string.storageProviderAuthorities), mControlLayout.saveToDirectory(mControlLayout.mLayoutFileName)); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java index 9c5000894..3f4dd7f7b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/ControlLayout.java @@ -1,6 +1,7 @@ package net.kdt.pojavlaunch.customcontrols; import static android.content.Context.INPUT_METHOD_SERVICE; +import static net.kdt.pojavlaunch.MainActivity.mControlLayout; import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics; import android.annotation.SuppressLint; @@ -27,6 +28,7 @@ import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton; import net.kdt.pojavlaunch.customcontrols.buttons.ControlDrawer; import net.kdt.pojavlaunch.customcontrols.buttons.ControlInterface; +import net.kdt.pojavlaunch.customcontrols.buttons.ControlJoystick; import net.kdt.pojavlaunch.customcontrols.buttons.ControlSubButton; import net.kdt.pojavlaunch.customcontrols.handleview.ActionRow; import net.kdt.pojavlaunch.customcontrols.handleview.ControlHandleView; @@ -107,6 +109,12 @@ public class ControlLayout extends FrameLayout { if(mModifiable) drawer.areButtonsVisible = true; } + // Joystick(s) + for(ControlData joystick : mLayout.mJoystickDataList){ + addJoystickView(joystick); + } + + mLayout.scaledAt = LauncherPreferences.PREF_BUTTONSIZE; setModified(false); @@ -186,6 +194,16 @@ public class ControlLayout extends FrameLayout { setModified(true); } + // JOYSTICK BUTTON + public void addJoystickButton(ControlData data){ + mLayout.mJoystickDataList.add(data); + addJoystickView(data); + } + + private void addJoystickView(ControlData data){ + addView(new ControlJoystick(this, data)); + } + private void removeAllButtons() { for(ControlInterface button : getButtonChildren()){ diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java index e089be988..a27c6c85a 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/CustomControls.java @@ -13,16 +13,18 @@ public class CustomControls { public float scaledAt; public List mControlDataList; public List mDrawerDataList; + public List mJoystickDataList; public CustomControls() { - this(new ArrayList<>(), new ArrayList<>()); + this(new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); } - public CustomControls(List mControlDataList, List mDrawerDataList) { + public CustomControls(List mControlDataList, List mDrawerDataList, List mJoystickDataList) { this.mControlDataList = mControlDataList; this.mDrawerDataList = mDrawerDataList; - this.scaledAt = 100f; + this.mJoystickDataList = mJoystickDataList; + this.scaledAt = 100f; } // Generate default control diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlJoystick.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlJoystick.java new file mode 100644 index 000000000..825988025 --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/buttons/ControlJoystick.java @@ -0,0 +1,180 @@ +package net.kdt.pojavlaunch.customcontrols.buttons; + +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NONE; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_NORTH_WEST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH_EAST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_SOUTH_WEST; +import static net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick.DIRECTION_WEST; + +import android.annotation.SuppressLint; +import android.view.View; + +import net.kdt.pojavlaunch.LwjglGlfwKeycode; +import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.customcontrols.ControlData; +import net.kdt.pojavlaunch.customcontrols.ControlLayout; +import net.kdt.pojavlaunch.customcontrols.gamepad.GamepadJoystick; +import net.kdt.pojavlaunch.customcontrols.handleview.EditControlPopup; + +import org.lwjgl.glfw.CallbackBridge; + +import io.github.controlwear.virtual.joystick.android.JoystickView; + +@SuppressLint("ViewConstructor") +public class ControlJoystick extends JoystickView implements ControlInterface{ + public ControlJoystick(ControlLayout parent, ControlData data) { + super(parent.getContext()); + init(data, parent); + } + + + public final static int DIRECTION_FORWARD_LOCK = 8; + + private ControlData mControlData; + private int mLastDirectionInt = GamepadJoystick.DIRECTION_NONE; + private int mCurrentDirectionInt = GamepadJoystick.DIRECTION_NONE; + + // Directions keycode + private final int[] mDirectionForwardLock = new int[]{LwjglGlfwKeycode.GLFW_KEY_W, LwjglGlfwKeycode.GLFW_KEY_LEFT_CONTROL}; + private final int[] mDirectionForward = new int[]{LwjglGlfwKeycode.GLFW_KEY_W}; + private final int[] mDirectionRight = new int[]{LwjglGlfwKeycode.GLFW_KEY_D}; + private final int[] mDirectionBackward = new int[]{LwjglGlfwKeycode.GLFW_KEY_S}; + private final int[] mDirectionLeft = new int[]{LwjglGlfwKeycode.GLFW_KEY_A}; + + private void init(ControlData data, ControlLayout layout){ + mControlData = data; + setProperties(preProcessProperties(data, layout)); + setDeadzone(40); + setFixedCenter(false); + setAutoReCenterButton(true); + //postDelayed(() -> setForwardLockDistance((int) (data.getHeight()* 0.66f)), 500); + setForwardLockDistance((int) Tools.dpToPx(30)); + layout.setClipChildren(false); + + + injectTouchEventBehavior(); + injectLayoutParamBehavior(); + + setOnMoveListener(new OnMoveListener() { + @Override + public void onMove(int angle, int strength) { + mLastDirectionInt = mCurrentDirectionInt; + mCurrentDirectionInt = getDirectionInt(angle, strength); + + if(mLastDirectionInt != mCurrentDirectionInt){ + sendDirectionalKeycode(mLastDirectionInt, false); + sendDirectionalKeycode(mCurrentDirectionInt, true); + } + } + + @Override + public void onForwardLock(boolean isLocked) { + mLastDirectionInt = mCurrentDirectionInt; + mCurrentDirectionInt = DIRECTION_FORWARD_LOCK; + + if(mLastDirectionInt != mCurrentDirectionInt){ + sendDirectionalKeycode(mLastDirectionInt, false); + sendDirectionalKeycode(mCurrentDirectionInt, true); + } + } + }); + } + + @Override + public View getControlView() {return this;} + + @Override + public ControlData getProperties() { + return mControlData; + } + + @Override + public void setProperties(ControlData properties, boolean changePos) { + mControlData = properties; + ControlInterface.super.setProperties(properties, changePos); + } + + @Override + public void removeButton() { + getControlLayoutParent().getLayout().mJoystickDataList.remove(getProperties()); + getControlLayoutParent().removeView(this); + } + + @Override + public void cloneButton() { + ControlData data = new ControlData(getProperties()); + getControlLayoutParent().addJoystickButton(data); + } + + @Override + public void setVisible(boolean isVisible) { + setVisibility(isVisible ? VISIBLE : GONE); + } + + @Override + public void setBackground() { + setBorderWidth(computeStrokeWidth(getProperties().strokeWidth)); + setBorderColor(getProperties().strokeColor); + setBackgroundColor(getProperties().bgColor); + } + + @Override + public void sendKeyPresses(boolean isDown) {/*STUB since non swipeable*/ } + + @Override + public void loadEditValues(EditControlPopup editControlPopup) { + editControlPopup.loadJoystickValues(mControlData); + } + + private int getDirectionInt(int angle, int intensity){ + if(intensity == 0) return DIRECTION_NONE; + return (int) (((angle+22.5)/45) % 8); + } + + private void sendDirectionalKeycode(int direction, boolean isDown){ + switch (direction){ + case DIRECTION_NORTH: + sendInput(mDirectionForward, isDown); + break; + case DIRECTION_NORTH_EAST: + sendInput(mDirectionForward, isDown); + sendInput(mDirectionRight, isDown); + break; + case DIRECTION_EAST: + sendInput(mDirectionRight, isDown); + break; + case DIRECTION_SOUTH_EAST: + sendInput(mDirectionRight, isDown); + sendInput(mDirectionBackward, isDown); + break; + case DIRECTION_SOUTH: + sendInput(mDirectionBackward, isDown); + break; + case DIRECTION_SOUTH_WEST: + sendInput(mDirectionBackward, isDown); + sendInput(mDirectionLeft, isDown); + break; + case DIRECTION_WEST: + sendInput(mDirectionLeft, isDown); + break; + case DIRECTION_NORTH_WEST: + sendInput(mDirectionForward, isDown); + sendInput(mDirectionLeft, isDown); + break; + case DIRECTION_FORWARD_LOCK: + sendInput(mDirectionForwardLock, isDown); + break; + } + } + + private static void sendInput(int[] keys, boolean isDown){ + for(int key : keys){ + CallbackBridge.sendKeyPress(key, CallbackBridge.getCurrentMods(), isDown); + } + } + +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java index 738e915c8..d2ef00e7a 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/handleview/EditControlPopup.java @@ -300,7 +300,7 @@ public class EditControlPopup { } /** Load values for the joystick */ - @SuppressWarnings("unused") public void loadJoystickValues(ControlData data){ + public void loadJoystickValues(ControlData data){ loadValues(data); mMappingTextView.setVisibility(GONE); diff --git a/app_pojavlauncher/src/main/res/values/headings_array.xml b/app_pojavlauncher/src/main/res/values/headings_array.xml index fb5d4c695..dd7e914c0 100644 --- a/app_pojavlauncher/src/main/res/values/headings_array.xml +++ b/app_pojavlauncher/src/main/res/values/headings_array.xml @@ -19,10 +19,11 @@ @string/customctrl_addbutton @string/customctrl_addbutton_drawer - @string/global_load - @string/global_save - @string/customctrl_selectdefault - @string/customctrl_export + @string/customctrl_addbutton_joystick + @string/global_load + @string/global_save + @string/customctrl_selectdefault + @string/customctrl_export diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index 9f571caf3..35b546bd9 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -205,6 +205,7 @@ Shift Add button Add button drawer + Add joystick Add sub-button Sub-button n°%d has been added !