diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index 9a8b75ad6..84292159c 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -35,6 +35,7 @@ import android.provider.OpenableColumns; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; +import android.view.InputDevice; import android.view.View; import android.view.WindowManager; import android.widget.EditText; @@ -1557,4 +1558,19 @@ public final class Tools { } return Integer.parseInt(iVersionArray[0] + iVersionArray[1] + iVersionArray[2]); } + + public static boolean isPointerDeviceConnected() { + int[] deviceIds = InputDevice.getDeviceIds(); + for (int id : deviceIds) { + InputDevice device = InputDevice.getDevice(id); + if (device == null) continue; + int sources = device.getSources(); + if ((sources & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE + || (sources & InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD + || (sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) { + return true; + } + } + return false; + } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java index 38f6dd4ca..4e918cb3b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java @@ -1,13 +1,18 @@ package net.kdt.pojavlaunch.customcontrols.mouse; +import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_MOUSE_GRAB_FORCE; + +import android.content.SharedPreferences; import android.os.Build; import android.view.InputDevice; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import net.kdt.pojavlaunch.GrabListener; import net.kdt.pojavlaunch.MinecraftGLSurface; import net.kdt.pojavlaunch.Tools; import net.kdt.pojavlaunch.prefs.LauncherPreferences; @@ -15,7 +20,7 @@ import net.kdt.pojavlaunch.prefs.LauncherPreferences; import org.lwjgl.glfw.CallbackBridge; @RequiresApi(api = Build.VERSION_CODES.O) -public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChangeListener, View.OnCapturedPointerListener { +public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChangeListener, View.OnCapturedPointerListener, GrabListener, SharedPreferences.OnSharedPreferenceChangeListener { private static final float TOUCHPAD_SCROLL_THRESHOLD = 1; private final AbstractTouchpad mTouchpad; private final View mHostView; @@ -32,14 +37,44 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan this.mHostView = hostView; hostView.setOnCapturedPointerListener(this); hostView.getViewTreeObserver().addOnWindowFocusChangeListener(this); + if (!PREF_MOUSE_GRAB_FORCE) + CallbackBridge.addGrabListener(this); } private void enableTouchpadIfNecessary() { - if(!mTouchpad.getDisplayState()) mTouchpad.enable(true); + if(!mTouchpad.getDisplayState() && !Tools.isPointerDeviceConnected()) mTouchpad.enable(true); + } + + // Needed so it releases the cursor when inside game menu + @Override + public void onGrabState(boolean isGrabbing) { + updateCursorState(isGrabbing); + } + // It's only here so the side-dialog changes it live + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) { + updateCursorState(CallbackBridge.isGrabbing()); + } + private void updateCursorState(boolean isGrabbing) { + if (!isGrabbing // Only capture if not in menu and user said so + && !PREF_MOUSE_GRAB_FORCE) { + mHostView.releasePointerCapture(); // Release the capture since user said so + } + // Capture the pointer when not inside a menu + // So user doesn't have to click to get rid of cursor + handleAutomaticCapture(); } public void handleAutomaticCapture() { - if(!mHostView.hasWindowFocus()) { + if (!CallbackBridge.isGrabbing() // Only capture if not in menu and user said so + && !PREF_MOUSE_GRAB_FORCE) { + return; + } + if (mHostView.hasPointerCapture()) { + enableTouchpadIfNecessary(); + return; + } + if (!mHostView.hasWindowFocus()) { mHostView.requestFocus(); } else { mHostView.requestPointerCapture(); @@ -128,7 +163,11 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan @Override public void onWindowFocusChanged(boolean hasFocus) { - if(hasFocus && Tools.isAndroid8OrHigher()) mHostView.requestPointerCapture(); + if (!CallbackBridge.isGrabbing() // Only capture if not in menu and user said so + && !PREF_MOUSE_GRAB_FORCE) { + return; + } + if (hasFocus && Tools.isAndroid8OrHigher()) mHostView.requestPointerCapture(); } public void detach() { 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 dc4dd71ad..ab8c0cddd 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 @@ -72,6 +72,8 @@ public class LauncherPreferences { public static boolean PREF_FORCE_ENABLE_TOUCHCONTROLLER = false; public static int PREF_TOUCHCONTROLLER_VIBRATE_LENGTH = 100; + public static boolean PREF_MOUSE_GRAB_FORCE = false; + public static void loadPreferences(Context ctx) { //Required for CTRLDEF_FILE and MultiRT @@ -114,6 +116,7 @@ public class LauncherPreferences { PREF_VSYNC_IN_ZINK = DEFAULT_PREF.getBoolean("vsync_in_zink", true); PREF_FORCE_ENABLE_TOUCHCONTROLLER = DEFAULT_PREF.getBoolean("forceEnableTouchController", false); PREF_TOUCHCONTROLLER_VIBRATE_LENGTH = DEFAULT_PREF.getInt("touchControllerVibrateLength", 100); + PREF_MOUSE_GRAB_FORCE = DEFAULT_PREF.getBoolean("always_grab_mouse", false); 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/QuickSettingSideDialog.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/QuickSettingSideDialog.java index 5458dbf57..6a2b82dd1 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/QuickSettingSideDialog.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/QuickSettingSideDialog.java @@ -7,6 +7,7 @@ import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GYRO_INVERT_Y; import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GYRO_SENSITIVITY; import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_LONGPRESS_TRIGGER; import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_MOUSESPEED; +import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_MOUSE_GRAB_FORCE; import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_SCALE_FACTOR; import android.annotation.SuppressLint; @@ -31,11 +32,11 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { private SharedPreferences.Editor mEditor; @SuppressLint("UseSwitchCompatOrMaterialCode") - private Switch mGyroSwitch, mGyroXSwitch, mGyroYSwitch, mGestureSwitch; + private Switch mGyroSwitch, mGyroXSwitch, mGyroYSwitch, mGestureSwitch, mMouseGrabSwitch; private CustomSeekbar mGyroSensitivityBar, mMouseSpeedBar, mGestureDelayBar, mResolutionBar; private TextView mGyroSensitivityText, mGyroSensitivityDisplayText, mMouseSpeedText, mGestureDelayText, mGestureDelayDisplayText, mResolutionText; - private boolean mOriginalGyroEnabled, mOriginalGyroXEnabled, mOriginalGyroYEnabled, mOriginalGestureDisabled; + private boolean mOriginalGyroEnabled, mOriginalGyroXEnabled, mOriginalGyroYEnabled, mOriginalGestureDisabled, mOriginalMouseGrab; private float mOriginalGyroSensitivity, mOriginalMouseSpeed, mOriginalResolution; private int mOriginalGestureDelay; @@ -65,6 +66,7 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { mGyroXSwitch = mDialogContent.findViewById(R.id.checkboxGyroX); mGyroYSwitch = mDialogContent.findViewById(R.id.checkboxGyroY); mGestureSwitch = mDialogContent.findViewById(R.id.checkboxGesture); + mMouseGrabSwitch = mDialogContent.findViewById(R.id.always_grab_mouse_side_dialog); mGyroSensitivityBar = mDialogContent.findViewById(R.id.editGyro_seekbar); mMouseSpeedBar = mDialogContent.findViewById(R.id.editMouseSpeed_seekbar); @@ -86,6 +88,7 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { mOriginalGyroXEnabled = PREF_GYRO_INVERT_X; mOriginalGyroYEnabled = PREF_GYRO_INVERT_Y; mOriginalGestureDisabled = PREF_DISABLE_GESTURES; + mOriginalMouseGrab = PREF_MOUSE_GRAB_FORCE; mOriginalGyroSensitivity = PREF_GYRO_SENSITIVITY; mOriginalMouseSpeed = PREF_MOUSESPEED; @@ -122,6 +125,10 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { mEditor.putBoolean("disableGestures", isChecked); }); + mMouseGrabSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { + mEditor.putBoolean("always_grab_mouse", isChecked); + }); + mGyroSensitivityBar.setOnSeekBarChangeListener((SimpleSeekBarListener) (seekBar, progress, fromUser) -> { PREF_GYRO_SENSITIVITY = progress / 100f; mEditor.putInt("gyroSensitivity", progress); @@ -156,6 +163,7 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { setSeekTextPercent(mResolutionText, mResolutionBar.getProgress()); + updateMouseGrabVisibility(); updateGyroVisibility(mOriginalGyroEnabled); updateGestureVisibility(mOriginalGestureDisabled); } @@ -172,6 +180,10 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { target.setText(target.getContext().getString(format, value)); } + private void updateMouseGrabVisibility(){ + mMouseGrabSwitch.setVisibility(Tools.isPointerDeviceConnected()? View.VISIBLE : View.GONE); + } + private void updateGyroVisibility(boolean isEnabled) { int visibility = isEnabled ? View.VISIBLE : View.GONE; mGyroXSwitch.setVisibility(visibility); @@ -202,6 +214,7 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { mGyroXSwitch.setOnCheckedChangeListener(null); mGyroYSwitch.setOnCheckedChangeListener(null); mGestureSwitch.setOnCheckedChangeListener(null); + mMouseGrabSwitch.setOnCheckedChangeListener(null); mGyroSensitivityBar.setOnSeekBarChangeListener(null); mMouseSpeedBar.setOnSeekBarChangeListener(null); @@ -225,6 +238,7 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView { PREF_GYRO_INVERT_X = mOriginalGyroXEnabled; PREF_GYRO_INVERT_Y = mOriginalGyroYEnabled; PREF_DISABLE_GESTURES = mOriginalGestureDisabled; + PREF_MOUSE_GRAB_FORCE = mOriginalMouseGrab; PREF_GYRO_SENSITIVITY = mOriginalGyroSensitivity; PREF_MOUSESPEED = mOriginalMouseSpeed; diff --git a/app_pojavlauncher/src/main/res/layout/dialog_quick_setting.xml b/app_pojavlauncher/src/main/res/layout/dialog_quick_setting.xml index b85a83f7c..1d0ec167e 100644 --- a/app_pojavlauncher/src/main/res/layout/dialog_quick_setting.xml +++ b/app_pojavlauncher/src/main/res/layout/dialog_quick_setting.xml @@ -202,4 +202,15 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="@id/editGestureDelay_textView" /> + + \ No newline at end of file diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index 04a41f500..15ff64e01 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -171,6 +171,8 @@ Disables double tapping on the hotbar item to swap it in the second hand. Mouse Speed Changes the speed of the virtual mouse. + Use virtual cursor + Ensures the cursor stays inside the game. Prevents mouse from clicking touch control layout. Mouse pass-thru Swipeable Forward lock diff --git a/app_pojavlauncher/src/main/res/xml/pref_control.xml b/app_pojavlauncher/src/main/res/xml/pref_control.xml index 77c02f91c..0f2a7ec02 100644 --- a/app_pojavlauncher/src/main/res/xml/pref_control.xml +++ b/app_pojavlauncher/src/main/res/xml/pref_control.xml @@ -97,6 +97,11 @@ android:title="@string/preference_mouse_start_title" android:summary="@string/preference_mouse_start_description" /> +