Skip to content

Commit e4d9055

Browse files
committed
ensure propagation of device creation events, fix enum-based button indexing
1 parent d7027f7 commit e4d9055

18 files changed

Lines changed: 208 additions & 212 deletions

sources/Input/Input/Handlers/InputContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class InputContext
1818
IMouseInputHandler,
1919
IPointerInputHandler,
2020
IKeyboardInputHandler,
21+
IInputHandler<ConnectionEvent>,
2122
IList<IInputBackend>,
2223
IReadOnlyList<IInputBackend>
2324
{
@@ -128,14 +129,18 @@ private void HandleBackendRemoval(IInputBackend backend)
128129
private void HandleBackendAddition(IInputBackend backend)
129130
{
130131
var timestamp = Stopwatch.GetTimestamp();
132+
InputLog.Debug($"Adding backend {backend.Name}");
131133
foreach (var device in backend.Devices)
132134
{
133135
HandleDeviceConnectionChanged(new ConnectionEvent(device, timestamp, true));
134136
}
135137
}
136138

139+
void IInputHandler<ConnectionEvent>.Handle(ConnectionEvent e) => HandleDeviceConnectionChanged(e);
140+
137141
private void HandleDeviceConnectionChanged(ConnectionEvent e)
138142
{
143+
InputLog.Debug($"Input device connection changed: {e}");
139144
_pointers?.HandleDeviceConnectionChanged(e);
140145
_joysticks?.HandleDeviceConnectionChanged(e);
141146
_gamepads?.HandleDeviceConnectionChanged(e);

sources/Input/Input/IKeyboardInputHandler.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ namespace Silk.NET.Input;
33
/// <summary>
44
/// An <see cref="IInputHandler"/> that also receives <see cref="IKeyboard"/> events.
55
/// </summary>
6-
public interface IKeyboardInputHandler : IButtonInputHandler<KeyName>, IInputHandler<KeyChangedEvent>
6+
public interface IKeyboardInputHandler : IButtonInputHandler<KeyName>, IInputHandler<KeyChangedEvent>, IInputHandler<KeyCharEvent>
77
{
88
/// <summary>
99
/// Called when a key is pressed or depressed.
@@ -21,5 +21,6 @@ public interface IKeyboardInputHandler : IButtonInputHandler<KeyName>, IInputHan
2121
/// <param name="event">The event details.</param>
2222
void HandleKeyChar(KeyCharEvent @event);
2323

24+
void IInputHandler<KeyCharEvent>.Handle(KeyCharEvent @event) => HandleKeyChar(@event);
2425
void IInputHandler<KeyChangedEvent>.Handle(KeyChangedEvent @event) => HandleKeyChanged(@event);
2526
}

sources/Input/Input/Implementations/EnumInfo.cs

Lines changed: 41 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ internal static class EnumInfo<T> where T : unmanaged, Enum
1919
/// <summary>
2020
/// All enum values sorted in increasing order (unstable sort)
2121
/// </summary>
22-
public static IReadOnlyList<T> All => _all;
22+
public static IReadOnlyList<T> AllValuesOrdered => _allValuesOrdered;
2323

2424
/// <summary>
2525
/// All enum values with distinct numerical values sorted in increasing order.
@@ -43,9 +43,8 @@ internal static class EnumInfo<T> where T : unmanaged, Enum
4343
/// </summary>
4444
public static readonly Type UnderlyingType = typeof(T).GetEnumUnderlyingType();
4545

46-
private static readonly T[] _all;
47-
private static readonly string[] _names;
48-
private static readonly Dictionary<T, int> _numericallyDistinctValues;
46+
private static readonly T[] _allValuesOrdered;
47+
private static readonly Dictionary<T, int> _numericallyDistinctIndices;
4948
private static readonly ulong[] _allEnumValuesRaw;
5049
private static readonly bool _unnamedAreIndexable;
5150

@@ -127,61 +126,23 @@ static unsafe EnumInfo()
127126
throw new InvalidOperationException("Enum provided uses an unknown numeric base??");
128127
}
129128

130-
131-
var names = new string[all.Length];
132-
for (var index = 0; index < all.Length; index++)
133-
{
134-
names[index] = all[index].ToString(); // todo: readable name attributes?
135-
}
136-
137129
var dict = new Dictionary<T, int>(vals.Length);
138-
for (var i = 0; i < vals.Length; i++)
130+
for (var index = 0; index < vals.Length; index++)
139131
{
140-
var enumVal = vals[i];
132+
var enumVal = vals[index];
141133

142134
// get attribute and check for ignore
143135

144-
dict.Add(enumVal, i);
136+
dict.Add(enumVal, index);
145137
}
146138

147-
_names = names;
148-
_all = all;
139+
_allValuesOrdered = all;
149140
UniqueValues = vals;
150-
_numericallyDistinctValues = dict;
151-
MinValue = All[0];
152-
MaxValue = All[^1];
141+
_numericallyDistinctIndices = dict;
142+
MinValue = AllValuesOrdered[0];
143+
MaxValue = AllValuesOrdered[^1];
153144
}
154145

