From d7499a0868ea79d9141d56ae091fb7f83f5d9a07 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 11 Jun 2023 13:29:53 +0200 Subject: [PATCH] Ported: Improve touchpad and mouse support for the Android editor - m4gr3d https://github.com/godotengine/godot/commit/ccd36e0dbec048ef1645691d0cf838465bfb4bd0 --- .../pandemonium/PandemoniumView.java | 11 +++++-- .../input/PandemoniumGestureHandler.kt | 19 ++++++------ .../input/PandemoniumInputHandler.java | 31 +++++++++++++++++-- .../android/java_pandemonium_view_wrapper.cpp | 13 +++++++- .../android/java_pandemonium_view_wrapper.h | 1 + 5 files changed, 60 insertions(+), 15 deletions(-) diff --git a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumView.java b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumView.java index 611336ea3..089ed400a 100644 --- a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumView.java +++ b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumView.java @@ -138,8 +138,15 @@ public class PandemoniumView extends PandemoniumGLSurfaceView { @Override public void onPointerCaptureChange(boolean hasCapture) { - super.onPointerCaptureChange(hasCapture); - inputHandler.onPointerCaptureChange(hasCapture); + if (canCapturePointer()) { + super.onPointerCaptureChange(hasCapture); + inputHandler.onPointerCaptureChange(hasCapture); + } + } + + @Keep + private boolean canCapturePointer() { + return inputHandler.canCapturePointer(); } @Override diff --git a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumGestureHandler.kt b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumGestureHandler.kt index 25c106037..f32358e2e 100644 --- a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumGestureHandler.kt +++ b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumGestureHandler.kt @@ -227,18 +227,16 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes ) dragInProgress = false } - return true } - dragInProgress = true - val x = terminusEvent.x val y = terminusEvent.y if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress) { PandemoniumLib.pan(x, y, distanceX / 5f, distanceY / 5f) - } else { + } else if (!scaleInProgress) { PandemoniumInputHandler.handleMotionEvent(terminusEvent) } + return true } @@ -246,11 +244,14 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes if (!panningAndScalingEnabled || pointerCaptureInProgress) { return false } - PandemoniumLib.magnify( - detector.focusX, - detector.focusY, - detector.scaleFactor - ) + + if (detector.scaleFactor >= 0.8f && detector.scaleFactor != 1f && detector.scaleFactor <= 1.2f) { + PandemoniumLib.magnify( + detector.focusX, + detector.focusY, + detector.scaleFactor + ) + } return true } diff --git a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumInputHandler.java b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumInputHandler.java index 61c7437ae..105228ea4 100644 --- a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumInputHandler.java +++ b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumInputHandler.java @@ -66,6 +66,11 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener private final ScaleGestureDetector scaleGestureDetector; private final PandemoniumGestureHandler pandemoniumGestureHandler; + /** + * Used to decide whether mouse capture can be enabled. + */ + private int lastSeenToolType = MotionEvent.TOOL_TYPE_UNKNOWN; + public PandemoniumInputHandler(PandemoniumView pandemoniumView) { final Context context = pandemoniumView.getContext(); this.pandemoniumView = pandemoniumView; @@ -105,6 +110,10 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener return (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD; } + public boolean canCapturePointer() { + return lastSeenToolType == MotionEvent.TOOL_TYPE_MOUSE; + } + public void onPointerCaptureChange(boolean hasCapture) { pandemoniumGestureHandler.onPointerCaptureChange(hasCapture); } @@ -176,6 +185,8 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener } public boolean onTouchEvent(final MotionEvent event) { + lastSeenToolType = event.getToolType(0); + this.scaleGestureDetector.onTouchEvent(event); if (this.gestureDetector.onTouchEvent(event)) { // The gesture detector has handled the event. @@ -200,6 +211,8 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener } public boolean onGenericMotionEvent(MotionEvent event) { + lastSeenToolType = event.getToolType(0); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) { // The gesture detector has handled the event. return true; @@ -479,15 +492,27 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener } static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) { + // Fix the buttonsMask + switch (eventAction) { + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + // Zero-up the button state + buttonsMask = 0; + break; + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_MOVE: + if (buttonsMask == 0) { + buttonsMask = MotionEvent.BUTTON_PRIMARY; + } + break; + } + // We don't handle ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE events as they typically // follow ACTION_DOWN and ACTION_UP events. As such, handling them would result in duplicate // stream of events to the engine. switch (eventAction) { case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: - // Zero-up the button state - buttonsMask = 0; - // FALL THROUGH case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_HOVER_ENTER: case MotionEvent.ACTION_HOVER_EXIT: diff --git a/platform/android/java_pandemonium_view_wrapper.cpp b/platform/android/java_pandemonium_view_wrapper.cpp index cd4292e17..b66cdf1b7 100644 --- a/platform/android/java_pandemonium_view_wrapper.cpp +++ b/platform/android/java_pandemonium_view_wrapper.cpp @@ -47,6 +47,8 @@ PandemoniumJavaViewWrapper::PandemoniumJavaViewWrapper(jobject pandemonium_view) _request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V"); _release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V"); } + + _can_capture_pointer = env->GetMethodID(_cls, "canCapturePointer", "()Z"); } bool PandemoniumJavaViewWrapper::can_update_pointer_icon() const { @@ -54,7 +56,16 @@ bool PandemoniumJavaViewWrapper::can_update_pointer_icon() const { } bool PandemoniumJavaViewWrapper::can_capture_pointer() const { - return _request_pointer_capture != nullptr && _release_pointer_capture != nullptr; + // We can capture the pointer if the other jni capture method ids are initialized, + // and PandemoniumView#canCapturePointer() returns true. + if (_request_pointer_capture != nullptr && _release_pointer_capture != nullptr && _can_capture_pointer != nullptr) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL_V(env, false); + + return env->CallBooleanMethod(_godot_view, _can_capture_pointer); + } + + return false; } void PandemoniumJavaViewWrapper::request_pointer_capture() { diff --git a/platform/android/java_pandemonium_view_wrapper.h b/platform/android/java_pandemonium_view_wrapper.h index a7aebb124..c515fe3d6 100644 --- a/platform/android/java_pandemonium_view_wrapper.h +++ b/platform/android/java_pandemonium_view_wrapper.h @@ -44,6 +44,7 @@ private: jclass _cls; jobject _pandemonium_view; + jmethodID _can_capture_pointer = 0; jmethodID _request_pointer_capture = 0; jmethodID _release_pointer_capture = 0;