Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
AvaloniaKeyboardAdapter.cs
1using System.Runtime.CompilerServices;
2using Avalonia;
3using Avalonia.Controls;
4using Avalonia.Input;
5using Avalonia.Interactivity;
7using Microsoft.Extensions.Logging;
8
10
17public sealed class AvaloniaKeyboardAdapter : IKeyboardAdapter, IDisposable
18{
24 public static int? GetKeyCodeFromString(string keyName)
25 {
26 if (Enum.TryParse<Key>(keyName, true, out var key))
27 return (int)key;
28
29 Engine.Logger.LogWarning("Invalid Avalonia key name: {KeyName}", keyName);
30 return null;
31 }
32
33 private readonly Control _lifetimeOwner;
34 private TopLevel? _topLevel;
35
36 // Key state table indexed by (int)Key
37 private readonly int[] _down = new int[512];
38
39 // Modifier bits published lock-free
40 private int _modsBits;
41
42 private bool _isDisposed;
43
48 (KeyboardModifierState)Volatile.Read(ref _modsBits);
49
58 public AvaloniaKeyboardAdapter(Control lifetimeOwner)
59 {
60 _lifetimeOwner = lifetimeOwner ?? throw new ArgumentNullException(nameof(lifetimeOwner));
61
62 _lifetimeOwner.AttachedToVisualTree += OnAttachedToVisualTree;
63 _lifetimeOwner.DetachedFromVisualTree += OnDetachedFromVisualTree;
64
65 // If the control is already part of the visual tree, connect immediately
66 if (TopLevel.GetTopLevel(_lifetimeOwner) != null)
67 ConnectToTopLevel();
68
69 Engine.Logger.LogInformation("AvaloniaKeyboardAdapter initialized.");
70 }
71
72 private void OnAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
73 => ConnectToTopLevel();
74
75 private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
76 => DisconnectFromTopLevel();
77
78 private void ConnectToTopLevel()
79 {
80 if (_isDisposed) return;
81
82 var tl = TopLevel.GetTopLevel(_lifetimeOwner);
83 if (tl == null || ReferenceEquals(tl, _topLevel)) return;
84
85 _topLevel = tl;
86 tl.AddHandler(InputElement.KeyDownEvent, OnKeyDown, RoutingStrategies.Tunnel);
87 tl.AddHandler(InputElement.KeyUpEvent, OnKeyUp, RoutingStrategies.Tunnel);
88 }
89
90 private void DisconnectFromTopLevel()
91 {
92 if (_topLevel == null) return;
93
94 _topLevel.RemoveHandler(InputElement.KeyDownEvent, OnKeyDown);
95 _topLevel.RemoveHandler(InputElement.KeyUpEvent, OnKeyUp);
96 _topLevel = null;
97 }
98
99 private void OnKeyDown(object? sender, KeyEventArgs e)
100 {
101 if (_isDisposed) return;
102 SetDown((int)e.Key, true);
103 UpdateMods(e.KeyModifiers);
104 }
105
106 private void OnKeyUp(object? sender, KeyEventArgs e)
107 {
108 if (_isDisposed) return;
109 SetDown((int)e.Key, false);
110 UpdateMods(e.KeyModifiers);
111 }
112
119 [MethodImpl(MethodImplOptions.AggressiveInlining)]
120 public bool IsDown(int keyCode)
121 {
122 if ((uint)keyCode >= (uint)_down.Length) return false;
123 return Volatile.Read(ref _down[keyCode]) != 0;
124 }
125
126 [MethodImpl(MethodImplOptions.AggressiveInlining)]
127 private void SetDown(int keyCode, bool down)
128 {
129 if ((uint)keyCode >= (uint)_down.Length) return;
130 Volatile.Write(ref _down[keyCode], down ? 1 : 0);
131 }
132
133 [MethodImpl(MethodImplOptions.AggressiveInlining)]
134 private void UpdateMods(KeyModifiers km)
135 {
136 int mods = 0;
137 if ((km & KeyModifiers.Shift) != 0) mods |= (int)KeyboardModifierState.Shift;
138 if ((km & KeyModifiers.Control) != 0) mods |= (int)KeyboardModifierState.Ctrl;
139 if ((km & KeyModifiers.Alt) != 0) mods |= (int)KeyboardModifierState.Alt;
140 Volatile.Write(ref _modsBits, mods);
141 }
142
146 public void Dispose()
147 {
148 if (_isDisposed) return;
149
150 _isDisposed = true;
151
152 DisconnectFromTopLevel();
153 _lifetimeOwner.AttachedToVisualTree -= OnAttachedToVisualTree;
154 _lifetimeOwner.DetachedFromVisualTree -= OnDetachedFromVisualTree;
155
156 Engine.Logger.LogInformation("AvaloniaKeyboardAdapter disposed.");
157 }
158}
void Dispose()
Releases all resources and removes all event handlers registered by this adapter.
AvaloniaKeyboardAdapter(Control lifetimeOwner)
Initializes a new instance of the AvaloniaKeyboardAdapter class.
KeyboardModifierState CurrentKeyboardModifiers
Gets the current state of keyboard modifiers (Shift, Ctrl, Alt).
bool IsDown(int keyCode)
Returns true if the key represented by keyCode (an Key value cast to int) is currently pressed.
static ? int GetKeyCodeFromString(string keyName)
Converts an Avalonia Key name (case-insensitive) to its integer key code.
Represents the core game engine singleton responsible for managing the main update loop,...
Definition Engine.cs:36
static ILogger< Engine > Logger
Gets the logger instance used by the engine for diagnostic and informational messages.
Definition Engine.cs:59
Represents an adapter for keyboard input, providing access to the currently pressed keys and active m...
KeyboardModifierState
Represents the state of keyboard modifier keys (Shift, Ctrl, Alt) that can be pressed simultaneously ...