155-
/// <summary>
156-
/// Get the ordered index of the value provided.
157-
/// Values with the same numerical value will *not* return the same index, and are not guaranteed to be
158-
/// stably sorted across application runs.
159-
/// The index provided
160-
/// </summary>
161-
/// <param name="value"></param>
162-
/// <returns>The index of the sorted enum value</returns>
163-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
164-
private static int NameIndexOf(T value) => Array.IndexOf(_all, value);
165-
166-
/// <inheritdoc cref="_names"/>
167-
168-
/// <summary>
169-
/// Returns the names of an enum value, pre-allocated
170-
/// </summary>
171-
public static string NameOf(T value) => _names[NameIndexOf(value)];
172-
173-
/// <summary>
174-
/// Get the ordered index of the value provided.
175-
/// Values with the same numerical value will return the same index
176-
/// </summary>
177-
/// <param name="value"></param>
178-
/// <returns>The index of the sorted enum numerical value, or -1 if not a named enum member.</returns>
179-
/// <exception cref="InvalidOperationException"></exception>
180-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
181-
public static int ValueIndexOf(T value) => !_unnamedAreIndexable
182-
? ValueOf<T, int>(value)
183-
: _numericallyDistinctValues.GetValueOrDefault(value, -1);
184-
185146
/// <summary>
186147
/// Gets the ordered index of the unnamed enum value provided. This index is calculated by:
187148
/// (the number of named members in this enum type) + (the raw value of the number if unnamed)
@@ -190,57 +151,60 @@ public static int ValueIndexOf(T value) => !_unnamedAreIndexable
190151
/// </summary>
191152
/// <param name="value"></param>
192153
/// <returns></returns>
193-
public static int ValueIndexOfUnnamed(T value)
154+
public static int ValueIndexOf(T value)
194155
{
195-
if (!_unnamedAreIndexable)
156+
// happy path - it's a named value we've already computed
157+
if(_numericallyDistinctIndices.TryGetValue(value, out var index))
196158
{
197-
return ValueOf<T, int>(value);
159+
return index;
198160
}
199161

200-
if(_numericallyDistinctValues.TryGetValue(value, out var index))
162+
// unhappy path - it's an unnamed value we haven't computed yet
163+
if (!_unnamedAreIndexable)
201164
{
202-
return index;
165+
// unnamed indexing is disabled
166+
return -1;
203167
}
204168

205-
var rawValue = ValueOf<T, int>(value);
169+
var rawValue = Convert<T, int>(value);
206170

207171
// todo - don't rely on joystickButton's unknown - find the MinValue
208-
if (rawValue <= 0 || rawValue >= ValueOf<ulong, int>(_allEnumValuesRaw[0]))
172+
if (rawValue <= 0 || rawValue >= Convert<ulong, int>(_allEnumValuesRaw[0]))
209173
{
210174
return -1;
211175
}
212176

213-
return _all.Length + rawValue;
177+
return _allValuesOrdered.Length + rawValue;
214178
}
215179

