Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using Silk.NET.Windowing;
using Silk.NET.Windowing.Internals;

namespace Silk.NET.Input.Internals;

internal abstract class InputContextImplementationBase : IInputContext
{
protected InputContextImplementationBase(IView window)
{
Window = window;
if (window is ViewImplementationBase view)
{
view.ProcessEvents += ProcessEvents;
}
else
{
window.Update += Update;
}
}

private void Update(double delta) => ProcessEvents();

public void Dispose()
{
if (Window is ViewImplementationBase view)
{
view.ProcessEvents -= ProcessEvents;
}
else
{
Window.Update -= Update;
}
CoreDispose();
}

public abstract void CoreDispose();
public abstract void ProcessEvents();
public IView Window { get; }
public abstract nint Handle { get; }
public abstract IReadOnlyList<IGamepad> Gamepads { get; }
public abstract IReadOnlyList<IJoystick> Joysticks { get; }
public abstract IReadOnlyList<IKeyboard> Keyboards { get; }
public abstract IReadOnlyList<IMouse> Mice { get; }
public abstract IReadOnlyList<IInputDevice> OtherDevices { get; }
public abstract event Action<IInputDevice, bool>? ConnectionChanged;
}
61 changes: 29 additions & 32 deletions src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,23 @@
using Silk.NET.Input.Internals;
using Silk.NET.Windowing;
using Silk.NET.Windowing.Glfw;
using Silk.NET.Windowing.Internals;

namespace Silk.NET.Input.Glfw
{
internal class GlfwInputContext : IInputContext
internal class GlfwInputContext : InputContextImplementationBase
{
private readonly GlfwGamepad[] _gamepads = new GlfwGamepad[16];
private readonly GlfwJoystick[] _joysticks = new GlfwJoystick[16];
private readonly GlfwKeyboard[] _keyboards = new GlfwKeyboard[1];
private readonly GlfwMouse[] _mice = new GlfwMouse[1];
private readonly IGlfwSubscriber[] _subscribers = new IGlfwSubscriber[2];
private Action<double> _update;
private IView _window;

public unsafe GlfwInputContext(IView window)
public unsafe GlfwInputContext(IView window) : base(window)
{
void OnConnectionChanged(IInputDevice a, bool b) => ConnectionChanged?.Invoke(a, b);

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

GlfwInputPlatform.RegisterWindow((WindowHandle*) Handle, _subscribers);
window.Update += _update = _ =>
}

public override void ProcessEvents()
{
foreach (var updatable in _mice)
{
updatable.Update();
}

foreach (var updatable in _gamepads)
{
foreach (var updatable in _mice)
{
updatable.Update();
}

foreach (var updatable in _gamepads)
{
updatable.Update();
}

foreach (var updatable in _joysticks)
{
updatable.Update();
}
};

_window = window;
updatable.Update();
}

foreach (var updatable in _joysticks)
{
updatable.Update();
}
}

public unsafe void Dispose()
public override unsafe void CoreDispose()
{
_window.Update -= _update;
GlfwInputPlatform.UnregisterWindow((WindowHandle*) Handle, _subscribers);
foreach (var gamepad in _gamepads)
{
Expand All @@ -91,12 +88,12 @@ public unsafe void Dispose()
}
}

public nint Handle { get; }
public IReadOnlyList<IGamepad> Gamepads { get; }
public IReadOnlyList<IJoystick> Joysticks { get; }
public IReadOnlyList<IKeyboard> Keyboards { get; }
public IReadOnlyList<IMouse> Mice { get; }
public IReadOnlyList<IInputDevice> OtherDevices { get; } = new IInputDevice[0];
public event Action<IInputDevice, bool>? ConnectionChanged;
public sealed override nint Handle { get; }
public override IReadOnlyList<IGamepad> Gamepads { get; }
public override IReadOnlyList<IJoystick> Joysticks { get; }
public override IReadOnlyList<IKeyboard> Keyboards { get; }
public override IReadOnlyList<IMouse> Mice { get; }
public override IReadOnlyList<IInputDevice> OtherDevices { get; } = Array.Empty<IInputDevice>();
public override event Action<IInputDevice, bool>? ConnectionChanged;
}
}
34 changes: 15 additions & 19 deletions src/Input/Silk.NET.Input.Sdl/SdlInputContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@

