@@ -2526,6 +2526,88 @@ void testMain() {
25262526 },
25272527 );
25282528
2529+ test ('ignores pointerId on coalesced events' , () {
2530+ final _MultiPointerEventMixin context = _PointerEventContext ();
2531+ final List <ui.PointerDataPacket > packets = < ui.PointerDataPacket > [];
2532+ List <ui.PointerData > data;
2533+ ui.PlatformDispatcher .instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
2534+ packets.add (packet);
2535+ };
2536+
2537+ context.multiTouchDown (const < _TouchDetails > [
2538+ _TouchDetails (pointer: 52 , clientX: 100 , clientY: 101 ),
2539+ ]).forEach (rootElement.dispatchEvent);
2540+ expect (packets.length, 1 );
2541+
2542+ data = packets.single.data;
2543+ expect (data, hasLength (2 ));
2544+ expect (data[0 ].change, equals (ui.PointerChange .add));
2545+ expect (data[0 ].synthesized, isTrue);
2546+ expect (data[0 ].device, equals (52 ));
2547+ expect (data[0 ].physicalX, equals (100 * dpi));
2548+ expect (data[0 ].physicalY, equals (101 * dpi));
2549+
2550+ expect (data[1 ].change, equals (ui.PointerChange .down));
2551+ expect (data[1 ].device, equals (52 ));
2552+ expect (data[1 ].buttons, equals (1 ));
2553+ expect (data[1 ].physicalX, equals (100 * dpi));
2554+ expect (data[1 ].physicalY, equals (101 * dpi));
2555+ expect (data[1 ].physicalDeltaX, equals (0 ));
2556+ expect (data[1 ].physicalDeltaY, equals (0 ));
2557+ packets.clear ();
2558+
2559+ // Pointer move with coaleasced events
2560+ context.multiTouchMove (const < _TouchDetails > [
2561+ _TouchDetails (pointer: 52 , coalescedEvents: < _CoalescedTouchDetails > [
2562+ _CoalescedTouchDetails (pointer: 0 , clientX: 301 , clientY: 302 ),
2563+ _CoalescedTouchDetails (pointer: 0 , clientX: 401 , clientY: 402 ),
2564+ ]),
2565+ ]).forEach (rootElement.dispatchEvent);
2566+ expect (packets.length, 1 );
2567+
2568+ data = packets.single.data;
2569+ expect (data, hasLength (2 ));
2570+ expect (data[0 ].change, equals (ui.PointerChange .move));
2571+ expect (data[0 ].device, equals (52 ));
2572+ expect (data[0 ].buttons, equals (1 ));
2573+ expect (data[0 ].physicalX, equals (301 * dpi));
2574+ expect (data[0 ].physicalY, equals (302 * dpi));
2575+ expect (data[0 ].physicalDeltaX, equals (201 * dpi));
2576+ expect (data[0 ].physicalDeltaY, equals (201 * dpi));
2577+
2578+ expect (data[1 ].change, equals (ui.PointerChange .move));
2579+ expect (data[1 ].device, equals (52 ));
2580+ expect (data[1 ].buttons, equals (1 ));
2581+ expect (data[1 ].physicalX, equals (401 * dpi));
2582+ expect (data[1 ].physicalY, equals (402 * dpi));
2583+ expect (data[1 ].physicalDeltaX, equals (100 * dpi));
2584+ expect (data[1 ].physicalDeltaY, equals (100 * dpi));
2585+ packets.clear ();
2586+
2587+ // Pointer up
2588+ context.multiTouchUp (const < _TouchDetails > [
2589+ _TouchDetails (pointer: 52 , clientX: 401 , clientY: 402 ),
2590+ ]).forEach (rootElement.dispatchEvent);
2591+ expect (packets, hasLength (1 ));
2592+ expect (packets[0 ].data, hasLength (2 ));
2593+ expect (packets[0 ].data[0 ].change, equals (ui.PointerChange .up));
2594+ expect (packets[0 ].data[0 ].device, equals (52 ));
2595+ expect (packets[0 ].data[0 ].buttons, equals (0 ));
2596+ expect (packets[0 ].data[0 ].physicalX, equals (401 * dpi));
2597+ expect (packets[0 ].data[0 ].physicalY, equals (402 * dpi));
2598+ expect (packets[0 ].data[0 ].physicalDeltaX, equals (0 ));
2599+ expect (packets[0 ].data[0 ].physicalDeltaY, equals (0 ));
2600+
2601+ expect (packets[0 ].data[1 ].change, equals (ui.PointerChange .remove));
2602+ expect (packets[0 ].data[1 ].device, equals (52 ));
2603+ expect (packets[0 ].data[1 ].buttons, equals (0 ));
2604+ expect (packets[0 ].data[1 ].physicalX, equals (401 * dpi));
2605+ expect (packets[0 ].data[1 ].physicalY, equals (402 * dpi));
2606+ expect (packets[0 ].data[1 ].physicalDeltaX, equals (0 ));
2607+ expect (packets[0 ].data[1 ].physicalDeltaY, equals (0 ));
2608+ packets.clear ();
2609+ });
2610+
25292611 test (
25302612 'correctly parses cancel event' ,
25312613 () {
@@ -3336,7 +3418,26 @@ mixin _ButtonedEventMixin on _BasicEventContext {
33363418}
33373419
33383420class _TouchDetails {
3339- const _TouchDetails ({this .pointer, this .clientX, this .clientY});
3421+ const _TouchDetails ({
3422+ this .pointer,
3423+ this .clientX,
3424+ this .clientY,
3425+ this .coalescedEvents,
3426+ });
3427+
3428+ final int ? pointer;
3429+ final double ? clientX;
3430+ final double ? clientY;
3431+
3432+ final List <_CoalescedTouchDetails >? coalescedEvents;
3433+ }
3434+
3435+ class _CoalescedTouchDetails {
3436+ const _CoalescedTouchDetails ({
3437+ this .pointer,
3438+ this .clientX,
3439+ this .clientY,
3440+ });
33403441
33413442 final int ? pointer;
33423443 final double ? clientX;
@@ -3395,6 +3496,10 @@ class _PointerEventContext extends _BasicEventContext
33953496
33963497 @override
33973498 List <DomEvent > multiTouchDown (List <_TouchDetails > touches) {
3499+ assert (
3500+ touches.every ((_TouchDetails details) => details.coalescedEvents == null ),
3501+ 'Coalesced events are not allowed for pointerdown events.' ,
3502+ );
33983503 return touches
33993504 .map ((_TouchDetails details) => _downWithFullDetails (
34003505 pointer: details.pointer,
@@ -3458,6 +3563,7 @@ class _PointerEventContext extends _BasicEventContext
34583563 clientX: details.clientX,
34593564 clientY: details.clientY,
34603565 pointerType: 'touch' ,
3566+ coalescedEvents: details.coalescedEvents,
34613567 ))
34623568 .toList ();
34633569 }
@@ -3487,8 +3593,9 @@ class _PointerEventContext extends _BasicEventContext
34873593 int ? buttons,
34883594 int ? pointer,
34893595 String ? pointerType,
3596+ List <_CoalescedTouchDetails >? coalescedEvents,
34903597 }) {
3491- return createDomPointerEvent ('pointermove' , < String , dynamic > {
3598+ final event = createDomPointerEvent ('pointermove' , < String , dynamic > {
34923599 'bubbles' : true ,
34933600 'pointerId' : pointer,
34943601 'button' : button,
@@ -3497,6 +3604,26 @@ class _PointerEventContext extends _BasicEventContext
34973604 'clientY' : clientY,
34983605 'pointerType' : pointerType,
34993606 });
3607+
3608+ if (coalescedEvents != null ) {
3609+ // There's no JS API for setting coalesced events, so we need to
3610+ // monkey-patch the `getCoalescedEvents` method to return what we want.
3611+ final coalescedEventJs = coalescedEvents
3612+ .map ((_CoalescedTouchDetails details) => _moveWithFullDetails (
3613+ pointer: details.pointer,
3614+ button: button,
3615+ buttons: buttons,
3616+ clientX: details.clientX,
3617+ clientY: details.clientY,
3618+ pointerType: 'touch' ,
3619+ )).toJSAnyDeep;
3620+
3621+ js_util.setProperty (event, 'getCoalescedEvents' , js_util.allowInterop (() {
3622+ return coalescedEventJs;
3623+ }));
3624+ }
3625+
3626+ return event;
35003627 }
35013628
35023629 @override
@@ -3537,6 +3664,10 @@ class _PointerEventContext extends _BasicEventContext
35373664
35383665 @override
35393666 List <DomEvent > multiTouchUp (List <_TouchDetails > touches) {
3667+ assert (
3668+ touches.every ((_TouchDetails details) => details.coalescedEvents == null ),
3669+ 'Coalesced events are not allowed for pointerup events.' ,
3670+ );
35403671 return touches
35413672 .map ((_TouchDetails details) => _upWithFullDetails (
35423673 pointer: details.pointer,
@@ -3587,6 +3718,10 @@ class _PointerEventContext extends _BasicEventContext
35873718
35883719 @override
35893720 List <DomEvent > multiTouchCancel (List <_TouchDetails > touches) {
3721+ assert (
3722+ touches.every ((_TouchDetails details) => details.coalescedEvents == null ),
3723+ 'Coalesced events are not allowed for pointercancel events.' ,
3724+ );
35903725 return touches
35913726 .map ((_TouchDetails details) =>
35923727 createDomPointerEvent ('pointercancel' , < String , dynamic > {
0 commit comments