216180
/// <summary>
217181
/// Returns the numerical value of the enum value provided in a type-safe way
218182
/// </summary>
219183
/// <param name="value"></param>
220-
/// <typeparam name="TValue"></typeparam>
221-
/// <typeparam name="TNumber"></typeparam>
184+
/// <typeparam name="TFrom"></typeparam>
185+
/// <typeparam name="TTo"></typeparam>
222186
/// <returns></returns>
223-
private static unsafe TNumber ValueOf<TValue, TNumber>(TValue value) where TNumber : unmanaged where TValue : unmanaged
187+
private static unsafe TTo Convert<TFrom, TTo>(TFrom value) where TTo : unmanaged where TFrom : unmanaged
224188
{
225-
if (sizeof(T) == sizeof(TNumber))
189+
if (sizeof(T) == sizeof(TTo))
226190
{
227-
return Unsafe.Read<TNumber>(&value);
191+
return Unsafe.Read<TTo>(&value);
228192
}
229193

230-
var minSize = Math.Min(sizeof(TNumber), sizeof(T));
194+
var minSize = Math.Min(sizeof(TTo), sizeof(T));
231195

232196
var originalValuePtr = (byte*)&value;
233197

234198
var valuePtr = &originalValuePtr[Math.Abs(minSize - sizeof(T))]; // does this assume little-endianness?
235-
var numberPtr = stackalloc byte[sizeof(TNumber)];
199+
var numberPtr = stackalloc byte[sizeof(TTo)];
236200

237201
// ensure block is initialized (as it isnt guaranteed?) so any missing bytes of the output will stay 0
238202
// if type TNumber is a larger size than type T
239-
Unsafe.InitBlock(numberPtr, 0, (uint)sizeof(TNumber));
203+
Unsafe.InitBlock(numberPtr, 0, (uint)sizeof(TTo));
240204

241-
var copyToPtr = &numberPtr[Math.Abs(minSize - sizeof(TNumber))];
242-
Buffer.MemoryCopy(valuePtr, copyToPtr, sizeof(TNumber), minSize);
243-
return *(TNumber*)numberPtr;
205+
var copyToPtr = &numberPtr[Math.Abs(minSize - sizeof(TTo))];
206+
Buffer.MemoryCopy(valuePtr, copyToPtr, sizeof(TTo), minSize);
207+
return *(TTo*)numberPtr;
244208
}
245209

246210
private static T[] OrderedValues<TNumber>(bool byNumericValue)
@@ -251,13 +215,13 @@ private static T[] OrderedValues<TNumber>(bool byNumericValue)
251215

252216
if (byNumericValue)
253217
{
254-
allValues = allValues.DistinctBy(ValueOf<T, TNumber>).ToArray();
218+
allValues = allValues.DistinctBy(Convert<T, TNumber>).ToArray();
255219
}
256220

257221
// sort by increasing order
258222
allValues.AsSpan().StableSort((a, b) => {
259-
var aNumber = ValueOf<T, TNumber>(a);
260-
var bNumber = ValueOf<T, TNumber>(b);
223+
var aNumber = Convert<T, TNumber>(a);
224+
var bNumber = Convert<T, TNumber>(b);
261225
return aNumber.CompareTo(bNumber);
262226
});
263227

@@ -271,4 +235,10 @@ private static bool IsIgnored(T value)
271235
}
272236

273237
public static unsafe bool HasValue(int value) => _allEnumValuesRaw.Contains(*(uint*)&value);
238+
239+
public static unsafe T ValueOfIndex(int index)
240+
{
241+
var value = _allEnumValuesRaw[index];
242+
return *(T*)&value;
243+
}
274244
}

sources/Input/Input/Implementations/SDL3/Devices/ISdlDevice.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Silk.NET.Input.SDL3;
99
/// <typeparam name="T"></typeparam>
1010
internal interface ISdlDevice<out T> : IInputDevice where T : SdlDevice
1111
{
12-
public static abstract T? CreateDevice(ulong sdlDeviceId, SdlInputBackend backend, SilkEventContext context);
12+
public static abstract T? CreateDevice(ulong sdlDeviceId, long timestamp, ulong sdlTimestamp, SdlInputBackend backend, SilkEventContext context);
1313
}
1414

1515
internal interface INeedFinalizationEachFrame

sources/Input/Input/Implementations/SDL3/Devices/Joysticks/SdlGamepad.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ protected override void Release()
139139

140140
#endregion
141141

