Add support for pointerover and pointerout

Summary: Changelog: [Internal] - Add pointerover, pointerout events

Reviewed By: vincentriemer

Differential Revision: D38559454

fbshipit-source-id: 829b9f2f22e1e41a64dcce80fcc79ab9e6352dcf
This commit is contained in:
Luna Wei
2022-08-15 12:51:58 -07:00
committed by Facebook GitHub Bot
parent 92e4ed6a28
commit dfcd9faaad
11 changed files with 210 additions and 17 deletions
@@ -58,6 +58,10 @@ constexpr MapBuffer::Key VP_ZINDEX = 34;
constexpr MapBuffer::Key VP_POINTER_ENTER_CAPTURE = 38;
constexpr MapBuffer::Key VP_POINTER_LEAVE_CAPTURE = 39;
constexpr MapBuffer::Key VP_POINTER_MOVE_CAPTURE = 40;
constexpr MapBuffer::Key VP_POINTER_OVER = 41;
constexpr MapBuffer::Key VP_POINTER_OVER_CAPTURE = 42;
constexpr MapBuffer::Key VP_POINTER_OUT = 43;
constexpr MapBuffer::Key VP_POINTER_OUT_CAPTURE = 44;
// Yoga values
constexpr MapBuffer::Key YG_BORDER_WIDTH = 100;
@@ -475,6 +479,17 @@ static inline MapBuffer viewPropsDiff(
builder.putBool(
VP_POINTER_MOVE_CAPTURE,
newProps.events[ViewEvents::Offset::PointerMoveCapture]);
builder.putBool(
VP_POINTER_OVER, newProps.events[ViewEvents::Offset::PointerOver]);
builder.putBool(
VP_POINTER_OVER_CAPTURE,
newProps.events[ViewEvents::Offset::PointerOverCapture]);
builder.putBool(
VP_POINTER_OUT, newProps.events[ViewEvents::Offset::PointerOut]);
builder.putBool(
VP_POINTER_OUT_CAPTURE,
newProps.events[ViewEvents::Offset::PointerOutCapture]);
}
if (oldProps.removeClippedSubviews != newProps.removeClippedSubviews) {
@@ -584,6 +584,16 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onPointerUp", "captured", "onPointerUpCapture")))
.put(
"topPointerOut",
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onPointerOut", "captured", "onPointerOutCapture")))
.put(
"topPointerOver",
MapBuilder.of(
"phasedRegistrationNames",
MapBuilder.of("bubbled", "onPointerOver", "captured", "onPointerOverCapture")))
.build());
return eventTypeConstants;
}
@@ -643,6 +653,26 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
view.setTag(R.id.pointer_enter_capture, value);
}
@ReactProp(name = "onPointerOver")
public void setPointerOver(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_over, value);
}
@ReactProp(name = "onPointerOverCapture")
public void setPointerOverCapture(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_over_capture, value);
}
@ReactProp(name = "onPointerOut")
public void setPointerOut(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_out, value);
}
@ReactProp(name = "onPointerOutCapture")
public void setPointerOutCapture(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_out_capture, value);
}
@ReactProp(name = "onPointerLeave")
public void setPointerLeave(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_leave, value);
@@ -119,6 +119,20 @@ public class JSPointerDispatcher {
mTouchEventCoalescingKeyHelper.addCoalescingKey(mDownStartTime);
if (!supportsHover) {
// Indirect OVER event dispatches before ENTER
boolean listeningForOver =
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OVER, EVENT.OVER_CAPTURE);
if (listeningForOver) {
eventDispatcher.dispatchEvent(
PointerEvent.obtain(
PointerEventHelper.POINTER_OVER,
surfaceId,
activeTargetTag,
motionEvent,
mTargetCoordinates,
mPrimaryPointerId));
}
List<ViewTarget> enterViewTargets =
filterByShouldDispatch(hitPath, EVENT.ENTER, EVENT.ENTER_CAPTURE, false);
@@ -158,6 +172,8 @@ public class JSPointerDispatcher {
if (action == MotionEvent.ACTION_POINTER_DOWN) {
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
// TODO(luwe) We need to fire indirect over,enter events for secondary pointers
boolean listeningForDown =
isAnyoneListeningForBubblingEvent(hitPath, EVENT.DOWN, EVENT.DOWN_CAPTURE);
if (listeningForDown) {
@@ -198,6 +214,8 @@ public class JSPointerDispatcher {
if (action == MotionEvent.ACTION_POINTER_UP) {
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mDownStartTime);
// TODO(luwe) We need to fire indirect out,leave events for secondary pointers
boolean listeningForUp =
isAnyoneListeningForBubblingEvent(hitPath, EVENT.UP, EVENT.UP_CAPTURE);
if (listeningForUp) {
@@ -235,6 +253,19 @@ public class JSPointerDispatcher {
}
if (!supportsHover) {
boolean listeningForOut =
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
if (listeningForOut) {
eventDispatcher.dispatchEvent(
PointerEvent.obtain(
PointerEventHelper.POINTER_OUT,
surfaceId,
activeTargetTag,
motionEvent,
mTargetCoordinates,
mPrimaryPointerId));
}
List<ViewTarget> leaveViewTargets =
filterByShouldDispatch(hitPath, EVENT.LEAVE, EVENT.LEAVE_CAPTURE, false);
@@ -408,6 +439,53 @@ public class JSPointerDispatcher {
// If something has changed in either enter/exit, let's start a new coalescing key
mTouchEventCoalescingKeyHelper.incrementCoalescingKey(mHoverInteractionKey);
// Out, Leave events
if (mLastHitPath.size() > 0) {
int lastTargetTag = mLastHitPath.get(0).getViewId();
boolean listeningForOut =
isAnyoneListeningForBubblingEvent(mLastHitPath, EVENT.OUT, EVENT.OUT_CAPTURE);
if (listeningForOut) {
eventDispatcher.dispatchEvent(
PointerEvent.obtain(
PointerEventHelper.POINTER_OUT,
surfaceId,
lastTargetTag,
motionEvent,
mTargetCoordinates,
mPrimaryPointerId));
}
// target -> root
List<ViewTarget> leaveViewTargets =
filterByShouldDispatch(
mLastHitPath.subList(0, mLastHitPath.size() - firstDivergentIndexFromBack),
EVENT.LEAVE,
EVENT.LEAVE_CAPTURE,
nonDivergentListeningToLeave);
if (leaveViewTargets.size() > 0) {
// We want to dispatch from target -> root, so no need to reverse
dispatchEventForViewTargets(
PointerEventHelper.POINTER_LEAVE,
leaveViewTargets,
eventDispatcher,
surfaceId,
motionEvent);
}
}
boolean listeningForOver =
isAnyoneListeningForBubblingEvent(hitPath, EVENT.OVER, EVENT.OVER_CAPTURE);
if (listeningForOver) {
eventDispatcher.dispatchEvent(
PointerEvent.obtain(
PointerEventHelper.POINTER_OVER,
surfaceId,
targetTag,
motionEvent,
mTargetCoordinates,
mPrimaryPointerId));
}
// target -> root
List<ViewTarget> enterViewTargets =
filterByShouldDispatch(
@@ -426,23 +504,6 @@ public class JSPointerDispatcher {
surfaceId,
motionEvent);
}
// target -> root
List<ViewTarget> leaveViewTargets =
filterByShouldDispatch(
mLastHitPath.subList(0, mLastHitPath.size() - firstDivergentIndexFromBack),
EVENT.LEAVE,
EVENT.LEAVE_CAPTURE,
nonDivergentListeningToLeave);
if (leaveViewTargets.size() > 0) {
// We want to dispatch from target -> root, so no need to reverse
dispatchEventForViewTargets(
PointerEventHelper.POINTER_LEAVE,
leaveViewTargets,
eventDispatcher,
surfaceId,
motionEvent);
}
}
int coalescingKey = mTouchEventCoalescingKeyHelper.getCoalescingKey(mHoverInteractionKey);
@@ -218,6 +218,8 @@ public class PointerEvent extends Event<PointerEvent> {
case PointerEventHelper.POINTER_DOWN:
case PointerEventHelper.POINTER_UP:
case PointerEventHelper.POINTER_LEAVE:
case PointerEventHelper.POINTER_OUT:
case PointerEventHelper.POINTER_OVER:
pointersEventData = Arrays.asList(createPointerEventData(activePointerIndex));
break;
}
@@ -36,6 +36,10 @@ public class PointerEventHelper {
MOVE_CAPTURE,
UP,
UP_CAPTURE,
OUT,
OUT_CAPTURE,
OVER,
OVER_CAPTURE,
};
public static final String POINTER_CANCEL = "topPointerCancel";
@@ -44,6 +48,8 @@ public class PointerEventHelper {
public static final String POINTER_LEAVE = "topPointerLeave";
public static final String POINTER_MOVE = "topPointerMove";
public static final String POINTER_UP = "topPointerUp";
public static final String POINTER_OVER = "topPointerOver";
public static final String POINTER_OUT = "topPointerOut";
/** We don't dispatch capture events from native; that's currently handled by JS. */
public static @Nullable String getDispatchableEventName(EVENT event) {
@@ -60,6 +66,10 @@ public class PointerEventHelper {
return PointerEventHelper.POINTER_CANCEL;
case UP:
return PointerEventHelper.POINTER_UP;
case OVER:
return PointerEventHelper.POINTER_OVER;
case OUT:
return PointerEventHelper.POINTER_OUT;
default:
FLog.e(ReactConstants.TAG, "No dispatchable event name for type: " + event);
return null;
@@ -121,6 +131,18 @@ public class PointerEventHelper {
case MOVE_CAPTURE:
value = view.getTag(R.id.pointer_move_capture);
break;
case OVER:
value = view.getTag(R.id.pointer_over);
break;
case OVER_CAPTURE:
value = view.getTag(R.id.pointer_over_capture);
break;
case OUT:
value = view.getTag(R.id.pointer_out);
break;
case OUT_CAPTURE:
value = view.getTag(R.id.pointer_out_capture);
break;
}
if (value == null) {
@@ -147,6 +169,8 @@ public class PointerEventHelper {
case POINTER_MOVE:
case POINTER_ENTER:
case POINTER_LEAVE:
case POINTER_OVER:
case POINTER_OUT:
return EventCategoryDef.CONTINUOUS;
}
@@ -58,6 +58,10 @@ object ReactMapBufferPropSetter {
private const val VP_POINTER_ENTER_CAPTURE = 38
private const val VP_POINTER_LEAVE_CAPTURE = 39
private const val VP_POINTER_MOVE_CAPTURE = 40
private const val VP_POINTER_OUT = 41
private const val VP_POINTER_OUT_CAPTURE = 42
private const val VP_POINTER_OVER = 43
private const val VP_POINTER_OVER_CAPTURE = 44
// Yoga values
private const val YG_BORDER_WIDTH = 100
@@ -197,6 +201,18 @@ object ReactMapBufferPropSetter {
VP_POINTER_MOVE_CAPTURE -> {
viewManager.setPointerMoveCapture(view, entry.booleanValue)
}
VP_POINTER_OUT -> {
viewManager.setPointerOut(view, entry.booleanValue)
}
VP_POINTER_OUT_CAPTURE -> {
viewManager.setPointerOutCapture(view, entry.booleanValue)
}
VP_POINTER_OVER -> {
viewManager.setPointerOver(view, entry.booleanValue)
}
VP_POINTER_OVER_CAPTURE -> {
viewManager.setPointerOverCapture(view, entry.booleanValue)
}
VP_REMOVE_CLIPPED_SUBVIEW -> {
viewManager.setRemoveClippedSubviews(view, entry.booleanValue)
}