diff --git a/shell/platform/darwin/macos/framework/Headers/FLEViewController.h b/shell/platform/darwin/macos/framework/Headers/FLEViewController.h index 246ae2040a2aa88ca808d55e34a9f9e636182ae7..e831934cd1911933cfd006607269fc7a5d5584c7 100644 --- a/shell/platform/darwin/macos/framework/Headers/FLEViewController.h +++ b/shell/platform/darwin/macos/framework/Headers/FLEViewController.h @@ -16,6 +16,17 @@ #import "FlutterMacros.h" #endif +typedef NS_ENUM(NSInteger, FlutterMouseTrackingMode) { + // Hover events will never be sent to Flutter. + FlutterMouseTrackingModeNone = 0, + // Hover events will be sent to Flutter when the view is in the key window. + FlutterMouseTrackingModeInKeyWindow, + // Hover events will be sent to Flutter when the view is in the active app. + FlutterMouseTrackingModeInActiveApp, + // Hover events will be sent to Flutter regardless of window and app focus. + FlutterMouseTrackingModeAlways, +}; + /** * Controls embedder plugins and communication with the underlying Flutter engine, managing a view * intended to handle key inputs and drawing protocols (see |view|). @@ -33,6 +44,12 @@ FLUTTER_EXPORT */ @property(nullable) NSView* view; +/** + * The style of mouse tracking to use for the view. Defaults to + * FlutterMouseTrackingModeNone. + */ +@property(nonatomic) FlutterMouseTrackingMode mouseTrackingMode; + /** * Launches the Flutter engine with the provided configuration. * diff --git a/shell/platform/darwin/macos/framework/Source/FLEViewController.mm b/shell/platform/darwin/macos/framework/Source/FLEViewController.mm index faf982dff1a9f2f5b2367022116d36341759daf1..ac901423ee1b6688146bf039b8a2dfe366d0bf6b 100644 --- a/shell/platform/darwin/macos/framework/Source/FLEViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FLEViewController.mm @@ -32,7 +32,18 @@ static const int kAndroidMetaStateMeta = 1 << 16; /** * A list of additional responders to keyboard events. Keybord events are forwarded to all of them. */ -@property NSMutableOrderedSet* additionalKeyResponders; +@property(nonatomic) NSMutableOrderedSet* additionalKeyResponders; + +/** + * The tracking area used to generate hover events, if enabled. + */ +@property(nonatomic) NSTrackingArea* trackingArea; + +/** + * Updates |trackingArea| for the current tracking settings, creating it with + * the correct mode if tracking is enabled, or removing it if not. + */ +- (void)configureTrackingArea; /** * Creates and registers plugins used by this view controller. @@ -202,12 +213,28 @@ static void CommonInit(FLEViewController* controller) { } } +- (void)setView:(NSView*)view { + if (_trackingArea) { + [self.view removeTrackingArea:_trackingArea]; + } + [super setView:view]; + [self configureTrackingArea]; +} + - (void)loadView { self.view = [[FLEView alloc] init]; } #pragma mark - Public methods +- (void)setMouseTrackingMode:(FlutterMouseTrackingMode)mode { + if (_mouseTrackingMode == mode) { + return; + } + _mouseTrackingMode = mode; + [self configureTrackingArea]; +} + - (BOOL)launchEngineWithAssetsPath:(NSURL*)assets commandLineArguments:(NSArray*)arguments { return [self launchEngineInternalWithAssetsPath:assets @@ -241,6 +268,35 @@ static void CommonInit(FLEViewController* controller) { #pragma mark - Private methods +- (void)configureTrackingArea { + if (_mouseTrackingMode != FlutterMouseTrackingModeNone && self.view) { + NSTrackingAreaOptions options = + NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect; + switch (_mouseTrackingMode) { + case FlutterMouseTrackingModeInKeyWindow: + options |= NSTrackingActiveInKeyWindow; + break; + case FlutterMouseTrackingModeInActiveApp: + options |= NSTrackingActiveInActiveApp; + break; + case FlutterMouseTrackingModeAlways: + options |= NSTrackingActiveAlways; + break; + default: + NSLog(@"Error: Unrecognized mouse tracking mode: %ld", _mouseTrackingMode); + return; + } + _trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect + options:options + owner:self + userInfo:nil]; + [self.view addTrackingArea:_trackingArea]; + } else if (_trackingArea) { + [self.view removeTrackingArea:_trackingArea]; + _trackingArea = nil; + } +} + - (void)addInternalPlugins { _textInputPlugin = [[FLETextInputPlugin alloc] initWithViewController:self]; _keyEventChannel = @@ -471,4 +527,16 @@ static void CommonInit(FLEViewController* controller) { [self dispatchMouseEvent:event phase:kMove]; } +- (void)mouseEntered:(NSEvent*)event { + [self dispatchMouseEvent:event phase:kAdd]; +} + +- (void)mouseExited:(NSEvent*)event { + [self dispatchMouseEvent:event phase:kRemove]; +} + +- (void)mouseMoved:(NSEvent*)event { + [self dispatchMouseEvent:event phase:kHover]; +} + @end