From db926ddd0cc891fc01ce1abbb0d75a218598c8b6 Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 13 Nov 2022 01:13:22 +0100 Subject: [PATCH] Ported: Add support for pointer capture - m4gr3d https://github.com/godotengine/godot/commit/5149311316c5b2dd2c699b829b65532b95dae8df --- platform/android/android_input_handler.cpp | 54 ++++++++---- platform/android/android_input_handler.h | 6 +- .../pandemonium/PandemoniumLib.java | 2 +- .../pandemonium/PandemoniumView.java | 23 +++++ .../input/PandemoniumEditText.java | 4 +- .../input/PandemoniumGestureHandler.kt | 86 +++++++++++++++---- .../input/PandemoniumInputHandler.java | 38 ++++++-- platform/android/java_pandemonium_lib_jni.cpp | 4 +- platform/android/java_pandemonium_lib_jni.h | 2 +- .../android/java_pandemonium_view_wrapper.cpp | 26 ++++++ .../android/java_pandemonium_view_wrapper.h | 7 ++ platform/android/os_android.cpp | 11 ++- 12 files changed, 216 insertions(+), 47 deletions(-) diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp index efb68a81a..5a3bd951b 100644 --- a/platform/android/android_input_handler.cpp +++ b/platform/android/android_input_handler.cpp @@ -209,7 +209,7 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const } } -void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click) { +void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative) { if (!mouse_event_info.valid) { return; } @@ -217,8 +217,16 @@ void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_press Ref ev; ev.instance(); _set_key_modifier_state(ev); - ev->set_position(mouse_event_info.pos); - ev->set_global_position(mouse_event_info.pos); + + if (p_source_mouse_relative) { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + } else { + ev->set_position(mouse_event_info.pos); + ev->set_global_position(mouse_event_info.pos); + hover_prev_pos = mouse_event_info.pos; + } + ev->set_pressed(p_pressed); int changed_button_mask = buttons_state ^ buttons_mask; @@ -228,15 +236,14 @@ void AndroidInputHandler::_parse_mouse_event_info(int buttons_mask, bool p_press ev->set_button_mask(buttons_mask); ev->set_doubleclick(p_double_click); input->parse_input_event(ev); - hover_prev_pos = mouse_event_info.pos; } -void AndroidInputHandler::_release_mouse_event_info() { - _parse_mouse_event_info(0, false, false); +void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative) { + _parse_mouse_event_info(0, false, false, p_source_mouse_relative); mouse_event_info.valid = false; } -void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click) { +void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative) { int event_buttons_mask = _android_button_mask_to_pandemonium_button_mask(p_event_android_buttons_mask); switch (p_event_action) { case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move @@ -260,13 +267,13 @@ void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_an mouse_event_info.valid = true; mouse_event_info.pos = p_event_pos; - _parse_mouse_event_info(event_buttons_mask, true, p_double_click); + _parse_mouse_event_info(event_buttons_mask, true, p_double_click, p_source_mouse_relative); } break; case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { - _release_mouse_event_info(); + _release_mouse_event_info(p_source_mouse_relative); } break; case AMOTION_EVENT_ACTION_MOVE: { @@ -277,21 +284,36 @@ void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_an Ref ev; ev.instance(); _set_key_modifier_state(ev); - ev->set_position(p_event_pos); - ev->set_global_position(p_event_pos); - ev->set_relative(p_event_pos - hover_prev_pos); + + if (p_source_mouse_relative) { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + ev->set_relative(p_event_pos); + } else { + ev->set_position(p_event_pos); + ev->set_global_position(p_event_pos); + ev->set_relative(p_event_pos - hover_prev_pos); + mouse_event_info.pos = p_event_pos; + hover_prev_pos = p_event_pos; + } + ev->set_button_mask(event_buttons_mask); input->parse_input_event(ev); - mouse_event_info.pos = p_event_pos; - hover_prev_pos = p_event_pos; } break; case AMOTION_EVENT_ACTION_SCROLL: { Ref ev; ev.instance(); _set_key_modifier_state(ev); - ev->set_position(p_event_pos); - ev->set_global_position(p_event_pos); + + if (p_source_mouse_relative) { + ev->set_position(hover_prev_pos); + ev->set_global_position(hover_prev_pos); + } else { + ev->set_position(p_event_pos); + ev->set_global_position(p_event_pos); + } + ev->set_pressed(true); buttons_state = event_buttons_mask; if (p_delta.y > 0) { diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h index e112bafb9..21cd1ef86 100644 --- a/platform/android/android_input_handler.h +++ b/platform/android/android_input_handler.h @@ -85,9 +85,9 @@ private: void _wheel_button_click(int event_buttons_mask, const Ref &ev, int wheel_button, float factor); - void _parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click); + void _parse_mouse_event_info(int buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative); - void _release_mouse_event_info(); + void _release_mouse_event_info(bool p_source_mouse_relative = false); void _parse_all_touch(bool p_pressed); @@ -96,7 +96,7 @@ private: public: void process_joy_event(const JoypadEvent &p_event); void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); - void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click); + void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative); void process_touch_event(int p_event, int p_pointer, const Vector &p_points); void process_magnify(Point2 p_pos, float p_factor); void process_pan(Point2 p_pos, Vector2 p_delta); diff --git a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumLib.java b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumLib.java index 7ff2a0128..06ba9fdba 100644 --- a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumLib.java +++ b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/PandemoniumLib.java @@ -98,7 +98,7 @@ public class PandemoniumLib { /** * Dispatch mouse events */ - public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick); + public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative); public static native void magnify(float x, float y, float factor); 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 02c02d0de..fcd16a572 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 @@ -123,6 +123,29 @@ public class PandemoniumView extends PandemoniumGLSurfaceView { return inputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event); } + @Override + public boolean onCapturedPointerEvent(MotionEvent event) { + return inputHandler.onGenericMotionEvent(event); + } + + @Override + public void onPointerCaptureChange(boolean hasCapture) { + super.onPointerCaptureChange(hasCapture); + inputHandler.onPointerCaptureChange(hasCapture); + } + + @Override + public void requestPointerCapture() { + super.requestPointerCapture(); + inputHandler.onPointerCaptureChange(true); + } + + @Override + public void releasePointerCapture() { + super.releasePointerCapture(); + inputHandler.onPointerCaptureChange(false); + } + /** * Called from JNI to change the pointer icon */ diff --git a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumEditText.java b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumEditText.java index bac91754c..19dfbca2a 100644 --- a/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumEditText.java +++ b/platform/android/java/lib/src/net/relintai/pandemonium/pandemonium/input/PandemoniumEditText.java @@ -131,7 +131,9 @@ public class PandemoniumEditText extends EditText { edit.setText(""); edit.append(text); if (msg.arg2 != -1) { - edit.setSelection(msg.arg1, msg.arg2); + int selectionStart = Math.min(msg.arg1, edit.length()); + int selectionEnd = Math.min(msg.arg2, edit.length()); + edit.setSelection(selectionStart, selectionEnd); edit.mInputWrapper.setSelection(true); } else { edit.mInputWrapper.setSelection(false); 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 bba4d5392..f3ec378e7 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 @@ -30,7 +30,9 @@ package net.relintai.pandemonium.pandemonium.input +import android.os.Build import android.view.GestureDetector.SimpleOnGestureListener +import android.view.InputDevice import android.view.MotionEvent import android.view.ScaleGestureDetector import android.view.ScaleGestureDetector.OnScaleGestureListener @@ -57,6 +59,7 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes private var dragInProgress = false private var scaleInProgress = false private var contextClickInProgress = false + private var pointerCaptureInProgress = false override fun onDown(event: MotionEvent): Boolean { // Don't send / register a down event while we're in the middle of a double-tap @@ -77,7 +80,7 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes } private fun contextClickRouter(event: MotionEvent) { - if (scaleInProgress) { + if (scaleInProgress || nextDownIsDoubleTap) { return } @@ -100,6 +103,27 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes contextClickInProgress = true } + fun onPointerCaptureChange(hasCapture: Boolean) { + if (pointerCaptureInProgress == hasCapture) { + return + } + + if (!hasCapture) { + // Dispatch a mouse relative ACTION_UP event to signal the end of the capture + PandemoniumInputHandler.handleMouseEvent( + MotionEvent.ACTION_UP, + 0, + 0f, + 0f, + 0f, + 0f, + false, + true + ) + } + pointerCaptureInProgress = hasCapture + } + fun onMotionEvent(event: MotionEvent): Boolean { return when (event.actionMasked) { MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> { @@ -113,30 +137,61 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes } private fun onActionUp(event: MotionEvent): Boolean { - if (dragInProgress) { - PandemoniumInputHandler.handleMotionEvent(event) - dragInProgress = false + if (event.actionMasked == MotionEvent.ACTION_CANCEL && pointerCaptureInProgress) { + // Don't dispatch the ACTION_CANCEL while a capture is in progress return true - } else if (contextClickInProgress) { - PandemoniumInputHandler.handleMouseEvent( - event.actionMasked, - 0, - event.x, - event.y - ) + } + + val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE) + } else { + false + } + + if (pointerCaptureInProgress || dragInProgress || contextClickInProgress) { + if (contextClickInProgress || PandemoniumInputHandler.isMouseEvent(event)) { + // This may be an ACTION_BUTTON_RELEASE event which we don't handle, + // so we convert it to an ACTION_UP event. + PandemoniumInputHandler.handleMouseEvent( + MotionEvent.ACTION_UP, + event.buttonState, + event.x, + event.y, + 0f, + 0f, + false, + sourceMouseRelative + ) + } else { + PandemoniumInputHandler.handleTouchEvent(event) + } + + pointerCaptureInProgress = false + dragInProgress = false contextClickInProgress = false return true } + return false } private fun onActionMove(event: MotionEvent): Boolean { if (contextClickInProgress) { + val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE) + } else { + false + } + PandemoniumInputHandler.handleMouseEvent( event.actionMasked, MotionEvent.BUTTON_SECONDARY, event.x, - event.y + event.y, + 0f, + 0f, + false, + sourceMouseRelative ) return true } @@ -160,6 +215,7 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes } else { MotionEvent.BUTTON_PRIMARY } + PandemoniumInputHandler.handleMouseEvent(MotionEvent.ACTION_DOWN, buttonMask, x, y, true) PandemoniumInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, 0, x, y, false) @@ -191,7 +247,7 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes val x = terminusEvent.x val y = terminusEvent.y - if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled) { + if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress) { PandemoniumLib.pan(x, y, distanceX / 5f, distanceY / 5f) } else { PandemoniumInputHandler.handleMotionEvent(terminusEvent) @@ -200,7 +256,7 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes } override fun onScale(detector: ScaleGestureDetector?): Boolean { - if (detector == null || !panningAndScalingEnabled) { + if (detector == null || !panningAndScalingEnabled && !pointerCaptureInProgress) { return false } PandemoniumLib.magnify( @@ -212,7 +268,7 @@ internal class PandemoniumGestureHandler : SimpleOnGestureListener(), OnScaleGes } override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean { - if (detector == null || !panningAndScalingEnabled) { + if (detector == null || !panningAndScalingEnabled && !pointerCaptureInProgress) { return false } scaleInProgress = 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 d2455a15e..1191fa248 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 @@ -105,6 +105,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 void onPointerCaptureChange(boolean hasCapture) { + pandemoniumGestureHandler.onPointerCaptureChange(hasCapture); + } + public boolean onKeyUp(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { return true; @@ -196,6 +200,11 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener return true; } + if (pandemoniumGestureHandler.onMotionEvent(event)) { + // The gesture handler has handled the event. + return true; + } + if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getActionMasked() == MotionEvent.ACTION_MOVE) { // Check if the device exists final int deviceId = event.getDeviceId(); @@ -232,7 +241,7 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener } return true; } - } else if (isMouseEvent(event)) { + } else { return handleMouseEvent(event); } @@ -409,7 +418,11 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener } private static boolean isMouseEvent(int eventSource) { - return ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS); + boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE); + } + return mouseSource; } static boolean handleMotionEvent(final MotionEvent event) { @@ -427,6 +440,7 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) { if (isMouseEvent(eventSource)) { return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false); + //return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false); } return handleTouchEvent(eventAction, x, y); @@ -440,18 +454,30 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); - return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false); + + boolean sourceMouseRelative = false; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE); + } + return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative); } static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) { - return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false); + return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false); + } + + static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) { + return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick, false); } static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) { return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick); } - static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick) { + static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) { + // 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: @@ -464,7 +490,7 @@ public class PandemoniumInputHandler implements InputManager.InputDeviceListener case MotionEvent.ACTION_HOVER_MOVE: case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_SCROLL: { - PandemoniumLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick); + PandemoniumLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative); return true; } } diff --git a/platform/android/java_pandemonium_lib_jni.cpp b/platform/android/java_pandemonium_lib_jni.cpp index de524e068..3ca587741 100644 --- a/platform/android/java_pandemonium_lib_jni.cpp +++ b/platform/android/java_pandemonium_lib_jni.cpp @@ -278,12 +278,12 @@ JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_ } // Called on the UI thread -JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click) { +JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative) { if (step.get() <= 0) { return; } - input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click); + input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click, p_source_mouse_relative); } // Called on the UI thread diff --git a/platform/android/java_pandemonium_lib_jni.h b/platform/android/java_pandemonium_lib_jni.h index 27e21ea25..414e6e0b6 100644 --- a/platform/android/java_pandemonium_lib_jni.h +++ b/platform/android/java_pandemonium_lib_jni.h @@ -44,7 +44,7 @@ JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_ JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_newcontext(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_step(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_back(JNIEnv *env, jclass clazz); -JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click); +JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor); JNIEXPORT void JNICALL Java_net_relintai_pandemonium_pandemonium_PandemoniumLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y); diff --git a/platform/android/java_pandemonium_view_wrapper.cpp b/platform/android/java_pandemonium_view_wrapper.cpp index cf2b3b1cc..88687a2ae 100644 --- a/platform/android/java_pandemonium_view_wrapper.cpp +++ b/platform/android/java_pandemonium_view_wrapper.cpp @@ -42,12 +42,38 @@ PandemoniumJavaViewWrapper::PandemoniumJavaViewWrapper(jobject pandemonium_view) if (android_device_api_level >= __ANDROID_API_N__) { _set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V"); } + if (android_device_api_level >= __ANDROID_API_O__) { + _request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V"); + _release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V"); + } } bool PandemoniumJavaViewWrapper::can_update_pointer_icon() const { return _set_pointer_icon != nullptr; } +bool PandemoniumJavaViewWrapper::can_capture_pointer() const { + return _request_pointer_capture != nullptr && _release_pointer_capture != nullptr; +} + +void PandemoniumJavaViewWrapper::request_pointer_capture() { + if (_request_pointer_capture != nullptr) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL(env); + + env->CallVoidMethod(_pandemonium_view, _request_pointer_capture); + } +} + +void PandemoniumJavaViewWrapper::release_pointer_capture() { + if (_release_pointer_capture != nullptr) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL(env); + + env->CallVoidMethod(_pandemonium_view, _release_pointer_capture); + } +} + void PandemoniumJavaViewWrapper::set_pointer_icon(int pointer_type) { if (_set_pointer_icon != nullptr) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_pandemonium_view_wrapper.h b/platform/android/java_pandemonium_view_wrapper.h index bb6e07b94..e225117c8 100644 --- a/platform/android/java_pandemonium_view_wrapper.h +++ b/platform/android/java_pandemonium_view_wrapper.h @@ -41,12 +41,19 @@ class PandemoniumJavaViewWrapper { private: jclass _cls; jobject _pandemonium_view; + + jmethodID _request_pointer_capture = 0; + jmethodID _release_pointer_capture = 0; jmethodID _set_pointer_icon = 0; public: PandemoniumJavaViewWrapper(jobject pandemonium_view); bool can_update_pointer_icon() const; + bool can_capture_pointer() const; + + void request_pointer_capture(); + void release_pointer_capture(); void set_pointer_icon(int pointer_type); ~PandemoniumJavaViewWrapper(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 704642fa8..dc4bf1471 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -235,10 +235,11 @@ Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_han } void OS_Android::set_mouse_mode(MouseMode p_mode) { - if (!pandemonium_java->get_pandemonium_view()->can_update_pointer_icon()) { + if (!pandemonium_java->get_pandemonium_view()->can_update_pointer_icon() || !pandemonium_java->get_pandemonium_view()->can_capture_pointer()) { return; } - if (mouse_mode == p_mode || p_mode == MouseMode::MOUSE_MODE_CAPTURED) { + + if (mouse_mode == p_mode) { return; } @@ -248,6 +249,12 @@ void OS_Android::set_mouse_mode(MouseMode p_mode) { set_cursor_shape(cursor_shape); } + if (p_mode == MouseMode::MOUSE_MODE_CAPTURED) { + pandemonium_java->get_pandemonium_view()->request_pointer_capture(); + } else { + pandemonium_java->get_pandemonium_view()->release_pointer_capture(); + } + mouse_mode = p_mode; }