diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm index b0ce1f4c9fde973ea675c2103691aed512dd22d5..6944041a1bf8d0976f1ff0e894dee3c5555cdbbf 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm @@ -504,7 +504,8 @@ static void CommonInit(FlutterViewController* controller) { return; } } - if ([self.nextResponder respondsToSelector:@selector(keyDown:)]) { + if ([self.nextResponder respondsToSelector:@selector(keyDown:)] && + event.type == NSEventTypeKeyDown) { [self.nextResponder keyDown:event]; } } else if ([type isEqual:@"keyup"]) { @@ -513,13 +514,20 @@ static void CommonInit(FlutterViewController* controller) { return; } } - if ([self.nextResponder respondsToSelector:@selector(keyUp:)]) { + if ([self.nextResponder respondsToSelector:@selector(keyUp:)] && + event.type == NSEventTypeKeyUp) { [self.nextResponder keyUp:event]; } } + if ([self.nextResponder respondsToSelector:@selector(flagsChanged:)] && + event.type == NSEventTypeFlagsChanged) { + [self.nextResponder flagsChanged:event]; + } } - (void)dispatchKeyEvent:(NSEvent*)event ofType:(NSString*)type { + // Be sure to add a handler in propagateKeyEvent if you allow more event + // types here. if (event.type != NSEventTypeKeyDown && event.type != NSEventTypeKeyUp && event.type != NSEventTypeFlagsChanged) { return; diff --git a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm index b4636c0bed5f6fa2dc5e174d31efb9ae593eb311..f078c2a5a3937770de088370651e66919d1335a9 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterViewControllerTest.mm @@ -18,6 +18,7 @@ - (bool)testKeyEventsAreSentToFramework; - (bool)testKeyEventsArePropagatedIfNotHandled; - (bool)testKeyEventsAreNotPropagatedIfHandled; +- (bool)testFlagsChangedEventsArePropagatedIfNotHandled; @end namespace flutter::testing { @@ -98,6 +99,11 @@ TEST(FlutterViewControllerTest, TestKeyEventsAreNotPropagatedIfHandled) { ASSERT_TRUE([[FlutterViewControllerTestObjC alloc] testKeyEventsAreNotPropagatedIfHandled]); } +TEST(FlutterViewControllerTest, TestFlagsChangedEventsArePropagatedIfNotHandled) { + ASSERT_TRUE( + [[FlutterViewControllerTestObjC alloc] testFlagsChangedEventsArePropagatedIfNotHandled]); +} + } // namespace flutter::testing @implementation FlutterViewControllerTestObjC @@ -185,6 +191,53 @@ TEST(FlutterViewControllerTest, TestKeyEventsAreNotPropagatedIfHandled) { return true; } +- (bool)testFlagsChangedEventsArePropagatedIfNotHandled { + id engineMock = OCMClassMock([FlutterEngine class]); + id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger)); + OCMStub( // NOLINT(google-objc-avoid-throwing-exception) + [engineMock binaryMessenger]) + .andReturn(binaryMessengerMock); + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock + nibName:@"" + bundle:nil]; + id responderMock = OCMClassMock([FlutterIntermediateKeyResponder class]); + [viewController addKeyResponder:responderMock]; + NSDictionary* expectedEvent = @{ + @"keymap" : @"macos", + @"type" : @"keydown", + @"keyCode" : @(56), // SHIFT key + @"modifiers" : @(537001986), + }; + NSData* encodedKeyEvent = [[FlutterJSONMessageCodec sharedInstance] encode:expectedEvent]; + CGEventRef cgEvent = CGEventCreateKeyboardEvent(NULL, 56, TRUE); // SHIFT key + CGEventSetType(cgEvent, kCGEventFlagsChanged); + NSEvent* event = [NSEvent eventWithCGEvent:cgEvent]; + OCMExpect( // NOLINT(google-objc-avoid-throwing-exception) + [binaryMessengerMock sendOnChannel:@"flutter/keyevent" + message:encodedKeyEvent + binaryReply:[OCMArg any]]) + .andDo((^(NSInvocation* invocation) { + FlutterBinaryReply handler; + [invocation getArgument:&handler atIndex:4]; + NSDictionary* reply = @{ + @"handled" : @(false), + }; + NSData* encodedReply = [[FlutterJSONMessageCodec sharedInstance] encode:reply]; + handler(encodedReply); + })); + [viewController viewWillAppear]; // Initializes the event channel. + [viewController flagsChanged:event]; + @try { + OCMVerify( // NOLINT(google-objc-avoid-throwing-exception) + [binaryMessengerMock sendOnChannel:@"flutter/keyevent" + message:encodedKeyEvent + binaryReply:[OCMArg any]]); + } @catch (...) { + return false; + } + return true; +} + - (bool)testKeyEventsAreNotPropagatedIfHandled { id engineMock = OCMClassMock([FlutterEngine class]); id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));