Skip to content

Commit

Permalink
fix(wasm): key tracking when no one is subscribing to Key<Down|Up>
Browse files Browse the repository at this point in the history
  • Loading branch information
ramezgerges committed Nov 5, 2024
1 parent 9ccb7bf commit 542a226
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
17 changes: 17 additions & 0 deletions src/Uno.UI/ts/WindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ namespace Uno.UI {
private static dispatchSuspendingMethod: any;
private static getDependencyPropertyValueMethod: any;
private static setDependencyPropertyValueMethod: any;
private static keyTrackingMethod: any;

private constructor(private containerElementId: string, private loadingElementId: string) {
this.initDom();
Expand Down Expand Up @@ -1437,6 +1438,7 @@ namespace Uno.UI {
WindowManager.dispatchEventMethod = exports.Microsoft.UI.Xaml.UIElement.DispatchEvent;
WindowManager.focusInMethod = exports.Microsoft.UI.Xaml.Input.FocusManager.ReceiveFocusNative;
WindowManager.dispatchSuspendingMethod = exports.Microsoft.UI.Xaml.Application.DispatchSuspending;
WindowManager.keyTrackingMethod = (<any>globalThis).DotnetExports.Uno.Uno.UI.Core.KeyboardStateTracker.UpdateKeyStateNative;

Check warning on line 1441 in src/Uno.UI/ts/WindowManager.ts

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Uno.UI/ts/WindowManager.ts#L1441

Exceeds maximum line length of 120
} else {
throw `Unable to find dotnet exports`;
}
Expand All @@ -1451,6 +1453,13 @@ namespace Uno.UI {
document.body.addEventListener("focusin", this.onfocusin);
document.body.appendChild(this.containerElement);

// On WASM, if no one subscribes to key<Down|Up>, not only will the event not fire on any UIElement,
// but the browser won't even notify us that a key was pressed/released, and this breaks KeyboardStateTracker
// key tracking, which depends on RaiseEvent being called even if no one is subscribing. Instead, we
// subscribe on the body and make sure to call KeyboardStateTracker ourselves here.
document.body.addEventListener("keydown", this.onBodyKeyDown);
document.body.addEventListener("keyup", this.onBodyKeyUp);

window.addEventListener("resize", x => WindowManager.resize());
window.addEventListener("contextmenu", x => {
if (!(x.target instanceof HTMLInputElement) ||
Expand Down Expand Up @@ -1593,6 +1602,14 @@ namespace Uno.UI {
public moveWindow(x: number, y: number) {
window.moveTo(x, y);
}

private onBodyKeyDown(event: KeyboardEvent) {
WindowManager.keyTrackingMethod(event.key, true);
}

private onBodyKeyUp(event: KeyboardEvent) {
WindowManager.keyTrackingMethod(event.key, false);
}
}

if (typeof define === "function") {
Expand Down
20 changes: 19 additions & 1 deletion src/Uno.UWP/UI/Core/Internal/KeyboardStateTracker.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices.JavaScript;
using Windows.System;
using Windows.UI.Core;

Expand All @@ -13,7 +14,7 @@ namespace Uno.UI.Core;
/// In UWP/WinUI, every key has a locked state (not only Caps Lock, etc.). The sequence of states is as follows:
/// (None) -> (Down) -> (None) -> (Down + Locked) -> (None + Locked) -> (Down) -> (None) -> etc.
/// </remarks>
internal static class KeyboardStateTracker
internal static partial class KeyboardStateTracker
{
private static readonly Dictionary<VirtualKey, CoreVirtualKeyStates> _keyStates = new Dictionary<VirtualKey, CoreVirtualKeyStates>();

Expand Down Expand Up @@ -106,4 +107,21 @@ internal static void Reset()
_keyStates.Clear();
}
}

#if __WASM__
#pragma warning disable IDE0051 // Remove unused private members
[JSExport]
private static void UpdateKeyStateNative(string key, bool down)
#pragma warning restore IDE0051 // Remove unused private members
{
if (down)
{
OnKeyDown(VirtualKeyHelper.FromKey(key));
}
else
{
OnKeyUp(VirtualKeyHelper.FromKey(key));
}
}
#endif
}

0 comments on commit 542a226

Please sign in to comment.