Skip to content

Commit

Permalink
[macOS, Keyboard] Duplicate down events are no longer ignored, but ke…
Browse files Browse the repository at this point in the history
…pt and preceded by up events (flutter#31800)
  • Loading branch information
dkwingsmt authored Mar 4, 2022
1 parent 6c67716 commit 756344a
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -680,12 +680,23 @@ - (void)handleDownEvent:(NSEvent*)event callback:(FlutterKeyCallbackGuard*)callb
bool isARepeat = event.isARepeat;
NSNumber* pressedLogicalKey = _pressingRecords[@(physicalKey)];
if (pressedLogicalKey != nil && !isARepeat) {
// Normally the key up events won't be missed since macOS always sends the
// key up event to the window where the corresponding key down occurred.
// However this might happen in add-to-app scenarios if the focus is changed
// This might happen in add-to-app scenarios if the focus is changed
// from the native view to the Flutter view amid the key tap.
[callback resolveTo:TRUE];
return;
//
// This might also happen when a key event is forged (such as by an
// IME) using the same keyCode as an unreleased key. See
// https://github.com/flutter/flutter/issues/82673#issuecomment-988661079
FlutterKeyEvent flutterEvent = {
.struct_size = sizeof(FlutterKeyEvent),
.timestamp = GetFlutterTimestampFrom(event.timestamp),
.type = kFlutterKeyEventTypeUp,
.physical = physicalKey,
.logical = [pressedLogicalKey unsignedLongLongValue],
.character = nil,
.synthesized = true,
};
[self sendSynthesizedFlutterEvent:flutterEvent guard:callback];
pressedLogicalKey = nil;
}

if (pressedLogicalKey == nil) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ - (void)dealloc {
[events removeAllObjects];
}

TEST(FlutterEmbedderKeyResponderUnittests, IgnoreDuplicateDownEvent) {
TEST(FlutterEmbedderKeyResponderUnittests, SynthesizeForDuplicateDownEvent) {
__block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
__block BOOL last_handled = TRUE;
FlutterKeyEvent* event;
Expand All @@ -319,7 +319,7 @@ - (void)dealloc {
userData:user_data]];
}];

last_handled = FALSE;
last_handled = TRUE;
[responder handleEvent:keyEvent(NSEventTypeKeyDown, 0x100, @"a", @"a", FALSE, kKeyCodeKeyA)
callback:^(BOOL handled) {
last_handled = handled;
Expand All @@ -332,44 +332,35 @@ - (void)dealloc {
EXPECT_EQ(event->logical, kLogicalKeyA);
EXPECT_STREQ(event->character, "a");
EXPECT_EQ(event->synthesized, false);
EXPECT_EQ(last_handled, FALSE);
[[events lastObject] respond:TRUE];
EXPECT_EQ(last_handled, TRUE);
[[events lastObject] respond:FALSE];
EXPECT_EQ(last_handled, FALSE);

[events removeAllObjects];

last_handled = FALSE;
[responder handleEvent:keyEvent(NSEventTypeKeyDown, 0x100, @"a", @"a", FALSE, kKeyCodeKeyA)
last_handled = TRUE;
[responder handleEvent:keyEvent(NSEventTypeKeyDown, 0x100, @"à", @"à", FALSE, kKeyCodeKeyA)
callback:^(BOOL handled) {
last_handled = handled;
}];

EXPECT_EQ([events count], 1u);
EXPECT_EQ(last_handled, TRUE);
event = [events lastObject].data;
EXPECT_EQ(event->physical, 0ull);
EXPECT_EQ(event->logical, 0ull);
EXPECT_FALSE([[events lastObject] hasCallback]);
EXPECT_EQ(last_handled, TRUE);

[events removeAllObjects];

last_handled = FALSE;
[responder handleEvent:keyEvent(NSEventTypeKeyUp, 0x100, @"a", @"a", FALSE, kKeyCodeKeyA)
callback:^(BOOL handled) {
last_handled = handled;
}];
EXPECT_EQ([events count], 2u);

EXPECT_EQ([events count], 1u);
event = [events lastObject].data;
event = [events firstObject].data;
EXPECT_EQ(event->type, kFlutterKeyEventTypeUp);
EXPECT_EQ(event->physical, kPhysicalKeyA);
EXPECT_EQ(event->logical, kLogicalKeyA);
EXPECT_STREQ(event->character, nullptr);
EXPECT_STREQ(event->character, NULL);
EXPECT_EQ(event->synthesized, true);

event = [events lastObject].data;
EXPECT_EQ(event->type, kFlutterKeyEventTypeDown);
EXPECT_EQ(event->physical, kPhysicalKeyA);
EXPECT_EQ(event->logical, 0xE0ull /* à */);
EXPECT_STREQ(event->character, "à");
EXPECT_EQ(event->synthesized, false);
[[events lastObject] respond:FALSE];
EXPECT_EQ(last_handled, FALSE);
[[events lastObject] respond:TRUE];
EXPECT_EQ(last_handled, TRUE);

[events removeAllObjects];
}
Expand Down

0 comments on commit 756344a

Please sign in to comment.