-
Notifications
You must be signed in to change notification settings - Fork 6k
[Web, keyboard] Locale layout mapping #34625
Conversation
…ngine into web-layout-detection
…b-layout-detection
Gold has detected about 1 new digest(s) on patchset 20. |
@mdebbar I've sync'd the PR with the latest master, addressing as many of you comments as possible. I've also made a non-trivial change that compresses the data, which reduces the package size overhead of this PR further (see PR body). I'm still resolving some CI issues. In the mean time, can you take another look? |
|
||
final DispatchKeyData performDispatchKeyData; | ||
// Whether the current platform is macOS, which affects how certain key events |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it the case that onMacOS
is only used to differentiate things for macOS, or are these keyboard quirks also present on iOS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice find. I've tested it on my iPad and I confirm that they also present on iOS. I'm changing it to onDarwin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me make it a separate PR after this PR.
result = result + _kCharLowerA - _kCharUpperA; | ||
} | ||
return result; | ||
return isUpperLetter(key.codeUnitAt(0)) && key.length > 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't key.length > 1
sufficient? Or can non-named keys have more than one character? Would it be true that key.length > 2
would be enough? Just trying to see if we can avoid checking the code unit range entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point.
Although I'm not sure if there are any character KeyboardKey.key
s that contain multiple JS characters, all keys that LocaleMapping
handles are single-character, which is the most important aspect what this function cares about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove this range check for now and revise it when we see a counterexample.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just did a quick check of the VSCode layouts. It turns out that en-in
has a key L̥
which is two characters. Although, my previous algorithm also fails on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do all named keys have a name that is >2 characters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure so. Because all named keys are alnum, therefore having only 1 character conflicts with letter keys.
Also this is the standard for KeyboardEvent.key
: https://w3c.github.io/uievents-key/ , which clearly says that key
can consist of a letter and a combining code unit (accents).
@gspencergoog I've addressed all your comments. I'd like to add another test for the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with some minor comments.
If you don't mind, I would like to wait for @eyebrowsoffire's input on the web_locale_keymap_sources
thing in web_sdk/BUILD.gn
. If it turns out it's needed, then I have to add web_unicode_sources
too.
final String? character = logicalKeyIsCharacter ? eventKey : null; | ||
final int logicalKey = () { | ||
final bool logicalKeyIsCharacter = !_eventKeyIsKeyName(eventKey); | ||
final ValueGetter<int> logicalKey = _cached<int>(() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for using _cached
here instead of late final
:
late final int logicalKey = () {
// ...
}();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function might not be evaluated: if the event is a key up event, the logical key is simply the pressed logical key, and this is not needed at all. In this case, I'm hoping not to run the function body, since it's not a trivial amount of work. And as far as I understand, late
still always evaluate the value. (I can add a comment to it.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the docs, the late
keyword makes the field lazy, which means the right-hand-side won't run until you access the field. At least that's my understanding.
https://dart.dev/null-safety/understanding-null-safety#lazy-initialization
web_sdk/BUILD.gn
Outdated
inputs = | ||
[ "sdk_rewriter.dart" ] + web_ui_sources + web_locale_keymap_sources |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried without web_locale_keymap_sources
? I'm curious because in my case, I didn't add sources from the third_party package, and everything seems to be working fine.
Any ideas @eyebrowsoffire ?
// Character keys, however, can also have more than 1 code unit: en-in | ||
// maps KeyL to L̥/l̥. To resolve this, we check the second code unit. | ||
static bool _eventKeyIsKeyName(String key) { | ||
return key.length > 1 && key.codeUnitAt(0) < 0x7F && key.codeUnitAt(1) < 0x7F; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you just say key.length > 2
? Are there any names that are only two characters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, such as Fn
and F1
. And I'm not sure if there are characters of 3 or more code units.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, OK. LGTM then.
@mdebbar I've applied the fix to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gold has detected about 1 new digest(s) on patchset 91. |
…116243) * 782d3a600 Roll Skia from 6d759de2e5b2 to 24207007711b (3 revisions) (flutter/engine#37968) * e20362343 [Web, keyboard] Locale layout mapping (flutter/engine#34625)
…lutter#116243) * 782d3a600 Roll Skia from 6d759de2e5b2 to 24207007711b (3 revisions) (flutter/engine#37968) * e20362343 [Web, keyboard] Locale layout mapping (flutter/engine#34625)
…lutter#116243) * 782d3a600 Roll Skia from 6d759de2e5b2 to 24207007711b (3 revisions) (flutter/engine#37968) * e20362343 [Web, keyboard] Locale layout mapping (flutter/engine#34625)
…lutter#116243) * 782d3a600 Roll Skia from 6d759de2e5b2 to 24207007711b (3 revisions) (flutter/engine#37968) * e20362343 [Web, keyboard] Locale layout mapping (flutter/engine#34625)
This PR changes how logical keys are mapped on Web, aligning it with other platforms. Part of flutter/flutter#100456.
This change ensures that non-latin layout can also use letter shortcuts. For example, before this change, on Russian layout, physical key
Ctrl-KeyA
will produce logical keyCtrl-ф
, which will not trigger any common shortcuts. After the change, it will produce logical keyCtrl-A
.Technical Details
The algorithm is as follows: Analyze every key of the current layout,
This algorithm, which we call the benchmark planner, has been applied to all other desktop platforms.
However, we can't simply apply it to Web: Web DOM API does not tell which keyboard layout the user is on, or how the current layout maps keys (there is a
KeyboardLayout
API that is supported only by Chrome, and explicitly refused by all other browsers). So we have to invent a "blind" algorithm that applies to any layout, while keeping the same result.Luckily, we're able to fetch a list of "all keyboard layouts" from
Microsoft/VSCode
repo, and we analyzed all layouts beforehand, and managed to combine the result into a hugecode -> key -> result
map. You would imagine it being impossible, since different layouts might use the same(code, key)
pair for different characters, but in fact such conflicts are surprisingly few, and all the conflicts are mapped to letters. For example,es-linux
maps('KeyY', '←')
toy
, whilede-linux
maps('KeyY', '←')
toz
.We can't distinguished these conflicts only by the
(code, key)
pair, but we can use other information:keyCode
. Now,keyCode
is a deprecated property, but we really don't see it being removed any time foreseeable. Also, althoughkeyCode
is infamous for being platform-dependent, for letter keys it is always equal to the letter character. Therefore such conflicting cases are all mapped to a special value,0x01
, indicating "use keyCode".Moreover, to reduce the size of the map, we noticed there are certain patterns that can be easily represented by some
if
statements. These patterns are extracted as the so-called "heuristic mapper". This reduces the map from over 1600 entries to ~450 entries.To further reduce the package size overhead, this PR also encodes the map into a string that is decoded at run time. This reduces the package size over by ~45% at the cost of code complexity.
Structure
A package called
gen_web_locale_keymap
is added totools/
, which:Microsoft/VSCode
web_locale_keymap
(see below)web_locale_keymap
A package called
web_locale_keymap
is added tothird_party
, which does the mapping for all printable characters. Since package must be placed inthird_party
because it uses Microsoft's code (of MIT license).The SDK rewriter and the license checker are modified to accommodate the new package.
Package size overhead
Compiling a very simple app that listens to key events:
Pre-launch Checklist
writing and running engine tests.
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.