@@ -2609,6 +2609,88 @@ void testMain() {
26092609 },
26102610 );
26112611
2612+ test ('ignores pointerId on coalesced events' , () {
2613+ final _MultiPointerEventMixin context = _PointerEventContext ();
2614+ final List <ui.PointerDataPacket > packets = < ui.PointerDataPacket > [];
2615+ List <ui.PointerData > data;
2616+ ui.PlatformDispatcher .instance.onPointerDataPacket = (ui.PointerDataPacket packet) {
2617+ packets.add (packet);
2618+ };
2619+
2620+ context.multiTouchDown (const < _TouchDetails > [
2621+ _TouchDetails (pointer: 52 , clientX: 100 , clientY: 101 ),
2622+ ]).forEach (rootElement.dispatchEvent);
2623+ expect (packets.length, 1 );
2624+
2625+ data = packets.single.data;
2626+ expect (data, hasLength (2 ));
2627+ expect (data[0 ].change, equals (ui.PointerChange .add));
2628+ expect (data[0 ].synthesized, isTrue);
2629+ expect (data[0 ].device, equals (52 ));
2630+ expect (data[0 ].physicalX, equals (100 * dpi));
2631+ expect (data[0 ].physicalY, equals (101 * dpi));
2632+
2633+ expect (data[1 ].change, equals (ui.PointerChange .down));
2634+ expect (data[1 ].device, equals (52 ));
2635+ expect (data[1 ].buttons, equals (1 ));
2636+ expect (data[1 ].physicalX, equals (100 * dpi));
2637+ expect (data[1 ].physicalY, equals (101 * dpi));
2638+ expect (data[1 ].physicalDeltaX, equals (0 ));
2639+ expect (data[1 ].physicalDeltaY, equals (0 ));
2640+ packets.clear ();
2641+
2642+ // Pointer move with coaleasced events
2643+ context.multiTouchMove (const < _TouchDetails > [
2644+ _TouchDetails (pointer: 52 , coalescedEvents: < _CoalescedTouchDetails > [
2645+ _CoalescedTouchDetails (pointer: 0 , clientX: 301 , clientY: 302 ),
2646+ _CoalescedTouchDetails (pointer: 0 , clientX: 401 , clientY: 402 ),
2647+ ]),
2648+ ]).forEach (rootElement.dispatchEvent);
2649+ expect (packets.length, 1 );
2650+
2651+ data = packets.single.data;
2652+ expect (data, hasLength (2 ));
2653+ expect (data[0 ].change, equals (ui.PointerChange .move));
2654+ expect (data[0 ].device, equals (52 ));
2655+ expect (data[0 ].buttons, equals (1 ));
2656+ expect (data[0 ].physicalX, equals (301 * dpi));
2657+ expect (data[0 ].physicalY, equals (302 * dpi));
2658+ expect (data[0 ].physicalDeltaX, equals (201 * dpi));
2659+ expect (data[0 ].physicalDeltaY, equals (201 * dpi));
2660+
2661+ expect (data[1 ].change, equals (ui.PointerChange .move));
2662+ expect (data[1 ].device, equals (52 ));
2663+ expect (data[1 ].buttons, equals (1 ));
2664+ expect (data[1 ].physicalX, equals (401 * dpi));
2665+ expect (data[1 ].physicalY, equals (402 * dpi));
2666+ expect (data[1 ].physicalDeltaX, equals (100 * dpi));
2667+ expect (data[1 ].physicalDeltaY, equals (100 * dpi));
2668+ packets.clear ();
2669+
2670+ // Pointer up
2671+ context.multiTouchUp (const < _TouchDetails > [
2672+ _TouchDetails (pointer: 52 , clientX: 401 , clientY: 402 ),
2673+ ]).forEach (rootElement.dispatchEvent);
2674+ expect (packets, hasLength (1 ));
2675+ expect (packets[0 ].data, hasLength (2 ));
2676+ expect (packets[0 ].data[0 ].change, equals (ui.PointerChange .up));
2677+ expect (packets[0 ].data[0 ].device, equals (52 ));
2678+ expect (packets[0 ].data[0 ].buttons, equals (0 ));
2679+ expect (packets[0 ].data[0 ].physicalX, equals (401 * dpi));
2680+ expect (packets[0 ].data[0 ].physicalY, equals (402 * dpi));
2681+ expect (packets[0 ].data[0 ].physicalDeltaX, equals (0 ));
2682+ expect (packets[0 ].data[0 ].physicalDeltaY, equals (0 ));
2683+
2684+ expect (packets[0 ].data[1 ].change, equals (ui.PointerChange .remove));
2685+ expect (packets[0 ].data[1 ].device, equals (52 ));
2686+ expect (packets[0 ].data[1 ].buttons, equals (0 ));
2687+ expect (packets[0 ].data[1 ].physicalX, equals (401 * dpi));
2688+ expect (packets[0 ].data[1 ].physicalY, equals (402 * dpi));
2689+ expect (packets[0 ].data[1 ].physicalDeltaX, equals (0 ));
2690+ expect (packets[0 ].data[1 ].physicalDeltaY, equals (0 ));
2691+ packets.clear ();
2692+ });
2693+
26122694 test (
26132695 'correctly parses cancel event' ,
26142696 () {
@@ -3419,7 +3501,26 @@ mixin _ButtonedEventMixin on _BasicEventContext {
34193501}
34203502
34213503class _TouchDetails {
3422- const _TouchDetails ({this .pointer, this .clientX, this .clientY});
3504+ const _TouchDetails ({
3505+ this .pointer,
3506+ this .clientX,
3507+ this .clientY,
3508+ this .coalescedEvents,
3509+ });
3510+
3511+ final int ? pointer;
3512+ final double ? clientX;
3513+ final double ? clientY;
3514+
3515+ final List <_CoalescedTouchDetails >? coalescedEvents;
3516+ }
3517+
3518+ class _CoalescedTouchDetails {
3519+ const _CoalescedTouchDetails ({
3520+ this .pointer,
3521+ this .clientX,
3522+ this .clientY,
3523+ });
34233524
34243525 final int ? pointer;
34253526 final double ? clientX;
@@ -3478,6 +3579,10 @@ class _PointerEventContext extends _BasicEventContext
34783579
34793580 @override
34803581 List <DomEvent > multiTouchDown (List <_TouchDetails > touches) {
3582+ assert (
3583+ touches.every ((_TouchDetails details) => details.coalescedEvents == null ),
3584+ 'Coalesced events are not allowed for pointerdown events.' ,
3585+ );
34813586 return touches
34823587 .map ((_TouchDetails details) => _downWithFullDetails (
34833588 pointer: details.pointer,
@@ -3541,6 +3646,7 @@ class _PointerEventContext extends _BasicEventContext
35413646 clientX: details.clientX,
35423647 clientY: details.clientY,
35433648 pointerType: 'touch' ,
3649+ coalescedEvents: details.coalescedEvents,
35443650 ))
35453651 .toList ();
35463652 }
@@ -3570,8 +3676,9 @@ class _PointerEventContext extends _BasicEventContext
35703676 int ? buttons,
35713677 int ? pointer,
35723678 String ? pointerType,
3679+ List <_CoalescedTouchDetails >? coalescedEvents,
35733680 }) {
3574- return createDomPointerEvent ('pointermove' , < String , dynamic > {
3681+ final event = createDomPointerEvent ('pointermove' , < String , dynamic > {
35753682 'bubbles' : true ,
35763683 'pointerId' : pointer,
35773684 'button' : button,
@@ -3580,6 +3687,26 @@ class _PointerEventContext extends _BasicEventContext
35803687 'clientY' : clientY,
35813688 'pointerType' : pointerType,
35823689 });
3690+
3691+ if (coalescedEvents != null ) {
3692+ // There's no JS API for setting coalesced events, so we need to
3693+ // monkey-patch the `getCoalescedEvents` method to return what we want.
3694+ final coalescedEventJs = coalescedEvents
3695+ .map ((_CoalescedTouchDetails details) => _moveWithFullDetails (
3696+ pointer: details.pointer,
3697+ button: button,
3698+ buttons: buttons,
3699+ clientX: details.clientX,
3700+ clientY: details.clientY,
3701+ pointerType: 'touch' ,
3702+ )).toJSAnyDeep;
3703+
3704+ js_util.setProperty (event, 'getCoalescedEvents' , js_util.allowInterop (() {
3705+ return coalescedEventJs;
3706+ }));
3707+ }
3708+
3709+ return event;
35833710 }
35843711
35853712 @override
@@ -3620,6 +3747,10 @@ class _PointerEventContext extends _BasicEventContext
36203747
36213748 @override
36223749 List <DomEvent > multiTouchUp (List <_TouchDetails > touches) {
3750+ assert (
3751+ touches.every ((_TouchDetails details) => details.coalescedEvents == null ),
3752+ 'Coalesced events are not allowed for pointerup events.' ,
3753+ );
36233754 return touches
36243755 .map ((_TouchDetails details) => _upWithFullDetails (
36253756 pointer: details.pointer,
@@ -3670,6 +3801,10 @@ class _PointerEventContext extends _BasicEventContext
36703801
36713802 @override
36723803 List <DomEvent > multiTouchCancel (List <_TouchDetails > touches) {
3804+ assert (
3805+ touches.every ((_TouchDetails details) => details.coalescedEvents == null ),
3806+ 'Coalesced events are not allowed for pointercancel events.' ,
3807+ );
36733808 return touches
36743809 .map ((_TouchDetails details) =>
36753810 createDomPointerEvent ('pointercancel' , < String , dynamic > {
0 commit comments