Skip to content

Commit 3ee33fa

Browse files
authored
Update input context in DoEvents instead of DoUpdate (#762)
* Update input context in DoEvents instead of DoUpdate * Apply suggestions from code review * Make ProcessEvents logic common in both Windowing and Input
1 parent 3a5f450 commit 3ee33fa

File tree

6 files changed

+108
-54
lines changed

6 files changed

+108
-54
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Silk.NET.Windowing;
7+
using Silk.NET.Windowing.Internals;
8+
9+
namespace Silk.NET.Input.Internals;
10+
11+
internal abstract class InputContextImplementationBase : IInputContext
12+
{
13+
protected InputContextImplementationBase(IView window)
14+
{
15+
Window = window;
16+
if (window is ViewImplementationBase view)
17+
{
18+
view.ProcessEvents += ProcessEvents;
19+
}
20+
else
21+
{
22+
window.Update += Update;
23+
}
24+
}
25+
26+
private void Update(double delta) => ProcessEvents();
27+
28+
public void Dispose()
29+
{
30+
if (Window is ViewImplementationBase view)
31+
{
32+
view.ProcessEvents -= ProcessEvents;
33+
}
34+
else
35+
{
36+
Window.Update -= Update;
37+
}
38+
CoreDispose();
39+
}
40+
41+
public abstract void CoreDispose();
42+
public abstract void ProcessEvents();
43+
public IView Window { get; }
44+
public abstract nint Handle { get; }
45+
public abstract IReadOnlyList<IGamepad> Gamepads { get; }
46+
public abstract IReadOnlyList<IJoystick> Joysticks { get; }
47+
public abstract IReadOnlyList<IKeyboard> Keyboards { get; }
48+
public abstract IReadOnlyList<IMouse> Mice { get; }
49+
public abstract IReadOnlyList<IInputDevice> OtherDevices { get; }
50+
public abstract event Action<IInputDevice, bool>? ConnectionChanged;
51+
}

src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,23 @@
77
using Silk.NET.Input.Internals;
88
using Silk.NET.Windowing;
99
using Silk.NET.Windowing.Glfw;
10+
using Silk.NET.Windowing.Internals;
1011

1112
namespace Silk.NET.Input.Glfw
1213
{
13-
internal class GlfwInputContext : IInputContext
14+
internal class GlfwInputContext : InputContextImplementationBase
1415
{
1516
private readonly GlfwGamepad[] _gamepads = new GlfwGamepad[16];
1617
private readonly GlfwJoystick[] _joysticks = new GlfwJoystick[16];
1718
private readonly GlfwKeyboard[] _keyboards = new GlfwKeyboard[1];
1819
private readonly GlfwMouse[] _mice = new GlfwMouse[1];
1920
private readonly IGlfwSubscriber[] _subscribers = new IGlfwSubscriber[2];
20-
private Action<double> _update;
21-
private IView _window;
2221

23-
public unsafe GlfwInputContext(IView window)
22+
public unsafe GlfwInputContext(IView window) : base(window)
2423
{
2524
void OnConnectionChanged(IInputDevice a, bool b) => ConnectionChanged?.Invoke(a, b);
2625

27-
if (!(window is GlfwWindow))
26+
if (window is not GlfwWindow)
2827
{
2928
throw new ArgumentNullException
3029
(nameof(window), "Attempted to create input context for null or non-GLFW window.");
@@ -50,30 +49,28 @@ public unsafe GlfwInputContext(IView window)
5049
Mice = _mice;
5150

5251
GlfwInputPlatform.RegisterWindow((WindowHandle*) Handle, _subscribers);
53-
window.Update += _update = _ =>
52+
}
53+
54+
public override void ProcessEvents()
55+
{
56+
foreach (var updatable in _mice)
57+
{
58+
updatable.Update();
59+
}
60+
61+
foreach (var updatable in _gamepads)
5462
{
55-
foreach (var updatable in _mice)
56-
{
57-
updatable.Update();
58-
}
59-
60-
foreach (var updatable in _gamepads)
61-
{
62-
updatable.Update();
63-
}
64-
65-
foreach (var updatable in _joysticks)
66-
{
67-
updatable.Update();
68-
}
69-
};
70-
71-
_window = window;
63+
updatable.Update();
64+
}
65+
66+
foreach (var updatable in _joysticks)
67+
{
68+
updatable.Update();
69+
}
7270
}
7371

74-
public unsafe void Dispose()
72+
public override unsafe void CoreDispose()
7573
{
76-
_window.Update -= _update;
7774
GlfwInputPlatform.UnregisterWindow((WindowHandle*) Handle, _subscribers);
7875
foreach (var gamepad in _gamepads)
7976
{
@@ -91,12 +88,12 @@ public unsafe void Dispose()
9188
}
9289
}
9390

94-
public nint Handle { get; }
95-
public IReadOnlyList<IGamepad> Gamepads { get; }
96-
public IReadOnlyList<IJoystick> Joysticks { get; }
97-
public IReadOnlyList<IKeyboard> Keyboards { get; }
98-
public IReadOnlyList<IMouse> Mice { get; }
99-
public IReadOnlyList<IInputDevice> OtherDevices { get; } = new IInputDevice[0];
100-
public event Action<IInputDevice, bool>? ConnectionChanged;
91+
public sealed override nint Handle { get; }
92+
public override IReadOnlyList<IGamepad> Gamepads { get; }
93+
public override IReadOnlyList<IJoystick> Joysticks { get; }
94+
public override IReadOnlyList<IKeyboard> Keyboards { get; }
95+
public override IReadOnlyList<IMouse> Mice { get; }
96+
public override IReadOnlyList<IInputDevice> OtherDevices { get; } = Array.Empty<IInputDevice>();
97+
public override event Action<IInputDevice, bool>? ConnectionChanged;
10198
}
10299
}

src/Input/Silk.NET.Input.Sdl/SdlInputContext.cs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,14 @@
1010

1111
namespace Silk.NET.Input.Sdl
1212
{
13-
internal class SdlInputContext : IInputContext
13+
internal class SdlInputContext : InputContextImplementationBase
1414
{
15-
private readonly IView _view;
1615
private readonly SdlView _sdlView; // to circumvent CS0122
1716
private nint _lastHandle;
1817

19-
public SdlInputContext(SdlView view)
18+
public SdlInputContext(SdlView view) : base(view)
2019
{
21-
_view = _sdlView = view;
22-
_sdlView.ProcessingEvents += ProcessEvents;
20+
_sdlView = view;
2321
SdlGamepads = new Dictionary<int, SdlGamepad>();
2422
SdlJoysticks = new Dictionary<int, SdlJoystick>();
2523
Gamepads = new IsConnectedWrapper<IGamepad>
@@ -37,31 +35,31 @@ public SdlInputContext(SdlView view)
3735
}
3836

3937
// Public properties
40-
public IReadOnlyList<IGamepad> Gamepads { get; }
41-
public IReadOnlyList<IJoystick> Joysticks { get; }
42-
public IReadOnlyList<IKeyboard> Keyboards { get; }
43-
public IReadOnlyList<IMouse> Mice { get; }
44-
public IReadOnlyList<IInputDevice> OtherDevices { get; } = new IInputDevice[0];
38+
public override IReadOnlyList<IGamepad> Gamepads { get; }
39+
public override IReadOnlyList<IJoystick> Joysticks { get; }
40+
public override IReadOnlyList<IKeyboard> Keyboards { get; }
41+
public override IReadOnlyList<IMouse> Mice { get; }
42+
public override IReadOnlyList<IInputDevice> OtherDevices { get; } = Array.Empty<IInputDevice>();
4543

4644
// Implementation-specific properties
4745
public Dictionary<int, SdlGamepad> SdlGamepads { get; }
4846
public Dictionary<int, SdlJoystick> SdlJoysticks { get; }
4947

5048
public SDL.Sdl Sdl => _sdlView.Sdl;
51-
public nint Handle => _view.Handle;
52-
public event Action<IInputDevice, bool>? ConnectionChanged;
49+
public override nint Handle => Window.Handle;
50+
public override event Action<IInputDevice, bool>? ConnectionChanged;
5351

54-
private void ProcessEvents()
52+
public override void ProcessEvents()
5553
{
56-
if (_view.Handle == 0)
54+
if (Window.Handle == 0)
5755
{
5856
throw new InvalidOperationException("Input update event fired without an underlying window.");
5957
}
6058

61-
if (_lastHandle != _view.Handle)
59+
if (_lastHandle != Window.Handle)
6260
{
6361
RefreshJoysticksAndGamepads();
64-
_lastHandle = _view.Handle;
62+
_lastHandle = Window.Handle;
6563
}
6664

6765
var i = 0;
@@ -304,10 +302,8 @@ private void RefreshJoysticksAndGamepads()
304302
}
305303
}
306304

307-
public void Dispose()
305+
public override void CoreDispose()
308306
{
309-
_sdlView.ProcessingEvents -= ProcessEvents;
310-
311307
foreach (var gp in SdlGamepads.Values)
312308
{
313309
gp.Dispose();

src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ protected ViewImplementationBase(ViewOptions opts)
8383
public event Action? Load;
8484
public event Action<double>? Update;
8585
public event Action<double>? Render;
86+
internal event Action? ProcessEvents;
8687

8788
// Lifetime controls
8889
public void Initialize()
@@ -271,6 +272,12 @@ public IVkSurface? VkSurface
271272
}
272273

273274
// Misc implementations
275+
void IView.DoEvents()
276+
{
277+
DoEvents();
278+
ProcessEvents?.Invoke();
279+
}
280+
274281
[MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions) 512)]
275282
public Vector2D<int> PointToFramebuffer(Vector2D<int> point)
276283
{

src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
1616
<_Parameter1>Silk.NET.Windowing.Sdl</_Parameter1>
1717
</AssemblyAttribute>
18+
<!-- I couldn't decide whether we wanted to trust the users with the power to hook into DoEvents (and do stuff
19+
pre-update, as I feel like that'd just be an arms race) so I made the ProcessEvents event internal for
20+
now -->
21+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
22+
<_Parameter1>Silk.NET.Input.Common</_Parameter1>
23+
</AssemblyAttribute>
1824
</ItemGroup>
1925

2026
<ItemGroup>

src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ protected override Vector2D<int> CoreSize
9393
}
9494
}
9595

96-
public event System.Action? ProcessingEvents;
97-
9896
// Methods
9997
public override void ContinueEvents() => Interlocked.Exchange(ref _continue, 1);
10098
protected override INativeWindow GetNativeWindow() => new SdlNativeWindow(Sdl, SdlWindow);
@@ -326,7 +324,6 @@ public void EndEventProcessing(bool taken)
326324
[SuppressMessage("ReSharper", "SwitchStatementHandlesSomeKnownEnumValuesWithDefault")]
327325
public virtual void ProcessEvents()
328326
{
329-
ProcessingEvents?.Invoke();
330327
var taken = false;
331328
BeginEventProcessing(ref taken);
332329
var count = Events.Count;

0 commit comments

Comments
 (0)