@@ -164,8 +164,6 @@ @interface FlutterViewWrapper : NSView
164164
165165- (void )setBackgroundColor : (NSColor *)color ;
166166
167- - (BOOL )performKeyEquivalent : (NSEvent *)event ;
168-
169167@end
170168
171169/* *
@@ -242,37 +240,6 @@ - (void)onKeyboardLayoutChanged;
242240
243241@end
244242
245- #pragma mark - NSEvent (KeyEquivalentMarker) protocol
246-
247- @interface NSEvent (KeyEquivalentMarker)
248-
249- // Internally marks that the event was received through performKeyEquivalent:.
250- // When text editing is active, keyboard events that have modifier keys pressed
251- // are received through performKeyEquivalent: instead of keyDown:. If such event
252- // is passed to TextInputContext but doesn't result in a text editing action it
253- // needs to be forwarded by FlutterKeyboardManager to the next responder.
254- - (void )markAsKeyEquivalent ;
255-
256- // Returns YES if the event is marked as a key equivalent.
257- - (BOOL )isKeyEquivalent ;
258-
259- @end
260-
261- @implementation NSEvent (KeyEquivalentMarker)
262-
263- // This field doesn't need a value because only its address is used as a unique identifier.
264- static char markerKey;
265-
266- - (void )markAsKeyEquivalent {
267- objc_setAssociatedObject (self, &markerKey, @true , OBJC_ASSOCIATION_RETAIN );
268- }
269-
270- - (BOOL )isKeyEquivalent {
271- return [objc_getAssociatedObject (self , &markerKey) boolValue ] == YES ;
272- }
273-
274- @end
275-
276243#pragma mark - Private dependant functions
277244
278245namespace {
@@ -312,19 +279,15 @@ - (void)setBackgroundColor:(NSColor*)color {
312279}
313280
314281- (BOOL )performKeyEquivalent : (NSEvent *)event {
315- if ([_controller isDispatchingKeyEvent: event]) {
316- // When NSWindow is nextResponder, keyboard manager will send to it
317- // unhandled events (through [NSWindow keyDown:]). If event has both
318- // control and cmd modifiers set (i.e. cmd+control+space - emoji picker)
319- // NSWindow will then send this event as performKeyEquivalent: to first
320- // responder, which might be FlutterTextInputPlugin. If that's the case, the
321- // plugin must not handle the event, otherwise the emoji picker would not
322- // work (due to first responder returning YES from performKeyEquivalent:)
323- // and there would be an infinite loop, because FlutterViewController will
324- // send the event back to [keyboardManager handleEvent:].
282+ // Do not intercept the event if flutterView is not first responder, otherwise this would
283+ // interfere with TextInputPlugin, which also handles key equivalents.
284+ //
285+ // Also do not intercept the event if key equivalent is a product of an event being
286+ // redispatched by the TextInputPlugin, in which case it needs to bubble up so that menus
287+ // can handle key equivalents.
288+ if (self.window .firstResponder != _flutterView || [_controller isDispatchingKeyEvent: event]) {
325289 return NO ;
326290 }
327- [event markAsKeyEquivalent ];
328291 [_flutterView keyDown: event];
329292 return YES ;
330293}
0 commit comments