Keyboard lock & layout
The Keyboard API proper: capture keys the browser would normally swallow while fullscreen, and find out what each physical key actually prints on the user's layout.
@inject Bit.Butil.KeyboardLock keyboardLock, KeyboardLayout keyboardLayoutMDN reference
The two halves are probed separately. During prerender/SSR both return false rather than throwing, so defer them to OnAfterRenderAsync.
@inject Bit.Butil.KeyboardLock keyboardLock
@inject Bit.Butil.KeyboardLayout keyboardLayout
var canLock = await keyboardLock.IsSupported();
var canReadLayout = await keyboardLayout.IsSupported();Enter fullscreen first, then lock. Passing no codes captures everything the platform allows; passing codes captures only those. Calling Lock again replaces the previous set rather than adding to it. Leaving fullscreen unlocks on its own, so Unlock is for the case where the page stays fullscreen and simply stops needing the keys.
Bit.Butil.KeyboardLock keyboardLock
<div @ref="_stage">...</div>
<button @onclick="Enter">Go fullscreen</button>
{
private ElementReference _stage;
// The lock only holds while the document is fullscreen, so the two go together: leaving
// fullscreen releases it, and asking for it outside fullscreen does nothing.
private async Task Enter()
{
await _stage.RequestFullScreen(null);
var locked = await keyboardLock.Lock("Escape", "KeyW", "F11");
}
private async Task Leave() => await keyboardLock.Unlock();
}A shortcut is bound to a physical key (KeyboardEvent.code), but the hint shown to the user has to be the character that key produces. Hard-coding 'W' is wrong on AZERTY, where the same key prints 'Z'. Look the code up and show what comes back.
var label = await keyboardLayout.Get("KeyW") ?? "W";
_shortcutHint = $"Ctrl+{label.ToUpperInvariant()}";API reference
ValueTask<bool> IsSupported()ValueTask<bool> Lock(params string[] codes)ValueTask Unlock()ValueTask<bool> IsSupported()ValueTask<KeyboardLayoutEntry[]> GetLayoutMap()ValueTask<string?> Get(string code)