Repository navigation
Add PointerEvent.endOfBatch - #108340
Add PointerEvent.endOfBatch#108340dkwingsmt wants to merge 6 commits into
Conversation
|
Does this play nicely/correctly when pointer events are resampled with PointerEventResampler? Maybe add a test for that case? |
That's a good point and I suspect that I do need extra changes.... I'll take a look soon. |
|
I have this on my list to review early next week. Just a quick fly-by comment, looks like the doc check is unhappy. |
| return data | ||
| final List<ui.PointerData> knownData = data | ||
| .where((ui.PointerData datum) => datum.signalKind != ui.PointerSignalKind.unknown) | ||
| .toList(); |
There was a problem hiding this comment.
This extra toList conversion is unfortunate and could be costly. I wonder if there's a way to avoid it?
| /// | ||
| /// Some pointer events are sent in batches. For example, when the device | ||
| /// is being operated with multiple fingers, events from each moving finger | ||
| /// constitute a batch and is sent together. Since pointer events are always |
There was a problem hiding this comment.
is -> are? since "events" is plural?
| typedef HandleEventCallback = void Function(PointerEvent event); | ||
|
|
||
| /// Class for pointer event resampling. | ||
| /// A [PointerEvent] that has everything ready except for `endOfBatch`. |
There was a problem hiding this comment.
Document: What does "everything ready" mean?
| ? _toMoveEvent( | ||
| event, position, delta, pointerIdentifier, timeStamp, buttons) | ||
| : _toHoverEvent(event, position, delta, timeStamp, buttons); | ||
| event, position, delta, pointerIdentifier, timeStamp, buttons, endOfBatch) |
There was a problem hiding this comment.
nit: I see this was already incorrectly formatted before, but could you fix formatting by moving this line to the previous one?
| final Offset delta = position - _position; | ||
| callback(_toMoveOrHoverEvent(event, position, delta, | ||
| _pointerIdentifier, sampleTime, wasDown, hadButtons)); | ||
| eventBuilders.add((bool endOfBatch) => |
There was a problem hiding this comment.
nit (here and elsewhere): https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods:
[...] only use ⇒ when everything, including the function declaration, fits on a single line.
| eventBuilders.add((bool endOfBatch) => | ||
| _toMoveOrHoverEvent(next, position, delta, _pointerIdentifier, | ||
| sampleTime, _isDown, _hasButtons, endOfBatch), |
| // current sample time. | ||
| final List<BatchEventBuilder> batchBuilder = <BatchEventBuilder>[]; | ||
| for (final PointerEventResampler resampler in _resamplers.values) { | ||
| batchBuilder.addAll(resampler.sample(sampleTime, nextSampleTime)); |
There was a problem hiding this comment.
While reading this I have been wondering why we need all this indirection via the BatchEventBuilder. For my own understanding: Is it possible that resampler.sample here my return an empty list and the endOfBatch event is actually produced by a Resampler other then the last one in _resamplers.values? If that's not true, could we just tell the last resampler.sample method that it is responsible for producing an endOfBatch event?
There was a problem hiding this comment.
If we have to sample all resamplers before we can determine the endOfBatch event, could this be simplified by just having resampler.sample return a list of pointer events and before calling handlePointerEvent below we copy the last event of the collected list to set endOfBatch: true?
|
Does this actually help with solving #106552 in all cases? Let's imagine a situation where the screen is split in two halves. One half is covered by a DragGestureRecognizer, the other half isn't. Two finger (F1 and F2) touch the screen and move around, one in each half. F1 moves around in the half covered by the DragGestureRecognizer, which tracks its every move. F2 moves around outside of that area and is not tracked by the DragGestureRecognizer. In a single PointerData packet ( |
You're right, thanks for bringing this up. Well, I can't think of a way of solving this without a complete overhaul of our gesture recognizer API by disptaching the filtered batch in a list, because now that the gesture recognizer can receive any portion of the batch, how can the recognizer know that it has received the last of this portion without receiving an event from the next batch? I would suggest reverting #106552 back to the previous approach, which is not beautiful but totally works (as far as I can see). |
So, the best way is what I said "make every pointer dispatch the event even some pointer not move". Android did this, but iOS not. I know why only moved pointer dispatches on iOS but not on Android. https://github.com/flutter/engine/blob/main/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm#:~:text=%2D%20(void)dispatchTouches,(UIEvent*)event%20%7B In the dispatchTouches function, it should use the event.alltouches. If we do this, we will not use All above, the |
|
I see, so you mean, if we switch to using |
After I tested, the behavior " the DragGestureRecognizer (which only tracks F1) will never know when the batch ended in this situation because the F2 event is never routed to it." exists indeed. But my fix code can handle it. Because I both use But I still suggest we can use |
Sorry, I don't fully follow what the new proposal is. |
Yeah. Can you try allTouches and without endOfBatch? |
|
I tested that changing |
Anything that relies on endOfBatch is easily broken when the gesture area does not cover the entire screen. I don't think it's an approach worth discussing any more. Sorry I was busy with other issues lately but I'll experiment on changing to allTouches soon. |
Oh, I forget that broken. Thank you for your expriment. I will try to change it too. |
|
This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
|
(triage) @dkwingsmt @xiaoyanermiemie What's the status on this one? Should this be closed or do you still plan to work in this particular PR in the near future? |
I still plan |
@dkwingsmt @goderbauer Here is the exception stack (tips: you can try some times, remember together): This bug block me, can you fix it firstly? |
Can you file a bug for this with some code to reproduce it? Thanks. |
|
@dkwingsmt @goderbauer Please see the discussion in flutter/engine |
Sorry, there is no bug. I had a mistake. |
|
@xiaoyanermiemie I tried switching to - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
- [self dispatchTouches:touches pointerDataChangeOverride:nullptr event:event];
+ [self dispatchTouches:event.allTouches pointerDataChangeOverride:nullptr event:event];
}And all similar methods below it. (I know you talked about changing |
@dkwingsmt |
|
(Triage): I am going to close this PR as it is getting stale. I would suggest filing an issue and discussing options there. |


This PR adds a new field
bool endOfBatchtoPointerEventand populates it.Some pointer events are sent in batches. For example, when the device is being operated with multiple fingers, events from each moving finger constitute a batch and is sent together. This information is necessary to implement the iOS behavior of multi-finger scrolling, which needs to know which event is the last of the batch so that it can start processing the entire batch as a whole.
What constitutes a batch? The iOS platform sends a batch of events in the same
allTouches, and the iOS embedding is already sending events from the sameallTouchesin the samePointerDataPacket. The framework just needs to mark all of them asendOfBatch: falseexcept for the last one.The harder part is when the events are being resampled. If there are multiple batches within two resampling frames, the two batches might not have the same order, or even the same set of devices. This PR considers all events resulting from traversing
PointerEventResamplers and callingPointerEventResampler.sample()a single batch. All of these events are collected, and are marked asendOfBatch: falseexcept for the last one.Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.