From b4ebd1868acce201c23c9532cff9cd7eac22b59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= <63123542+m-bert@users.noreply.github.com> Date: Tue, 20 Feb 2024 14:05:40 +0100 Subject: [PATCH] Add `mouseButton` implementation on Android (#2680) ## Description This PR adds implementation of `mouseButton` prop on android. Since `actionButton` field is available only in API >= 23, we provide full support only for those versions. The only thing that changes for API < 23 is ignoring `ACTION_BUTTON_*`, because we don't want handlers to react to both type of events. Note that it requires [this PR](https://github.com/software-mansion/react-native-gesture-handler/pull/2676) to work. ## Test plan Tested on `MouseButtons` example. --- .../core/FlingGestureHandler.kt | 4 ++ .../gesturehandler/core/GestureHandler.kt | 47 +++++++++++++++++++ .../core/LongPressGestureHandler.kt | 6 ++- .../gesturehandler/core/PanGestureHandler.kt | 6 ++- .../gesturehandler/core/TapGestureHandler.kt | 10 ++-- .../react/RNGestureHandlerModule.kt | 3 ++ src/web/interfaces.ts | 4 +- 7 files changed, 73 insertions(+), 7 deletions(-) diff --git a/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt b/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt index e3078d0dbf..75acef796a 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt @@ -67,6 +67,10 @@ class FlingGestureHandler : GestureHandler() { } override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + if (!shouldActivateWithMouse(sourceEvent)) { + return + } + val state = state if (state == STATE_UNDETERMINED) { startFling(sourceEvent) diff --git a/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt b/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt index 5cb420ad2b..93780407fd 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt @@ -5,6 +5,7 @@ import android.content.Context import android.content.ContextWrapper import android.graphics.PointF import android.graphics.Rect +import android.os.Build import android.view.MotionEvent import android.view.MotionEvent.PointerCoords import android.view.MotionEvent.PointerProperties @@ -68,6 +69,8 @@ open class GestureHandler= 23, we will use events with infix BUTTON, otherwise we use standard action events (like ACTION_DOWN). + + with(sourceEvent) { + // To use actionButton, we need API >= 23. + if (getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // While using mouse, we want to ignore default events for touch. + if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) { + return@shouldActivateWithMouse false + } + + // We don't want to do anything if wrong button was clicked. If we received event for BUTTON, we have to use actionButton to get which one was clicked. + if (action != MotionEvent.ACTION_MOVE && !isButtonInConfig(actionButton)) { + return@shouldActivateWithMouse false + } + + // When we receive ACTION_MOVE, we have to check buttonState field. + if (action == MotionEvent.ACTION_MOVE && !isButtonInConfig(buttonState)) { + return@shouldActivateWithMouse false + } + } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + // We do not fully support mouse below API 23, so we will ignore BUTTON events. + if (action == MotionEvent.ACTION_BUTTON_PRESS || action == MotionEvent.ACTION_BUTTON_RELEASE) { + return@shouldActivateWithMouse false + } + } + } + + return true + } + /** * Transforms a point in the coordinate space of the wrapperView (GestureHandlerRootView) to * coordinate space of the view the gesture is attached to. diff --git a/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt b/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt index 23a72545a0..38cd67386d 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt @@ -38,6 +38,10 @@ class LongPressGestureHandler(context: Context) : GestureHandler() } override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + if (!shouldActivateWithMouse(sourceEvent)) { + return + } + val state = state val action = sourceEvent.actionMasked if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_POINTER_DOWN) { @@ -246,7 +250,7 @@ class PanGestureHandler(context: Context?) : GestureHandler() velocityX = velocityTracker!!.xVelocity velocityY = velocityTracker!!.yVelocity } - if (action == MotionEvent.ACTION_UP) { + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_BUTTON_RELEASE) { if (state == STATE_ACTIVE) { end() } else { diff --git a/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt b/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt index cb8adc77b1..703ba7a0cf 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt @@ -105,6 +105,10 @@ class TapGestureHandler : GestureHandler() { } override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { + if (!shouldActivateWithMouse(sourceEvent)) { + return + } + val state = state val action = sourceEvent.actionMasked if (state == STATE_UNDETERMINED) { @@ -130,14 +134,14 @@ class TapGestureHandler : GestureHandler() { if (shouldFail()) { fail() } else if (state == STATE_UNDETERMINED) { - if (action == MotionEvent.ACTION_DOWN) { + if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_BUTTON_PRESS) { begin() } startTap() } else if (state == STATE_BEGAN) { - if (action == MotionEvent.ACTION_UP) { + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_BUTTON_RELEASE) { endTap() - } else if (action == MotionEvent.ACTION_DOWN) { + } else if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_BUTTON_PRESS) { startTap() } } diff --git a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt index c8aa3122d3..68c108e87b 100644 --- a/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt +++ b/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt @@ -71,6 +71,9 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) : if (config.hasKey(KEY_MANUAL_ACTIVATION)) { handler.setManualActivation(config.getBoolean(KEY_MANUAL_ACTIVATION)) } + if (config.hasKey("mouseButton")) { + handler.setMouseButton(config.getInt("mouseButton")) + } } abstract fun createEventBuilder(handler: T): GestureHandlerEventDataBuilder diff --git a/src/web/interfaces.ts b/src/web/interfaces.ts index 155ee59a43..43c44baa95 100644 --- a/src/web/interfaces.ts +++ b/src/web/interfaces.ts @@ -133,8 +133,8 @@ export interface AdaptedEvent { export enum MouseButton { LEFT = 1, - MIDDLE = 2, - RIGHT = 4, + RIGHT = 2, + MIDDLE = 4, BUTTON_4 = 8, BUTTON_5 = 16, ALL = 31,