142-
public static SdlGamepad? CreateDevice(ulong sdlDeviceId, SdlInputBackend backend, SilkEventContext context)
142+
public static SdlGamepad? CreateDevice(ulong sdlDeviceId, long timestamp, ulong sdlTimestamp, SdlInputBackend backend, SilkEventContext context)
143143
{
144-
if (!backend.TryGetOrCreateDevice<SdlJoystick>(sdlDeviceId, out var joystick))
144+
if (!backend.TryGetOrCreateDevice<SdlJoystick>(sdlDeviceId, timestamp, sdlTimestamp, out var joystick))
145145
{
146146
return null;
147147
}

sources/Input/Input/Implementations/SDL3/Devices/Joysticks/SdlJoystick.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal sealed unsafe partial class SdlJoystick : SdlDevice, IJoystick, ISdlDev
1313
private JoystickType _joystickType;
1414
internal JoystickHandle JoystickHandle { get; private set; }
1515

16-
public static SdlJoystick CreateDevice(ulong sdlDeviceId, SdlInputBackend backend, SilkEventContext silkEvents)
16+
public static SdlJoystick CreateDevice(ulong sdlDeviceId, long timestamp, ulong sdlTimestamp, SdlInputBackend backend, SilkEventContext silkEvents)
1717
{
1818
nint uniqueId = 0;
1919

sources/Input/Input/Implementations/SDL3/Devices/Pointers/SdlMouse.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ private unsafe SdlMouseInputFlags GetMouseState(ref float x, ref float y) =>
7171
(SdlMouseInputFlags)NativeBackend.GetMouseState((float*)Unsafe.AsPointer(ref x),
7272
(float*)Unsafe.AsPointer(ref y));
7373

74-
public static SdlMouse CreateDevice(ulong sdlDeviceId, SdlInputBackend backend, SilkEventContext silkEvents)
74+
public static SdlMouse CreateDevice(ulong sdlDeviceId, long timestamp, ulong sdlTimestamp, SdlInputBackend backend, SilkEventContext silkEvents)
7575
{
7676
var deviceName = backend.Sdl.GetMouseNameForID((uint)sdlDeviceId);
7777
nint uniqueId = 0;

sources/Input/Input/Implementations/SDL3/Devices/Pointers/SdlPen.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public SdlPen(SdlInputBackend backend, nint silkId, ulong sdlDeviceId, string na
1616
State = new PointerState(Buttons, Points);
1717
}
1818

19-
public static SdlPen CreateDevice(ulong sdlDeviceId, SdlInputBackend backend, SilkEventContext silkEvents)
19+
public static SdlPen CreateDevice(ulong sdlDeviceId, long timestamp, ulong sdlTimestamp, SdlInputBackend backend, SilkEventContext silkEvents)
2020
{
2121
nint uniqueId = 0;
2222

sources/Input/Input/Implementations/SDL3/Devices/Pointers/SdlPointerDevice.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ protected void AddButtonEvent(PointerButton button, long timestamp, ulong sdlTim
3232
float? pressure = null)
3333
{
3434
pressure ??= isDown ? 1.0f : 0.0f;
35-
var idx = EnumInfo<PointerButton>.ValueIndexOfUnnamed(button);
35+
var idx = EnumInfo<PointerButton>.ValueIndexOf(button);
3636

3737
while (idx >= _buttons.Count)
3838
{

sources/Input/Input/Implementations/SDL3/Devices/Pointers/SdlTouchSurface.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace Silk.NET.Input.SDL3.Devices.Pointers;
2020
/// </summary>
2121
internal class SdlTouchSurface : SdlPointerDevice, ISdlDevice<SdlTouchSurface>, IPointerDevice
2222
{
23-
public static SdlTouchSurface CreateDevice(ulong sdlDeviceId, SdlInputBackend backend, SilkEventContext silkEvents)
23+
public static SdlTouchSurface CreateDevice(ulong sdlDeviceId, long timestamp, ulong sdlTimestamp, SdlInputBackend backend, SilkEventContext silkEvents)
2424
{
2525
var namePtr = backend.Sdl.GetTouchDeviceName(sdlDeviceId);
2626

0 commit comments

Comments
 (0)