From f496368f2c6f834cff33c51d35cdb22df08a0138 Mon Sep 17 00:00:00 2001 From: artdeell Date: Thu, 4 Jul 2024 14:27:45 +0300 Subject: [PATCH] Fix[capture]: modify trackpad touch handling, read relative axes only if they are supported --- .../mouse/AndroidPointerCapture.java | 61 ++++++++++++++++--- .../src/main/res/layout/activity_basemain.xml | 3 +- 2 files changed, 54 insertions(+), 10 deletions(-) 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 398d54b9c5..ec512ee0a0 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,6 +1,7 @@ package net.kdt.pojavlaunch.customcontrols.mouse; import android.os.Build; +import android.view.InputDevice; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; @@ -20,7 +21,12 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan private final View mHostView; private final float mScaleFactor; private final float mMousePrescale = Tools.dpToPx(1); + private final PointerTracker mPointerTracker = new PointerTracker(); private final Scroller mScroller = new Scroller(TOUCHPAD_SCROLL_THRESHOLD); + private final float[] mVector = mPointerTracker.getMotionVector(); + + private int mInputDeviceIdentifier; + private boolean mDeviceSupportsRelativeAxis; public AndroidPointerCapture(AbstractTouchpad touchpad, View hostView, float scaleFactor) { this.mScaleFactor = scaleFactor; @@ -44,26 +50,45 @@ public void handleAutomaticCapture() { @Override public boolean onCapturedPointer(View view, MotionEvent event) { + checkSameDevice(event.getDevice()); // Yes, we actually not only receive relative mouse events here, but also absolute touchpad ones! - // Read from relative axis directly to work around. - float relX = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X); - float relY = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); + // Therefore, we need to know when it's a touchpad and when it's a mouse. + + if((event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) { + // If the source claims to be a relative device by belonging to the trackball class, + // use its coordinates directly. + if(mDeviceSupportsRelativeAxis) { + // If some OEM decides to do a funny and make an absolute touchpad report itself as + // a trackball, we will at least have semi-valid relative positions + mVector[0] = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X); + mVector[1] = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); + }else { + // Otherwise trust the OS, i guess?? + mVector[0] = event.getX(); + mVector[1] = event.getY(); + } + }else { + // If it's not a trackball, it's likely a touchpad and needs tracking like a touchscreen. + mPointerTracker.trackEvent(event); + // The relative position will already be written down into the mVector variable. + } + if(!CallbackBridge.isGrabbing()) { enableTouchpadIfNecessary(); // Yes, if the user's touchpad is multi-touch we will also receive events for that. // So, handle the scrolling gesture ourselves. - relX *= mMousePrescale; - relY *= mMousePrescale; + mVector[0] *= mMousePrescale; + mVector[1] *= mMousePrescale; if(event.getPointerCount() < 2) { - mTouchpad.applyMotionVector(relX, relY); + mTouchpad.applyMotionVector(mVector); mScroller.resetScrollOvershoot(); } else { - mScroller.performScroll(relX, relY); + mScroller.performScroll(mVector); } } else { // Position is updated by many events, hence it is send regardless of the event value - CallbackBridge.mouseX += (relX * mScaleFactor); - CallbackBridge.mouseY += (relY * mScaleFactor); + CallbackBridge.mouseX += (mVector[0] * mScaleFactor); + CallbackBridge.mouseY += (mVector[1] * mScaleFactor); CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY); } @@ -80,11 +105,29 @@ public boolean onCapturedPointer(View view, MotionEvent event) { event.getAxisValue(MotionEvent.AXIS_VSCROLL) ); return true; + case MotionEvent.ACTION_UP: + mPointerTracker.cancelTracking(); + return true; default: return false; } } + private void checkSameDevice(InputDevice inputDevice) { + int newIdentifier = inputDevice.getId(); + if(mInputDeviceIdentifier != newIdentifier) { + reinitializeDeviceSpecificProperties(inputDevice); + mInputDeviceIdentifier = newIdentifier; + } + } + + private void reinitializeDeviceSpecificProperties(InputDevice inputDevice) { + mPointerTracker.cancelTracking(); + boolean relativeXSupported = inputDevice.getMotionRange(MotionEvent.AXIS_RELATIVE_X) != null; + boolean relativeYSupported = inputDevice.getMotionRange(MotionEvent.AXIS_RELATIVE_Y) != null; + mDeviceSupportsRelativeAxis = relativeXSupported && relativeYSupported; + } + @Override public void onWindowFocusChanged(boolean hasFocus) { if(hasFocus && MainActivity.isAndroid8OrHigher()) mHostView.requestPointerCapture(); diff --git a/app_pojavlauncher/src/main/res/layout/activity_basemain.xml b/app_pojavlauncher/src/main/res/layout/activity_basemain.xml index 7558399ef3..c97c03d065 100644 --- a/app_pojavlauncher/src/main/res/layout/activity_basemain.xml +++ b/app_pojavlauncher/src/main/res/layout/activity_basemain.xml @@ -24,7 +24,8 @@ android:id="@+id/main_game_render_view" android:layout_width="fill_parent" android:layout_height="fill_parent" - /> + android:defaultFocusHighlightEnabled="false" + tools:ignore="UnusedAttribute" />