Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Web]: Command and shift keys on MacOS causes other keys to stay pressed for about 1 second #97589

Closed
vogtb opened this issue Feb 1, 2022 · 7 comments
Labels
a: text input Entering text in a text field or keyboard related problems engine flutter/engine repository. See also e: labels. found in release: 2.8 Found to occur in 2.8 found in release: 2.10 Found to occur in 2.10 has reproducible steps The issue has been confirmed reproducible and is ready to work on platform-mac Building on or for macOS specifically platform-web Web applications specifically r: solved Issue is closed as solved

Comments

@vogtb
Copy link

vogtb commented Feb 1, 2022

tldr; triggering Command + Shift + {key} causes the final {key} to "stay pressed" (or rather causes the KeyUpEvent to be delayed) by 1 second.

related: #75934

Steps to Reproduce (for Flutter Web on MacOS):

Use the main.dart file below

  1. Press and hold Command, and Shift keys.
  2. While those are held down, press and release the A key normally (quickly, don't hold it.)
  3. In the console we see:
key event: down 'Meta Left' time=2022-02-01 11:50:08.223
key event: down 'Shift Left' time=2022-02-01 11:50:08.456
key event: down 'A' time=2022-02-01 11:50:09.298
key event: up 'A' time=2022-02-01 11:50:10.304
key event: up 'Meta Left' time=2022-02-01 11:50:11.168
key event: up 'Shift Left' time=2022-02-01 11:50:11.176

You'll notice that there is 1.006 seconds between when the A key was pressed down, and when the release was released.

You can further reproduce the issue here:

  1. Press and hold "Command", "Shift", and "A" keys in quick succession.
  2. Release all three together immediately.
  3. In the console we see:
key event: down 'Meta Left' time=2022-02-01 11:53:38.473
key event: down 'Shift Left' time=2022-02-01 11:53:38.523
key event: down 'A' time=2022-02-01 11:53:38.648
key event: up 'Shift Left' time=2022-02-01 11:53:38.851
key event: up 'Meta Left' time=2022-02-01 11:53:38.861
key event: up 'A' time=2022-02-01 11:53:39.653

You'll notice that, again, the final A key-down event is triggered 1.005 seconds after it was pressed down.

This can be reproduced with the keys: A, =, +, X, Y, J, and so on.

To be clear, my expectation is that the key events should be trigger in the order that they occur, and the final "A" key does not stay down for a second after it was pressed.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Focus(
          autofocus: true,
          onKey: (_n, e) {
            String downOrUp = e is RawKeyDownEvent ? "down" : "up";
            print(
                "key event: " + downOrUp + " '" + e.logicalKey.keyLabel +
                    "' time=" +
                    DateTime.now().toString());
            return KeyEventResult.handled;
          },
          child: Container()
      ),
    );
  }
}

Output of flutter doctor:

flutter doctor -v
[✓] Flutter (Channel stable, 2.8.1, on macOS 12.1 21C52 darwin-arm,
    locale en-US)
    • Flutter version 2.8.1 at
      /opt/homebrew/Caskroom/flutter/2.8.1/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 77d935af4d (7 weeks ago), 2021-12-16 08:37:33
      -0800
    • Engine revision 890a5fca2e
    • Dart version 2.15.1

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from:
      https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK
      components.
      (or visit
      https://flutter.dev/docs/get-started/install/macos#android-setup
      for detailed instructions).
      If the Android SDK has been installed to a custom location,
      please use
      `flutter config --android-sdk` to update to that location.


