dotnet / dotnet/wpf

StylusPlugIn OnStylusDown/Move/Up invoked on UI thread and called out of order

Open
#11,103 3 comments 0 reactions 0 assignees View on GitHub
:beetle: bug area-Touch
Dominant language
C#
Stars
7.7k
Forks
1.3k
Avg merge
1d 11h
Merged PRs (30d)
61

Description

### Description

• StylusPlugIn.OnStylusDown / OnStylusUp are sometimes invoked out of order: I see OnStylusUp called on the UI thread, then later OnStylusDown called on the Stylus (pen/touch) thread.

• The incoming message is a touch (StylusDeviceId != 0, e.g. 123), so it should not be handled as a mouse message on the UI thread.

### Reproduction Steps

How to reproduce (minimal)

1. Create a class inheriting StylusPlugIn and override OnStylusDown, OnStylusMove, OnStylusUp.
2. Add Thread.Sleep calls inside these methods to simulate expensive work.
3. Rapid multi-finger taps on a touch screen. And set the DPI to 300%
4. Observe that OnStylusUp (UI thread) can be called before OnStylusDown (stylus thread) for the same StylusDeviceId.

I put a minimal repro/demo on GitHub: https://github.com/lindexi/lindexi_gd/tree/107caecee7f847355d23744bf6fc7b970d5e8c69/WPFDemo/LoqairjaniferNudalcefinay

### Expected behavior

Events for a given touch/stylus input should be delivered in order and handled on the correct thread for that input type (touch/pen events on the stylus/pen input thread or otherwise consistently marshalled), not processed as mouse/UI-thread messages if StylusDeviceId indicates a touch/pen device.

### Actual behavior

OnStylusUp invoked on the UI thread (before OnStylusDown), then OnStylusDown invoked later on the stylus thread. This produces incorrect ordering and state corruption in StylusPlugIn implementations.

### Regression?

_No response_

### Known Workarounds

_No response_

### Impact

_No response_

### Configuration

_No response_

### Other information

In WispLogic.cs there is a comment: "We are on the pen thread, just call directly." This is misleading/wrong in context — that line is inside VerifyStylusPlugInCollectionTarget.

https://github.com/dotnet/wpf/blob/348310ee9e945f9d70187e19e15132a1977983ce/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/Stylus/Wisp/WispLogic.cs#L2741

VerifyStylusPlugInCollectionTarget is only called from `WispLogic.PreNotifyInput`, and `PreNotifyInput` is wired to InputManager.PreNotifyInput: `_inputManager.Value.PreNotifyInput += new NotifyInputEventHandler(PreNotifyInput);` . `InputManager.PreNotifyInput` is raised on the UI thread, so the code path does not guarantee we are on the Stylus Input thread.

Because `targetPIC.FireRawStylusInput` in `VerifyStylusPlugInCollectionTarget` assumes "Stylus Input thread", StylusPlugIn callbacks can be invoked on the UI thread incorrectly.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.