Skip to content

Fix/all touch and perf fixes#10

Open
gmacmaster wants to merge 6 commits intomainfrom
fix/all-touch-and-perf-fixes
Open

Fix/all touch and perf fixes#10
gmacmaster wants to merge 6 commits intomainfrom
fix/all-touch-and-perf-fixes

Conversation

@gmacmaster
Copy link
Copy Markdown

No description provided.

gmacmaster and others added 2 commits April 19, 2026 09:17
- Fix touch/pen pointer device type detection and screenPoint coordinates
- Fix touch cancel to include all active touches per W3C spec
- Synthesize touch-cancel for stale pointers and releases outside views
- Fix TextInput pointer message translation (use mouse-style messages for RichEdit)
- Fix ShouldSubmit modifier key checks (altDown, ctrlKey)
- Add null safety to RootComponentView() for island teardown
- Fix Pressability hover timeout and tabIndex focusable mapping
- Cache event path to root to avoid repeated tree walks
- Use unordered_set for pointer capture tracking
- Eliminate O(n²) hit testing by caching visual children
- Skip snap scroll reconfiguration when unchanged
- Improve TextInput reliability: thread-safe loading, null safety, use-after-free fix
- Fix Timing data race and remove duplicate image error allocation
- Use unordered_set for animated node and component registry lookups
- Clean up dead code in ScrollView and simplify Modal event emitter init

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 19, 2026

Greptile Summary

This PR consolidates a broad set of touch correctness fixes and performance improvements across the Windows Composition layer. Key behavioural fixes include: stale-pointer cancellation on repeated press (replacing a silent early-return), correct pointer-device-type detection (Touch/Pen/Mouse), proper screenPoint assignment in UpdateActiveTouch, an altDown key check that was querying the Control key instead of Menu/Alt, a duplicate altKey guard in the submit-key condition, and a hover-out timer stored in the wrong field (_hoverInDelayTimeout). Performance improvements include m_childrenCache for O(1) child lookup, vector → unordered_set for captured pointers / component names / animated-node children, and an O(n²)→O(n) rewrite of anyHitTestHelper. Thread safety is tightened with std::call_once for DLL loading and std::atomic<bool> for m_usingRendering.

Confidence Score: 5/5

PR is safe to merge; all findings are confirmations of intentional bug fixes, with no new defects introduced.

All inline comments describe fixes rather than new bugs. The comments left are P2 observations confirming that the fixes are correct. No regressions found across the C++ or JS changes.

CompositionEventHandler.cpp deserves a manual touch-flow smoke-test given the scope of the stale-pointer cancellation logic.

Important Files Changed

Filename Overview
vnext/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp Major touch-handling overhaul: stale-pointer cancellation, correct device-type detection (Touch/Pen/Mouse), screenPoint fix, unordered_set for captured pointers, null-safe RootComponentView, PointerExited revoker, and new DispatchSynthesizedTouchCancelForActiveTouch helper.
vnext/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp Added m_childrenCache vector for O(1) GetAt; fixed InsertAt to maintain cache on both code paths; added snap-position change detection to avoid redundant InteractionTracker reconfiguration.
vnext/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp Added destructor, CompTextHost::Detach(), and m_outer null-guards throughout to prevent UAF; std::call_once for DLL load; touch messages now mapped to WM_LBUTTONDOWN/WM_LBUTTONDBLCLK/WM_MOUSEMOVE; altDown key and duplicate altKey guard fixed; OnTxSetCursor moved inside m_textServices guard.
vnext/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp anyHitTestHelper now snapshots children into a local vector to avoid O(n²) IVector::GetAt access pattern; semantics and reverse-iteration order preserved.
vnext/src-win/Libraries/Pressability/Pressability.windows.js Two fixes: hoverOut timer correctly stored in _hoverOutDelayTimeout (was _hoverInDelayTimeout); disabled check simplified to disabled !== true.
vnext/src-win/Libraries/Components/View/View.windows.js tabIndex focusable logic fixed: !tabIndex (treated positive tabIndex as non-focusable) replaced with tabIndex >= 0 (correct HTML semantics).
vnext/Microsoft.ReactNative/Modules/Timing.h m_usingRendering changed to std::atomic to eliminate a data race between the UI thread and the rendering callback.

Sequence Diagram

sequenceDiagram
    participant OS as OS Pointer Source
    participant CEH as CompositionEventHandler
    participant AT as m_activeTouches
    participant EE as EventEmitter (JS)

    OS->>CEH: onPointerPressed(pointerId)
    CEH->>AT: find(pointerId)
    alt stale touch found
        AT-->>CEH: staleTouch
        CEH->>EE: DispatchSynthesizedTouchCancel(staleTouch)
        CEH->>AT: erase(pointerId)
    end
    CEH->>AT: insert new ActiveTouch (Touch/Pen/Mouse type)
    CEH->>EE: onTouchStart / onPointerDown

    OS->>CEH: onPointerReleased(pointerId)
    CEH->>AT: find(pointerId)
    alt tag == -1 (pointer left surface)
        CEH->>EE: DispatchSynthesizedTouchCancel
        CEH->>AT: erase(pointerId)
    else normal release
        CEH->>EE: onTouchEnd / onPointerUp
        CEH->>AT: erase(pointerId)
    end

    OS->>CEH: onPointerCaptureLost
    CEH->>AT: releasePointerCapture (unordered_set.erase)
Loading

Reviews (2): Last reviewed commit: "pr comments" | Re-trigger Greptile

Comment thread vnext/src-win/Libraries/Pressability/Pressability.windows.js Outdated
@gmacmaster
Copy link
Copy Markdown
Author

@greptile review

- Fix IsPointerWithinInitialTree to hit-test at current pointer coords
  instead of trivially matching tree membership (P1 fix)
- Add runtime bounds clamp in InsertAt to prevent cache/layer desync
  in release builds where assert is stripped
- Remove unnecessary vector copy in anyHitTestHelper since
  single_threaded_vector::GetAt is already O(1)
- Replace silent nullptr return with winrt::check_bool in createVisual
  for unrecoverable text services init failure

Made-with: Cursor
Addresses P1 review feedback: GetAt returning nullptr silently
shifts crashes to opaque call sites. The assert fires in debug
builds so the root cause is caught at the source.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant