From 1c66cf4d45d3fee1105b4619580ee2afb5da27b5 Mon Sep 17 00:00:00 2001 From: Dylan Perks Date: Thu, 6 Jan 2022 16:18:36 +0000 Subject: [PATCH 1/3] Update input context in DoEvents instead of DoUpdate --- .../Silk.NET.Input.Glfw/GlfwInputContext.cs | 54 ++++++++++++------- .../Internals/ViewImplementationBase.cs | 7 +++ .../Silk.NET.Windowing.Common.csproj | 6 +++ 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs b/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs index c2536d4178..45909705c5 100644 --- a/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs +++ b/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs @@ -7,6 +7,7 @@ using Silk.NET.Input.Internals; using Silk.NET.Windowing; using Silk.NET.Windowing.Glfw; +using Silk.NET.Windowing.Internals; namespace Silk.NET.Input.Glfw { @@ -17,7 +18,6 @@ internal class GlfwInputContext : IInputContext private readonly GlfwKeyboard[] _keyboards = new GlfwKeyboard[1]; private readonly GlfwMouse[] _mice = new GlfwMouse[1]; private readonly IGlfwSubscriber[] _subscribers = new IGlfwSubscriber[2]; - private Action _update; private IView _window; public unsafe GlfwInputContext(IView window) @@ -50,30 +50,48 @@ public unsafe GlfwInputContext(IView window) Mice = _mice; GlfwInputPlatform.RegisterWindow((WindowHandle*) Handle, _subscribers); - window.Update += _update = _ => + if (window is ViewImplementationBase view) { - foreach (var updatable in _mice) - { - updatable.Update(); - } - - foreach (var updatable in _gamepads) - { - updatable.Update(); - } - - foreach (var updatable in _joysticks) - { - updatable.Update(); - } - }; + view.ProcessEvents += ProcessEvents; + } + else + { + window.Update += Update; + } _window = window; } + private void Update(double delta) => ProcessEvents(); + private void ProcessEvents() + { + foreach (var updatable in _mice) + { + updatable.Update(); + } + + foreach (var updatable in _gamepads) + { + updatable.Update(); + } + + foreach (var updatable in _joysticks) + { + updatable.Update(); + } + } + public unsafe void Dispose() { - _window.Update -= _update; + if (_window is ViewImplementationBase view) + { + view.ProcessEvents += ProcessEvents; + } + else + { + _window.Update += Update; + } + GlfwInputPlatform.UnregisterWindow((WindowHandle*) Handle, _subscribers); foreach (var gamepad in _gamepads) { diff --git a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs index 69fe7c06c9..d84a600ce2 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs @@ -83,6 +83,7 @@ protected ViewImplementationBase(ViewOptions opts) public event Action? Load; public event Action? Update; public event Action? Render; + internal event Action? ProcessEvents; // Lifetime controls public void Initialize() @@ -271,6 +272,12 @@ public IVkSurface? VkSurface } // Misc implementations + void IView.DoEvents() + { + ProcessEvents?.Invoke(); + DoEvents(); + } + [MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions) 512)] public Vector2D PointToFramebuffer(Vector2D point) { diff --git a/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj b/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj index a57998f824..a1904f42c3 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj +++ b/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj @@ -15,6 +15,12 @@ <_Parameter1>Silk.NET.Windowing.Sdl + + + <_Parameter1>Silk.NET.Input.Glfw + From f90d3c1d15206603f50d3f833f0222a1687c2a90 Mon Sep 17 00:00:00 2001 From: Dylan Perks <11160611+Perksey@users.noreply.github.com> Date: Thu, 6 Jan 2022 16:46:04 +0000 Subject: [PATCH 2/3] Apply suggestions from code review --- src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs b/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs index 45909705c5..712de34629 100644 --- a/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs +++ b/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs @@ -85,11 +85,11 @@ public unsafe void Dispose() { if (_window is ViewImplementationBase view) { - view.ProcessEvents += ProcessEvents; + view.ProcessEvents -= ProcessEvents; } else { - _window.Update += Update; + _window.Update -= Update; } GlfwInputPlatform.UnregisterWindow((WindowHandle*) Handle, _subscribers); From 00c3b59a94b9fd24c2c9c1e61beebc1f7f9e91eb Mon Sep 17 00:00:00 2001 From: Dylan Perks Date: Thu, 6 Jan 2022 17:49:20 +0000 Subject: [PATCH 3/3] Make ProcessEvents logic common in both Windowing and Input --- .../InputContextImplementationBase.cs | 51 +++++++++++++++++++ .../Silk.NET.Input.Glfw/GlfwInputContext.cs | 45 +++++----------- .../Silk.NET.Input.Sdl/SdlInputContext.cs | 34 ++++++------- .../Internals/ViewImplementationBase.cs | 2 +- .../Silk.NET.Windowing.Common.csproj | 2 +- .../Silk.NET.Windowing.Sdl/SdlView.cs | 3 -- 6 files changed, 80 insertions(+), 57 deletions(-) create mode 100644 src/Input/Silk.NET.Input.Common/Internals/InputContextImplementationBase.cs diff --git a/src/Input/Silk.NET.Input.Common/Internals/InputContextImplementationBase.cs b/src/Input/Silk.NET.Input.Common/Internals/InputContextImplementationBase.cs new file mode 100644 index 0000000000..1dd7721a8a --- /dev/null +++ b/src/Input/Silk.NET.Input.Common/Internals/InputContextImplementationBase.cs @@ -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 Gamepads { get; } + public abstract IReadOnlyList Joysticks { get; } + public abstract IReadOnlyList Keyboards { get; } + public abstract IReadOnlyList Mice { get; } + public abstract IReadOnlyList OtherDevices { get; } + public abstract event Action? ConnectionChanged; +} diff --git a/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs b/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs index 712de34629..9e7a2f9f56 100644 --- a/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs +++ b/src/Input/Silk.NET.Input.Glfw/GlfwInputContext.cs @@ -11,20 +11,19 @@ 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 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."); @@ -50,20 +49,9 @@ public unsafe GlfwInputContext(IView window) Mice = _mice; GlfwInputPlatform.RegisterWindow((WindowHandle*) Handle, _subscribers); - if (window is ViewImplementationBase view) - { - view.ProcessEvents += ProcessEvents; - } - else - { - window.Update += Update; - } - - _window = window; } - private void Update(double delta) => ProcessEvents(); - private void ProcessEvents() + public override void ProcessEvents() { foreach (var updatable in _mice) { @@ -81,17 +69,8 @@ private void ProcessEvents() } } - public unsafe void Dispose() + public override unsafe void CoreDispose() { - if (_window is ViewImplementationBase view) - { - view.ProcessEvents -= ProcessEvents; - } - else - { - _window.Update -= Update; - } - GlfwInputPlatform.UnregisterWindow((WindowHandle*) Handle, _subscribers); foreach (var gamepad in _gamepads) { @@ -109,12 +88,12 @@ public unsafe void Dispose() } } - public nint Handle { get; } - public IReadOnlyList Gamepads { get; } - public IReadOnlyList Joysticks { get; } - public IReadOnlyList Keyboards { get; } - public IReadOnlyList Mice { get; } - public IReadOnlyList OtherDevices { get; } = new IInputDevice[0]; - public event Action? ConnectionChanged; + public sealed override nint Handle { get; } + public override IReadOnlyList Gamepads { get; } + public override IReadOnlyList Joysticks { get; } + public override IReadOnlyList Keyboards { get; } + public override IReadOnlyList Mice { get; } + public override IReadOnlyList OtherDevices { get; } = Array.Empty(); + public override event Action? ConnectionChanged; } } diff --git a/src/Input/Silk.NET.Input.Sdl/SdlInputContext.cs b/src/Input/Silk.NET.Input.Sdl/SdlInputContext.cs index 77bdc395b5..ef9b429a43 100644 --- a/src/Input/Silk.NET.Input.Sdl/SdlInputContext.cs +++ b/src/Input/Silk.NET.Input.Sdl/SdlInputContext.cs @@ -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(); SdlJoysticks = new Dictionary(); Gamepads = new IsConnectedWrapper @@ -37,31 +35,31 @@ public SdlInputContext(SdlView view) } // Public properties - public IReadOnlyList Gamepads { get; } - public IReadOnlyList Joysticks { get; } - public IReadOnlyList Keyboards { get; } - public IReadOnlyList Mice { get; } - public IReadOnlyList OtherDevices { get; } = new IInputDevice[0]; + public override IReadOnlyList Gamepads { get; } + public override IReadOnlyList Joysticks { get; } + public override IReadOnlyList Keyboards { get; } + public override IReadOnlyList Mice { get; } + public override IReadOnlyList OtherDevices { get; } = Array.Empty(); // Implementation-specific properties public Dictionary SdlGamepads { get; } public Dictionary SdlJoysticks { get; } public SDL.Sdl Sdl => _sdlView.Sdl; - public nint Handle => _view.Handle; - public event Action? ConnectionChanged; + public override nint Handle => Window.Handle; + public override event Action? 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; @@ -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(); diff --git a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs index d84a600ce2..44ba8f7cf8 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs @@ -274,8 +274,8 @@ public IVkSurface? VkSurface // Misc implementations void IView.DoEvents() { - ProcessEvents?.Invoke(); DoEvents(); + ProcessEvents?.Invoke(); } [MethodImpl(MethodImplOptions.AggressiveInlining | (MethodImplOptions) 512)] diff --git a/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj b/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj index a1904f42c3..a7eb3e435c 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj +++ b/src/Windowing/Silk.NET.Windowing.Common/Silk.NET.Windowing.Common.csproj @@ -19,7 +19,7 @@ pre-update, as I feel like that'd just be an arms race) so I made the ProcessEvents event internal for now --> - <_Parameter1>Silk.NET.Input.Glfw + <_Parameter1>Silk.NET.Input.Common diff --git a/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs b/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs index 8d19239c56..36a7fbf893 100644 --- a/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs +++ b/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs @@ -93,8 +93,6 @@ protected override Vector2D CoreSize } } - public event System.Action? ProcessingEvents; - // Methods public override void ContinueEvents() => Interlocked.Exchange(ref _continue, 1); protected override INativeWindow GetNativeWindow() => new SdlNativeWindow(Sdl, SdlWindow); @@ -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;