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

Conversation

@erickzanardo
Copy link
Member

@erickzanardo erickzanardo commented Jul 10, 2020

Description

The current implementation of the keyboard on the web engine had a logic to automatically trigger keyup events, when repeat events stoped occurring for a time.

That works great when only one key is pressed down, but when two keys are being pressed down together, the first key will stop to send repeat events and only the last key been pressed down will send repeat events.

That was causing a strange behaviour, as a keyup event would be triggered, even if the key was still pressed down.

I did some investigation, and due to some comments on the code, I discovered that this logic that auto triggers keyup when repeat event cease, was created to prevent the framework be on a invalid state due to a keyup event not happening because the browser don't trigger keyups when a key is used on a browser/system shortcut. So my solution was built to that same idea, and I add a small new logic, that only synthesise keyup events when a key can be used in a shortcut, which is when a modifier (control, alt, shift or meta) key is pressed together.

Related Issues

Fixes flutter/flutter#58727

Tests

  • test/keyboard_test.dart

Checklist

  • I read the [contributor guide] and followed the process outlined there for submitting PRs.
  • I signed the [CLA].
  • I read and followed the [C++, Objective-C, Java style guides] for the engine.
  • I read the [tree hygiene] wiki page, which explains my responsibilities.
  • I updated/added relevant documentation.
  • All existing and new tests are passing.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read [handling breaking changes].

  • No, no existing tests failed, so this is not a breaking change.

@fluttergithubbot
Copy link
Contributor

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@erickzanardo
Copy link
Member Author

/cc: @mdebbar

@erickzanardo
Copy link
Member Author

I couldn't find any tests for this file, I tried looking on the test folder but apparently there is no test for this class.

I just realised that I just failed to find the test file, but it exists, here it is: https://github.com/erickzanardo/engine/blob/bec9c89fabfecf4ef529ed90214740bfaa6aa52f/lib/web_ui/test/keyboard_test.dart

Will try to work on the test case for this change soon

@mdebbar
Copy link
Contributor

mdebbar commented Jul 29, 2020

Apologies for the late response, I missed the email notification for the PR.

Thanks for working on this issue. Yes, the correct place to add tests for this is in test/keyboard_test.dart. You'll find plenty of examples there that you can learn and copy from.

This PR is causing one test to fail: "do not synthesize keyup when we receive repeat events" in test/keyboard_test.dart. Could you please take a look and see why it's failing? Let me know if you need help.

@erickzanardo
Copy link
Member Author

Apologies for the late response, I missed the email notification for the PR.

Thanks for working on this issue. Yes, the correct place to add tests for this is in test/keyboard_test.dart. You'll find plenty of examples there that you can learn and copy from.

This PR is causing one test to fail: "do not synthesize keyup when we receive repeat events" in test/keyboard_test.dart. Could you please take a look and see why it's failing? Let me know if you need help.

Sure thing, I will be working on the tests for this PR someday this week, I will report back here if I succeed or if I have any issue, thanks!!

@erickzanardo
Copy link
Member Author

@mdebbar it took me some time to be able to get back to this sorry.

I have added the a new test and fixed the one breaking.

That test was breaking because since with this change, only keys affected by the meta modifiers are synthesised, triggering repeat events don't cancel that synthesizing.

From what I tested on the navigators, when a short is pressed, repeat events should not follow, so this should not be any problems, nevertheless I changed the test to trigger meta modified repeat events, in the case I missed some case in my tests on the browsers.

Please, let me know what do you think.

key: 'i',
code: 'KeyI',
repeat: true,
isMetaPressed: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is trying to simulate the case where the meta keys have been released. I think we shouldn't use isMetaPressed: true because the meta key has been released already (see line 436 above).

'key': 'i',
'code': 'KeyI',
'metaState': 0x0,
'metaState': 0x08,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here. Meta keys have been released so this should remain 0x0.

