99#include < IReactContext.h>
1010#include < React.h>
1111#include < Views/DevMenu.h>
12- #include < Views/ShadowNodeBase.h>
1312#include < windows.h>
1413#include < windowsx.h>
1514#include < winrt/Windows.UI.Core.h>
@@ -637,17 +636,6 @@ void CompositionEventHandler::HandleIncomingPointerEvent(
637636
638637 auto eventPathViews = GetTouchableViewsInPathToRoot (targetView);
639638
640- // Over
641- if (targetView != nullptr && previousTargetTag != targetView.Tag ()) {
642- bool shouldEmitOverEvent =
643- IsAnyViewInPathListeningToEvent (eventPathViews, facebook::react::ViewEvents::Offset::PointerOver);
644- const auto eventEmitter = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(targetView)
645- ->eventEmitterAtPoint (event.offsetPoint );
646- if (shouldEmitOverEvent && eventEmitter != nullptr ) {
647- eventEmitter->onPointerOver (event);
648- }
649- }
650-
651639 // Entering
652640
653641 // We only want to emit events to JS if there is a view that is currently listening to said event
@@ -664,7 +652,6 @@ void CompositionEventHandler::HandleIncomingPointerEvent(
664652 auto componentView = *itComponentView;
665653 bool shouldEmitEvent = componentView != nullptr &&
666654 (hasParentEnterListener ||
667- IsViewListeningToEvent (componentView, facebook::react::ViewEvents::Offset::PointerEnter) ||
668655 IsViewListeningToEvent (componentView, facebook::react::WindowsViewEvents::Offset::MouseEnter));
669656
670657 if (std::find (currentlyHoveredViews.begin (), currentlyHoveredViews.end (), componentView) ==
@@ -674,16 +661,12 @@ void CompositionEventHandler::HandleIncomingPointerEvent(
674661 m_context, componentView.Tag (), pointerPoint, keyModifiers);
675662 winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(componentView)
676663 ->OnPointerEntered (args);
677-
678664 if (shouldEmitEvent) {
679665 const auto eventEmitter =
680666 winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(componentView)
681667 ->eventEmitter ();
682- if (eventEmitter) {
683- eventEmitter->onPointerEnter (event);
684- if (IsMousePointerEvent (event)) {
685- eventEmitter->onMouseEnter (event);
686- }
668+ if (eventEmitter && IsMousePointerEvent (event)) {
669+ eventEmitter->onMouseEnter (event);
687670 }
688671 }
689672 }
@@ -696,41 +679,25 @@ void CompositionEventHandler::HandleIncomingPointerEvent(
696679 // Call the underlaying pointer handler
697680 handler (eventPathViews);
698681
699- // Out
700- if (previousTargetTag != -1 && previousTargetTag != (targetView ? targetView.Tag () : -1 )) {
701- bool shouldEmitOutEvent =
702- IsAnyViewInPathListeningToEvent (currentlyHoveredViews, facebook::react::ViewEvents::Offset::PointerOut);
703- const auto eventEmitter =
704- winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(prevTargetView)->eventEmitter ();
705- if (shouldEmitOutEvent && eventEmitter != nullptr ) {
706- eventEmitter->onPointerOut (event);
707- }
708- }
709-
710682 // Leaving
711683
712684 // pointerleave events need to be emitted from the deepest target to the root but
713685 // we also need to efficiently keep track of if a view has a parent which is listening to the leave events,
714686 // so we first iterate from the root to the target, collecting the views which need events fired for, of which
715687 // we reverse iterate (now from target to root), actually emitting the events.
716- std::vector<winrt::Microsoft::ReactNative::ComponentView>
717- viewsToEmitJSLeaveEventsTo; // NSMutableOrderedSet<UIView *> *viewsToEmitLeaveEventsTo =
718- // [NSMutableOrderedSet orderedSet];
688+ std::vector<winrt::Microsoft::ReactNative::ComponentView> viewsToEmitJSLeaveEventsTo;
719689
720690 std::vector<winrt::Microsoft::ReactNative::ComponentView> viewsToEmitLeaveEventsTo;
721691
722692 winrt::Microsoft::ReactNative::ComponentView viewToEmitNativeExitedEvent{nullptr };
723693
724694 bool hasParentLeaveListener = false ;
725695 for (auto itComponentView = currentlyHoveredViews.rbegin (); itComponentView != currentlyHoveredViews.rend ();
726- itComponentView++) { // for (RCTReactTaggedView *taggedView in [currentlyHoveredViews
727- // reverseObjectEnumerator])
728- // {
696+ itComponentView++) {
729697 auto componentView = *itComponentView;
730698
731699 bool shouldEmitJSEvent = componentView != nullptr &&
732700 (hasParentLeaveListener ||
733- IsViewListeningToEvent (componentView, facebook::react::ViewEvents::Offset::PointerLeave) ||
734701 IsViewListeningToEvent (componentView, facebook::react::WindowsViewEvents::Offset::MouseLeave));
735702
736703 if (std::find (eventPathViews.begin (), eventPathViews.end (), componentView) == eventPathViews.end ()) {
@@ -755,17 +722,13 @@ void CompositionEventHandler::HandleIncomingPointerEvent(
755722 }
756723
757724 for (auto itComponentView = viewsToEmitJSLeaveEventsTo.rbegin (); itComponentView != viewsToEmitJSLeaveEventsTo.rend ();
758- itComponentView++) { // for (UIView *componentView in [viewsToEmitJSLeaveEventsTo
759- // reverseObjectEnumerator]) {
725+ itComponentView++) {
760726 auto componentView = *itComponentView;
761727
762728 const auto eventEmitter =
763729 winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(componentView)->eventEmitter ();
764- if (eventEmitter) {
765- eventEmitter->onPointerLeave (event);
766- if (IsMousePointerEvent (event)) {
767- eventEmitter->onMouseLeave (event);
768- }
730+ if (eventEmitter && IsMousePointerEvent (event)) {
731+ eventEmitter->onMouseLeave (event);
769732 }
770733 }
771734
@@ -815,41 +778,39 @@ void CompositionEventHandler::SetCursor(facebook::react::Cursor cursor, HCURSOR
815778 case facebook::react::Cursor::Pointer:
816779 type = winrt::Windows::UI::Core::CoreCursorType::Hand;
817780 break ;
818- /* -- Additional cursors not added in core until later version
819- case facebook::react::Cursor::Help:
820- type = winrt::Windows::UI::Core::CoreCursorType::Help;
821- break;
822- case facebook::react::Cursor::NotAllowed:
823- type = winrt::Windows::UI::Core::CoreCursorType::UniversalNo;
824- break;
825- case facebook::react::Cursor::Wait:
826- type = winrt::Windows::UI::Core::CoreCursorType::Wait;
827- break;
828- case facebook::react::Cursor::Move:
829- type = winrt::Windows::UI::Core::CoreCursorType::SizeAll;
830- break;
831- case facebook::react::Cursor::NESWResize:
832- type = winrt::Windows::UI::Core::CoreCursorType::SizeNortheastSouthwest;
833- break;
834- case facebook::react::Cursor::NSResize:
835- type = winrt::Windows::UI::Core::CoreCursorType::SizeNorthSouth;
836- break;
837- case facebook::react::Cursor::NWSEResize:
838- type = winrt::Windows::UI::Core::CoreCursorType::SizeNorthwestSoutheast;
839- break;
840- case facebook::react::Cursor::EWResize:
841- type = winrt::Windows::UI::Core::CoreCursorType::SizeWestEast;
842- break;
843- case facebook::react::Cursor::Text:
844- type = winrt::Windows::UI::Core::CoreCursorType::IBeam;
845- break;
846- case facebook::react::Cursor::Progress:
847- type = winrt::Windows::UI::Core::CoreCursorType::Wait; // IDC_APPSTARTING not mapped to CoreCursor?
848- break;
849- case facebook::react::Cursor::Crosshair:
850- type = winrt::Windows::UI::Core::CoreCursorType::Cross;
851- break;
852- */
781+ case facebook::react::Cursor::Help:
782+ type = winrt::Windows::UI::Core::CoreCursorType::Help;
783+ break ;
784+ case facebook::react::Cursor::NotAllowed:
785+ type = winrt::Windows::UI::Core::CoreCursorType::UniversalNo;
786+ break ;
787+ case facebook::react::Cursor::Wait:
788+ type = winrt::Windows::UI::Core::CoreCursorType::Wait;
789+ break ;
790+ case facebook::react::Cursor::Move:
791+ type = winrt::Windows::UI::Core::CoreCursorType::SizeAll;
792+ break ;
793+ case facebook::react::Cursor::NESWResize:
794+ type = winrt::Windows::UI::Core::CoreCursorType::SizeNortheastSouthwest;
795+ break ;
796+ case facebook::react::Cursor::NSResize:
797+ type = winrt::Windows::UI::Core::CoreCursorType::SizeNorthSouth;
798+ break ;
799+ case facebook::react::Cursor::NWSEResize:
800+ type = winrt::Windows::UI::Core::CoreCursorType::SizeNorthwestSoutheast;
801+ break ;
802+ case facebook::react::Cursor::EWResize:
803+ type = winrt::Windows::UI::Core::CoreCursorType::SizeWestEast;
804+ break ;
805+ case facebook::react::Cursor::Text:
806+ type = winrt::Windows::UI::Core::CoreCursorType::IBeam;
807+ break ;
808+ case facebook::react::Cursor::Progress:
809+ type = winrt::Windows::UI::Core::CoreCursorType::Wait; // IDC_APPSTARTING not mapped to CoreCursor?
810+ break ;
811+ case facebook::react::Cursor::Crosshair:
812+ type = winrt::Windows::UI::Core::CoreCursorType::Cross;
813+ break ;
853814 default :
854815 break ;
855816 }
@@ -880,7 +841,6 @@ void CompositionEventHandler::SetCursor(facebook::react::Cursor cursor, HCURSOR
880841 case facebook::react::Cursor::Pointer:
881842 idc = IDC_HAND;
882843 break ;
883- /* -- Additional cursors not added in core until later version
884844 case facebook::react::Cursor::Help:
885845 idc = IDC_HELP;
886846 break ;
@@ -914,7 +874,6 @@ void CompositionEventHandler::SetCursor(facebook::react::Cursor cursor, HCURSOR
914874 case facebook::react::Cursor::Crosshair:
915875 idc = IDC_CROSS;
916876 break ;
917- */
918877 default :
919878 break ;
920879 }
@@ -1064,21 +1023,48 @@ void CompositionEventHandler::onPointerMoved(
10641023
10651024 facebook::react::PointerEvent pointerEvent = CreatePointerEventFromIncompleteHoverData (ptScaled, ptLocal);
10661025
1067- auto handler = [&targetView,
1068- &pointerEvent](std::vector<winrt::Microsoft::ReactNative::ComponentView> &eventPathViews) {
1026+ // check if this pointer corresponds to active touch that has a responder
1027+ auto activeTouch = m_activeTouches.find (pointerId);
1028+ bool isActiveTouch = activeTouch != m_activeTouches.end () && activeTouch->second .eventEmitter != nullptr ;
1029+
1030+ auto handler = [&, targetView, pointerEvent, isActiveTouch](
1031+ std::vector<winrt::Microsoft::ReactNative::ComponentView> &eventPathViews) {
10691032 const auto eventEmitter = targetView
10701033 ? winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(targetView)
10711034 ->eventEmitterAtPoint (pointerEvent.offsetPoint )
1072- : nullptr ;
1073- bool hasMoveEventListeners =
1074- IsAnyViewInPathListeningToEvent (eventPathViews, facebook::react::ViewEvents::Offset::PointerMove) ||
1075- IsAnyViewInPathListeningToEvent (eventPathViews, facebook::react::ViewEvents::Offset::PointerMoveCapture);
1076- if (eventEmitter != nullptr && hasMoveEventListeners) {
1035+ : RootComponentView ().eventEmitterAtPoint (pointerEvent.offsetPoint );
1036+
1037+ if (eventEmitter != nullptr ) {
10771038 eventEmitter->onPointerMove (pointerEvent);
1039+ } else {
1040+ ClearAllHoveredForPointer (pointerEvent);
10781041 }
10791042 };
10801043
10811044 HandleIncomingPointerEvent (pointerEvent, targetView, pointerPoint, keyModifiers, handler);
1045+
1046+ if (isActiveTouch) {
1047+ // For active touches with responders, also dispatch through touch event system
1048+ UpdateActiveTouch (activeTouch->second , ptScaled, ptLocal);
1049+ DispatchTouchEvent (TouchEventType::Move, pointerId, pointerPoint, keyModifiers);
1050+ }
1051+ }
1052+ }
1053+
1054+ void CompositionEventHandler::ClearAllHoveredForPointer (const facebook::react::PointerEvent &pointerEvent) noexcept {
1055+ // special case if we have no target
1056+ // PointerEventsProcessor requires move events to keep track of the hovered components in core.
1057+ // It also treats a onPointerLeave event as a special case that removes the hover state of all currently hovered
1058+ // events. If we get null for the targetView, that means that the mouse is no over any components, so we have no
1059+ // element to send the move event to. However we need to send something so that any previously hovered elements
1060+ // are no longer hovered.
1061+ auto children = RootComponentView ().Children ();
1062+ if (auto size = children.Size ()) {
1063+ auto firstChild = children.GetAt (0 );
1064+ if (auto childEventEmitter =
1065+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(firstChild)->eventEmitter ()) {
1066+ childEventEmitter->onPointerLeave (pointerEvent);
1067+ }
10821068 }
10831069}
10841070
@@ -1104,7 +1090,9 @@ void CompositionEventHandler::onPointerExited(
11041090
11051091 facebook::react::PointerEvent pointerEvent = CreatePointerEventFromIncompleteHoverData (ptScaled, ptLocal);
11061092
1107- auto handler = [](std::vector<winrt::Microsoft::ReactNative::ComponentView> &eventPathViews) {};
1093+ auto handler = [&](std::vector<winrt::Microsoft::ReactNative::ComponentView> &eventPathViews) {
1094+ ClearAllHoveredForPointer (pointerEvent);
1095+ };
11081096
11091097 HandleIncomingPointerEvent (pointerEvent, nullptr , pointerPoint, keyModifiers, handler);
11101098 }
@@ -1392,12 +1380,7 @@ void CompositionEventHandler::DispatchTouchEvent(
13921380 activeTouch.eventEmitter ->onPointerDown (pointerEvent);
13931381 break ;
13941382 case TouchEventType::Move: {
1395- bool hasMoveEventListeners =
1396- IsAnyViewInPathListeningToEvent (eventPathViews, facebook::react::ViewEvents::Offset::PointerMove) ||
1397- IsAnyViewInPathListeningToEvent (eventPathViews, facebook::react::ViewEvents::Offset::PointerMoveCapture);
1398- if (hasMoveEventListeners) {
1399- activeTouch.eventEmitter ->onPointerMove (pointerEvent);
1400- }
1383+ activeTouch.eventEmitter ->onPointerMove (pointerEvent);
14011384 break ;
14021385 }
14031386 case TouchEventType::End:
@@ -1452,4 +1435,4 @@ void CompositionEventHandler::DispatchTouchEvent(
14521435 }
14531436}
14541437
1455- } // namespace Microsoft::ReactNative
1438+ } // namespace Microsoft::ReactNative
0 commit comments