diff --git a/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj b/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj
index 10be6e0..5996778 100644
--- a/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj
+++ b/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj
@@ -44,6 +44,8 @@
+
+
@@ -52,4 +54,7 @@
Blarg.GameFramework
+
+
+
\ No newline at end of file
diff --git a/Blarg.GameFramework.SDL2/Input/SDLKeyboard.cs b/Blarg.GameFramework.SDL2/Input/SDLKeyboard.cs
new file mode 100644
index 0000000..f74e775
--- /dev/null
+++ b/Blarg.GameFramework.SDL2/Input/SDLKeyboard.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using SDL2;
+
+namespace Blarg.GameFramework.Input
+{
+ public class SDLKeyboard : IKeyboard
+ {
+ bool[] _keys;
+ bool[] _lockedKeys;
+ IList _listeners;
+
+ public SDLKeyboard()
+ {
+ _keys = new bool[(int)Key.LastKey];
+ _lockedKeys = new bool[(int)Key.LastKey];
+ _listeners = new List();
+ }
+
+ public bool OnKeyEvent(SDL.SDL_KeyboardEvent e)
+ {
+ int keyCode = (int)e.keysym.sym;
+
+ if (e.state == SDL.SDL_PRESSED)
+ {
+ _keys[keyCode] = !(_lockedKeys[keyCode]); // pressed only if not locked
+
+ // always report keydown events
+ // NOTE: we're ignoring the "locked key" state because listeners
+ // don't have support for it (yet)
+ for (int i = 0; i < _listeners.Count; ++i)
+ {
+ if (_listeners[i].OnKeyDown((Key)keyCode))
+ break;
+ }
+ }
+ else
+ {
+ // if the key is just being released this tick, then trigger an event in all listeners
+ if (_keys[keyCode])
+ {
+ for (int i = 0; i < _listeners.Count; ++i)
+ {
+ if (_listeners[i].OnKeyUp((Key)keyCode))
+ break;
+ }
+ }
+
+ _keys[keyCode] = false;
+ _lockedKeys[keyCode] = false;
+ }
+
+ return true;
+ }
+
+ public bool IsDown(Key key)
+ {
+ return _keys[(int)key] && !_lockedKeys[(int)key];
+ }
+
+ public bool IsPressed(Key key)
+ {
+ if (_keys[(int)key] && !_lockedKeys[(int)key])
+ {
+ _lockedKeys[(int)key] = true;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ public void Lock(Key key)
+ {
+ _lockedKeys[(int)key] = true;
+ }
+
+ public void OnPostUpdate(float delta)
+ {
+ }
+
+ public void Reset()
+ {
+ for (int i = 0; i < _keys.Length; ++i)
+ _keys[i] = false;
+ for (int i = 0; i < _lockedKeys.Length; ++i)
+ _lockedKeys[i] = false;
+ }
+
+ public void RegisterListener(IKeyboardListener listener)
+ {
+ if (_listeners.Contains(listener))
+ throw new InvalidOperationException("Duplicate listener registration.");
+
+ _listeners.Add(listener);
+ }
+
+ public void UnregisterListener(IKeyboardListener listener)
+ {
+ int index = _listeners.IndexOf(listener);
+ if (index == -1)
+ throw new InvalidOperationException("Listener not registered.");
+
+ _listeners.RemoveAt(index);
+ }
+
+ public bool HasPhysicalKeysForGameControls
+ {
+ get { return true; }
+ }
+ }
+}
+
diff --git a/Blarg.GameFramework.SDL2/Input/SDLMouse.cs b/Blarg.GameFramework.SDL2/Input/SDLMouse.cs
new file mode 100644
index 0000000..4f0c227
--- /dev/null
+++ b/Blarg.GameFramework.SDL2/Input/SDLMouse.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Collections.Generic;
+using SDL2;
+
+namespace Blarg.GameFramework.Input
+{
+ public class SDLMouse : IMouse
+ {
+ bool[] _buttons;
+ bool[] _lockedButtons;
+ IList _listeners;
+
+ public SDLMouse()
+ {
+ _buttons = new bool[(int)MouseButton.LastButton];
+ _lockedButtons = new bool[(int)MouseButton.LastButton];
+ _listeners = new List();
+ }
+
+ public bool OnButtonEvent(SDL.SDL_MouseButtonEvent e)
+ {
+ int button = (int)e.button - 1;
+
+ if (e.state == SDL.SDL_PRESSED)
+ {
+ // Pressed only if not locked
+ _buttons[button] = !(_lockedButtons[button]);
+
+ // always report button down events
+ // NOTE: we're ignoring the "locked button" state because listeners
+ // don't have support for it (yet)
+ for (int i = 0; i < _listeners.Count; ++i)
+ {
+ if (_listeners[i].OnMouseButtonDown((MouseButton)button, X, Y))
+ break;
+ }
+ }
+ else
+ {
+ // if the button is just being released this tick, then trigger an event in all listeners
+ if (_buttons[button])
+ {
+ for (int i = 0; i < _listeners.Count; ++i)
+ {
+ if (_listeners[i].OnMouseButtonUp((MouseButton)button, X, Y))
+ break;
+ }
+ }
+
+ _buttons[button] = false;
+ _lockedButtons[button] = false;
+ }
+
+ return true;
+ }
+
+ public bool OnMotionEvent(SDL.SDL_MouseMotionEvent e)
+ {
+ DeltaX = e.x - X;
+ DeltaY = e.y - Y;
+
+ X = e.x;
+ Y = e.y;
+
+ // raise listener events for the mouse position only if it's moved this tick
+ if (DeltaX != 0 || DeltaY != 0)
+ {
+ for (int i = 0; i < _listeners.Count; ++i)
+ {
+ if (_listeners[i].OnMouseMove(X, Y, DeltaX, DeltaY))
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ public int X { get; private set; }
+ public int Y { get; private set; }
+ public int DeltaX { get; private set; }
+ public int DeltaY { get; private set; }
+
+ public bool IsDown(MouseButton button)
+ {
+ return _buttons[(int)button] && !_lockedButtons[(int)button];
+ }
+
+ public bool IsPressed(MouseButton button)
+ {
+ if (_buttons[(int)button] && !_lockedButtons[(int)button])
+ {
+ _lockedButtons[(int)button] = true;
+ return true;
+ }
+ else
+ return true;
+ }
+
+ public void Lock(MouseButton button)
+ {
+ _lockedButtons[(int)button] = true;
+ }
+
+ public void OnPostUpdate(float delta)
+ {
+ DeltaX = 0;
+ DeltaY = 0;
+ }
+
+ public void Reset()
+ {
+ for (int i = 0; i < _buttons.Length; ++i)
+ _buttons[i] = false;
+ for (int i = 0; i < _lockedButtons.Length; ++i)
+ _lockedButtons[i] = false;
+
+ X = 0;
+ Y = 0;
+ DeltaX = 0;
+ DeltaY = 0;
+ }
+
+ public void RegisterListener(IMouseListener listener)
+ {
+ if (_listeners.Contains(listener))
+ throw new InvalidOperationException("Duplicate listener registration.");
+
+ _listeners.Add(listener);
+ }
+
+ public void UnregisterListener(IMouseListener listener)
+ {
+ int index = _listeners.IndexOf(listener);
+ if (index == -1)
+ throw new InvalidOperationException("Listener not registered.");
+
+ _listeners.RemoveAt(index);
+ }
+ }
+}
+