@@ -39,6 +39,14 @@ @interface FLEViewController ()
39
39
*/
40
40
@property (nonatomic ) NSTrackingArea * trackingArea;
41
41
42
+ /* *
43
+ * Whether or not a kAdd event has been sent for the mouse (or sent again since
44
+ * the last kRemove was sent if tracking is enabled). Used to determine whether
45
+ * to send an Add event before sending an incoming mouse event, since Flutter
46
+ * expects a pointers to be added before events are sent for them.
47
+ */
48
+ @property (nonatomic ) BOOL mouseCurrentlyAdded;
49
+
42
50
/* *
43
51
* Updates |trackingArea| for the current tracking settings, creating it with
44
52
* the correct mode if tracking is enabled, or removing it if not.
@@ -416,16 +424,54 @@ - (void)handlePlatformMessage:(const FlutterPlatformMessage*)message {
416
424
}
417
425
418
426
- (void )dispatchMouseEvent : (NSEvent *)event phase : (FlutterPointerPhase)phase {
427
+ // If a pointer added event hasn't been sent, synthesize one using this event for the basic
428
+ // information.
429
+ if (!_mouseCurrentlyAdded && phase != kAdd ) {
430
+ // Only the values extracted for use in flutterEvent below matter, the rest are dummy values.
431
+ NSEvent * addEvent = [NSEvent enterExitEventWithType: NSEventTypeMouseEntered
432
+ location: event.locationInWindow
433
+ modifierFlags: 0
434
+ timestamp: event.timestamp
435
+ windowNumber: event.windowNumber
436
+ context: nil
437
+ eventNumber: 0
438
+ trackingNumber: 0
439
+ userData: NULL ];
440
+ [self dispatchMouseEvent: addEvent phase: kAdd ];
441
+ }
442
+
419
443
NSPoint locationInView = [self .view convertPoint: event.locationInWindow fromView: nil ];
420
444
NSPoint locationInBackingCoordinates = [self .view convertPointToBacking: locationInView];
421
- const FlutterPointerEvent flutterEvent = {
445
+ FlutterPointerEvent flutterEvent = {
422
446
.struct_size = sizeof (flutterEvent),
423
447
.phase = phase,
424
448
.x = locationInBackingCoordinates.x ,
425
449
.y = -locationInBackingCoordinates.y , // convertPointToBacking makes this negative.
426
450
.timestamp = static_cast <size_t >(event.timestamp * NSEC_PER_MSEC),
427
451
};
452
+
453
+ if (event.type == NSEventTypeScrollWheel) {
454
+ flutterEvent.signal_kind = kFlutterPointerSignalKindScroll ;
455
+
456
+ double pixelsPerLine = 1.0 ;
457
+ if (!event.hasPreciseScrollingDeltas ) {
458
+ CGEventSourceRef source = CGEventCreateSourceFromEvent (event.CGEvent );
459
+ pixelsPerLine = CGEventSourceGetPixelsPerLine (source);
460
+ if (source) {
461
+ CFRelease (source);
462
+ }
463
+ }
464
+ double scaleFactor = self.view .layer .contentsScale ;
465
+ flutterEvent.scroll_delta_x = event.scrollingDeltaX * pixelsPerLine * scaleFactor;
466
+ flutterEvent.scroll_delta_y = -event.scrollingDeltaY * pixelsPerLine * scaleFactor;
467
+ }
428
468
FlutterEngineSendPointerEvent (_engine, &flutterEvent, 1 );
469
+
470
+ if (phase == kAdd ) {
471
+ _mouseCurrentlyAdded = YES ;
472
+ } else if (phase == kRemove ) {
473
+ _mouseCurrentlyAdded = NO ;
474
+ }
429
475
}
430
476
431
477
- (void )dispatchKeyEvent : (NSEvent *)event ofType : (NSString *)type {
@@ -539,4 +585,10 @@ - (void)mouseMoved:(NSEvent*)event {
539
585
[self dispatchMouseEvent: event phase: kHover ];
540
586
}
541
587
588
+ - (void )scrollWheel : (NSEvent *)event {
589
+ // TODO: Add gesture-based (trackpad) scroll support once it's supported by the engine rather
590
+ // than always using kHover.
591
+ [self dispatchMouseEvent: event phase: kHover ];
592
+ }
593
+
542
594
@end
0 commit comments