Visitar URL original
fix(input): Tap order, iOS touch text editing and Android browser IME (backport #25818, #25619, #25804) by agneszitte · Pull Request #26072 · unoplatform/uno · GitHub
Skip to content

fix(input): Tap order, iOS touch text editing and Android browser IME (backport #25818, #25619, #25804) - #26072

Merged
agneszitte merged 3 commits into
release/stable/6.7from
dev/agzi/touch-input-backports-6.7
Nov 4, 2026
Merged

agneszitte merged 3 commits into
release/stable/6.7from
dev/agzi/touch-input-backports-6.7

Conversation

@agneszitte

Copy link
Copy Markdown
Member

GitHub Issue: related to private#1193 (6.7 SR3)

PR Type:

🐞 Bugfix

What changed? 🚀

Backports of three touch and input fixes to release/stable/6.7, for the next 6.7 core build. Each one is a single commit, by its original author, taken from its servicing/6.8 backport (conflicts already resolved there, CI green):

Commit Backport of 6.8 backport Change
fix(input) #25818 #25976 Skia: Tapped and RightTapped are raised once PointerReleased has bubbled to the root, like WinUI. A flyout or focus change made in Tapped inside a ScrollViewer no longer loses the focus, and the page no longer jumps.
feat(textbox) #25619 #25952 Skia TextBox under the iOS touch convention follows native iOS editing: caret tap menu, double and triple tap, press-and-hold caret drag, loupe, Select in the menu.
fix(textbox) #25804 #25984 Skia WebAssembly on Android browsers: IME composition no longer repeats text or loses spaces, and double-tap selects the right word.

They go in this order: #25804 builds on the other two (shared TextBox files and tests).

Differences from servicing/6.8: none in the 41 changed files, except one test exclusion that only 6.8 has (When_OuterScrollViewer_BringIntoView_Scrolls_To_Caret on Skia WebAssembly, see #24157).

For reviewers:

PR Checklist ✅

🤖 Generated with Claude Code

ajpinedam and others added 3 commits November 4, 2026 17:33
…s (backport #25818)

Backport of #25818 to release/stable/6.7, from its servicing/6.8
backport #25976 (same resolved code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Backport of #25619 to release/stable/6.7, from its servicing/6.8
backport #25952 (same resolved code).

Co-authored-by: Jacques Bourque <jbourque@kahua.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…25804)

Backport of #25804 to release/stable/6.7, from its servicing/6.8
backport #25984 (same resolved code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added platform/ios 🍎 Categorizes an issue or PR as relevant to the iOS platform area/skia ✏️ Categorizes an issue or PR as relevant to Skia kind/documentation labels Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @agneszitte's task in 12m 29s —— View job


PR Review

  • Gather PR diff and context
  • Review InputManager.Pointers.Managed.cs — tap event ordering
  • Review UIElement.Pointers.cs — tap event ordering
  • Review TextBox.pointers.skia.cs — iOS touch editing
  • Review TextBox.skia.cs — iOS touch editing
  • Review TextBox.Loupe.skia.cs / loupe infrastructure
  • Review BrowserInvisibleTextBoxViewExtension.ts/.cs — Android IME
  • Review WasmImeTextBoxExtension.cs — Android IME
  • Review test files
  • Review docs / feature flags
  • Post inline comments and write summary

Overall verdict: ✅ Ship (with minor notes)

This is a well-engineered backport. All three fixes are correctly scoped, and the implementation is high quality. No blocking issues found.

Fix 1 — Tap event ordering (#25818)

The RaiseReleasedThenGestures / TryDeferUntilReleaseBubbled / TryDeferUntilReleaseCompleted machinery is a clean implementation of the WinUI RaiseDelayedPointerUpEvent pattern. The save-restore pattern for _pendingRelease correctly handles reentrancy (injected pointer events during dispatch). The _releaseDepth counter handles nesting correctly. The UIElement.RaiseAfterPointerReleased / RaiseRightTapped refactor properly moves the ContextRequestedEvent position/root resolution before the deferral, matching the WinUI design intent. Test coverage in Given_UIElement.GestureEventOrder.cs is thorough.

Fix 2 — iOS touch text editing (#25619)

The touch state machine (_touchMultiTapAnchor, _selectionFlyoutOpenAtPress, _iosHoldTimer, _deferredTouchFlyoutTimer, _deferGripperTapFlyout, _suppressGripperTapFlyout) is complex but well-factored. All state is correctly cleared in OnUnloadedPartial, OnPointerCaptureLostPartial, OnPointerCanceledPartial, and OnPointerExitedPartial. The iOS hold timer at 500 ms (before the GR's 800 ms Holding) is the right threshold. The IsAncestorScrollViewerManipulating guard on the timer tick correctly yields to scroll. RequestPlatformTextInput deferred via TryDeferUntilReleaseCompleted correctly prevents the soft keyboard from flashing when focus moves away in a Tapped handler. The loupe infrastructure (INativeTextLoupeExtension / TextBoxTouchLoupe) with the _isLoupeActive / SelectPartial suppression during drag is correct — EndCaretLoupe syncs the final selection. The AutoFill content-type assignment in InvisibleTextBoxViewExtension is a nice addition.

Fix 3 — Android browser IME (#25804)

The TypeScript overhaul correctly addresses the browser-applies-first model. syncedValue tracks the last value both sides agree on, isSyncingFromNative gates echo-back, and compositionGeneration invalidates stale composition events from replaced inputs or invalidateComposition. The isSoftKeyboardDeletion guard for Samsung Keyboard code-less Backspace/Delete is targeted and correct. restartComposition blur/focus cycle correctly resets the IME state between TextBox switches while preserving focus from managed code's perspective. The RunFromNative exception boundary on all [JSExport] callbacks is the right pattern for the DOM/managed boundary.

Issues found (5 inline comments, all low severity)

# File Severity Topic
1 BrowserInvisibleTextBoxViewExtension.ts Low resetComposition doesn't reset compositionStart; stale value participates in candidate search before being overwritten
2 TextCommandBarFlyout.Uno.cs Low m_platformButtons grows by unique command ID and is never evicted; fine for the fixed iOS command set, worth a comment
3 InputManager.Pointers.Managed.cs Low Reentrancy contract of _afterRelease loop when _releaseDepth == 0 is subtle; worth a comment for future readers
4 TextBox.skia.cs Low _isPlatformTextInputRequestPending guard behavior on re-focus during deferral is correct (re-reads FocusState at execution time) but non-obvious
5 TextBox.pointers.skia.cs Low _deferredTouchFlyoutTimer / _iosHoldTimer Tick subscription is never unsubscribed (forms a reference cycle with the TextBox); consistent with existing class patterns
6 BrowserInvisibleTextBoxViewExtension.cs Low GetSelectionStartBeforeKeyDown / GetSelectionLengthBeforeKeyDown semantics changed; a short comment would prevent accidental revert

Code-review assessment: Correct by inspection, consistent with the architecture, no SOLID violations, no async void without try/catch, no event Action, no missing braces in production code, no Generated/ edits.
Runtime validation: Not run locally (WASM CI required for items 2–3; iOS device required for item 2).

@agneszitte
agneszitte merged commit d86c582 into release/stable/6.7 Nov 4, 2026
19 of 34 checks passed
@agneszitte
agneszitte deleted the dev/agzi/touch-input-backports-6.7 branch November 4, 2026 22:57
@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Sample App stage site is ready! Visit it here:

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-26072/docs/index.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/skia ✏️ Categorizes an issue or PR as relevant to Skia kind/documentation platform/ios 🍎 Categorizes an issue or PR as relevant to the iOS platform

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants