From 7f4f62d48c75b71e92892bf96fad84dc2310ea6e Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Fri, 30 Jul 2021 18:06:10 +0200 Subject: [PATCH 1/6] Do not generate keydown event for empty modifier flags --- .../framework/Source/FlutterChannelKeyResponder.mm | 3 ++- .../Source/FlutterChannelKeyResponderUnittests.mm | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm index b6aaae1376247..b8ba7ff043f9e 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm @@ -50,7 +50,8 @@ - (void)handleEvent:(NSEvent*)event callback:(FlutterAsyncKeyCallback)callback { case NSEventTypeFlagsChanged: if (event.modifierFlags < _previouslyPressedFlags) { type = @"keyup"; - } else if (event.modifierFlags > _previouslyPressedFlags) { + } else if (event.modifierFlags > _previouslyPressedFlags && + event.modifierFlags > 0x100) { // 0x100 is empty modifierFlags type = @"keydown"; } else { // ignore duplicate modifiers; This can happen in situations like switching diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm index 01254d6b7c780..9db070a52c289 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm @@ -52,9 +52,18 @@ callback(keyMessage); })); - // Key down FlutterChannelKeyResponder* responder = [[FlutterChannelKeyResponder alloc] initWithChannel:mockKeyEventChannel]; + + // Empty modifiers. Shouldn't result in any event + [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x100, @"", @"", FALSE, 60) + callback:^(BOOL handled) { + [responses addObject:@(handled)]; + }]; + + EXPECT_EQ([messages count], 0u); + + // Key down [responder handleEvent:keyEvent(NSEventTypeKeyDown, 0x100, @"a", @"a", FALSE, 0) callback:^(BOOL handled) { [responses addObject:@(handled)]; From 388aaf7704ffee65a4715a81eab7fdd962478b5d Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sat, 31 Jul 2021 01:07:24 +0200 Subject: [PATCH 2/6] Mask 0x100 bit instead of comparison --- .../macos/framework/Source/FlutterChannelKeyResponder.mm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm index b8ba7ff043f9e..7ae49c0c45145 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm @@ -39,6 +39,8 @@ - (nonnull instancetype)initWithChannel:(nonnull FlutterBasicMessageChannel*)cha } - (void)handleEvent:(NSEvent*)event callback:(FlutterAsyncKeyCallback)callback { + // Remove the 0x100 bit set by Cocoa when no modifiers are pressed. + NSEventModifierFlags modifierFlags = event.modifierFlags & ~0x100; NSString* type; switch (event.type) { case NSEventTypeKeyDown: @@ -48,10 +50,9 @@ - (void)handleEvent:(NSEvent*)event callback:(FlutterAsyncKeyCallback)callback { type = @"keyup"; break; case NSEventTypeFlagsChanged: - if (event.modifierFlags < _previouslyPressedFlags) { + if (modifierFlags < _previouslyPressedFlags) { type = @"keyup"; - } else if (event.modifierFlags > _previouslyPressedFlags && - event.modifierFlags > 0x100) { // 0x100 is empty modifierFlags + } else if (modifierFlags > _previouslyPressedFlags) { type = @"keydown"; } else { // ignore duplicate modifiers; This can happen in situations like switching @@ -62,7 +63,7 @@ - (void)handleEvent:(NSEvent*)event callback:(FlutterAsyncKeyCallback)callback { default: NSAssert(false, @"Unexpected key event type (got %lu).", event.type); } - _previouslyPressedFlags = event.modifierFlags; + _previouslyPressedFlags = modifierFlags; NSMutableDictionary* keyMessage = [@{ @"keymap" : @"macos", @"type" : type, From 603795763c87241ea7549bc18569bf80c60aff06 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sat, 31 Jul 2021 01:43:31 +0200 Subject: [PATCH 3/6] Comment --- .../framework/Source/FlutterChannelKeyResponderUnittests.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm index 9db070a52c289..6667644d59f77 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm @@ -55,7 +55,8 @@ FlutterChannelKeyResponder* responder = [[FlutterChannelKeyResponder alloc] initWithChannel:mockKeyEventChannel]; - // Empty modifiers. Shouldn't result in any event + // Initial empty modifiers. This can happen when user opens window while modifier key is present + // and then releases the modifier. Shouldn't result in any event being sent. [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x100, @"", @"", FALSE, 60) callback:^(BOOL handled) { [responses addObject:@(handled)]; From 4b7969b8544e6a0751b598c97df5d0775311894e Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sat, 31 Jul 2021 01:45:03 +0200 Subject: [PATCH 4/6] Update comment --- .../darwin/macos/framework/Source/FlutterChannelKeyResponder.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm index 7ae49c0c45145..29436dec17ea1 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.mm @@ -39,7 +39,7 @@ - (nonnull instancetype)initWithChannel:(nonnull FlutterBasicMessageChannel*)cha } - (void)handleEvent:(NSEvent*)event callback:(FlutterAsyncKeyCallback)callback { - // Remove the 0x100 bit set by Cocoa when no modifiers are pressed. + // Remove the modifier bits that Flutter is not interested in. NSEventModifierFlags modifierFlags = event.modifierFlags & ~0x100; NSString* type; switch (event.type) { From 8e3ea7e2f1c4745cf47d8cc18dccd9b22c4b21a3 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sat, 31 Jul 2021 01:52:09 +0200 Subject: [PATCH 5/6] comment --- .../framework/Source/FlutterChannelKeyResponderUnittests.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm index 6667644d59f77..1375e48527979 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm @@ -55,8 +55,8 @@ FlutterChannelKeyResponder* responder = [[FlutterChannelKeyResponder alloc] initWithChannel:mockKeyEventChannel]; - // Initial empty modifiers. This can happen when user opens window while modifier key is present - // and then releases the modifier. Shouldn't result in any event being sent. + // Initial empty modifiers. This can happen when user opens window while modifier key is pressed + // and then releases the modifier. Shouldn't result in an event being sent. [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x100, @"", @"", FALSE, 60) callback:^(BOOL handled) { [responses addObject:@(handled)]; From 8d0006c2ae35c065ad29749425876afc24cf3e30 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Sat, 31 Jul 2021 02:03:30 +0200 Subject: [PATCH 6/6] Add comment --- .../framework/Source/FlutterChannelKeyResponderUnittests.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm index 1375e48527979..d5629e900bea8 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponderUnittests.mm @@ -57,6 +57,7 @@ // Initial empty modifiers. This can happen when user opens window while modifier key is pressed // and then releases the modifier. Shouldn't result in an event being sent. + // Regression test for https://github.com/flutter/flutter/issues/87339. [responder handleEvent:keyEvent(NSEventTypeFlagsChanged, 0x100, @"", @"", FALSE, 60) callback:^(BOOL handled) { [responses addObject:@(handled)];