Flutter macOS Embedder
FlutterMenuPlugin.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #import "FlutterMenuPlugin.h"
6 
7 #include <map>
8 
12 
13 // Channel constants
14 static NSString* const kChannelName = @"flutter/menu";
15 static NSString* const kIsPluginAvailableMethod = @"Menu.isPluginAvailable";
16 static NSString* const kMenuSetMenusMethod = @"Menu.setMenus";
17 static NSString* const kMenuSelectedCallbackMethod = @"Menu.selectedCallback";
18 static NSString* const kMenuOpenedMethod = @"Menu.opened";
19 static NSString* const kMenuClosedMethod = @"Menu.closed";
20 
21 // Serialization keys for menu objects
22 static NSString* const kIdKey = @"id";
23 static NSString* const kLabelKey = @"label";
24 static NSString* const kEnabledKey = @"enabled";
25 static NSString* const kChildrenKey = @"children";
26 static NSString* const kDividerKey = @"isDivider";
27 static NSString* const kShortcutCharacterKey = @"shortcutCharacter";
28 static NSString* const kShortcutTriggerKey = @"shortcutTrigger";
29 static NSString* const kShortcutModifiersKey = @"shortcutModifiers";
30 static NSString* const kPlatformProvidedMenuKey = @"platformProvidedMenu";
31 
32 // Key shortcut constants
33 constexpr int kFlutterShortcutModifierMeta = 1 << 0;
34 constexpr int kFlutterShortcutModifierShift = 1 << 1;
35 constexpr int kFlutterShortcutModifierAlt = 1 << 2;
36 constexpr int kFlutterShortcutModifierControl = 1 << 3;
37 
38 constexpr uint64_t kFlutterKeyIdPlaneMask = 0xff00000000l;
39 constexpr uint64_t kFlutterKeyIdUnicodePlane = 0x0000000000l;
40 constexpr uint64_t kFlutterKeyIdValueMask = 0x00ffffffffl;
41 
42 static const NSDictionary* logicalKeyToKeyCode = {};
43 
44 // What to look for in menu titles to replace with the application name.
45 static NSString* const kAppName = @"APP_NAME";
46 
47 // Odd facts about AppKit key equivalents:
48 //
49 // 1) ⌃⇧1 and ⇧1 cannot exist in the same app, or the former triggers the latter’s
50 // action.
51 // 2) ⌃⌥⇧1 and ⇧1 cannot exist in the same app, or the former triggers the latter’s
52 // action.
53 // 3) ⌃⌥⇧1 and ⌃⇧1 cannot exist in the same app, or the former triggers the latter’s
54 // action.
55 // 4) ⌃⇧a is equivalent to ⌃A: If a keyEquivalent is a capitalized alphabetical
56 // letter and keyEquivalentModifierMask does not include
57 // NSEventModifierFlagShift, AppKit will add ⇧ automatically in the UI.
58 
59 /**
60  * Maps the string used by NSMenuItem for the given special key equivalent.
61  * Keys are the logical key ids of matching trigger keys.
62  */
63 static NSDictionary<NSNumber*, NSNumber*>* GetMacOsSpecialKeys() {
64  return @{
65  @0x00100000008 : [NSNumber numberWithInt:NSBackspaceCharacter],
66  @0x00100000009 : [NSNumber numberWithInt:NSTabCharacter],
67  @0x0010000000a : [NSNumber numberWithInt:NSNewlineCharacter],
68  @0x0010000000c : [NSNumber numberWithInt:NSFormFeedCharacter],
69  @0x0010000000d : [NSNumber numberWithInt:NSCarriageReturnCharacter],
70  @0x0010000007f : [NSNumber numberWithInt:NSDeleteCharacter],
71  @0x00100000801 : [NSNumber numberWithInt:NSF1FunctionKey],
72  @0x00100000802 : [NSNumber numberWithInt:NSF2FunctionKey],
73  @0x00100000803 : [NSNumber numberWithInt:NSF3FunctionKey],
74  @0x00100000804 : [NSNumber numberWithInt:NSF4FunctionKey],
75  @0x00100000805 : [NSNumber numberWithInt:NSF5FunctionKey],
76  @0x00100000806 : [NSNumber numberWithInt:NSF6FunctionKey],
77  @0x00100000807 : [NSNumber numberWithInt:NSF7FunctionKey],
78  @0x00100000808 : [NSNumber numberWithInt:NSF8FunctionKey],
79  @0x00100000809 : [NSNumber numberWithInt:NSF9FunctionKey],
80  @0x0010000080a : [NSNumber numberWithInt:NSF10FunctionKey],
81  @0x0010000080b : [NSNumber numberWithInt:NSF11FunctionKey],
82  @0x0010000080c : [NSNumber numberWithInt:NSF12FunctionKey],
83  @0x0010000080d : [NSNumber numberWithInt:NSF13FunctionKey],
84  @0x0010000080e : [NSNumber numberWithInt:NSF14FunctionKey],
85  @0x0010000080f : [NSNumber numberWithInt:NSF15FunctionKey],
86  @0x00100000810 : [NSNumber numberWithInt:NSF16FunctionKey],
87  @0x00100000811 : [NSNumber numberWithInt:NSF17FunctionKey],
88  @0x00100000812 : [NSNumber numberWithInt:NSF18FunctionKey],
89  @0x00100000813 : [NSNumber numberWithInt:NSF19FunctionKey],
90  @0x00100000814 : [NSNumber numberWithInt:NSF20FunctionKey],
91 
92  // For some reason, there don't appear to be constants for these in ObjC. In
93  // Swift, there is a class with static members for these: KeyEquivalent. The
94  // values below are taken from that (where they don't already appear above).
95  @0x00100000302 : @0xf702, // ArrowLeft
96  @0x00100000303 : @0xf703, // ArrowRight
97  @0x00100000304 : @0xf700, // ArrowUp
98  @0x00100000301 : @0xf701, // ArrowDown
99  @0x00100000306 : @0xf729, // Home
100  @0x00100000305 : @0xf72B, // End
101  @0x00100000308 : @0xf72c, // PageUp
102  @0x00100000307 : @0xf72d, // PageDown
103  @0x0010000001b : @0x001B, // Escape
104  };
105 }
106 
107 /**
108  * The mapping from the PlatformProvidedMenu enum to the macOS selectors for the provided
109  * menus.
110  */
111 static const std::map<flutter::PlatformProvidedMenu, SEL> GetMacOSProvidedMenus() {
112  return {
113  {flutter::PlatformProvidedMenu::kAbout, @selector(orderFrontStandardAboutPanel:)},
114  {flutter::PlatformProvidedMenu::kQuit, @selector(terminate:)},
115  // servicesSubmenu is handled specially below: it is assumed to be the first
116  // submenu in the preserved platform provided menus, since it doesn't have a
117  // definitive selector like the rest.
118  {flutter::PlatformProvidedMenu::kServicesSubmenu, @selector(submenuAction:)},
119  {flutter::PlatformProvidedMenu::kHide, @selector(hide:)},
120  {flutter::PlatformProvidedMenu::kHideOtherApplications, @selector(hideOtherApplications:)},
121  {flutter::PlatformProvidedMenu::kShowAllApplications, @selector(unhideAllApplications:)},
122  {flutter::PlatformProvidedMenu::kStartSpeaking, @selector(startSpeaking:)},
123  {flutter::PlatformProvidedMenu::kStopSpeaking, @selector(stopSpeaking:)},
124  {flutter::PlatformProvidedMenu::kToggleFullScreen, @selector(toggleFullScreen:)},
125  {flutter::PlatformProvidedMenu::kMinimizeWindow, @selector(performMiniaturize:)},
126  {flutter::PlatformProvidedMenu::kZoomWindow, @selector(performZoom:)},
127  {flutter::PlatformProvidedMenu::kArrangeWindowsInFront, @selector(arrangeInFront:)},
128  };
129 }
130 
131 /**
132  * Returns the NSEventModifierFlags of |modifiers|, a value from
133  * kShortcutKeyModifiers.
134  */
135 static NSEventModifierFlags KeyEquivalentModifierMaskForModifiers(NSNumber* modifiers) {
136  int flutterModifierFlags = modifiers.intValue;
137  NSEventModifierFlags flags = 0;
138  if (flutterModifierFlags & kFlutterShortcutModifierMeta) {
139  flags |= NSEventModifierFlagCommand;
140  }
141  if (flutterModifierFlags & kFlutterShortcutModifierShift) {
142  flags |= NSEventModifierFlagShift;
143  }
144  if (flutterModifierFlags & kFlutterShortcutModifierAlt) {
145  flags |= NSEventModifierFlagOption;
146  }
147  if (flutterModifierFlags & kFlutterShortcutModifierControl) {
148  flags |= NSEventModifierFlagControl;
149  }
150  // There are also modifier flags for things like the function (Fn) key, but
151  // the framework doesn't support those.
152  return flags;
153 }
154 
155 /**
156  * An NSMenuDelegate used to listen for changes in the menu when it opens and
157  * closes.
158  */
159 @interface FlutterMenuDelegate : NSObject <NSMenuDelegate>
160 /**
161  * When this delegate receives notification that the menu opened or closed, it
162  * will send a message on the given channel to that effect for the menu item
163  * with the given id (the ID comes from the data supplied by the framework to
164  * |FlutterMenuPlugin.setMenus|).
165  */
166 - (instancetype)initWithIdentifier:(int64_t)identifier channel:(FlutterMethodChannel*)channel;
167 @end
168 
169 @implementation FlutterMenuDelegate {
170  FlutterMethodChannel* _channel;
171  int64_t _identifier;
172 }
173 
174 - (instancetype)initWithIdentifier:(int64_t)identifier channel:(FlutterMethodChannel*)channel {
175  self = [super init];
176  if (self) {
177  _identifier = identifier;
178  _channel = channel;
179  }
180  return self;
181 }
182 
183 - (void)menuWillOpen:(NSMenu*)menu {
184  [_channel invokeMethod:kMenuOpenedMethod arguments:@(_identifier)];
185 }
186 
187 - (void)menuDidClose:(NSMenu*)menu {
188  [_channel invokeMethod:kMenuClosedMethod arguments:@(_identifier)];
189 }
190 @end
191 
192 @interface FlutterMenuPlugin ()
193 // Initialize the plugin with the given method channel.
194 - (instancetype)initWithChannel:(FlutterMethodChannel*)channel;
195 
196 // Iterates through the given menu hierarchy, and replaces "APP_NAME"
197 // with the localized running application name.
198 - (void)replaceAppName:(NSArray<NSMenuItem*>*)items;
199 
200 // Look up the menu item with the given selector in the list of provided menus
201 // and return it.
202 - (NSMenuItem*)findProvidedMenuItem:(NSMenu*)menu ofType:(SEL)selector;
203 
204 // Create a platform-provided menu from the given enum type.
205 - (NSMenuItem*)createPlatformProvidedMenu:(flutter::PlatformProvidedMenu)type;
206 
207 // Create an NSMenuItem from information in the dictionary sent by the framework.
208 - (NSMenuItem*)menuItemFromFlutterRepresentation:(NSDictionary*)representation;
209 
210 // Invokes kMenuSelectedCallbackMethod with the senders ID.
211 //
212 // Used as the callback for all Flutter-created menu items that have IDs.
213 - (void)flutterMenuItemSelected:(id)sender;
214 
215 // Replaces the NSApp.mainMenu with menus created from an array of top level
216 // menus sent by the framework.
217 - (void)setMenus:(nonnull NSDictionary*)representation;
218 @end
219 
220 @implementation FlutterMenuPlugin {
221  // The channel used to communicate with Flutter.
222  FlutterMethodChannel* _channel;
223 
224  // This contains a copy of the default platform provided items.
225  NSArray<NSMenuItem*>* _platformProvidedItems;
226  // These are the menu delegates that will listen to open/close events for menu
227  // items. This array is holding them so that we can deallocate them when
228  // rebuilding the menus.
229  NSMutableArray<FlutterMenuDelegate*>* _menuDelegates;
230 }
231 
232 #pragma mark - Private Methods
233 
234 - (instancetype)initWithChannel:(FlutterMethodChannel*)channel {
235  self = [super init];
236  if (self) {
237  _channel = channel;
239  _menuDelegates = [[NSMutableArray alloc] init];
240 
241  // Make a copy of all the platform provided menus for later use.
242  _platformProvidedItems = [[NSApp.mainMenu itemArray] mutableCopy];
243 
244  // As copied, these platform provided menu items don't yet have the APP_NAME
245  // string replaced in them, so this rectifies that.
246  [self replaceAppName:_platformProvidedItems];
247  }
248  return self;
249 }
250 
251 /**
252  * Iterates through the given menu hierarchy, and replaces "APP_NAME"
253  * with the localized running application name.
254  */
255 - (void)replaceAppName:(NSArray<NSMenuItem*>*)items {
256  NSString* appName = [NSRunningApplication currentApplication].localizedName;
257  for (NSMenuItem* item in items) {
258  if ([[item title] containsString:kAppName]) {
259  [item setTitle:[[item title] stringByReplacingOccurrencesOfString:kAppName
260  withString:appName]];
261  }
262  if ([item hasSubmenu]) {
263  [self replaceAppName:[[item submenu] itemArray]];
264  }
265  }
266 }
267 
268 - (NSMenuItem*)findProvidedMenuItem:(NSMenu*)menu ofType:(SEL)selector {
269  const NSArray<NSMenuItem*>* items = menu ? menu.itemArray : _platformProvidedItems;
270  for (NSMenuItem* item in items) {
271  if ([item action] == selector) {
272  return item;
273  }
274  if ([[item submenu] numberOfItems] > 0) {
275  NSMenuItem* foundChild = [self findProvidedMenuItem:[item submenu] ofType:selector];
276  if (foundChild) {
277  return foundChild;
278  }
279  }
280  }
281  return nil;
282 }
283 
284 - (NSMenuItem*)createPlatformProvidedMenu:(flutter::PlatformProvidedMenu)type {
285  const std::map<flutter::PlatformProvidedMenu, SEL> providedMenus = GetMacOSProvidedMenus();
286  auto found_type = providedMenus.find(type);
287  if (found_type == providedMenus.end()) {
288  return nil;
289  }
290  SEL selectorTarget = found_type->second;
291  // Since it doesn't have a definitive selector, the Services submenu is
292  // assumed to be the first item with a submenu action in the first menu item
293  // of the default menu set. We can't just get the title to check, since that
294  // is localized, and the contents of the menu aren't fixed (or even available).
295  NSMenu* startingMenu = type == flutter::PlatformProvidedMenu::kServicesSubmenu
296  ? [_platformProvidedItems[0] submenu]
297  : nil;
298  NSMenuItem* found = [self findProvidedMenuItem:startingMenu ofType:selectorTarget];
299  // Return a copy because the original menu item might not have been removed
300  // from the main menu yet, and AppKit doesn't like menu items that exist in
301  // more than one menu at a time.
302  return [found copy];
303 }
304 
305 - (NSMenuItem*)menuItemFromFlutterRepresentation:(NSDictionary*)representation {
306  if ([(NSNumber*)([representation valueForKey:kDividerKey]) intValue] == YES) {
307  return [NSMenuItem separatorItem];
308  }
309  NSNumber* platformProvidedMenuId = representation[kPlatformProvidedMenuKey];
310  NSString* keyEquivalent = @"";
311 
312  if (platformProvidedMenuId) {
313  return [self
314  createPlatformProvidedMenu:(flutter::PlatformProvidedMenu)platformProvidedMenuId.intValue];
315  } else {
316  if (representation[kShortcutCharacterKey]) {
317  keyEquivalent = representation[kShortcutCharacterKey];
318  } else {
319  NSNumber* triggerKeyId = representation[kShortcutTriggerKey];
320  const NSDictionary<NSNumber*, NSNumber*>* specialKeys = GetMacOsSpecialKeys();
321  NSNumber* trigger = specialKeys[triggerKeyId];
322  if (trigger) {
323  keyEquivalent = [NSString stringWithFormat:@"%C", [trigger unsignedShortValue]];
324  } else {
325  if (([triggerKeyId unsignedLongLongValue] & kFlutterKeyIdPlaneMask) ==
327  keyEquivalent = [[NSString
328  stringWithFormat:@"%C", (unichar)([triggerKeyId unsignedLongLongValue] &
329  kFlutterKeyIdValueMask)] lowercaseString];
330  }
331  }
332  }
333  }
334 
335  NSNumber* identifier = representation[kIdKey];
336  SEL action = (identifier ? @selector(flutterMenuItemSelected:) : NULL);
337  NSString* appName = [NSRunningApplication currentApplication].localizedName;
338  NSString* title = [representation[kLabelKey] stringByReplacingOccurrencesOfString:kAppName
339  withString:appName];
340  NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:title
341  action:action
342  keyEquivalent:keyEquivalent];
343  if ([keyEquivalent length] > 0) {
344  item.keyEquivalentModifierMask =
346  }
347  if (identifier) {
348  item.tag = identifier.longLongValue;
349  item.target = self;
350  }
351  NSNumber* enabled = representation[kEnabledKey];
352  if (enabled) {
353  item.enabled = enabled.boolValue;
354  }
355 
356  NSArray* children = representation[kChildrenKey];
357  if (children && children.count > 0) {
358  NSMenu* submenu = [[NSMenu alloc] initWithTitle:title];
359  FlutterMenuDelegate* delegate = [[FlutterMenuDelegate alloc] initWithIdentifier:item.tag
360  channel:_channel];
361  [_menuDelegates addObject:delegate];
362  submenu.delegate = delegate;
363  submenu.autoenablesItems = NO;
364  for (NSDictionary* child in children) {
365  NSMenuItem* newItem = [self menuItemFromFlutterRepresentation:child];
366  if (newItem) {
367  [submenu addItem:newItem];
368  }
369  }
370  item.submenu = submenu;
371  }
372  return item;
373 }
374 
375 - (void)flutterMenuItemSelected:(id)sender {
376  NSMenuItem* item = sender;
377  [_channel invokeMethod:kMenuSelectedCallbackMethod arguments:@(item.tag)];
378 }
379 
380 - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
381  if ([call.method isEqualToString:kIsPluginAvailableMethod]) {
382  result(@YES);
383  } else if ([call.method isEqualToString:kMenuSetMenusMethod]) {
384  NSDictionary* menus = call.arguments;
385  [self setMenus:menus];
386  result(nil);
387  } else {
389  }
390 }
391 
392 - (void)setMenus:(NSDictionary*)representation {
393  [_menuDelegates removeAllObjects];
394  NSMenu* newMenu = [[NSMenu alloc] init];
395  // There's currently only one window, named "0", but there could be other
396  // eventually, with different menu configurations.
397  for (NSDictionary* item in representation[@"0"]) {
398  NSMenuItem* menuItem = [self menuItemFromFlutterRepresentation:item];
399  menuItem.representedObject = self;
400  NSNumber* identifier = item[kIdKey];
401  FlutterMenuDelegate* delegate =
402  [[FlutterMenuDelegate alloc] initWithIdentifier:identifier.longLongValue channel:_channel];
403  [_menuDelegates addObject:delegate];
404  [menuItem submenu].delegate = delegate;
405  [newMenu addItem:menuItem];
406  }
407  NSApp.mainMenu = newMenu;
408 }
409 
410 #pragma mark - Public Class Methods
411 
412 + (void)registerWithRegistrar:(nonnull id<FlutterPluginRegistrar>)registrar {
414  binaryMessenger:registrar.messenger];
415  FlutterMenuPlugin* instance = [[FlutterMenuPlugin alloc] initWithChannel:channel];
416  [registrar addMethodCallDelegate:instance channel:channel];
417 }
418 
419 @end
kIsPluginAvailableMethod
static NSString *const kIsPluginAvailableMethod
Definition: FlutterMenuPlugin.mm:15
kFlutterShortcutModifierAlt
constexpr int kFlutterShortcutModifierAlt
Definition: FlutterMenuPlugin.mm:35
kIdKey
static NSString *const kIdKey
Definition: FlutterMenuPlugin.mm:22
FlutterMenuPlugin.h
flutter::PlatformProvidedMenu::kServicesSubmenu
@ kServicesSubmenu
kFlutterShortcutModifierShift
constexpr int kFlutterShortcutModifierShift
Definition: FlutterMenuPlugin.mm:34
KeyEquivalentModifierMaskForModifiers
static NSEventModifierFlags KeyEquivalentModifierMaskForModifiers(NSNumber *modifiers)
Definition: FlutterMenuPlugin.mm:135
FlutterMethodChannel
Definition: FlutterChannels.h:220
flutter::PlatformProvidedMenu::kStopSpeaking
@ kStopSpeaking
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
kFlutterShortcutModifierControl
constexpr int kFlutterShortcutModifierControl
Definition: FlutterMenuPlugin.mm:36
kAppName
static NSString *const kAppName
Definition: FlutterMenuPlugin.mm:45
kMenuClosedMethod
static NSString *const kMenuClosedMethod
Definition: FlutterMenuPlugin.mm:19
flutter::PlatformProvidedMenu::kMinimizeWindow
@ kMinimizeWindow
GetMacOSProvidedMenus
static const std::map< flutter::PlatformProvidedMenu, SEL > GetMacOSProvidedMenus()
Definition: FlutterMenuPlugin.mm:111
FlutterChannels.h
kDividerKey
static NSString *const kDividerKey
Definition: FlutterMenuPlugin.mm:26
kFlutterShortcutModifierMeta
constexpr int kFlutterShortcutModifierMeta
Definition: FlutterMenuPlugin.mm:33
kFlutterKeyIdUnicodePlane
constexpr uint64_t kFlutterKeyIdUnicodePlane
Definition: FlutterMenuPlugin.mm:39
FlutterMethodCall::method
NSString * method
Definition: FlutterCodecs.h:233
kLabelKey
static NSString *const kLabelKey
Definition: FlutterMenuPlugin.mm:23
_menuDelegates
NSMutableArray< FlutterMenuDelegate * > * _menuDelegates
Definition: FlutterMenuPlugin.mm:229
kChildrenKey
static NSString *const kChildrenKey
Definition: FlutterMenuPlugin.mm:25
flutter::PlatformProvidedMenu::kToggleFullScreen
@ kToggleFullScreen
FlutterMenuPlugin
Definition: FlutterMenuPlugin.h:20
FlutterPluginRegistrar-p
Definition: FlutterPluginRegistrarMacOS.h:28
kEnabledKey
static NSString *const kEnabledKey
Definition: FlutterMenuPlugin.mm:24
flutter::PlatformProvidedMenu::kStartSpeaking
@ kStartSpeaking
platform_provided_menu.h
kFlutterKeyIdPlaneMask
constexpr uint64_t kFlutterKeyIdPlaneMask
Definition: FlutterMenuPlugin.mm:38
-[FlutterPluginRegistrar-p addMethodCallDelegate:channel:]
void addMethodCallDelegate:channel:(nonnull id< FlutterPlugin > delegate,[channel] nonnull FlutterMethodChannel *channel)
FlutterMethodCall
Definition: FlutterCodecs.h:220
kMenuSelectedCallbackMethod
static NSString *const kMenuSelectedCallbackMethod
Definition: FlutterMenuPlugin.mm:17
flutter
Definition: AccessibilityBridgeMac.h:16
flutter::PlatformProvidedMenu::kHideOtherApplications
@ kHideOtherApplications
FlutterMenuDelegate
Definition: FlutterMenuPlugin.mm:159
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
FlutterCodecs.h
kPlatformProvidedMenuKey
static NSString *const kPlatformProvidedMenuKey
Definition: FlutterMenuPlugin.mm:30
_platformProvidedItems
NSArray< NSMenuItem * > * _platformProvidedItems
Definition: FlutterMenuPlugin.mm:220
flutter::PlatformProvidedMenu::kArrangeWindowsInFront
@ kArrangeWindowsInFront
kChannelName
static NSString *const kChannelName
Definition: FlutterMenuPlugin.mm:14
flutter::PlatformProvidedMenu
PlatformProvidedMenu
Definition: platform_provided_menu.h:12
flutter::PlatformProvidedMenu::kAbout
@ kAbout
flutter::PlatformProvidedMenu::kShowAllApplications
@ kShowAllApplications
kShortcutModifiersKey
static NSString *const kShortcutModifiersKey
Definition: FlutterMenuPlugin.mm:29
logicalKeyToKeyCode
static const NSDictionary * logicalKeyToKeyCode
Definition: FlutterMenuPlugin.mm:42
kMenuSetMenusMethod
static NSString *const kMenuSetMenusMethod
Definition: FlutterMenuPlugin.mm:16
kShortcutTriggerKey
static NSString *const kShortcutTriggerKey
Definition: FlutterMenuPlugin.mm:28
+[FlutterMethodChannel methodChannelWithName:binaryMessenger:]
instancetype methodChannelWithName:binaryMessenger:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger)
kMenuOpenedMethod
static NSString *const kMenuOpenedMethod
Definition: FlutterMenuPlugin.mm:18
flutter::PlatformProvidedMenu::kQuit
@ kQuit
GetMacOsSpecialKeys
static NSDictionary< NSNumber *, NSNumber * > * GetMacOsSpecialKeys()
Definition: FlutterMenuPlugin.mm:63
kShortcutCharacterKey
static NSString *const kShortcutCharacterKey
Definition: FlutterMenuPlugin.mm:27
FlutterMethodCall::arguments
id arguments
Definition: FlutterCodecs.h:238
flutter::PlatformProvidedMenu::kZoomWindow
@ kZoomWindow
kFlutterKeyIdValueMask
constexpr uint64_t kFlutterKeyIdValueMask
Definition: FlutterMenuPlugin.mm:40
_identifier
int64_t _identifier
Definition: FlutterMenuPlugin.mm:169
flutter::PlatformProvidedMenu::kHide
@ kHide