[✓] Xcode - develop for iOS and macOS (Xcode 13.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google
      Chrome

[!] Android Studio (not installed)
    • Android Studio not found; download from
      https://developer.android.com/studio/index.html
      (or visit
      https://flutter.dev/docs/get-started/install/macos#android-setup
      for detailed instructions).

[☠] IntelliJ IDEA Community Edition (the doctor check crashed)
    ✗ Due to an error, the doctor check did not complete. If the error
      message below is not helpful, please let us know about this issue
      at https://github.com/flutter/flutter/issues.
    ✗ FormatException: Unexpected extension byte (at offset 5)
    • #0      _Utf8Decoder.convertSingle
      (dart:convert-patch/convert_patch.dart:1789:7)
      #1      Utf8Decoder.convert (dart:convert/utf.dart:318:42)
      #2      InputStream.readString
      (package:archive/src/util/input_stream.dart:207:30)
      #3      new ZipDirectory.read
      (package:archive/src/zip/zip_directory.dart:40:30)
      #4      ZipDecoder.decodeBuffer
      (package:archive/src/zip_decoder.dart:19:30)
      #5      ZipDecoder.decodeBytes
      (package:archive/src/zip_decoder.dart:14:12)
      #6      IntelliJPlugins._findPluginXml
      (package:flutter_tools/src/intellij/intellij.dart:130:44)
      #7      IntelliJPlugins._readPackageVersion
      (package:flutter_tools/src/intellij/intellij.dart:141:40)
      #8      IntelliJPlugins.validatePackage
      (package:flutter_tools/src/intellij/intellij.dart:63:35)
      #9      IntelliJValidator.validate
      (package:flutter_tools/src/intellij/intellij_validator.dart:103:1
      5)
      #10     asyncGuard.<anonymous closure>
      (package:flutter_tools/src/base/async_guard.dart:111:32)
      #11     asyncGuard.<anonymous closure>
      (package:flutter_tools/src/base/async_guard.dart:109:18)
      #12     _rootRun (dart:async/zone.dart:1428:13)
      #13     _CustomZone.run (dart:async/zone.dart:1328:19)
      #14     _runZoned (dart:async/zone.dart:1863:10)
      #15     runZonedGuarded (dart:async/zone.dart:1851:12)
      #16     runZoned (dart:async/zone.dart:1782:12)
      #17     asyncGuard
      (package:flutter_tools/src/base/async_guard.dart:109:3)
      #18     Doctor.startValidatorTasks
      (package:flutter_tools/src/doctor.dart:197:9)
      #19     Doctor.diagnose
      (package:flutter_tools/src/doctor.dart:301:47)
      #20     DoctorCommand.runCommand
      (package:flutter_tools/src/commands/doctor.dart:53:47)
      #21     FlutterCommand.verifyThenRunCommand
      (package:flutter_tools/src/runner/flutter_command.dart:1290:12)
      <asynchronous suspension>
      #22     FlutterCommand.run.<anonymous closure>
      (package:flutter_tools/src/runner/flutter_command.dart:1140:27)
      <asynchronous suspension>
      #23     AppContext.run.<anonymous closure>
      (package:flutter_tools/src/base/context.dart:150:19)
      <asynchronous suspension>
      #24     CommandRunner.runCommand
      (package:args/command_runner.dart:209:13)
      <asynchronous suspension>
      #25     FlutterCommandRunner.runCommand.<anonymous closure>
      (package:flutter_tools/src/runner/flutter_command_runner.dart:288
      :9)
      <asynchronous suspension>
      #26     AppContext.run.<anonymous closure>
      (package:flutter_tools/src/base/context.dart:150:19)
      <asynchronous suspension>
      #27     FlutterCommandRunner.runCommand
      (package:flutter_tools/src/runner/flutter_command_runner.dart:236
      :5)
      <asynchronous suspension>
      #28     run.<anonymous closure>.<anonymous closure>
      (package:flutter_tools/runner.dart:62:9)
      <asynchronous suspension>
      #29     AppContext.run.<anonymous closure>
      (package:flutter_tools/src/base/context.dart:150:19)
      <asynchronous suspension>
      #30     main (package:flutter_tools/executable.dart:94:3)
      <asynchronous suspension>


[✓] VS Code (version 1.63.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.29.0

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-arm64   • macOS 12.1 21C52
      darwin-arm
    • Chrome (web)    • chrome • web-javascript • Google Chrome
      97.0.4692.99
@maheshmnj maheshmnj added the in triage Presently being triaged by the triage team label Feb 2, 2022
@darshankawar
Copy link
Member

Thanks for the report. I verified this behavior using latest stable and master and ran it on web using Mac machine and do see the same behavior as reported, ie, there's a delay of about 1 second when key press is released. This is more evident using shift+cmd+A combination, but also replicates using other keys sometimes (e.g X, =`).

console log showing key press events

key event: down 'X' time=2022-02-02 15:18:39.377
key event: up 'Meta Left' time=2022-02-02 15:18:39.442
key event: up 'Shift Left' time=2022-02-02 15:18:39.451
key event: up 'X' time=2022-02-02 15:18:40.378


key event: up 'Meta Left' time=2022-02-02 15:18:20.242
key event: up 'Shift Left' time=2022-02-02 15:18:20.258
key event: up 'A' time=2022-02-02 15:18:21.194


key event: up 'Meta Left' time=2022-02-02 15:27:28.833
key event: up 'Shift Left' time=2022-02-02 15:27:28.863
key event: up 'A' time=2022-02-02 15:27:30.739

I tried the same scenario on macOS (desktop) but didn't see the same behavior / delay, so this could be specific to web.

master stable flutter doctor -v

[✓] Flutter (Channel master, 2.10.0-1.0.pre.369, on Mac OS X 10.15.4 19E2269 darwin-x64, locale en-GB)
    • Flutter version 2.10.0-1.0.pre.369 at /Users/dhs/documents/fluttersdk/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 9bdf809e53 (4 hours ago), 2022-02-01 22:25:19 -0500
    • Engine revision f22420acf7
    • Dart version 2.17.0 (build 2.17.0-69.0.dev)
    • DevTools version 2.10.0-dev.1

[!] Xcode - develop for iOS and macOS (Xcode 12.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    ! Flutter recommends a minimum Xcode version of 13.
      Download the latest version or update via the Mac App Store.
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] VS Code (version 1.62.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.21.0

[✓] Connected device (4 available)
    • Darshan's iphone (mobile)  • 21150b119064aecc249dfcfe05e259197461ce23 • ios            • iOS 14.4.1
      18D61
    • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729     • ios            •
      com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
    • macOS (desktop)            • macos                                    • darwin-x64     • Mac OS X
      10.15.4 19E2269 darwin-x64
    • Chrome (web)               • chrome                                   • web-javascript • Google Chrome
      97.0.4692.99

[✓] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.


[✓] Flutter (Channel stable, 2.8.1, on Mac OS X 10.15.4 19E2269 darwin-x64,
    locale en-GB)
    • Flutter version 2.8.1 at /Users/dhs/documents/fluttersdk/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 77d935af4d (6 weeks ago), 2021-12-16 08:37:33 -0800
    • Engine revision 890a5fca2e
    • Dart version 2.15.1

[!] Xcode - develop for iOS and macOS (Xcode 12.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    ! Flutter recommends a minimum Xcode version of 13.0.0.
      Download the latest version or update via the Mac App Store.
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] VS Code (version 1.62.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.21.0

[✓] Connected device (4 available)
    • Darshan's iphone (mobile)  • 21150b119064aecc249dfcfe05e259197461ce23 • ios            • iOS 14.4.1
      18D61
    • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729     • ios            •
      com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
    • macOS (desktop)            • macos                                    • darwin-x64     • Mac OS X
      10.15.4 19E2269 darwin-x64
    • Chrome (web)               • chrome                                   • web-javascript • Google Chrome
      97.0.4692.99

! Doctor found issues in 1 category.

@darshankawar darshankawar added platform-mac Building on or for macOS specifically platform-web Web applications specifically found in release: 2.8 Found to occur in 2.8 found in release: 2.10 Found to occur in 2.10 has reproducible steps The issue has been confirmed reproducible and is ready to work on a: text input Entering text in a text field or keyboard related problems engine flutter/engine repository. See also e: labels. and removed in triage Presently being triaged by the triage team labels Feb 2, 2022
@darshankawar darshankawar changed the title Command and shift keys in Flutter Web on MacOS causes other keys to stay pressed for about 1 second [Web]: Command and shift keys on MacOS causes other keys to stay pressed for about 1 second Feb 2, 2022
@yjbanov
Copy link
Contributor

yjbanov commented Feb 3, 2022

I think this is because certain shortcuts on the web cause some control keys to never issue an "up" event, so we have to time out ourselves.

cc @dkwingsmt @cbracken

@vogtb
Copy link
Author

vogtb commented Feb 6, 2022

That looks about right. It seems like macOS never fires an "up" event for the final key in Cmd+Shift+{key}.

For example, when I use https://unixpapa.com/js/testkey.html in macOS + Chrome, with Cmd+Shift+A, I see the output:

keydown  keyCode=91  ([)   which=91  ([)   charCode=0        
keydown  keyCode=16        which=16        charCode=0        
keydown  keyCode=65  (A)   which=65  (A)   charCode=0        
keypress keyCode=97  (a)   which=97  (a)   charCode=97  (a)  
keyup    keyCode=16        which=16        charCode=0        
keyup    keyCode=91  ([)   which=91  ([)   charCode=0        
keyup    keyCode=65  (A)   which=65  (A)   charCode=0     

The reason I found this issue is because I was using the Shortcuts widget. When I bind on Cmd+Shift+A to trigger an action, and I trigger it twice (pressing and releasing Cmd+Shift+A twice short succession) I end up with three actions fired instead of two. This is because I get one action from Cmd+Shift+A, a second action one from Cmd+Shift on the second combo because RawKeyboard.instance still believes that the A key is still pressed, and a third action from the full Cmd+Shift+A combo.

It would seem that since macOS doesn't fire an up-event for the final key in a Cmd+Shift+{key} set, this issue as it stands is not actionable.

Should I file an issue for Shortcuts or ShortcutManager to not use RawKeyboard when matching on key sets?

@yjbanov
Copy link
Contributor

yjbanov commented Feb 10, 2022

Is this fixed with flutter/engine#30488? cc @dkwingsmt

@dkwingsmt
Copy link
Contributor

dkwingsmt commented Mar 4, 2022

@vogtb Thanks for such detailed explanation! This is an intended behavior, but should not necessarily cause shortcuts on macOS Web unusable. Your problem is probably due to using LogicalKeySet instead of SingleActivator.

  1. Why this behavior: As yjbanov has explained, due to a technical limitation that macOS does not fire the up events for existing shortcuts, Flutter checks if a letter key is still pressed by expecting its repeat events, and consider it released if no repeat events come for a few seconds. The allows the key to be released, but only after a delay.
  2. How to fix your problem: When defining shortcuts that combines "modifier keys and a final key", do not use LogicalKeySet but use SingleActivator. LogicalKeySet has a few problems (such as not allowing extra non-modifier keys to recognize a key combination) and should not be used unless absolutely necessary.

Can you check if this problem no longer appears if you switch to using SingleActivator?

@dkwingsmt dkwingsmt added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Mar 4, 2022
@vogtb
Copy link
Author

vogtb commented Mar 8, 2022

Heck yeah, that works! Thanks @dkwingsmt, keep up the good work, love working with Flutter 👍

@vogtb vogtb closed this as completed Mar 8, 2022
@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Mar 8, 2022
@darshankawar darshankawar added the r: solved Issue is closed as solved label Mar 8, 2022
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: text input Entering text in a text field or keyboard related problems engine flutter/engine repository. See also e: labels. found in release: 2.8 Found to occur in 2.8 found in release: 2.10 Found to occur in 2.10 has reproducible steps The issue has been confirmed reproducible and is ready to work on platform-mac Building on or for macOS specifically platform-web Web applications specifically r: solved Issue is closed as solved
Projects
None yet
Development

No branches or pull requests

5 participants