From 3460ff5d0492bb70806afec9c3c0b5edc00a7908 Mon Sep 17 00:00:00 2001 From: Alex Danoff Date: Thu, 6 Jul 2023 10:26:42 -0700 Subject: [PATCH] W3CPointerEvents: include screen coordinates in pointer events (#38222) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/38222 Changelog: [Android] [Fixed] - W3CPointerEvents: include screen coordinates in pointer events The [spec](https://www.w3.org/TR/uievents/#idl-mouseevent) says there should be properties on mouse events (and hence pointer events) indicating the screen coordinates of the event (i.e. coords relative to screen of the device). This change adds those properties. Reviewed By: javache Differential Revision: D47162962 fbshipit-source-id: 5bb9780882459b3550bbac792b7d7cf9f5c10860 --- .../react/uimanager/JSPointerDispatcher.java | 23 +++++++++++++++++++ .../react/uimanager/events/PointerEvent.java | 13 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java index 4d61f51c56f358..d65ecbea8bcfbc 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/JSPointerDispatcher.java @@ -50,6 +50,8 @@ public class JSPointerDispatcher { private int mLastButtonState = 0; private final ViewGroup mRootViewGroup; + private static final int[] sRootScreenCoords = {0, 0}; + // Set globally for hover interactions, referenced for coalescing hover events public JSPointerDispatcher(ViewGroup viewGroup) { @@ -255,10 +257,21 @@ private void onDown( } } + private float[] eventCoordsToScreenCoords(float[] eventCoords) { + float[] screenCoords = new float[2]; + mRootViewGroup.getLocationOnScreen(sRootScreenCoords); + + screenCoords[0] = eventCoords[0] + sRootScreenCoords[0]; + screenCoords[1] = eventCoords[1] + sRootScreenCoords[1]; + + return screenCoords; + } + private PointerEventState createEventState(int activePointerId, MotionEvent motionEvent) { Map offsetByPointerId = new HashMap(); Map> hitPathByPointerId = new HashMap>(); Map eventCoordinatesByPointerId = new HashMap(); + Map screenCoordinatesByPointerId = new HashMap(); for (int index = 0; index < motionEvent.getPointerCount(); index++) { float[] offsetCoordinates = new float[2]; float[] eventCoordinates = new float[] {motionEvent.getX(index), motionEvent.getY(index)}; @@ -270,6 +283,7 @@ private PointerEventState createEventState(int activePointerId, MotionEvent moti offsetByPointerId.put(pointerId, offsetCoordinates); hitPathByPointerId.put(pointerId, hitPath); eventCoordinatesByPointerId.put(pointerId, eventCoordinates); + screenCoordinatesByPointerId.put(pointerId, eventCoordsToScreenCoords(eventCoordinates)); } int surfaceId = UIManagerHelper.getSurfaceId(mRootViewGroup); @@ -282,6 +296,7 @@ private PointerEventState createEventState(int activePointerId, MotionEvent moti offsetByPointerId, hitPathByPointerId, eventCoordinatesByPointerId, + screenCoordinatesByPointerId, mHoveringPointerIds); // Creates a copy of hovering pointer ids, as they may be updated } @@ -673,6 +688,8 @@ private int[] getChildOffsetRelativeToRoot(View childView) { private PointerEventState normalizeToRoot(PointerEventState original, float rootX, float rootY) { Map newOffsets = new HashMap<>(original.getOffsetByPointerId()); Map newEventCoords = new HashMap<>(original.getEventCoordinatesByPointerId()); + Map newScreenCoords = + new HashMap<>(original.getScreenCoordinatesByPointerId()); float[] rootOffset = {rootX, rootY}; for (Map.Entry offsetEntry : newOffsets.entrySet()) { @@ -684,6 +701,11 @@ private PointerEventState normalizeToRoot(PointerEventState original, float root eventCoordsEntry.setValue(zeroOffset); } + float[] screenCoords = eventCoordsToScreenCoords(rootOffset); + for (Map.Entry screenCoordsEntry : newScreenCoords.entrySet()) { + screenCoordsEntry.setValue(screenCoords); + } + return new PointerEventState( original.getPrimaryPointerId(), original.getActivePointerId(), @@ -692,6 +714,7 @@ private PointerEventState normalizeToRoot(PointerEventState original, float root newOffsets, new HashMap<>(original.getHitPathByPointerId()), newEventCoords, + newScreenCoords, new HashSet<>(original.getHoveringPointerIds())); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java index d0f221d127de7c..66f3c1bdcfc12c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/PointerEvent.java @@ -215,6 +215,12 @@ private WritableMap createW3CPointerEvent(int index) { pointerEvent.putDouble("clientX", clientX); pointerEvent.putDouble("clientY", clientY); + float[] screenCoords = mEventState.getScreenCoordinatesByPointerId().get(pointerId); + double screenX = PixelUtil.toDIPFromPixel(screenCoords[0]); + double screenY = PixelUtil.toDIPFromPixel(screenCoords[1]); + pointerEvent.putDouble("screenX", screenX); + pointerEvent.putDouble("screenY", screenY); + // x,y values are aliases of clientX, clientY pointerEvent.putDouble("x", clientX); pointerEvent.putDouble("y", clientY); @@ -338,6 +344,7 @@ public static class PointerEventState { private Map mOffsetByPointerId; private Map> mHitPathByPointerId; private Map mEventCoordinatesByPointerId; + private Map mScreenCoordinatesByPointerId; private Set mHoveringPointerIds; public PointerEventState( @@ -348,6 +355,7 @@ public PointerEventState( Map offsetByPointerId, Map> hitPathByPointerId, Map eventCoordinatesByPointerId, + Map screenCoordinatesByPointerId, Set hoveringPointerIds) { mPrimaryPointerId = primaryPointerId; mActivePointerId = activePointerId; @@ -356,6 +364,7 @@ public PointerEventState( mOffsetByPointerId = offsetByPointerId; mHitPathByPointerId = hitPathByPointerId; mEventCoordinatesByPointerId = eventCoordinatesByPointerId; + mScreenCoordinatesByPointerId = screenCoordinatesByPointerId; mHoveringPointerIds = new HashSet<>(hoveringPointerIds); } @@ -395,6 +404,10 @@ public final Map getEventCoordinatesByPointerId() { return mEventCoordinatesByPointerId; } + public final Map getScreenCoordinatesByPointerId() { + return mScreenCoordinatesByPointerId; + } + public final List getHitPathForActivePointer() { return mHitPathByPointerId.get(mActivePointerId); }