if (!_isModifierKey(event)) {
// Don't synthesize a keyup event for modifier keys, or keys not affected by modifiers,
// because the browser always sends a keyup event for those.
if (!_isModifierKey(event) && _isAffectedByModifiers(event)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the issue that's making tests fail, let's move the new condition inside. This way we guarantee that the syntehsizing timer is always canceled.

Does something like this work:

if (!_isModifierKey(event)) {
  _keydownTimers[timerKey]?.cancel();
  if (event.type == 'keydown' && _isAffectedByModifiers(event)) {
    _keydownTimers[timerKey] = Timer(_keydownCancelDuration, () {
      _keydownTimers.remove(timerKey);
      _synthesizeKeyup(event);
    });
  } else {
    _keydownTimers.remove(timerKey);
  }
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remembering trying that, but that didn't solved the issue (flutter/flutter#58727), but right now, I can't remember why, I will give this another try, because looking again, this suggestion should work! Maybe I have confused things.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erickzanardo did you have a chance to try it out?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I haven't yet, sorry, I have been really overwhelmed at work. But I am planning on getting back to this PR on this saturday or sunday.

Copy link
Contributor

@mdebbar mdebbar Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No rush.

If the suggestion doesn't work, please ping me so we can discuss it further.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the PR, let me know if this is ok now! Thanks for the instructions on this!

// Wait for a long-enough period of time and no events
// should be synthesized
async.elapse(Duration(seconds: 3));
expect(messages, <Map<String, dynamic>>[
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdebbar Your suggestion worked, and moving the condition deeper inside the if worked fine to solve the original issue.

To fix the test, I needed to remove this last assertion, which I realize, is not needed anymore, since we only synthesise key ups for meta affected keys, and up in the test, we trigger a bunch of repeat events, those would have cleared the synthesising timer, and therefore, no keyup should be synthesise. Let me know if this makes sense.

Copy link
Contributor

@mdebbar mdebbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mdebbar
Copy link
Contributor

mdebbar commented Aug 25, 2020

@erickzanardo your branch is based on an old commit in master. Could you please pull master and rebase your branch? Then push your branch.

Once that's done, we'll wait for all the tests to pass then I'll merge the PR.

Thanks again for the contribution!

@erickzanardo
Copy link
Member Author

@erickzanardo your branch is based on an old commit in master. Could you please pull master and rebase your branch? Then push your branch.

Once that's done, we'll wait for all the tests to pass then I'll merge the PR.

Thanks again for the contribution!

Sure thing, will do that tonight!

@erickzanardo
Copy link
Member Author

@mdebbar Rebased with master! Let me know if that is ok.

Thanks

@erickzanardo
Copy link
Member Author

@mdebbar I notice that some tests will failed, which seems unrelated to the change on this PR? Let me know if a new rebase would be required

@mdebbar
Copy link
Contributor

mdebbar commented Aug 26, 2020

You are right. Both are unrelated. There's no need to rebase at the moment.

  • luci-engine: This represents the state of the tree. It'll become green as soon as the tree is green.
  • Mac iOS Engine: It's likely a flaky failure, so I kicked off a re-run.

Once the re-run passes, and the luci-engine goes green, we can merge the PR.

@erickzanardo
Copy link
Member Author

You are right. Both are unrelated. There's no need to rebase at the moment.

  • luci-engine: This represents the state of the tree. It'll become green as soon as the tree is green.
  • Mac iOS Engine: It's likely a flaky failure, so I kicked off a re-run.

Once the re-run passes, and the luci-engine goes green, we can merge the PR.

Great, thanks for clarifying it!

@mdebbar mdebbar added platform-web Code specifically for the web engine waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land. labels Aug 26, 2020
@fluttergithubbot fluttergithubbot merged commit b08c6b9 into flutter:master Aug 26, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Aug 26, 2020
tvolkert pushed a commit to flutter/flutter that referenced this pull request Aug 27, 2020
* b08c6b9 Fixing synthesizing keys for multiple keys pressed down on flutter web (flutter/engine#19632)

* 8308b6a Avoid passing nil to IOS accessibility announcement  (flutter/engine#20700)

* 950b6a0 Roll Skia from ead4ca052b99 to 5da7327358e3 (1 revision) (flutter/engine#20782)

* 87fd0e4 Guard recording_canvas against restore calls without ending recording (flutter/engine#20786)

* 388193a Add tests for lerpDouble (flutter/engine#20778)
smadey pushed a commit to smadey/flutter that referenced this pull request Aug 27, 2020
* b08c6b9 Fixing synthesizing keys for multiple keys pressed down on flutter web (flutter/engine#19632)

* 8308b6a Avoid passing nil to IOS accessibility announcement  (flutter/engine#20700)

* 950b6a0 Roll Skia from ead4ca052b99 to 5da7327358e3 (1 revision) (flutter/engine#20782)

* 87fd0e4 Guard recording_canvas against restore calls without ending recording (flutter/engine#20786)

* 388193a Add tests for lerpDouble (flutter/engine#20778)
@erickzanardo erickzanardo deleted the fixing-web-multiple-keydowns branch August 27, 2020 13:41
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
* b08c6b9 Fixing synthesizing keys for multiple keys pressed down on flutter web (flutter/engine#19632)

* 8308b6a Avoid passing nil to IOS accessibility announcement  (flutter/engine#20700)

* 950b6a0 Roll Skia from ead4ca052b99 to 5da7327358e3 (1 revision) (flutter/engine#20782)

* 87fd0e4 Guard recording_canvas against restore calls without ending recording (flutter/engine#20786)

* 388193a Add tests for lerpDouble (flutter/engine#20778)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla: yes platform-web Code specifically for the web engine waiting for tree to go green This PR is approved and tested, but waiting for the tree to be green to land.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RawKeyboard triggers incorrect KeyUp when two keys are pressed and auto-repeating on web

4 participants