12public sealed class WinFormsKeyboardAdapter :
IKeyboardAdapter, IMessageFilter, IDisposable
32 if (Enum.TryParse<Keys>(keyName,
true, out var key))
35 Engine.
Logger.LogWarning(
"Invalid key name: {KeyName}", keyName);
39 private readonly Control _lifetimeOwner;
42 private readonly
int[] _down =
new int[256];
45 private int _modsBits;
47 private bool _isDisposed;
55 internal WinFormsKeyboardAdapter(Control lifetimeOwner)
57 _lifetimeOwner = lifetimeOwner ??
throw new ArgumentNullException(nameof(lifetimeOwner));
59 Application.AddMessageFilter(
this);
60 _lifetimeOwner.Disposed += OnOwnerDisposed;
62 Engine.
Logger.LogInformation(
"WinFormsKeyboardAdapter initialized. Using IMessageFilter for key polling.");
65 private void OnOwnerDisposed(
object? sender, EventArgs e) =>
Dispose();
75 const int WM_KEYDOWN = 0x0100;
76 const int WM_KEYUP = 0x0101;
77 const int WM_SYSKEYDOWN = 0x0104;
78 const int WM_SYSKEYUP = 0x0105;
87 SetDown(ExtractVk(m),
true);
92 SetDown(ExtractVk(m),
false);
104 [MethodImpl(MethodImplOptions.AggressiveInlining)]
107 int idx = keyCode & 0xFF;
108 return Volatile.Read(ref _down[idx]) != 0;
111 [MethodImpl(MethodImplOptions.AggressiveInlining)]
112 private void SetDown(
int keyCode,
bool down)
114 int idx = keyCode & 0xFF;
115 Volatile.Write(ref _down[idx], down ? 1 : 0);
119 [MethodImpl(MethodImplOptions.AggressiveInlining)]
120 private void UpdateMods()
123 var mk = Control.ModifierKeys;
129 Volatile.Write(ref _modsBits, mods);
132 [MethodImpl(MethodImplOptions.AggressiveInlining)]
133 private static int ExtractVk(in Message m)
136 return m.WParam.ToInt32() & 0xFFFF;
149 Application.RemoveMessageFilter(
this);
150 _lifetimeOwner.Disposed -= OnOwnerDisposed;
152 Engine.
Logger.LogInformation(
"WinFormsKeyboardAdapter disposed.");