Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 0087948

Browse files
authored
[macOS] performKeyEquivalent cleanup (#45946)
#40706 added a duplicate `NSEvent (KeyEquivalentMarker)` category. This PR removes it. It also removes the call to `markAsKeyEquivalent` from `FlutterViewController`. That call is internal to `FlutterTextInputPlugin` and classes outside should not be calling it. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 9789dbc commit 0087948

File tree

2 files changed

+14
-44
lines changed

2 files changed

+14
-44
lines changed

shell/platform/darwin/macos/framework/Source/FlutterViewController.mm

Lines changed: 7 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -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

278245
namespace {
@@ -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
}

shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,13 @@ - (bool)testCtrlTabKeyEventIsPropagated {
331331
const uint64_t kPhysicalKeyTab = 0x7002b;
332332

333333
[viewController viewWillAppear]; // Initializes the event channel.
334+
// Creates a NSWindow so that FlutterView view can be first responder.
335+
NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
336+
styleMask:NSBorderlessWindowMask
337+
backing:NSBackingStoreBuffered
338+
defer:NO];
339+
window.contentView = viewController.view;
340+
[window makeFirstResponder:viewController.flutterView];
334341
[viewController.view performKeyEquivalent:event];
335342

336343
EXPECT_TRUE(called);

0 commit comments

Comments
 (0)