-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Winform like keyboard-events with JS event interception with fine-grained preventDefault control directly baked into C# Blazor Server/Webassembly. #62636
-
if we could do this enterprise level of keyboard navigations, key-level operations, key-prevention for typing everything would be very appreciable or if not possible in anyway it should provide keyboard helper package to accomplish the task.
like suggested by ChatGPT below or better so that developer need not to worry what's going inside js. developer should feel all c# native :-
// wwwroot/keyboardHelper.js
export function initKeyboardHandler(dotNetHelper, options) {
const keysToPrevent = options.keysToPrevent || [];
const keyMappings = options.keyMappings || {};
function getComboKey(e) {
let combo = '';
if (e.ctrlKey) combo += 'Ctrl+';
if (e.shiftKey) combo += 'Shift+';
if (e.altKey) combo += 'Alt+';
combo += e.key.toLowerCase();
return combo;
}
function onKeyDown(e) {
const combo = getComboKey(e);
if (keysToPrevent.some(k => k.toLowerCase() === combo)) {
e.preventDefault();
return;
}
const mappedKey = keyMappings[combo] || e.key;
dotNetHelper.invokeMethodAsync('OnKeyAllowed', mappedKey, e.code);
}
window.addEventListener('keydown', onKeyDown);
return {
dispose: () => window.removeEventListener('keydown', onKeyDown)
};
}
KeyboardHelper service
csharp
Copy
Edit
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.JSInterop;
namespace BlazorKeyboardHelper
{
public class KeyboardHelper : IAsyncDisposable
{
private readonly IJSRuntime _js;
private IJSObjectReference _module;
private DotNetObjectReference _objRef;
public event Func<KeyboardAction, string, Task> OnKeyPressed;
public KeyboardHelper(IJSRuntime js)
{
_js = js;
}
public async Task InitializeAsync(IEnumerable<string> keysToPrevent, Dictionary<string, string> keyMappings)
{
_module = await _js.InvokeAsync<IJSObjectReference>("import", "./_content/BlazorKeyboardHelper/keyboardHelper.js");
_objRef = DotNetObjectReference.Create(this);
var options = new
{
keysToPrevent,
keyMappings
};
await _module.InvokeVoidAsync("initKeyboardHandler", _objRef, options);
}
[JSInvokable]
public async Task OnKeyAllowed(string mappedKey, string code)
{
if (Enum.TryParse<KeyboardAction>(mappedKey, true, out var action))
{
if (OnKeyPressed != null)
await OnKeyPressed.Invoke(action, code);
}
else
{
// Optionally handle unmapped keys or ignore
}
}
public async ValueTask DisposeAsync()
{
if (_module != null)
{
await _module.DisposeAsync();
}
_objRef?.Dispose();
}
}
}
public enum KeyboardAction
{
// Letters
A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
// Numbers (top row)
Digit0, Digit1, Digit2, Digit3, Digit4,
Digit5, Digit6, Digit7, Digit8, Digit9,
// Numpad keys
Numpad0, Numpad1, Numpad2, Numpad3, Numpad4,
Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
NumpadMultiply, NumpadAdd, NumpadSubtract,
NumpadDecimal, NumpadDivide,
// Function keys
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
// Navigation keys
ArrowUp, ArrowDown, ArrowLeft, ArrowRight,
Home, End, PageUp, PageDown,
// Modifiers
Shift, Control, Alt, Meta, CapsLock,
// Editing keys
Backspace, Tab, Enter, Escape, Space,
Delete, Insert,
// Other common keys
ContextMenu, NumLock, ScrollLock, Pause, PrintScreen,
// Symbols & punctuation (common US layout)
Minus, Equal, BracketLeft, BracketRight,
Backslash, Semicolon, Quote, Backquote, Comma, Period, Slash,
// Media keys (optional)
MediaPlayPause, MediaStop, MediaNextTrack, MediaPreviousTrack,
// Additional keys can be added here as needed
}
builder.Services.AddScoped();
protected override async Task OnInitializedAsync()
{
KeyboardHelper.OnKeyPressed += HandleKeyPressed;
}
Beta Was this translation helpful? Give feedback.