@@ -164,8 +164,6 @@ @interface FlutterViewWrapper : NSView
164
164
165
165
- (void )setBackgroundColor : (NSColor *)color ;
166
166
167
- - (BOOL )performKeyEquivalent : (NSEvent *)event ;
168
-
169
167
@end
170
168
171
169
/* *
@@ -242,37 +240,6 @@ - (void)onKeyboardLayoutChanged;
242
240
243
241
@end
244
242
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
-
276
243
#pragma mark - Private dependant functions
277
244
278
245
namespace {
@@ -312,19 +279,15 @@ - (void)setBackgroundColor:(NSColor*)color {
312
279
}
313
280
314
281
- (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]) {
325
289
return NO ;
326
290
}
327
- [event markAsKeyEquivalent ];
328
291
[_flutterView keyDown: event];
329
292
return YES ;
330
293
}
0 commit comments