Skip to content

Commit a44bd72

Browse files
committed
fix(Pointer/Capture): Make non-opportunistic grabbing opt-in
Adds a new config option whether or not you want your mouse to be able to click your touch controls! Default is you can! Should also now let DeX users get their cursor out of the window by just moving it by default. This reverts commit 7631e3c.
1 parent 9c15bba commit a44bd72

7 files changed

Lines changed: 95 additions & 7 deletions

File tree

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import android.util.ArrayMap;
3636
import android.util.DisplayMetrics;
3737
import android.util.Log;
38+
import android.view.InputDevice;
3839
import android.view.View;
3940
import android.view.WindowManager;
4041
import android.widget.EditText;
@@ -1506,5 +1507,18 @@ public static void hasNoOnlineProfileDialog(Activity activity, String customTitl
15061507
hasNoOnlineProfileDialog(activity, null, customTitle, customMessage);
15071508
}
15081509

1509-
1510+
public static boolean isPointerDeviceConnected() {
1511+
int[] deviceIds = InputDevice.getDeviceIds();
1512+
for (int id : deviceIds) {
1513+
InputDevice device = InputDevice.getDevice(id);
1514+
if (device == null) continue;
1515+
int sources = device.getSources();
1516+
if ((sources & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE
1517+
|| (sources & InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD
1518+
|| (sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
1519+
return true;
1520+
}
1521+
}
1522+
return false;
1523+
}
15101524
}

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/customcontrols/mouse/AndroidPointerCapture.java

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
package net.kdt.pojavlaunch.customcontrols.mouse;
22

3+
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_MOUSE_GRAB_FORCE;
4+
5+
import android.content.SharedPreferences;
36
import android.os.Build;
47
import android.view.InputDevice;
58
import android.view.MotionEvent;
69
import android.view.View;
710
import android.view.ViewTreeObserver;
811

12+
import androidx.annotation.Nullable;
913
import androidx.annotation.RequiresApi;
1014

15+
import net.kdt.pojavlaunch.GrabListener;
1116
import net.kdt.pojavlaunch.MinecraftGLSurface;
1217
import net.kdt.pojavlaunch.Tools;
1318
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
1419

1520
import org.lwjgl.glfw.CallbackBridge;
1621

1722
@RequiresApi(api = Build.VERSION_CODES.O)
18-
public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChangeListener, View.OnCapturedPointerListener {
23+
public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChangeListener, View.OnCapturedPointerListener, GrabListener, SharedPreferences.OnSharedPreferenceChangeListener {
1924
private static final float TOUCHPAD_SCROLL_THRESHOLD = 1;
2025
private final AbstractTouchpad mTouchpad;
2126
private final View mHostView;
@@ -32,14 +37,44 @@ public AndroidPointerCapture(AbstractTouchpad touchpad, View hostView) {
3237
this.mHostView = hostView;
3338
hostView.setOnCapturedPointerListener(this);
3439
hostView.getViewTreeObserver().addOnWindowFocusChangeListener(this);
40+
if (!PREF_MOUSE_GRAB_FORCE)
41+
CallbackBridge.addGrabListener(this);
3542
}
3643

3744
private void enableTouchpadIfNecessary() {
38-
if(!mTouchpad.getDisplayState()) mTouchpad.enable(true);
45+
if(!mTouchpad.getDisplayState() && !Tools.isPointerDeviceConnected()) mTouchpad.enable(true);
46+
}
47+
48+
// Needed so it releases the cursor when inside game menu
49+
@Override
50+
public void onGrabState(boolean isGrabbing) {
51+
updateCursorState(isGrabbing);
52+
}
53+
// It's only here so the side-dialog changes it live
54+
@Override
55+
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
56+
updateCursorState(CallbackBridge.isGrabbing());
57+
}
58+
private void updateCursorState(boolean isGrabbing) {
59+
if (!isGrabbing // Only capture if not in menu and user said so
60+
&& !PREF_MOUSE_GRAB_FORCE) {
61+
mHostView.releasePointerCapture(); // Release the capture since user said so
62+
}
63+
// Capture the pointer when not inside a menu
64+
// So user doesn't have to click to get rid of cursor
65+
handleAutomaticCapture();
3966
}
4067

4168
public void handleAutomaticCapture() {
42-
if(!mHostView.hasWindowFocus()) {
69+
if (!CallbackBridge.isGrabbing() // Only capture if not in menu and user said so
70+
&& !PREF_MOUSE_GRAB_FORCE) {
71+
return;
72+
}
73+
if (mHostView.hasPointerCapture()) {
74+
enableTouchpadIfNecessary();
75+
return;
76+
}
77+
if (!mHostView.hasWindowFocus()) {
4378
mHostView.requestFocus();
4479
} else {
4580
mHostView.requestPointerCapture();
@@ -128,7 +163,11 @@ private void reinitializeDeviceSpecificProperties(InputDevice inputDevice) {
128163

129164
@Override
130165
public void onWindowFocusChanged(boolean hasFocus) {
131-
if(hasFocus && Tools.isAndroid8OrHigher()) mHostView.requestPointerCapture();
166+
if (!CallbackBridge.isGrabbing() // Only capture if not in menu and user said so
167+
&& !PREF_MOUSE_GRAB_FORCE) {
168+
return;
169+
}
170+
if (hasFocus && Tools.isAndroid8OrHigher()) mHostView.requestPointerCapture();
132171
}
133172

134173
public void detach() {

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ public class LauncherPreferences {
7373
public static boolean PREF_FORCE_ENABLE_TOUCHCONTROLLER = false;
7474
public static int PREF_TOUCHCONTROLLER_VIBRATE_LENGTH = 100;
7575

76+
public static boolean PREF_MOUSE_GRAB_FORCE = false;
77+
7678

7779
public static void loadPreferences(Context ctx) {
7880
//Required for CTRLDEF_FILE and MultiRT
@@ -116,6 +118,7 @@ public static void loadPreferences(Context ctx) {
116118
PREF_VSYNC_IN_ZINK = DEFAULT_PREF.getBoolean("vsync_in_zink", true);
117119
PREF_FORCE_ENABLE_TOUCHCONTROLLER = DEFAULT_PREF.getBoolean("forceEnableTouchController", false);
118120
PREF_TOUCHCONTROLLER_VIBRATE_LENGTH = DEFAULT_PREF.getInt("touchControllerVibrateLength", 100);
121+
PREF_MOUSE_GRAB_FORCE = DEFAULT_PREF.getBoolean("always_grab_mouse", false);
119122

120123
String argLwjglLibname = "-Dorg.lwjgl.opengl.libname=";
121124
for (String arg : JREUtils.parseJavaArguments(PREF_CUSTOM_JAVA_ARGS)) {

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/QuickSettingSideDialog.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_GYRO_SENSITIVITY;
88
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_LONGPRESS_TRIGGER;
99
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_MOUSESPEED;
10+
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_MOUSE_GRAB_FORCE;
1011
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_SCALE_FACTOR;
1112

1213
import android.annotation.SuppressLint;
@@ -31,11 +32,11 @@ public abstract class QuickSettingSideDialog extends com.kdt.SideDialogView {
3132

3233
private SharedPreferences.Editor mEditor;
3334
@SuppressLint("UseSwitchCompatOrMaterialCode")
34-
private Switch mGyroSwitch, mGyroXSwitch, mGyroYSwitch, mGestureSwitch;
35+
private Switch mGyroSwitch, mGyroXSwitch, mGyroYSwitch, mGestureSwitch, mMouseGrabSwitch;
3536
private CustomSeekbar mGyroSensitivityBar, mMouseSpeedBar, mGestureDelayBar, mResolutionBar;
3637
private TextView mGyroSensitivityText, mGyroSensitivityDisplayText, mMouseSpeedText, mGestureDelayText, mGestureDelayDisplayText, mResolutionText;
3738

38-
private boolean mOriginalGyroEnabled, mOriginalGyroXEnabled, mOriginalGyroYEnabled, mOriginalGestureDisabled;
39+
private boolean mOriginalGyroEnabled, mOriginalGyroXEnabled, mOriginalGyroYEnabled, mOriginalGestureDisabled, mOriginalMouseGrab;
3940
private float mOriginalGyroSensitivity, mOriginalMouseSpeed, mOriginalResolution;
4041
private int mOriginalGestureDelay;
4142

@@ -65,6 +66,7 @@ private void bindLayout() {
6566
mGyroXSwitch = mDialogContent.findViewById(R.id.checkboxGyroX);
6667
mGyroYSwitch = mDialogContent.findViewById(R.id.checkboxGyroY);
6768
mGestureSwitch = mDialogContent.findViewById(R.id.checkboxGesture);
69+
mMouseGrabSwitch = mDialogContent.findViewById(R.id.always_grab_mouse_side_dialog);
6870

6971
mGyroSensitivityBar = mDialogContent.findViewById(R.id.editGyro_seekbar);
7072
mMouseSpeedBar = mDialogContent.findViewById(R.id.editMouseSpeed_seekbar);
@@ -86,6 +88,7 @@ private void setupListeners() {
8688
mOriginalGyroXEnabled = PREF_GYRO_INVERT_X;
8789
mOriginalGyroYEnabled = PREF_GYRO_INVERT_Y;
8890
mOriginalGestureDisabled = PREF_DISABLE_GESTURES;
91+
mOriginalMouseGrab = PREF_MOUSE_GRAB_FORCE;
8992

9093
mOriginalGyroSensitivity = PREF_GYRO_SENSITIVITY;
9194
mOriginalMouseSpeed = PREF_MOUSESPEED;
@@ -122,6 +125,10 @@ private void setupListeners() {
122125
mEditor.putBoolean("disableGestures", isChecked);
123126
});
124127

128+
mMouseGrabSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
129+
mEditor.putBoolean("always_grab_mouse", isChecked);
130+
});
131+
125132
mGyroSensitivityBar.setOnSeekBarChangeListener((SimpleSeekBarListener) (seekBar, progress, fromUser) -> {
126133
PREF_GYRO_SENSITIVITY = progress / 100f;
127134
mEditor.putInt("gyroSensitivity", progress);
@@ -156,6 +163,7 @@ private void setupListeners() {
156163
setSeekTextPercent(mResolutionText, mResolutionBar.getProgress());
157164

158165

166+
updateMouseGrabVisibility();
159167
updateGyroVisibility(mOriginalGyroEnabled);
160168
updateGestureVisibility(mOriginalGestureDisabled);
161169
}
@@ -172,6 +180,10 @@ private static void setSeekText(TextView target, int format, int value) {
172180
target.setText(target.getContext().getString(format, value));
173181
}
174182

183+
private void updateMouseGrabVisibility(){
184+
mMouseGrabSwitch.setVisibility(Tools.isPointerDeviceConnected()? View.VISIBLE : View.GONE);
185+
}
186+
175187
private void updateGyroVisibility(boolean isEnabled) {
176188
int visibility = isEnabled ? View.VISIBLE : View.GONE;
177189
mGyroXSwitch.setVisibility(visibility);
@@ -202,6 +214,7 @@ private void removeListeners() {
202214
mGyroXSwitch.setOnCheckedChangeListener(null);
203215
mGyroYSwitch.setOnCheckedChangeListener(null);
204216
mGestureSwitch.setOnCheckedChangeListener(null);
217+
mMouseGrabSwitch.setOnCheckedChangeListener(null);
205218

206219
mGyroSensitivityBar.setOnSeekBarChangeListener(null);
207220
mMouseSpeedBar.setOnSeekBarChangeListener(null);
@@ -225,6 +238,7 @@ public void cancel() {
225238
PREF_GYRO_INVERT_X = mOriginalGyroXEnabled;
226239
PREF_GYRO_INVERT_Y = mOriginalGyroYEnabled;
227240
PREF_DISABLE_GESTURES = mOriginalGestureDisabled;
241+
PREF_MOUSE_GRAB_FORCE = mOriginalMouseGrab;
228242

229243
PREF_GYRO_SENSITIVITY = mOriginalGyroSensitivity;
230244
PREF_MOUSESPEED = mOriginalMouseSpeed;

app_pojavlauncher/src/main/res/layout/dialog_quick_setting.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,4 +202,15 @@
202202
app:layout_constraintEnd_toEndOf="parent"
203203
app:layout_constraintTop_toTopOf="@id/editGestureDelay_textView" />
204204

205+
<Switch
206+
android:id="@+id/always_grab_mouse_side_dialog"
207+
android:layout_width="match_parent"
208+
android:layout_height="@dimen/_36sdp"
209+
android:text="@string/mcl_setting_title_grab_mouse"
210+
211+
212+
app:layout_constraintBottom_toBottomOf="parent"
213+
app:layout_constraintTop_toBottomOf="@+id/editGestureDelay_seekbar"
214+
tools:ignore="UseSwitchCompatOrMaterialXml" />
215+
205216
</androidx.constraintlayout.widget.ConstraintLayout>

app_pojavlauncher/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,4 +469,6 @@
469469
<string name="preference_force_enable_touchcontroller_description">Force enable TouchController integration, even if mod file is not found.</string>
470470
<string name="preference_touchcontroller_vibrate_length_title">TouchController vibrate length</string>
471471
<string name="preference_touchcontroller_vibrate_length_description">Set the length of the vibration when using TouchController.</string>
472+
<string name="mcl_setting_title_grab_mouse">Mouse grabbing</string>
473+
<string name="mcl_setting_subtitle_grab_mouse">Grabs the mouse to ensure it stays inside the game window. Prevents mouse from clicking touch control layout.</string>
472474
</resources>

app_pojavlauncher/src/main/res/xml/pref_control.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@
9797
android:title="@string/preference_mouse_start_title"
9898
android:summary="@string/preference_mouse_start_description"
9999
/>
100+
<SwitchPreference
101+
android:key="always_grab_mouse"
102+
android:title="@string/mcl_setting_title_grab_mouse"
103+
android:summary="@string/mcl_setting_subtitle_grab_mouse"
104+
android:defaultValue="false"/>
100105
</PreferenceCategory>
101106

102107
<PreferenceCategory

0 commit comments

Comments
 (0)