Fix[capture]: modify trackpad touch handling, read relative axes only if they are supported

This commit is contained in:
artdeell 2024-07-04 14:27:45 +03:00 committed by Maksim Belov
parent 7631e3c9e7
commit 181f81131f
2 changed files with 54 additions and 10 deletions

View File

@ -1,6 +1,7 @@
package net.kdt.pojavlaunch.customcontrols.mouse; package net.kdt.pojavlaunch.customcontrols.mouse;
import android.os.Build; import android.os.Build;
import android.view.InputDevice;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
@ -20,7 +21,12 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan
private final View mHostView; private final View mHostView;
private final float mScaleFactor; private final float mScaleFactor;
private final float mMousePrescale = Tools.dpToPx(1); private final float mMousePrescale = Tools.dpToPx(1);
private final PointerTracker mPointerTracker = new PointerTracker();
private final Scroller mScroller = new Scroller(TOUCHPAD_SCROLL_THRESHOLD); 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) { public AndroidPointerCapture(AbstractTouchpad touchpad, View hostView, float scaleFactor) {
this.mScaleFactor = scaleFactor; this.mScaleFactor = scaleFactor;
@ -44,26 +50,45 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan
@Override @Override
public boolean onCapturedPointer(View view, MotionEvent event) { 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! // Yes, we actually not only receive relative mouse events here, but also absolute touchpad ones!
// Read from relative axis directly to work around. // Therefore, we need to know when it's a touchpad and when it's a mouse.
float relX = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
float relY = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y); 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()) { if(!CallbackBridge.isGrabbing()) {
enableTouchpadIfNecessary(); enableTouchpadIfNecessary();
// Yes, if the user's touchpad is multi-touch we will also receive events for that. // Yes, if the user's touchpad is multi-touch we will also receive events for that.
// So, handle the scrolling gesture ourselves. // So, handle the scrolling gesture ourselves.
relX *= mMousePrescale; mVector[0] *= mMousePrescale;
relY *= mMousePrescale; mVector[1] *= mMousePrescale;
if(event.getPointerCount() < 2) { if(event.getPointerCount() < 2) {
mTouchpad.applyMotionVector(relX, relY); mTouchpad.applyMotionVector(mVector);
mScroller.resetScrollOvershoot(); mScroller.resetScrollOvershoot();
} else { } else {
mScroller.performScroll(relX, relY); mScroller.performScroll(mVector);
} }
} else { } else {
// Position is updated by many events, hence it is send regardless of the event value // Position is updated by many events, hence it is send regardless of the event value
CallbackBridge.mouseX += (relX * mScaleFactor); CallbackBridge.mouseX += (mVector[0] * mScaleFactor);
CallbackBridge.mouseY += (relY * mScaleFactor); CallbackBridge.mouseY += (mVector[1] * mScaleFactor);
CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY); CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY);
} }
@ -80,11 +105,29 @@ public class AndroidPointerCapture implements ViewTreeObserver.OnWindowFocusChan
event.getAxisValue(MotionEvent.AXIS_VSCROLL) event.getAxisValue(MotionEvent.AXIS_VSCROLL)
); );
return true; return true;
case MotionEvent.ACTION_UP:
mPointerTracker.cancelTracking();
return true;
default: default:
return false; 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 @Override
public void onWindowFocusChanged(boolean hasFocus) { public void onWindowFocusChanged(boolean hasFocus) {
if(hasFocus && MainActivity.isAndroid8OrHigher()) mHostView.requestPointerCapture(); if(hasFocus && MainActivity.isAndroid8OrHigher()) mHostView.requestPointerCapture();

View File

@ -24,7 +24,8 @@
android:id="@+id/main_game_render_view" android:id="@+id/main_game_render_view"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
/> android:defaultFocusHighlightEnabled="false"
tools:ignore="UnusedAttribute" />
<net.kdt.pojavlaunch.customcontrols.mouse.Touchpad <net.kdt.pojavlaunch.customcontrols.mouse.Touchpad
android:layout_height="match_parent" android:layout_height="match_parent"