Skip to content

Commit

Permalink
Fix[capture]: modify trackpad touch handling, read relative axes only…
Browse files Browse the repository at this point in the history
… if they are supported
  • Loading branch information
artdeell committed Jul 5, 2024
1 parent 7631e3c commit 181f811
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -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);
}

Expand All @@ -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();
Expand Down
3 changes: 2 additions & 1 deletion app_pojavlauncher/src/main/res/layout/activity_basemain.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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" />

<net.kdt.pojavlaunch.customcontrols.mouse.Touchpad
android:layout_height="match_parent"
Expand Down

0 comments on commit 181f811

Please sign in to comment.