namespace Silk.NET.Input.Sdl
{
internal class SdlInputContext : IInputContext
internal class SdlInputContext : InputContextImplementationBase
{
private readonly IView _view;
private readonly SdlView _sdlView; // to circumvent CS0122
private nint _lastHandle;

public SdlInputContext(SdlView view)
public SdlInputContext(SdlView view) : base(view)
{
_view = _sdlView = view;
_sdlView.ProcessingEvents += ProcessEvents;
_sdlView = view;
SdlGamepads = new Dictionary<int, SdlGamepad>();
SdlJoysticks = new Dictionary<int, SdlJoystick>();
Gamepads = new IsConnectedWrapper<IGamepad>
Expand All @@ -37,31 +35,31 @@ public SdlInputContext(SdlView view)
}

// Public properties
public IReadOnlyList<IGamepad> Gamepads { get; }
public IReadOnlyList<IJoystick> Joysticks { get; }
public IReadOnlyList<IKeyboard> Keyboards { get; }
public IReadOnlyList<IMouse> Mice { get; }
public IReadOnlyList<IInputDevice> OtherDevices { get; } = new IInputDevice[0];
public override IReadOnlyList<IGamepad> Gamepads { get; }
public override IReadOnlyList<IJoystick> Joysticks { get; }
public override IReadOnlyList<IKeyboard> Keyboards { get; }
public override IReadOnlyList<IMouse> Mice { get; }
public override IReadOnlyList<IInputDevice> OtherDevices { get; } = Array.Empty<IInputDevice>();

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

public SDL.Sdl Sdl => _sdlView.Sdl;
public nint Handle => _view.Handle;
public event Action<IInputDevice, bool>? ConnectionChanged;
public override nint Handle => Window.Handle;
public override event Action<IInputDevice, bool>? ConnectionChanged;

private void ProcessEvents()
public override void ProcessEvents()
{
if (_view.Handle == 0)
if (Window.Handle == 0)
{
throw new InvalidOperationException("Input update event fired without an underlying window.");
}

if (_lastHandle != _view.Handle)
if (_lastHandle != Window.Handle)
{
RefreshJoysticksAndGamepads();
_lastHandle = _view.Handle;
_lastHandle = Window.Handle;
}

var i = 0;
Expand Down Expand Up @@ -304,10 +302,8 @@ private void RefreshJoysticksAndGamepads()
}
}

public void Dispose()
public override void CoreDispose()
{
_sdlView.ProcessingEvents -= ProcessEvents;

foreach (var gp in SdlGamepads.Values)
{
gp.Dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ protected ViewImplementationBase(ViewOptions opts)
public event Action? Load;
public event Action<double>? Update;
public event Action<double>? Render;
internal event Action? ProcessEvents;

// Lifetime controls
public void Initialize()
Expand Down Expand Up @@ -271,6 +272,12 @@ public IVkSurface? VkSurface
}

// Misc implementations
void IView.DoEvents()
{
DoEvents();
ProcessEvents?.Invoke();
}

[MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions) 512)]
public Vector2D<int> PointToFramebuffer(Vector2D<int> point)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>Silk.NET.Windowing.Sdl</_Parameter1>
</AssemblyAttribute>
<!-- I couldn't decide whether we wanted to trust the users with the power to hook into DoEvents (and do stuff
pre-update, as I feel like that'd just be an arms race) so I made the ProcessEvents event internal for
now -->
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>Silk.NET.Input.Common</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 0 additions & 3 deletions src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ protected override Vector2D<int> CoreSize
}
}

public event System.Action? ProcessingEvents;

// Methods
public override void ContinueEvents() => Interlocked.Exchange(ref _continue, 1);
protected override INativeWindow GetNativeWindow() => new SdlNativeWindow(Sdl, SdlWindow);
Expand Down Expand Up @@ -326,7 +324,6 @@ public void EndEventProcessing(bool taken)
[SuppressMessage("ReSharper", "SwitchStatementHandlesSomeKnownEnumValuesWithDefault")]
public virtual void ProcessEvents()
{
ProcessingEvents?.Invoke();
var taken = false;
BeginEventProcessing(ref taken);
var count = Events.Count;
Expand Down