Visitar URL original
fix(input): Raise Tapped and RightTapped after PointerReleased bubbles (backport #25818) by mergify[bot] · Pull Request #25976 · unoplatform/uno · GitHub
Skip to content

fix(input): Raise Tapped and RightTapped after PointerReleased bubbles (backport #25818) - #25976

Merged
agneszitte merged 7 commits into
servicing/6.8from
mergify/bp/servicing/6.8/pr-25818
Nov 3, 2026
Merged

agneszitte merged 7 commits into
servicing/6.8from
mergify/bp/servicing/6.8/pr-25818

Conversation

@mergify

@mergify mergify Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

GitHub Issue: closes unoplatform/kahua-private#559

PR Type:

🐞 Bugfix

What changed? 🚀

On Skia heads (managed pointers), Tapped and RightTapped were raised while PointerReleased was still bubbling to the ancestors of the tapped element. WinUI raises them only once PointerReleased has reached the root (CInputServices::RaiseDelayedPointerUpEvent).

That broke a common case: an element inside a ScrollViewer whose Tapped handler opens a flyout or moves the focus, while the focus is outside the ScrollViewer. The ScrollViewer handled the release after the flyout took the focus, so it took the focus back for its first TextBox, and that TextBox scrolled itself into view on its late GotFocus. On an Android tablet the page jumped to the top and the soft keyboard flashed.

Gesture order (Skia, managed pointers)

  • Tapped and RightTapped, and the ContextRequested that follows RightTapped, are raised once PointerReleased has bubbled to the root, like WinUI. They're still raised before the captures are released (PointerCaptureLost), and an ancestor isn't tapped twice.
  • DoubleTapped is unchanged: like in WinUI, it's raised on the second press, when no release is in progress.
  • An exception in a deferred gesture handler is logged, like one in a PointerReleased handler, and the release still completes.

TextBox and PasswordBox

  • A TextBox or PasswordBox whose GotFocus is raised after the focus already moved on no longer brings itself into view. RichEditBox already ignores such a GotFocus, as WinUI's TextBoxBase::OnGotFocus does.
  • Like in WinUI, the ScrollViewer still focuses its first text input for an instant during the release. The platform text input is now started only once the pointer release has completed, and not at all if the focus has moved away by then. This covers the soft keyboard on Android, the hidden <input> on WebAssembly and the IME session. It removes the keyboard flash on Android, and on the web the hidden input's focus and blur, which made Chrome's autofill bar flicker.
  • Tapping an already-focused TextBox notifies the platform again, to re-show a soft keyboard the user hid. That notification is deferred the same way.
  • The deferred start still runs inside the same browser event, so iOS Safari still opens the keyboard on a direct tap.

This builds on the fix-ready report, patches and runtime tests attached to the issue. The gesture deferral is reworked to live on the InputManager, per pointer release, and extended to the platform text input.

Validation

  • Runtime, Skia Desktop (macOS): Given_UIElement_GestureEventOrder, Given_TextBox and Given_PasswordBox: 311 passed, 8 skipped, 2 inconclusive, 2 failed. The 2 failures (When_Multiline_Pointer_Tap, When_Pointer_RightClick_Selection, caret off by one) fail the same way on the base commit on this machine.
  • Runtime, Skia WebAssembly (headless Chrome): Given_UIElement_GestureEventOrder and the TextBox family (Given_TextBox, Given_PasswordBox, Given_ImeSessionCoordinator, Given_AutoSuggestBox, Given_NumberBox): 312 passed, 0 failed, 65 skipped (other platforms). This ran before the re-show deferral was added.
  • Tests fail before the fix:
    • Given_UIElement_GestureEventOrder, run on the base commit ab14387c90 with only the test file added: 8 of 13 cases fail. These are Tapped raised by an ancestor of the hit element (mouse and touch), Tapped before PointerCaptureLost (both rows), RightTapped by mouse and by touch hold, and the ScrollViewer focus case (mouse and touch). The 5 that pass guard behavior the base already had: Tapped raised by the hit element itself, which was already raised after the bubble, the two "not raised twice" tests, and the throwing ContextRequested handler.
    • The text-input tests were run against a build with the deferral narrowed back to PointerReleased and the browser input started on focus. The 3 cases expected to fail did fail: the PointerExited test, and the ScrollViewer test for both TextBox and PasswordBox.
    • The re-show test fails without its fix when the focus moves away: the platform is notified twice.
  • Real devices, with a manual repro page (not included):
    • Galaxy Tab A8, Chrome: the flyout keeps the focus, the page doesn't scroll, and the hidden input is never focused. A direct tap on a TextBox still opens the keyboard.
    • iPad Pro, iPadOS 26.6.1, Safari: same result. The screen was recorded and checked frame by frame: the keyboard opens on a direct tap and never flashes when the flyout opens or the focus moves.
    • Galaxy Tab A8, Skia Android (Release): the keyboard flashed in 3 of 4 taps before the fix and in none of 6 after.
    • The device checks ran on an earlier revision. It deferred the text input until the release's gestures were raised and the root cleaned up the focus, but not past the release of the captures and the exit events. Widening the deferral to the end of the release, and deferring the re-show, were validated with the runtime tests only.

Not verified

  • Touch on native WinUI: the order there was checked with a mouse, as described in the issue.
  • The iOS Skia head.
  • The full runtime suite.
  • InputPane.skia.cs brings a captured element into view without checking it still has the focus. It's the same pattern, but it's not needed here and isn't changed.

PR Checklist ✅

🤖 Generated with Claude Code


This is an automatic backport of pull request #25818 done by [Mergify](https://mergify.com).

(cherry picked from commit d09ed95)

# Conflicts:
#	src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.GestureEventOrder.cs
#	src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs
(cherry picked from commit 76232b4)

# Conflicts:
#	src/Uno.UI.RuntimeTests/Microsoft/UI/Xaml/Controls/Given_PasswordBox.cs
#	src/Uno.UI/UI/Xaml/Controls/PasswordBox/PasswordBox.cs
#	src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs
#	src/Uno.UI/UI/Xaml/Controls/TextBoxCore/TextBoxCore.cs
(cherry picked from commit 82f9274)

# Conflicts:
#	src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.skia.cs
#	src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Properties.cs
#	src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.skia.cs
@mergify mergify Bot added the conflicts Automated merge hit conflicts label Nov 3, 2026
@mergify

mergify Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Cherry-pick of d09ed95 has failed:

On branch mergify/bp/servicing/6.8/pr-25818
Your branch is up to date with 'origin/servicing/6.8'.

You are currently cherry-picking commit d09ed95.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	modified:   src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.Managed.cs
	modified:   src/Uno.UI/UI/Xaml/UIElement.Pointers.cs

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	added by them:   src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_UIElement.GestureEventOrder.cs
	both modified:   src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.cs

Cherry-pick of 76232b4 has failed:

On branch mergify/bp/servicing/6.8/pr-25818
Your branch is ahead of 'origin/servicing/6.8' by 1 commit.
  (use "git push" to publish your local commits)

You are currently cherry-picking commit 76232b4.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	modified:   src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.cs

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
	deleted by us:   src/Uno.UI.RuntimeTests/Microsoft/UI/Xaml/Controls/Given_PasswordBox.cs
	both modified:   src/Uno.UI/UI/Xaml/Controls/PasswordBox/PasswordBox.cs
	both modified:   src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs
	deleted by us:   src/Uno.UI/UI/Xaml/Controls/TextBoxCore/TextBoxCore.cs

Cherry-pick of 82f9274 has failed:

On branch mergify/bp/servicing/6.8/pr-25818
Your branch is ahead of 'origin/servicing/6.8' by 2 commits.
  (use "git push" to publish your local commits)

You are currently cherry-picking commit 82f9274.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	modified:   src/Uno.UI/UI/Xaml/Internal/InputManager.Pointers.Managed.cs
	modified:   src/Uno.UI/UI/Xaml/UIElement.Pointers.cs

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
	both modified:   src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TextBox.skia.cs
	deleted by us:   src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Properties.cs
	both modified:   src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.skia.cs

To fix up this pull request, you can check it out locally. See documentation: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally

@github-actions github-actions Bot added the area/skia ✏️ Categorizes an issue or PR as relevant to Skia label Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

WinAppSDK sync generator drift detected on b57cfb4

The Uno.WinAppSDKSyncGenerator produced changes that are not committed on this PR.

To apply automatically (PRs from branches in this repo only): comment /apply-sync-gen on this PR and a bot will push chore: Sync generator run to the head branch.

To apply manually (required for PRs from forks):

  1. Download the sync-generator-patch artifact from this run.
  2. In your local checkout of the PR branch:
    git apply sync-generator.patch
    git add -A
    git commit -m "chore: Sync generator run"
    git push
    

Or re-run the generator locally on Windows via build\run-api-sync-tool.cmd.

@ajpinedam

Copy link
Copy Markdown
Contributor

Resolved the conflicts in e80b8d0.

Mergify's cherry-picks of 3 of the 6 commits conflicted. It committed the conflict markers and three master-only files: TextBoxCore/TextBoxCore.cs, TextBox/TextBox.Properties.cs and Microsoft/UI/Xaml/Controls/Given_PasswordBox.cs. So every build failed, and the stray TextBox.Properties.cs also caused the WinAppSDK sync-generator drift. The keyboard re-show change had only landed in the stray TextBoxCore.cs.

All the conflicts come from master-only changes, so no backport is missing: TextBox moved into TextBoxCore and PasswordBox reparented (#24038), the .skia.cs files merged (#24001), the native renderers dropped (#23470), and the IME session model of #23924.

The commit resets the touched files to 6.8, removes the stray files and ports the master merge's changes:

  • InputManager.Pointers.Managed.cs, InputManager.Pointers.cs, UIElement.Pointers.cs: the same changes as on master. In ProcessPointerUp, the release deferral goes after 6.8's Android/iOS-only exit block.
  • TextBox.skia.cs gets master's TextBoxCore.Input.cs changes: the deferred platform text input, NotifyFocusedAgain and the test hook. The UseOverlayOnSkia mode keeps its synchronous TextBoxView.OnFocusStateChanged.
  • TextBox.cs gets the stale GotFocus check (PasswordBox inherits it on 6.8) and the two re-show calls. The check is under #if __SKIA__, since this file also builds for the native renderers.
  • Tests: moved to 6.8's folders, with the IME and notification fakes on 6.8's TextBox-based interfaces and Uno.UI.Toolkit.DevTools.Input. The new tests exclude the native renderers, which this change doesn't touch.

Validated locally on macOS:

  • Skia Desktop, Given_TextBox, Given_PasswordBox and Given_UIElement_GestureEventOrder: 272 passed, 3 failed. All 22 ported tests pass. The 3 failures (When_Multiline_Pointer_Tap, When_Pointer_RightClick_Selection, When_Caret_Line_Straddles_Viewport_Edge_Grippers_Are_Hidden) fail the same way on unmodified 6.8 on this machine.
  • Uno.UI compiles for Skia, WebAssembly, Android and Reference. The WebAssembly and Android runtime-test projects report no errors in the ported files. They already fail to compile on 6.8 because of 4 unrelated test files.
  • The WASM runtime tests weren't run locally.

@unodevops

Copy link
Copy Markdown
Contributor

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

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 243309 did not find any UI Test snapshots differences.

@agneszitte
agneszitte merged commit 4abea1c into servicing/6.8 Nov 3, 2026
42 checks passed
@agneszitte
agneszitte deleted the mergify/bp/servicing/6.8/pr-25818 branch November 3, 2026 20:36
mikernet added a commit to Singulink/uno that referenced this pull request Nov 14, 2026
Takes Uno's servicing/6.8 from 6951c2c up to 5254ace (42 pull
requests). Conflicts, by area:

IME and TextBox (unoplatform#25984, backport of unoplatform#25804; unoplatform#25952, backport of unoplatform#25619;
unoplatform#25976, backport of unoplatform#25818)
- Takes upstream's composition design (unoplatform#25804): the browser's input is
  the source of truth for the text, compositions included. This drops
  the composition parts of the unoplatform#24502 port (90746b8): its
  TypeScript composition handling, the StartIndex/TextChangePending
  event arguments, the IsReadOnly forwarding to the hidden input, and
  its Given_TextBox.BrowserSoftKeyboard tests.
- Keeps the non-IME browser fixes on top of it, in the form their
  master pull requests have on unoplatform#25804: Enter raised once per press and
  tracked by key code (unoplatform#25174, with Given_TextBox.BrowserEnterKey from
  master in place of the Enter tests that lived in the dropped file),
  the iOS refocus on tap (unoplatform#25185), pastes without text and isIOS from
  BrowserInputHelper.
- Moves the unoplatform#26005 MaxLength fixes onto unoplatform#25804's native input path, as
  master has them: a refused browser edit keeps the TextBox's selection,
  TextBoxView.UpdateTextFromNative reports whether the edit went in, and
  the IME keeps its range on the applied text (master be85699, which
  d226897 had ported onto the unoplatform#24502 IME). Adds that commit's browser
  and platform-applied IME tests.
- TextBox.pointers.skia.cs: upstream's file (unoplatform#25619 iOS touch editing,
  unoplatform#25818, unoplatform#25804), with the unoplatform#25126 port (the hold acts when it starts,
  a touch right-tap keeps the caret) in the form master's unoplatform#25126 branch
  has it on unoplatform#25619, including focusing before the iOS hold timer acts
  and its iOS not-focusable test.

Pointers (unoplatform#25976, backport of unoplatform#25818)
- Tapped and RightTapped are raised once the PointerReleased bubbled
  (unoplatform#25818), with the unoplatform#25732 port's window coordinates (2-argument
  routed event args, RawPosition for ContextRequested), as master's
  unoplatform#25732 branch has them.
- The release wrapper of unoplatform#25818 keeps the unoplatform#25126 port's
  StopContextMenuTimer at the start of the release.

DependencyObject (unoplatform#26142, backport of unoplatform#26123)
- Takes upstream, then the code of unoplatform#25839 (97a2f17), which replaces
  this branch's unoplatform#25102 ports (800247f, be41da6, fd40bf9,
  7546379). DependencyObjectStore.Binder.cs, .alc.cs,
  Application.Alc.cs, ResourceDictionary.alc.cs and their tests now
  match unoplatform#25839; this drops 800247f's own
  SingleParentNonFE_Parent_Removes_Value_Then_Next_Parent_Starts_Clean
  test, which unoplatform#25839 doesn't have.

Imaging (unoplatform#25597, unoplatform#25915, unoplatform#25911, unoplatform#25897)
- Keeps this branch's side: it has the later forms of these fixes
  (unoplatform#25124, unoplatform#25559, unoplatform#25633 and unoplatform#26370 ports), where upstream has the
  6.8-only unoplatform#25597 design and earlier snapshots. Upstream's shared
  download, IgnoreImageCache and failed-load fixes are covered by
  SharedImageDecode. Adds upstream's When_Source_Outlives_Brushes test.

ToolTip (unoplatform#26098, backport of unoplatform#25137 and unoplatform#26096)
- Keeps this branch's unoplatform#25137 port and adds unoplatform#26096 in master's form: the
  service releases only a ToolTip it opened, and leaves one the app
  opened during the show delay to the app. Keeps both sides' tests.

Flyout (unoplatform#26062, backport of unoplatform#26060)
- This branch had the same commits already; keeps the "Keep
  non-resizable flyouts in window" port and its tests.

Also removes a helper pair in Given_AccessibleTextBox that both sides
added.
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 conflicts Automated merge hit conflicts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants