diff --git a/Hypercube.Client/Graphics/Windows/Realisation/GLFW/GlfwWindowManager.Callbacks.cs b/Hypercube.Client/Graphics/Windows/Realisation/GLFW/GlfwWindowManager.Callbacks.cs index 7236508..7dc8144 100644 --- a/Hypercube.Client/Graphics/Windows/Realisation/GLFW/GlfwWindowManager.Callbacks.cs +++ b/Hypercube.Client/Graphics/Windows/Realisation/GLFW/GlfwWindowManager.Callbacks.cs @@ -55,12 +55,12 @@ private void OnErrorHandled(ErrorCode error, string description) private void OnWindowKeyHandled(Window* window, Keys glfwKey, int scanCode, InputAction action, GlfwKeyModifiers mods) { - RaiseInput(new WindowingKeyHandledEvent(new KeyStateChangedArgs( + RaiseInput(new WindowingKeyHandledEvent( (Key)glfwKey, Convert(action), (KeyModifiers)mods, scanCode - ))); + )); } private void OnWindowCharHandled(Window* window, uint codepoint) @@ -75,11 +75,11 @@ private void OnWindowScrollHandled(Window* window, double offsetX, double offset private void OnMouseButtonHandled(Window* window, GlfwMouseButton button, InputAction action, GlfwKeyModifiers mods) { - RaiseInput(new WindowingMouseButtonHandledEvent(new MouseButtonChangedArgs( + RaiseInput(new WindowingMouseButtonHandledEvent( (MouseButton)button, Convert(action), (KeyModifiers)mods - ))); + )); } private void RaiseInput(T args) where T : IEventArgs diff --git a/Hypercube.Client/Input/Events/KeyHandledEvent.cs b/Hypercube.Client/Input/Events/KeyHandledEvent.cs new file mode 100644 index 0000000..163e824 --- /dev/null +++ b/Hypercube.Client/Input/Events/KeyHandledEvent.cs @@ -0,0 +1,6 @@ +namespace Hypercube.Client.Input.Events; + +public class KeyHandledEvent +{ + +} \ No newline at end of file diff --git a/Hypercube.Client/Input/Events/Windowing/WindowingKeyHandledEvent.cs b/Hypercube.Client/Input/Events/Windowing/WindowingKeyHandledEvent.cs index 68f88fc..223c99b 100644 --- a/Hypercube.Client/Input/Events/Windowing/WindowingKeyHandledEvent.cs +++ b/Hypercube.Client/Input/Events/Windowing/WindowingKeyHandledEvent.cs @@ -3,4 +3,9 @@ namespace Hypercube.Client.Input.Events.Windowing; -public readonly record struct WindowingKeyHandledEvent(KeyStateChangedArgs State) : IEventArgs; \ No newline at end of file +public sealed class WindowingKeyHandledEvent : KeyStateChangedArgs, IEventArgs +{ + public WindowingKeyHandledEvent(Key key, KeyState state, KeyModifiers modifiers, int scanCode) : base(key, state, modifiers, scanCode) + { + } +} \ No newline at end of file diff --git a/Hypercube.Client/Input/Events/Windowing/WindowingMouseButtonHandledEvent.cs b/Hypercube.Client/Input/Events/Windowing/WindowingMouseButtonHandledEvent.cs index 26198e4..dae7373 100644 --- a/Hypercube.Client/Input/Events/Windowing/WindowingMouseButtonHandledEvent.cs +++ b/Hypercube.Client/Input/Events/Windowing/WindowingMouseButtonHandledEvent.cs @@ -3,4 +3,9 @@ namespace Hypercube.Client.Input.Events.Windowing; -public readonly record struct WindowingMouseButtonHandledEvent(MouseButtonChangedArgs State) : IEventArgs; \ No newline at end of file +public class WindowingMouseButtonHandledEvent : MouseButtonChangedArgs, IEventArgs +{ + public WindowingMouseButtonHandledEvent(MouseButton button, KeyState state, KeyModifiers modifiers) : base(button, state, modifiers) + { + } +} \ No newline at end of file diff --git a/Hypercube.Client/Input/Handler/IInputHandler.cs b/Hypercube.Client/Input/Handler/IInputHandler.cs index fcb3442..0a20480 100644 --- a/Hypercube.Client/Input/Handler/IInputHandler.cs +++ b/Hypercube.Client/Input/Handler/IInputHandler.cs @@ -15,4 +15,10 @@ public interface IInputHandler : IEventSubscriber bool IsKeyPressed(Key key); bool IsKeyReleased(Key key); void KeyClear(); + + bool IsMouseButtonState(MouseButton button, KeyState state); + bool IsMouseButtonHeld(MouseButton button); + bool IsMouseButtonPressed(MouseButton button); + bool IsMouseButtonReleased(MouseButton button); + void MouseButtonClear(); } \ No newline at end of file diff --git a/Hypercube.Client/Input/Handler/InputHandler.cs b/Hypercube.Client/Input/Handler/InputHandler.cs index c78185a..6c2ba9c 100644 --- a/Hypercube.Client/Input/Handler/InputHandler.cs +++ b/Hypercube.Client/Input/Handler/InputHandler.cs @@ -1,56 +1,120 @@ -using Hypercube.Client.Input.Events.Windowing; +using System.Collections.Frozen; +using Hypercube.Client.Input.Events.Windowing; using Hypercube.Input; using Hypercube.Shared.Dependency; using Hypercube.Shared.EventBus; using Hypercube.Shared.Logging; +using Hypercube.Shared.Runtimes.Loop.Event; namespace Hypercube.Client.Input.Handler; public sealed class InputHandler : IInputHandler, IPostInject { [Dependency] private readonly IEventBus _eventBus = default!; - - private readonly Dictionary _keys = []; + private readonly FrozenDictionary> _keys = new Dictionary> + { + { KeyState.Held, [] }, + { KeyState.Release, [] }, + { KeyState.Pressed, [] }, + }.ToFrozenDictionary(); + + private readonly FrozenDictionary> _mouseButtons = new Dictionary> + { + { KeyState.Held, [] }, + { KeyState.Release, [] }, + { KeyState.Pressed, [] }, + }.ToFrozenDictionary(); + + private readonly Logger _logger = LoggingManager.GetLogger("input_handler"); public void PostInject() { + _eventBus.Subscribe(this, OnInputFrameUpdate); + _eventBus.Subscribe(this, OnCharHandled); _eventBus.Subscribe(this, OnKeyHandled); _eventBus.Subscribe(this, OnMouseButtonHandled); _eventBus.Subscribe(this, OnScrollHandled); } + private void OnInputFrameUpdate(ref InputFrameEvent args) + { + _keys[KeyState.Pressed].Clear(); + _keys[KeyState.Release].Clear(); + _mouseButtons[KeyState.Pressed].Clear(); + _mouseButtons[KeyState.Release].Clear(); + } + private void OnCharHandled(ref WindowingCharHandledEvent args) { - throw new NotImplementedException(); } private void OnKeyHandled(ref WindowingKeyHandledEvent args) { - var state = args.State.State; - var key = args.State.Key; - #if DEBUG // Use only in Debug build, // as this check can take quite a lot of performance during input processing - if (!Enum.IsDefined(typeof(Key), key)) + if (!Enum.IsDefined(typeof(Key), args.Key)) { - _logger.Warning($"Unknown key {key} handled"); + _logger.Warning($"Unknown {args.Key} handled"); return; } #endif // Legacy shit, maybe will eat many ram and cpu // We made many shit because fucking Key rollover: https://en.wikipedia.org/wiki/Key_rollover - - - _logger.Warning($"{key} {state}"); + switch (args.State) + { + case KeyState.Pressed: + _keys[KeyState.Held].Add(args.Key); + _keys[KeyState.Pressed].Add(args.Key); + break; + + case KeyState.Release: + _keys[KeyState.Held].Remove(args.Key); + _keys[KeyState.Pressed].Add(args.Key); + break; + + case KeyState.Held: + break; + + default: + throw new ArgumentOutOfRangeException(); + } } private void OnMouseButtonHandled(ref WindowingMouseButtonHandledEvent args) { +#if DEBUG + // Use only in Debug build, + // as this check can take quite a lot of performance during input processing + if (!Enum.IsDefined(typeof(MouseButton), args.Button)) + { + _logger.Warning($"Unknown {args.Button} handled"); + return; + } +#endif + + switch (args.State) + { + case KeyState.Pressed: + _mouseButtons[KeyState.Held].Add(args.Button); + _mouseButtons[KeyState.Pressed].Add(args.Button); + break; + + case KeyState.Release: + _mouseButtons[KeyState.Held].Remove(args.Button); + _mouseButtons[KeyState.Pressed].Add(args.Button); + break; + + case KeyState.Held: + break; + + default: + throw new ArgumentOutOfRangeException(); + } } private void OnScrollHandled(ref WindowingScrollHandledEvent args) @@ -59,12 +123,12 @@ private void OnScrollHandled(ref WindowingScrollHandledEvent args) public bool IsKeyState(Key key, KeyState state) { - return _keys.TryGetValue(key, out var keyState) && keyState == state; + return _keys[state].Contains(key); } public bool IsKeyHeld(Key key) { - return _keys.TryGetValue(key, out var keyState) && keyState is KeyState.Held or KeyState.Pressed; + return IsKeyState(key, KeyState.Held); } public bool IsKeyPressed(Key key) @@ -76,9 +140,40 @@ public bool IsKeyReleased(Key key) { return IsKeyState(key, KeyState.Pressed); } - + public void KeyClear() { - _keys.Clear(); + foreach (var (_, key) in _keys) + { + key.Clear(); + } + } + + public bool IsMouseButtonState(MouseButton button, KeyState state) + { + return _mouseButtons[state].Contains(button); + } + + public bool IsMouseButtonHeld(MouseButton button) + { + return IsMouseButtonState(button, KeyState.Held); + } + + public bool IsMouseButtonPressed(MouseButton button) + { + return IsMouseButtonState(button, KeyState.Pressed); + } + + public bool IsMouseButtonReleased(MouseButton button) + { + return IsMouseButtonState(button, KeyState.Release); + } + + public void MouseButtonClear() + { + foreach (var (_, mouseButtons) in _mouseButtons) + { + mouseButtons.Clear(); + } } } \ No newline at end of file diff --git a/Hypercube.Input/KeyStateChangedArgs.cs b/Hypercube.Input/KeyStateChangedArgs.cs index a390194..ff6ca14 100644 --- a/Hypercube.Input/KeyStateChangedArgs.cs +++ b/Hypercube.Input/KeyStateChangedArgs.cs @@ -1,6 +1,6 @@ namespace Hypercube.Input; -public readonly struct KeyStateChangedArgs +public class KeyStateChangedArgs { public bool Shift => Modifiers.HasFlag(KeyModifiers.Shift); public bool Control => Modifiers.HasFlag(KeyModifiers.Control); diff --git a/Hypercube.Input/MouseButtonChangedArgs.cs b/Hypercube.Input/MouseButtonChangedArgs.cs index d59e2e3..855764d 100644 --- a/Hypercube.Input/MouseButtonChangedArgs.cs +++ b/Hypercube.Input/MouseButtonChangedArgs.cs @@ -1,6 +1,6 @@ namespace Hypercube.Input; -public readonly struct MouseButtonChangedArgs +public class MouseButtonChangedArgs { public bool Shift => Modifiers.HasFlag(KeyModifiers.Shift); public bool Control => Modifiers.HasFlag(KeyModifiers.Control);