diff --git a/MonoGameLibrary.sln.DotSettings.user b/MonoGameLibrary.sln.DotSettings.user
new file mode 100644
index 0000000..75bd3ff
--- /dev/null
+++ b/MonoGameLibrary.sln.DotSettings.user
@@ -0,0 +1,2 @@
+
+ ForceIncluded
\ No newline at end of file
diff --git a/MonoGameLibrary/Core.cs b/MonoGameLibrary/Core.cs
index 0e031c4..bb54015 100644
--- a/MonoGameLibrary/Core.cs
+++ b/MonoGameLibrary/Core.cs
@@ -2,6 +2,7 @@ using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
+using MonoGameLibrary.Input;
namespace MonoGameLibrary;
@@ -88,4 +89,9 @@ public class Core : Game
// Create the sprite batch instance.
spriteBatch = new SpriteBatch(graphicsDevice);
}
+
+ protected override void Update(GameTime gameTime) {
+ InputManager.NextInputCycle();
+ base.Update(gameTime);
+ }
}
\ No newline at end of file
diff --git a/MonoGameLibrary/Input/InputListenerHook.cs b/MonoGameLibrary/Input/InputListenerHook.cs
new file mode 100644
index 0000000..eb63870
--- /dev/null
+++ b/MonoGameLibrary/Input/InputListenerHook.cs
@@ -0,0 +1,6 @@
+namespace MonoGameLibrary.Input;
+
+public class InputListenerHook(bool enabled, bool oneTimeOnly = false) {
+ public bool Enabled { get; set; } = enabled;
+ public bool RemoveOnNextTrigger { get; set; } = oneTimeOnly;
+}
\ No newline at end of file
diff --git a/MonoGameLibrary/Input/InputManager.cs b/MonoGameLibrary/Input/InputManager.cs
new file mode 100644
index 0000000..533fa06
--- /dev/null
+++ b/MonoGameLibrary/Input/InputManager.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework.Input;
+
+namespace MonoGameLibrary.Input;
+
+
+public static class InputManager {
+ private static Dictionary> keyPressListeners = new();
+ private static Dictionary> keyHoldListeners = new(); // The bool is for enabling/disabling that method
+ private static Dictionary> keyReleaseListeners = new();
+
+ private static Dictionary labelDict = new();
+
+ private static KeyboardState oldState = Keyboard.GetState();
+ private static KeyboardState newState;
+
+ // public static ConcurrentQueue inputEventQueue = new();
+
+ public delegate void KeypressHandler(KeyboardState state);
+
+ private static int nextUnnamedId = 0;
+
+
+
+
+ // public static void StartListening() {
+ // processInputThread.Start();
+ // Console.WriteLine("Started listening for input");
+ // }
+
+ public static void NextInputCycle() {
+ Queue inputEventQueue = new();
+
+ // Read
+
+ newState = Keyboard.GetState();
+ Keys[] pressed = newState.GetPressedKeys();
+ Keys[] pressedLastFrame = oldState.GetPressedKeys();
+
+ Array.ForEach(pressed, key => {
+ if (oldState.IsKeyUp(key)){
+ if (keyPressListeners.TryGetValue(key, out var pressHandlers)){
+ pressHandlers.ForEach(t => {
+ if (t.Enabled){
+ inputEventQueue.Enqueue(t.Action);
+ }
+ if (t.Hook.RemoveOnNextTrigger){
+ pressHandlers.Remove(t);
+ }
+ });
+ }
+ }
+
+ if (keyHoldListeners.TryGetValue(key, out var holdHandlers)){
+ holdHandlers.ForEach(t => {
+ if (t.Enabled){
+ inputEventQueue.Enqueue(t.Action);
+ }
+ if (t.Hook.RemoveOnNextTrigger){
+ holdHandlers.Remove(t);
+ }
+ });
+ }
+ });
+
+ Array.ForEach(pressedLastFrame, key => {
+ if (!keyReleaseListeners.ContainsKey(key)){
+ return;
+ }
+
+ if (newState.IsKeyUp(key)){
+ if (keyReleaseListeners.TryGetValue(key, out var releaseHandlers))
+ releaseHandlers.ForEach(t => {
+ if (t.Enabled){
+ inputEventQueue.Enqueue(t.Action);
+ }
+ if (t.Hook.RemoveOnNextTrigger){
+ releaseHandlers.Remove(t);
+ }
+ });
+ }
+ });
+ oldState = newState;
+
+ // Execute
+
+ foreach (KeypressHandler handler in inputEventQueue){
+ handler(newState);
+ }
+}
+
+ // private static Thread processInputThread = new(() => {
+ //
+ // });
+
+ public static void AddListener(string label, Keys key, KeypressHandler action, InputTiming timing, InputListenerHook hook) {
+ if (label.StartsWith("!")){
+ throw new ArgumentException("Label cannot start with !");
+ }
+ InputEntry entry = new (label, key, action, timing, hook);
+ _addListener(entry);
+ }
+
+ public static void AddListener(Keys key, KeypressHandler action, InputTiming timing, InputListenerHook hook) {
+ InputEntry entry = new ($"!{Enum.GetName(typeof(Keys), key)}Handler{nextUnnamedId++}", key, action, timing, hook);
+ _addListener(entry);
+ }
+
+ private static void _addListener(InputEntry entry) {
+ Dictionary> workingDict;
+
+ switch (entry.Timing){
+ case InputTiming.PRESS:
+ workingDict = keyPressListeners;
+ break;
+ case InputTiming.HOLD:
+ workingDict = keyHoldListeners;
+ break;
+ case InputTiming.RELEASE:
+ workingDict = keyReleaseListeners;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(entry.Timing), entry.Timing, null);
+ }
+
+ if (!workingDict.ContainsKey(entry.Key)){
+ workingDict.Add(entry.Key, new());
+ }
+
+ workingDict[entry.Key].Add(entry);
+
+ labelDict.Add(entry.Label, entry);
+ }
+
+ public static InputEntry GetEntry(string label) {
+ return labelDict[label];
+ }
+
+ public class InputEntry {
+
+ public string Label;
+ public Keys Key;
+ public KeypressHandler Action;
+ public InputTiming Timing;
+ public InputListenerHook Hook;
+
+ public bool Enabled => Hook.Enabled;
+
+ public InputEntry(string label, Keys key, KeypressHandler action, InputTiming timing, InputListenerHook hook) {
+ Key = key;
+ Action = action;
+ Timing = timing;
+ Hook = hook;
+ Label = label;
+ }
+ }
+ // private static List inputQueue = new();
+}
\ No newline at end of file
diff --git a/MonoGameLibrary/Input/InputTiming.cs b/MonoGameLibrary/Input/InputTiming.cs
new file mode 100644
index 0000000..1948d7e
--- /dev/null
+++ b/MonoGameLibrary/Input/InputTiming.cs
@@ -0,0 +1,7 @@
+namespace MonoGameLibrary.Input;
+
+public enum InputTiming {
+ PRESS,
+ HOLD,
+ RELEASE
+}
\ No newline at end of file