2019-08-07 22:25:33 +02:00
|
|
|
using System;
|
2019-08-09 22:04:26 +02:00
|
|
|
using System.Collections.Generic;
|
2019-08-29 18:12:02 +02:00
|
|
|
using System.Collections.ObjectModel;
|
2019-08-09 22:04:26 +02:00
|
|
|
using System.Linq;
|
2019-08-07 22:25:33 +02:00
|
|
|
using Microsoft.Xna.Framework;
|
|
|
|
using Microsoft.Xna.Framework.Input;
|
2019-08-29 18:12:02 +02:00
|
|
|
using Microsoft.Xna.Framework.Input.Touch;
|
2019-09-04 18:49:59 +02:00
|
|
|
using MLEM.Extensions;
|
2019-08-09 22:04:26 +02:00
|
|
|
using MLEM.Misc;
|
2019-08-07 22:25:33 +02:00
|
|
|
|
|
|
|
namespace MLEM.Input {
|
|
|
|
public class InputHandler {
|
|
|
|
|
|
|
|
public KeyboardState LastKeyboardState { get; private set; }
|
|
|
|
public KeyboardState KeyboardState { get; private set; }
|
2019-09-04 18:49:59 +02:00
|
|
|
public Keys[] PressedKeys { get; private set; }
|
2019-08-29 18:12:02 +02:00
|
|
|
public bool HandleKeyboard;
|
2019-08-07 22:25:33 +02:00
|
|
|
|
|
|
|
public MouseState LastMouseState { get; private set; }
|
|
|
|
public MouseState MouseState { get; private set; }
|
|
|
|
public Point MousePosition => this.MouseState.Position;
|
|
|
|
public Point LastMousePosition => this.LastMouseState.Position;
|
|
|
|
public int ScrollWheel => this.MouseState.ScrollWheelValue;
|
|
|
|
public int LastScrollWheel => this.LastMouseState.ScrollWheelValue;
|
2019-08-29 18:12:02 +02:00
|
|
|
public bool HandleMouse;
|
2019-08-07 22:25:33 +02:00
|
|
|
|
|
|
|
private readonly GamePadState[] lastGamepads = new GamePadState[GamePad.MaximumGamePadCount];
|
|
|
|
private readonly GamePadState[] gamepads = new GamePadState[GamePad.MaximumGamePadCount];
|
2019-08-29 10:26:18 +02:00
|
|
|
public int ConnectedGamepads { get; private set; }
|
2019-08-29 18:12:02 +02:00
|
|
|
public bool HandleGamepads;
|
2019-08-07 22:25:33 +02:00
|
|
|
|
2019-08-29 18:12:02 +02:00
|
|
|
public TouchCollection LastTouchState { get; private set; }
|
|
|
|
public TouchCollection TouchState { get; private set; }
|
|
|
|
public readonly ReadOnlyCollection<GestureSample> Gestures;
|
|
|
|
private readonly List<GestureSample> gestures = new List<GestureSample>();
|
|
|
|
public bool HandleTouch;
|
|
|
|
|
2019-09-04 18:49:59 +02:00
|
|
|
public TimeSpan KeyRepeatDelay = TimeSpan.FromSeconds(0.65);
|
|
|
|
public TimeSpan KeyRepeatRate = TimeSpan.FromSeconds(0.05);
|
2019-09-09 20:56:10 +02:00
|
|
|
|
|
|
|
public bool HandleKeyboardRepeats = true;
|
2019-09-04 18:49:59 +02:00
|
|
|
private DateTime heldKeyStart;
|
|
|
|
private DateTime lastKeyRepeat;
|
2019-09-09 20:56:10 +02:00
|
|
|
private bool triggerKeyRepeat;
|
2019-09-04 18:49:59 +02:00
|
|
|
private Keys heldKey;
|
|
|
|
|
2019-09-09 20:56:10 +02:00
|
|
|
public bool HandleGamepadRepeats = true;
|
2019-09-10 11:41:13 +02:00
|
|
|
private readonly DateTime[] heldGamepadButtonStarts = new DateTime[GamePad.MaximumGamePadCount];
|
|
|
|
private readonly DateTime[] lastGamepadButtonRepeats = new DateTime[GamePad.MaximumGamePadCount];
|
|
|
|
private readonly bool[] triggerGamepadButtonRepeat = new bool[GamePad.MaximumGamePadCount];
|
|
|
|
private readonly Buttons?[] heldGamepadButtons = new Buttons?[GamePad.MaximumGamePadCount];
|
2019-09-09 20:56:10 +02:00
|
|
|
|
2019-08-29 18:12:02 +02:00
|
|
|
public InputHandler(bool handleKeyboard = true, bool handleMouse = true, bool handleGamepads = true, bool handleTouch = true) {
|
|
|
|
this.HandleKeyboard = handleKeyboard;
|
|
|
|
this.HandleMouse = handleMouse;
|
|
|
|
this.HandleGamepads = handleGamepads;
|
|
|
|
this.HandleTouch = handleTouch;
|
|
|
|
this.Gestures = this.gestures.AsReadOnly();
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void Update() {
|
2019-08-29 18:12:02 +02:00
|
|
|
if (this.HandleKeyboard) {
|
2019-08-07 22:25:33 +02:00
|
|
|
this.LastKeyboardState = this.KeyboardState;
|
|
|
|
this.KeyboardState = Keyboard.GetState();
|
2019-09-04 18:49:59 +02:00
|
|
|
this.PressedKeys = this.KeyboardState.GetPressedKeys();
|
|
|
|
|
|
|
|
if (this.HandleKeyboardRepeats) {
|
2019-09-09 20:56:10 +02:00
|
|
|
this.triggerKeyRepeat = false;
|
2019-09-04 18:49:59 +02:00
|
|
|
if (this.heldKey == Keys.None) {
|
|
|
|
// if we're not repeating a key, set the first key being held to the repeat key
|
|
|
|
// note that modifier keys don't count as that wouldn't really make sense
|
|
|
|
var key = this.PressedKeys.FirstOrDefault(k => !k.IsModifier());
|
|
|
|
if (key != Keys.None) {
|
|
|
|
this.heldKey = key;
|
|
|
|
this.heldKeyStart = DateTime.UtcNow;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// if the repeating key isn't being held anymore, reset
|
2019-09-04 18:52:50 +02:00
|
|
|
if (!this.IsKeyDown(this.heldKey)) {
|
2019-09-04 18:49:59 +02:00
|
|
|
this.heldKey = Keys.None;
|
|
|
|
} else {
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
var holdTime = now - this.heldKeyStart;
|
|
|
|
// if we've been holding the key longer than the initial delay...
|
|
|
|
if (holdTime >= this.KeyRepeatDelay) {
|
|
|
|
var diff = now - this.lastKeyRepeat;
|
|
|
|
// and we've been holding it for longer than a repeat...
|
|
|
|
if (diff >= this.KeyRepeatRate) {
|
|
|
|
this.lastKeyRepeat = now;
|
|
|
|
// then trigger a repeat, causing IsKeyPressed to be true once
|
2019-09-09 20:56:10 +02:00
|
|
|
this.triggerKeyRepeat = true;
|
2019-09-04 18:49:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
2019-09-09 20:56:10 +02:00
|
|
|
|
2019-08-29 18:12:02 +02:00
|
|
|
if (this.HandleMouse) {
|
2019-08-07 22:25:33 +02:00
|
|
|
this.LastMouseState = this.MouseState;
|
|
|
|
this.MouseState = Mouse.GetState();
|
|
|
|
}
|
2019-09-09 20:56:10 +02:00
|
|
|
|
2019-08-29 18:12:02 +02:00
|
|
|
if (this.HandleGamepads) {
|
2019-09-09 15:22:15 +02:00
|
|
|
this.ConnectedGamepads = GamePad.MaximumGamePadCount;
|
2019-08-07 22:25:33 +02:00
|
|
|
for (var i = 0; i < GamePad.MaximumGamePadCount; i++) {
|
|
|
|
this.lastGamepads[i] = this.gamepads[i];
|
|
|
|
this.gamepads[i] = GamePad.GetState(i);
|
2019-08-29 10:26:18 +02:00
|
|
|
if (this.ConnectedGamepads > i && !this.gamepads[i].IsConnected)
|
|
|
|
this.ConnectedGamepads = i;
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
2019-09-09 20:56:10 +02:00
|
|
|
|
|
|
|
if (this.HandleGamepadRepeats) {
|
|
|
|
for (var i = 0; i < this.ConnectedGamepads; i++) {
|
|
|
|
this.triggerGamepadButtonRepeat[i] = false;
|
|
|
|
|
|
|
|
if (!this.heldGamepadButtons[i].HasValue) {
|
|
|
|
foreach (var b in EnumHelper.Buttons) {
|
|
|
|
if (this.IsGamepadButtonDown(b, i)) {
|
|
|
|
this.heldGamepadButtons[i] = b;
|
|
|
|
this.heldGamepadButtonStarts[i] = DateTime.UtcNow;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!this.IsGamepadButtonDown(this.heldGamepadButtons[i].Value, i)) {
|
|
|
|
this.heldGamepadButtons[i] = null;
|
|
|
|
} else {
|
|
|
|
var now = DateTime.UtcNow;
|
|
|
|
var holdTime = now - this.heldGamepadButtonStarts[i];
|
|
|
|
if (holdTime >= this.KeyRepeatDelay) {
|
|
|
|
var diff = now - this.lastGamepadButtonRepeats[i];
|
|
|
|
if (diff >= this.KeyRepeatRate) {
|
|
|
|
this.lastGamepadButtonRepeats[i] = now;
|
|
|
|
this.triggerGamepadButtonRepeat[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
2019-09-09 20:56:10 +02:00
|
|
|
|
2019-08-29 18:12:02 +02:00
|
|
|
if (this.HandleTouch) {
|
|
|
|
this.LastTouchState = this.TouchState;
|
|
|
|
this.TouchState = TouchPanel.GetState();
|
|
|
|
|
|
|
|
this.gestures.Clear();
|
|
|
|
while (TouchPanel.IsGestureAvailable)
|
|
|
|
this.gestures.Add(TouchPanel.ReadGesture());
|
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public GamePadState GetLastGamepadState(int index) {
|
|
|
|
return this.lastGamepads[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
public GamePadState GetGamepadState(int index) {
|
|
|
|
return this.gamepads[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsKeyDown(Keys key) {
|
|
|
|
return this.KeyboardState.IsKeyDown(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsKeyUp(Keys key) {
|
|
|
|
return this.KeyboardState.IsKeyUp(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool WasKeyDown(Keys key) {
|
|
|
|
return this.LastKeyboardState.IsKeyDown(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool WasKeyUp(Keys key) {
|
|
|
|
return this.LastKeyboardState.IsKeyUp(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsKeyPressed(Keys key) {
|
2019-09-04 18:49:59 +02:00
|
|
|
// if the queried key is the held key and a repeat should be triggered, return true
|
2019-09-09 20:56:10 +02:00
|
|
|
if (this.HandleKeyboardRepeats && key == this.heldKey && this.triggerKeyRepeat)
|
2019-09-04 18:49:59 +02:00
|
|
|
return true;
|
2019-08-07 22:25:33 +02:00
|
|
|
return this.WasKeyUp(key) && this.IsKeyDown(key);
|
|
|
|
}
|
|
|
|
|
2019-08-28 18:27:17 +02:00
|
|
|
public bool IsModifierKeyDown(ModifierKey modifier) {
|
2019-09-04 18:49:59 +02:00
|
|
|
return modifier.GetKeys().Any(this.IsKeyDown);
|
2019-08-28 18:27:17 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 22:25:33 +02:00
|
|
|
public bool IsMouseButtonDown(MouseButton button) {
|
2019-09-04 18:49:59 +02:00
|
|
|
return this.MouseState.GetState(button) == ButtonState.Pressed;
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsMouseButtonUp(MouseButton button) {
|
2019-09-04 18:49:59 +02:00
|
|
|
return this.MouseState.GetState(button) == ButtonState.Released;
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool WasMouseButtonDown(MouseButton button) {
|
2019-09-04 18:49:59 +02:00
|
|
|
return this.LastMouseState.GetState(button) == ButtonState.Pressed;
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool WasMouseButtonUp(MouseButton button) {
|
2019-09-04 18:49:59 +02:00
|
|
|
return this.LastMouseState.GetState(button) == ButtonState.Released;
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public bool IsMouseButtonPressed(MouseButton button) {
|
|
|
|
return this.WasMouseButtonUp(button) && this.IsMouseButtonDown(button);
|
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool IsGamepadButtonDown(Buttons button, int index = -1) {
|
|
|
|
if (index < 0) {
|
2019-08-29 10:26:18 +02:00
|
|
|
for (var i = 0; i < this.ConnectedGamepads; i++)
|
2019-08-28 22:44:59 +02:00
|
|
|
if (this.GetGamepadState(i).IsButtonDown(button))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
return this.GetGamepadState(index).IsButtonDown(button);
|
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool IsGamepadButtonUp(Buttons button, int index = -1) {
|
|
|
|
if (index < 0) {
|
2019-08-29 10:26:18 +02:00
|
|
|
for (var i = 0; i < this.ConnectedGamepads; i++)
|
2019-08-28 22:44:59 +02:00
|
|
|
if (this.GetGamepadState(i).IsButtonUp(button))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
return this.GetGamepadState(index).IsButtonUp(button);
|
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool WasGamepadButtonDown(Buttons button, int index = -1) {
|
|
|
|
if (index < 0) {
|
2019-08-29 10:26:18 +02:00
|
|
|
for (var i = 0; i < this.ConnectedGamepads; i++)
|
2019-08-28 22:44:59 +02:00
|
|
|
if (this.GetLastGamepadState(i).IsButtonDown(button))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
return this.GetLastGamepadState(index).IsButtonDown(button);
|
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool WasGamepadButtonUp(Buttons button, int index = -1) {
|
|
|
|
if (index < 0) {
|
2019-08-29 10:26:18 +02:00
|
|
|
for (var i = 0; i < this.ConnectedGamepads; i++)
|
2019-08-28 22:44:59 +02:00
|
|
|
if (this.GetLastGamepadState(i).IsButtonUp(button))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
return this.GetLastGamepadState(index).IsButtonUp(button);
|
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool IsGamepadButtonPressed(Buttons button, int index = -1) {
|
2019-09-09 20:56:10 +02:00
|
|
|
if (this.HandleGamepadRepeats) {
|
|
|
|
if (index < 0) {
|
|
|
|
for (var i = 0; i < this.ConnectedGamepads; i++)
|
|
|
|
if (this.heldGamepadButtons[i] == button && this.triggerGamepadButtonRepeat[i])
|
|
|
|
return true;
|
|
|
|
} else if (this.heldGamepadButtons[index] == button && this.triggerGamepadButtonRepeat[index]) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2019-08-28 22:44:59 +02:00
|
|
|
return this.WasGamepadButtonUp(button, index) && this.IsGamepadButtonDown(button, index);
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|
|
|
|
|
2019-08-30 18:15:50 +02:00
|
|
|
public bool GetGesture(GestureType type, out GestureSample sample) {
|
2019-08-29 18:12:02 +02:00
|
|
|
foreach (var gesture in this.Gestures) {
|
2019-08-30 18:15:50 +02:00
|
|
|
if (gesture.GestureType == type) {
|
|
|
|
sample = gesture;
|
|
|
|
return true;
|
|
|
|
}
|
2019-08-29 18:12:02 +02:00
|
|
|
}
|
2019-08-30 18:15:50 +02:00
|
|
|
return false;
|
2019-08-29 18:12:02 +02:00
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool IsDown(object control, int index = -1) {
|
2019-08-28 19:36:24 +02:00
|
|
|
if (control is Keys key)
|
|
|
|
return this.IsKeyDown(key);
|
|
|
|
if (control is Buttons button)
|
2019-08-28 22:44:59 +02:00
|
|
|
return this.IsGamepadButtonDown(button, index);
|
2019-08-28 19:36:24 +02:00
|
|
|
if (control is MouseButton mouse)
|
|
|
|
return this.IsMouseButtonDown(mouse);
|
|
|
|
throw new ArgumentException(nameof(control));
|
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool IsUp(object control, int index = -1) {
|
2019-08-28 19:36:24 +02:00
|
|
|
if (control is Keys key)
|
|
|
|
return this.IsKeyUp(key);
|
|
|
|
if (control is Buttons button)
|
2019-08-28 22:44:59 +02:00
|
|
|
return this.IsGamepadButtonUp(button, index);
|
2019-08-28 19:36:24 +02:00
|
|
|
if (control is MouseButton mouse)
|
|
|
|
return this.IsMouseButtonUp(mouse);
|
|
|
|
throw new ArgumentException(nameof(control));
|
|
|
|
}
|
|
|
|
|
2019-08-28 22:44:59 +02:00
|
|
|
public bool IsPressed(object control, int index = -1) {
|
2019-08-28 19:36:24 +02:00
|
|
|
if (control is Keys key)
|
|
|
|
return this.IsKeyPressed(key);
|
|
|
|
if (control is Buttons button)
|
2019-08-28 22:44:59 +02:00
|
|
|
return this.IsGamepadButtonPressed(button, index);
|
2019-08-28 19:36:24 +02:00
|
|
|
if (control is MouseButton mouse)
|
|
|
|
return this.IsMouseButtonPressed(mouse);
|
|
|
|
throw new ArgumentException(nameof(control));
|
|
|
|
}
|
|
|
|
|
2019-08-31 19:32:22 +02:00
|
|
|
public static void EnableGestures(params GestureType[] gestures) {
|
|
|
|
foreach (var gesture in gestures)
|
|
|
|
TouchPanel.EnabledGestures |= gesture;
|
|
|
|
}
|
|
|
|
|
2019-08-28 18:27:17 +02:00
|
|
|
}
|
2019-08-07 22:25:33 +02:00
|
|
|
}
|