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

[Problem/Bug]: KeyboardEvent repeat is false initially when holding down a key (and handling the first one in the desktop app) #4810

Open
pushkin- opened this issue Sep 13, 2024 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@pushkin-
Copy link

pushkin- commented Sep 13, 2024

What happened?

My app handles KeyDown/KeyUp events. If it detects a key like F10, say, it sets e.Handled = true. If it detects that the key is being held down, it keeps Handled false.

When Handled is false, the webapp gets the keydown events, but the first handle that's called has e.repeat set to false for some reason. All subsequent logs due to the held down key have repeat correctly set to true.

This doesn't happen in my Electron app.

Importance

Moderate. My app's user experience is affected, but still usable.

Runtime Channel

Stable release (WebView2 Runtime)

Runtime Version

128.0.2739.67

SDK Version

1.0.2535.41

Framework

Winforms

Operating System

Windows 11

OS Version

22631.4037

Repro steps

If you open this Electron gist:

  1. hold down F10
  2. in the devtools, you'll see the capture and bubble handlers firing with logs indicating that e.repeat is true.
  3. In the WebView2 app, the first bubble/capture handlers have e.repeat of false and then it gets set to true.
    I can kind of repro in Edge when holding down the Space key on google.com:
    execute this code in devtools:
  window.document.body.addEventListener("keydown", (e) =>
  {
      handler(e, true);
  }, true)

  window.document.body.addEventListener("keydown", (e) =>
  {
      handler(e, false);
  }, false)

  function handler(e, isCapture)
  {
      console.log(`${Date.now()}: ${(isCapture ? "capture" : "bubble")} handler: ${e.key} ${e.type} repeat: ${e.repeat}`);
  }

and see logs:

1726256395642: capture handler:   keydown repeat: false
1726256395642: bubble handler:   keydown repeat: false
1726256396144: capture handler:   keydown repeat: true
1726256396144: bubble handler:   keydown repeat: true

but the difference is that the desktop app is presumably not handling that first key press which is why repeat is false. In my app, I handle the first key press and only subsequent, repeated pressed I don't handle, so I'd expect the devtools in my app to say repeat is always true.

To repro:

  1. open WinForms sample app
  2. add this to AppStartPage.js:
  window.document.body.addEventListener("keydown", (e) =>
  {
      handler(e, true);
  }, true)

  window.document.body.addEventListener("keydown", (e) =>
  {
      handler(e, false);
  }, false)

  function handler(e, isCapture)
  {
      console.log(`${Date.now()}: ${(isCapture ? "capture" : "bubble")} handler: ${e.key} ${e.type} repeat: ${e.repeat}`);
  }

In BrowserForm.cs, since we don't have a built in way to tell if a key is held down, I had to add the following logic. Copy this code in:

	private readonly Dictionary<Keys, bool> _keysDown = new Dictionary<Keys, bool>();

	[LibraryImport("user32.dll")]
	private static partial short GetKeyState(int key);

	private void UpdateKeyStates()
	{
		foreach (KeyValuePair<Keys, bool> entry in _keysDown)
		{
			Keys key = entry.Key;
			if (!IsKeyPressed(key))
			{
				_keysDown.Remove(key);
			}
		}
	}

	private bool IsKeyPressed(Keys key)
	{
		short state = GetKeyState((int)key);
		return state < 0; // the high-order bit being one means the key is pressed
	}

(also updated the project to use .net 8.0)

In the KeyUp handler, call UpdateKeyStates();

In the KeyDown handler, also call UpdateKeyStates(); and then do:

	bool isKeyHeldDown = !_keysDown.TryAdd(e.KeyCode, true);
	if (e.KeyCode == Keys.F10 && !isKeyHeldDown)
	{
		e.Handled = true;
	}
  1. start the app
  2. open devtools
  3. hold down F10
  4. first capture/bubble handler logs in devtools show that repeat is false.
  5. I added tracepoints in the keydown handler to log DateTimeOffset.Now.ToUnixTimeMilliseconds() and isKeyHeldDown. This shows that the repeat=false log happens after the repeated key that we don't handle.

Repros in Edge Browser

No, issue does not reproduce in the corresponding Edge version

Regression

No, this never worked

Last working version (if regression)

No response

@pushkin- pushkin- added the bug Something isn't working label Sep 13, 2024
@pushkin-
Copy link
Author

pushkin- commented Nov 18, 2024

possibly related issue https://stackoverflow.com/questions/78836450/keydown-firing-twice-when-the-previous-keydown-was-held which points to this Chromium issue (though again, Electron doesn't have this issue)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants