Skip to content

Shortcut activator - #78522

Merged
dkwingsmt merged 59 commits into
flutter:masterfrom
dkwingsmt:shortcut-prompt
Apr 15, 2021
Merged

dkwingsmt merged 59 commits into
flutter:masterfrom
dkwingsmt:shortcut-prompt

Conversation

@dkwingsmt

@dkwingsmt dkwingsmt commented Mar 18, 2021 •

Copy link
Copy Markdown
Contributor

This PR introduced a new class, ShortcutActivator, and refactored the the definition and lookup system of shortcuts, in order to solve a few issues of the previous algorithm.

ShortcutActivator is designed to be another base class of LogicalKeySet, and the new standard interface to define a key combination and be mapped to an Intent. LogicalKeySet now implements ShortcutActivator, keeping its previous behavior. However, when defining typical shortcuts such as Delete or Ctrl-C, it's recommended to use the new SingleActivator instead, which behaves more closely to how common OSs do by addressing following issues.

This is part of the general keyboard project as in #44918.

Why

LogicalKeySet as a set of keys does not satisfy the need for properly defining shortcut key combinations. Most typical OSs handle shortcuts by treating modifiers and non-modifiers differently.

  • Although modifiers must strictly match the definition (unsided), while non-modifiers allow extra keys. For example, pressing C while holding Ctrl-A also triggers Ctrl-C.
  • Also, the last key of the key combination must be the non-modifier key. For example, pressing Ctrl while holding C will not trigger Ctrl-C.

This shows that modifiers and non-modifiers are born unequal, and it's impossible to properly handle them using a set.

Lookup

Some extent of indexing, instead full linear search, is still desired for performance. ShortcutActivator therefore splits requirements into two parts:

  • triggers, a set of logical keys, and
  • accepts, a predicate function to judge whether the event and keyboard state fully satisty the conditions.

Prompt-intent pairs are indexed by triggers, such as key C as in Ctrl-C, or both A and B as in Alt-A-B. When a trigger key occurs, all activators are tested linearly to find the first matching intent.

Other changes

The algorithm to synchronize modifiers on Web has been change to allow more refined behaviors related to modifiers. More specifically,

  • If a modifier key was recorded pressed, but the metaState reports their flag as released, the keys of both sides will be set as released. (Previously: unhandled.)
  • If a modifier key was recorded released, but the metaState reports their flag as pressed, the left key will be set as pressed. (Previously: both sides pressed.)
  • If a modifier key was recorded pressed, and the metaState reports their flag as pressed too, no synchronization will be added. (Previously: both sides pressed.)

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard flutter-dashboard Bot added a: tests "flutter test", flutter_test, or one of our tests framework flutter/packages/flutter repository. See also f: labels. c: contributor-productivity Team-specific productivity, code health, technical debt. labels Mar 18, 2021
@google-cla google-cla Bot added the cla: yes label Mar 18, 2021
@dkwingsmt
dkwingsmt requested a review from gspencergoog April 7, 2021 07:26
@dkwingsmt

Copy link
Copy Markdown
Contributor Author

@gspencergoog I think this PR is ready for review. Can you take a look?

Comment thread packages/flutter/lib/src/services/raw_keyboard.dart Outdated
Comment thread packages/flutter/lib/src/services/raw_keyboard.dart Outdated
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart Outdated
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart Outdated
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart Outdated
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart Outdated
Comment thread packages/flutter_test/lib/src/controller.dart Outdated
Comment thread packages/flutter_test/lib/src/controller.dart Outdated
Comment thread packages/flutter_test/lib/src/controller.dart Outdated
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart Outdated
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart
Comment thread packages/flutter/lib/src/widgets/shortcuts.dart
///
/// The `trigger` should be the non-modifier key that is pressed after all the
/// modifiers, such as [LogicalKeyboardKey.keyC] as in `Ctrl+C`. It must not be
/// a modifier key (sided or unsided).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think it's a good idea to limit the keys that can be used in a shortcut: people won't implement their own subclass, they'll just assume it can't be done. I think that if we're deprecating LogicalKeySet, we should add that other class (it could be the KeySetActivator that you're already planning) to give people a way to migrate without having to implement a new subclass.

Is the reason that you don't want modifier-only shortcuts to be a goal of SingleActivator because of the non-sidedness of the control, meta, etc. flags?

I can see that it might be confusing to say SingleActivator(LogicalKeyboardKey.shiftLeft, shift: true), since now it's not clear whether you're talking about any shift or just shiftLeft, but you could just assert that the trigger isn't a shift, shiftLeft or shiftRight if the shift flag is true. Other than that, I don't see why the modifier keys should be excluded from being triggers.

Comment thread packages/flutter/lib/src/widgets/shortcuts.dart Outdated

@gspencergoog gspencergoog left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

32384589-a60f0e74-c078-11e7-9bc1-e5b5287aea9d

///
/// The `trigger` should be the non-modifier key that is pressed after all the
/// modifiers, such as [LogicalKeyboardKey.keyC] as in `Ctrl+C`. It must not be
/// a modifier key (sided or unsided).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ahh, OK, I didn't notice that it also enforces the key is not pressed. OK, then I guess it'll just have to be a separate class.

@dkwingsmt

dkwingsmt commented Apr 14, 2021 •

Copy link
Copy Markdown
Contributor Author

Update: I'm waiting for the current roll backlog to resolve before merging this potentially breaking PR.

@fluttergithubbot

Copy link
Copy Markdown
Contributor

This pull request is not suitable for automatic merging in its current state.

  • The status or check suite Google testing has failed. Please fix the issues identified (or deflake) before re-applying this label.

@dkwingsmt
dkwingsmt merged commit eb73516 into flutter:master Apr 15, 2021
@dkwingsmt dkwingsmt mentioned this pull request Apr 19, 2021
8 tasks done
dkwingsmt added a commit that referenced this pull request Apr 26, 2021
Applies #78522 to existing code, by replacing all occurrences of LogicalKeySet to SingleActivator or ShortcutActivator.
@dkwingsmt dkwingsmt added the a: text input Entering text in a text field or keyboard related problems label Jul 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: tests "flutter test", flutter_test, or one of our tests a: text input Entering text in a text field or keyboard related problems c: contributor-productivity Team-specific productivity, code health, technical debt. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants