summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-03-08 14:53:41 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2020-03-08 14:53:41 -0400
commite80b7712f7e4c78a5b016289ca19efaf7d39cd8b (patch)
tree5ca5277b1755504a1e95b655b16ff696114d26b8
parente39b9e0d699079edfbcf8595d7499aff894578b6 (diff)
downloadSMAPI-e80b7712f7e4c78a5b016289ca19efaf7d39cd8b.tar.gz
SMAPI-e80b7712f7e4c78a5b016289ca19efaf7d39cd8b.tar.bz2
SMAPI-e80b7712f7e4c78a5b016289ca19efaf7d39cd8b.zip
encapsulate logic for each input type
-rw-r--r--src/SMAPI/Framework/Input/GamePadStateBuilder.cs177
-rw-r--r--src/SMAPI/Framework/Input/IInputStateBuilder.cs29
-rw-r--r--src/SMAPI/Framework/Input/KeyboardStateBuilder.cs45
-rw-r--r--src/SMAPI/Framework/Input/MouseStateBuilder.cs93
-rw-r--r--src/SMAPI/Framework/Input/SInputState.cs185
5 files changed, 305 insertions, 224 deletions
diff --git a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
index 315aa920..36622066 100644
--- a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs
@@ -4,14 +4,23 @@ using Microsoft.Xna.Framework.Input;
namespace StardewModdingAPI.Framework.Input
{
- /// <summary>Manipulates controller state.</summary>
- internal class GamePadStateBuilder
+ /// <summary>Manages controller state.</summary>
+ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, GamePadState>
{
/*********
** Fields
*********/
+ /// <summary>The maximum direction to ignore for the left thumbstick.</summary>
+ private const float LeftThumbstickDeadZone = 0.2f;
+
+ /// <summary>The maximum direction to ignore for the right thumbstick.</summary>
+ private const float RightThumbstickDeadZone = 0.9f;
+
+ /// <summary>The underlying controller state.</summary>
+ private GamePadState? State;
+
/// <summary>The current button states.</summary>
- private readonly IDictionary<SButton, ButtonState> ButtonStates;
+ private IDictionary<SButton, ButtonState> ButtonStates;
/// <summary>The left trigger value.</summary>
private float LeftTrigger;
@@ -27,43 +36,74 @@ namespace StardewModdingAPI.Framework.Input
/*********
+ ** Accessors
+ *********/
+ /// <summary>Whether the gamepad is currently connected.</summary>
+ public bool IsConnected { get; private set; }
+
+
+ /*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="state">The initial state.</param>
- public GamePadStateBuilder(GamePadState state)
+ /// <param name="state">The initial state, or <c>null</c> to get the latest state.</param>
+ public GamePadStateBuilder(GamePadState? state = null)
+ {
+ this.Reset(state);
+ }
+
+ /// <summary>Reset the tracked state.</summary>
+ /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param>
+ public GamePadStateBuilder Reset(GamePadState? state = null)
{
+ this.State = state ??= GamePad.GetState(PlayerIndex.One);
+ this.IsConnected = state.Value.IsConnected;
+
+ if (!this.IsConnected)
+ return this;
+
+ GamePadDPad pad = state.Value.DPad;
+ GamePadButtons buttons = state.Value.Buttons;
+ GamePadTriggers triggers = state.Value.Triggers;
+ GamePadThumbSticks sticks = state.Value.ThumbSticks;
this.ButtonStates = new Dictionary<SButton, ButtonState>
{
- [SButton.DPadUp] = state.DPad.Up,
- [SButton.DPadDown] = state.DPad.Down,
- [SButton.DPadLeft] = state.DPad.Left,
- [SButton.DPadRight] = state.DPad.Right,
-
- [SButton.ControllerA] = state.Buttons.A,
- [SButton.ControllerB] = state.Buttons.B,
- [SButton.ControllerX] = state.Buttons.X,
- [SButton.ControllerY] = state.Buttons.Y,
- [SButton.LeftStick] = state.Buttons.LeftStick,
- [SButton.RightStick] = state.Buttons.RightStick,
- [SButton.LeftShoulder] = state.Buttons.LeftShoulder,
- [SButton.RightShoulder] = state.Buttons.RightShoulder,
- [SButton.ControllerBack] = state.Buttons.Back,
- [SButton.ControllerStart] = state.Buttons.Start,
- [SButton.BigButton] = state.Buttons.BigButton
+ [SButton.DPadUp] = pad.Up,
+ [SButton.DPadDown] = pad.Down,
+ [SButton.DPadLeft] = pad.Left,
+ [SButton.DPadRight] = pad.Right,
+
+ [SButton.ControllerA] = buttons.A,
+ [SButton.ControllerB] = buttons.B,
+ [SButton.ControllerX] = buttons.X,
+ [SButton.ControllerY] = buttons.Y,
+ [SButton.LeftStick] = buttons.LeftStick,
+ [SButton.RightStick] = buttons.RightStick,
+ [SButton.LeftShoulder] = buttons.LeftShoulder,
+ [SButton.RightShoulder] = buttons.RightShoulder,
+ [SButton.ControllerBack] = buttons.Back,
+ [SButton.ControllerStart] = buttons.Start,
+ [SButton.BigButton] = buttons.BigButton
};
- this.LeftTrigger = state.Triggers.Left;
- this.RightTrigger = state.Triggers.Right;
- this.LeftStickPos = state.ThumbSticks.Left;
- this.RightStickPos = state.ThumbSticks.Right;
+ this.LeftTrigger = triggers.Left;
+ this.RightTrigger = triggers.Right;
+ this.LeftStickPos = sticks.Left;
+ this.RightStickPos = sticks.Right;
+
+ return this;
}
/// <summary>Override the states for a set of buttons.</summary>
/// <param name="overrides">The button state overrides.</param>
public GamePadStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides)
{
+ if (!this.IsConnected)
+ return this;
+
foreach (var pair in overrides)
{
+ bool changed = true;
+
bool isDown = pair.Value.IsDown();
switch (pair.Key)
{
@@ -107,45 +147,92 @@ namespace StardewModdingAPI.Framework.Input
default:
if (this.ButtonStates.ContainsKey(pair.Key))
this.ButtonStates[pair.Key] = isDown ? ButtonState.Pressed : ButtonState.Released;
+ else
+ changed = false;
break;
}
+
+ if (changed)
+ this.State = null;
}
return this;
}
- /// <summary>Construct an equivalent state.</summary>
- public GamePadState ToState()
+ /// <summary>Get the currently pressed buttons.</summary>
+ public IEnumerable<SButton> GetPressedButtons()
+ {
+ if (!this.IsConnected)
+ yield break;
+
+ // buttons
+ foreach (var pair in this.ButtonStates)
+ {
+ if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
+ yield return button.ToSButton();
+ }
+
+ // triggers
+ if (this.LeftTrigger > 0.2f)
+ yield return SButton.LeftTrigger;
+ if (this.RightTrigger > 0.2f)
+ yield return SButton.RightTrigger;
+
+ // left thumbstick direction
+ if (this.LeftStickPos.Y > GamePadStateBuilder.LeftThumbstickDeadZone)
+ yield return SButton.LeftThumbstickUp;
+ if (this.LeftStickPos.Y < -GamePadStateBuilder.LeftThumbstickDeadZone)
+ yield return SButton.LeftThumbstickDown;
+ if (this.LeftStickPos.X > GamePadStateBuilder.LeftThumbstickDeadZone)
+ yield return SButton.LeftThumbstickRight;
+ if (this.LeftStickPos.X < -GamePadStateBuilder.LeftThumbstickDeadZone)
+ yield return SButton.LeftThumbstickLeft;
+
+ // right thumbstick direction
+ if (this.RightStickPos.Length() > GamePadStateBuilder.RightThumbstickDeadZone)
+ {
+ if (this.RightStickPos.Y > 0)
+ yield return SButton.RightThumbstickUp;
+ if (this.RightStickPos.Y < 0)
+ yield return SButton.RightThumbstickDown;
+ if (this.RightStickPos.X > 0)
+ yield return SButton.RightThumbstickRight;
+ if (this.RightStickPos.X < 0)
+ yield return SButton.RightThumbstickLeft;
+ }
+ }
+
+ /// <summary>Get the equivalent state.</summary>
+ public GamePadState GetState()
{
- return new GamePadState(
- leftThumbStick: this.LeftStickPos,
- rightThumbStick: this.RightStickPos,
- leftTrigger: this.LeftTrigger,
- rightTrigger: this.RightTrigger,
- buttons: this.GetBitmask(this.GetPressedButtons()) // MonoDevelop requires one bitmask here; don't specify multiple values
- );
+ if (this.State == null)
+ {
+ this.State = new GamePadState(
+ leftThumbStick: this.LeftStickPos,
+ rightThumbStick: this.RightStickPos,
+ leftTrigger: this.LeftTrigger,
+ rightTrigger: this.RightTrigger,
+ buttons: this.GetButtonBitmask() // MonoGame requires one bitmask here; don't specify multiple values
+ );
+ }
+
+ return this.State.Value;
}
+
/*********
** Private methods
*********/
- /// <summary>Get all pressed buttons.</summary>
- private IEnumerable<Buttons> GetPressedButtons()
+ /// <summary>Get a bitmask representing the pressed buttons.</summary>
+ private Buttons GetButtonBitmask()
{
+ Buttons flag = 0;
foreach (var pair in this.ButtonStates)
{
if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
- yield return button;
+ flag |= button;
}
- }
- /// <summary>Get a bitmask representing the given buttons.</summary>
- /// <param name="buttons">The buttons to represent.</param>
- private Buttons GetBitmask(IEnumerable<Buttons> buttons)
- {
- Buttons flag = 0;
- foreach (Buttons button in buttons)
- flag |= button;
return flag;
}
}
diff --git a/src/SMAPI/Framework/Input/IInputStateBuilder.cs b/src/SMAPI/Framework/Input/IInputStateBuilder.cs
new file mode 100644
index 00000000..193e5216
--- /dev/null
+++ b/src/SMAPI/Framework/Input/IInputStateBuilder.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+
+namespace StardewModdingAPI.Framework.Input
+{
+ /// <summary>Manages input state.</summary>
+ /// <typeparam name="THandler">The handler type.</typeparam>
+ /// <typeparam name="TState">The state type.</typeparam>
+ internal interface IInputStateBuilder<out THandler, TState>
+ where TState : struct
+ where THandler : IInputStateBuilder<THandler, TState>
+ {
+ /*********
+ ** Methods
+ *********/
+ /// <summary>Reset the tracked state.</summary>
+ /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param>
+ THandler Reset(TState? state = null);
+
+ /// <summary>Override the states for a set of buttons.</summary>
+ /// <param name="overrides">The button state overrides.</param>
+ THandler OverrideButtons(IDictionary<SButton, SButtonState> overrides);
+
+ /// <summary>Get the currently pressed buttons.</summary>
+ IEnumerable<SButton> GetPressedButtons();
+
+ /// <summary>Get the equivalent state.</summary>
+ TState GetState();
+ }
+}
diff --git a/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs b/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs
index 12d780f6..f95a28bf 100644
--- a/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs
@@ -4,24 +4,40 @@ using Microsoft.Xna.Framework.Input;
namespace StardewModdingAPI.Framework.Input
{
- /// <summary>Manipulates keyboard state.</summary>
- internal class KeyboardStateBuilder
+ /// <summary>Manages keyboard state.</summary>
+ internal class KeyboardStateBuilder : IInputStateBuilder<KeyboardStateBuilder, KeyboardState>
{
/*********
** Fields
*********/
+ /// <summary>The underlying keyboard state.</summary>
+ private KeyboardState? State;
+
/// <summary>The pressed buttons.</summary>
- private readonly HashSet<Keys> PressedButtons;
+ private readonly HashSet<Keys> PressedButtons = new HashSet<Keys>();
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="state">The initial state.</param>
- public KeyboardStateBuilder(KeyboardState state)
+ /// <param name="state">The initial state, or <c>null</c> to get the latest state.</param>
+ public KeyboardStateBuilder(KeyboardState? state = null)
{
- this.PressedButtons = new HashSet<Keys>(state.GetPressedKeys());
+ this.Reset(state);
+ }
+
+ /// <summary>Reset the tracked state.</summary>
+ /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param>
+ public KeyboardStateBuilder Reset(KeyboardState? state = null)
+ {
+ this.State = state ??= Keyboard.GetState();
+
+ this.PressedButtons.Clear();
+ foreach (var button in state.Value.GetPressedKeys())
+ this.PressedButtons.Add(button);
+
+ return this;
}
/// <summary>Override the states for a set of buttons.</summary>
@@ -32,6 +48,8 @@ namespace StardewModdingAPI.Framework.Input
{
if (pair.Key.TryGetKeyboard(out Keys key))
{
+ this.State = null;
+
if (pair.Value.IsDown())
this.PressedButtons.Add(key);
else
@@ -42,10 +60,19 @@ namespace StardewModdingAPI.Framework.Input
return this;
}
- /// <summary>Build an equivalent state.</summary>
- public KeyboardState ToState()
+ /// <summary>Get the currently pressed buttons.</summary>
+ public IEnumerable<SButton> GetPressedButtons()
+ {
+ foreach (Keys key in this.PressedButtons)
+ yield return key.ToSButton();
+ }
+
+ /// <summary>Get the equivalent state.</summary>
+ public KeyboardState GetState()
{
- return new KeyboardState(this.PressedButtons.ToArray());
+ return
+ this.State
+ ?? (this.State = new KeyboardState(this.PressedButtons.ToArray())).Value;
}
}
}
diff --git a/src/SMAPI/Framework/Input/MouseStateBuilder.cs b/src/SMAPI/Framework/Input/MouseStateBuilder.cs
index 9c6f6f95..cff3e05e 100644
--- a/src/SMAPI/Framework/Input/MouseStateBuilder.cs
+++ b/src/SMAPI/Framework/Input/MouseStateBuilder.cs
@@ -3,43 +3,61 @@ using Microsoft.Xna.Framework.Input;
namespace StardewModdingAPI.Framework.Input
{
- /// <summary>Manipulates mouse state.</summary>
- internal class MouseStateBuilder
+ /// <summary>Manages mouse state.</summary>
+ internal class MouseStateBuilder : IInputStateBuilder<MouseStateBuilder, MouseState>
{
/*********
** Fields
*********/
+ /// <summary>The underlying mouse state.</summary>
+ private MouseState? State;
+
/// <summary>The current button states.</summary>
- private readonly IDictionary<SButton, ButtonState> ButtonStates;
+ private IDictionary<SButton, ButtonState> ButtonStates;
+
+ /// <summary>The mouse wheel scroll value.</summary>
+ private int ScrollWheelValue;
+
+ /*********
+ ** Accessors
+ *********/
/// <summary>The X cursor position.</summary>
- private readonly int X;
+ public int X { get; private set; }
/// <summary>The Y cursor position.</summary>
- private readonly int Y;
-
- /// <summary>The mouse wheel scroll value.</summary>
- private readonly int ScrollWheelValue;
+ public int Y { get; private set; }
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="state">The initial state.</param>
- public MouseStateBuilder(MouseState state)
+ /// <param name="state">The initial state, or <c>null</c> to get the latest state.</param>
+ public MouseStateBuilder(MouseState? state = null)
+ {
+ this.Reset(state);
+ }
+
+ /// <summary>Reset the tracked state.</summary>
+ /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param>
+ public MouseStateBuilder Reset(MouseState? state = null)
{
+ this.State = state ??= Mouse.GetState();
+
this.ButtonStates = new Dictionary<SButton, ButtonState>
{
- [SButton.MouseLeft] = state.LeftButton,
- [SButton.MouseMiddle] = state.MiddleButton,
- [SButton.MouseRight] = state.RightButton,
- [SButton.MouseX1] = state.XButton1,
- [SButton.MouseX2] = state.XButton2
+ [SButton.MouseLeft] = state.Value.LeftButton,
+ [SButton.MouseMiddle] = state.Value.MiddleButton,
+ [SButton.MouseRight] = state.Value.RightButton,
+ [SButton.MouseX1] = state.Value.XButton1,
+ [SButton.MouseX2] = state.Value.XButton2
};
- this.X = state.X;
- this.Y = state.Y;
- this.ScrollWheelValue = state.ScrollWheelValue;
+ this.X = state.Value.X;
+ this.Y = state.Value.Y;
+ this.ScrollWheelValue = state.Value.ScrollWheelValue;
+
+ return this;
}
/// <summary>Override the states for a set of buttons.</summary>
@@ -56,19 +74,34 @@ namespace StardewModdingAPI.Framework.Input
return this;
}
- /// <summary>Construct an equivalent mouse state.</summary>
- public MouseState ToMouseState()
+ /// <summary>Get the currently pressed buttons.</summary>
+ public IEnumerable<SButton> GetPressedButtons()
{
- return new MouseState(
- x: this.X,
- y: this.Y,
- scrollWheel: this.ScrollWheelValue,
- leftButton: this.ButtonStates[SButton.MouseLeft],
- middleButton: this.ButtonStates[SButton.MouseMiddle],
- rightButton: this.ButtonStates[SButton.MouseRight],
- xButton1: this.ButtonStates[SButton.MouseX1],
- xButton2: this.ButtonStates[SButton.MouseX2]
- );
+ foreach (var pair in this.ButtonStates)
+ {
+ if (pair.Value == ButtonState.Pressed)
+ yield return pair.Key;
+ }
+ }
+
+ /// <summary>Get the equivalent state.</summary>
+ public MouseState GetState()
+ {
+ if (this.State == null)
+ {
+ this.State = new MouseState(
+ x: this.X,
+ y: this.Y,
+ scrollWheel: this.ScrollWheelValue,
+ leftButton: this.ButtonStates[SButton.MouseLeft],
+ middleButton: this.ButtonStates[SButton.MouseMiddle],
+ rightButton: this.ButtonStates[SButton.MouseRight],
+ xButton1: this.ButtonStates[SButton.MouseX1],
+ xButton2: this.ButtonStates[SButton.MouseX2]
+ );
+ }
+
+ return this.State.Value;
}
}
}
diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs
index 06a7ac3b..333f5726 100644
--- a/src/SMAPI/Framework/Input/SInputState.cs
+++ b/src/SMAPI/Framework/Input/SInputState.cs
@@ -14,9 +14,6 @@ namespace StardewModdingAPI.Framework.Input
/*********
** Accessors
*********/
- /// <summary>The maximum amount of direction to ignore for the left thumbstick.</summary>
- private const float LeftThumbstickDeadZone = 0.2f;
-
/// <summary>The cursor position on the screen adjusted for the zoom level.</summary>
private CursorPosition CursorPositionImpl;
@@ -29,8 +26,8 @@ namespace StardewModdingAPI.Framework.Input
/// <summary>The buttons to consider released until the actual button is released.</summary>
private readonly HashSet<SButton> CustomReleasedKeys = new HashSet<SButton>();
- /// <summary>The buttons which were actually down as of the last update, ignoring overrides.</summary>
- private HashSet<SButton> LastRealButtonPresses = new HashSet<SButton>();
+ /// <summary>Whether there are new overrides in <see cref="CustomPressedKeys"/> or <see cref="CustomReleasedKeys"/> that haven't been applied to the previous state.</summary>
+ private bool HasNewOverrides;
/*********
@@ -73,16 +70,12 @@ namespace StardewModdingAPI.Framework.Input
/// <param name="setDown">Whether to mark it pressed; else mark it released.</param>
public void OverrideButton(SButton button, bool setDown)
{
- if (setDown)
- {
- this.CustomPressedKeys.Add(button);
- this.CustomReleasedKeys.Remove(button);
- }
- else
- {
- this.CustomPressedKeys.Remove(button);
- this.CustomReleasedKeys.Add(button);
- }
+ bool changed = setDown
+ ? this.CustomPressedKeys.Add(button) | this.CustomReleasedKeys.Remove(button)
+ : this.CustomPressedKeys.Remove(button) | this.CustomReleasedKeys.Add(button);
+
+ if (changed)
+ this.HasNewOverrides = true;
}
/// <summary>Get whether a mod has indicated the key was already handled, so the game shouldn't handle it.</summary>
@@ -104,9 +97,9 @@ namespace StardewModdingAPI.Framework.Input
float zoomMultiplier = (1f / Game1.options.zoomLevel);
// get real values
- GamePadState controller = GamePad.GetState(PlayerIndex.One);
- KeyboardState keyboard = Keyboard.GetState();
- MouseState mouse = Mouse.GetState();
+ var controller = new GamePadStateBuilder();
+ var keyboard = new KeyboardStateBuilder();
+ var mouse = new MouseStateBuilder();
Vector2 cursorAbsolutePos = new Vector2((mouse.X * zoomMultiplier) + Game1.viewport.X, (mouse.Y * zoomMultiplier) + Game1.viewport.Y);
Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.getTileLocation() : (Vector2?)null;
HashSet<SButton> reallyDown = new HashSet<SButton>(this.GetPressedButtons(keyboard, mouse, controller));
@@ -120,7 +113,7 @@ namespace StardewModdingAPI.Framework.Input
this.CustomReleasedKeys.RemoveWhere(key => !reallyDown.Contains(key));
// apply overrides
- if (this.ApplyOverrides(this.CustomPressedKeys, this.CustomReleasedKeys, ref keyboard, ref mouse, ref controller))
+ if (this.ApplyOverrides(this.CustomPressedKeys, this.CustomReleasedKeys, controller, keyboard, mouse))
hasOverrides = true;
// remove pressed keys
@@ -131,18 +124,18 @@ namespace StardewModdingAPI.Framework.Input
var pressedButtons = hasOverrides
? new HashSet<SButton>(this.GetPressedButtons(keyboard, mouse, controller))
: reallyDown;
- var activeButtons = this.DeriveStates(this.LastButtonStates, pressedButtons, keyboard, mouse, controller);
+ var activeButtons = this.DeriveStates(this.LastButtonStates, pressedButtons);
// update
- this.LastController = controller;
- this.LastKeyboard = keyboard;
- this.LastMouse = mouse;
+ this.HasNewOverrides = false;
+ this.LastController = controller.GetState();
+ this.LastKeyboard = keyboard.GetState();
+ this.LastMouse = mouse.GetState();
this.LastButtonStates = activeButtons;
- this.LastRealButtonPresses = reallyDown;
if (cursorAbsolutePos != this.CursorPositionImpl?.AbsolutePixels || playerTilePos != this.LastPlayerTile)
{
this.LastPlayerTile = playerTilePos;
- this.CursorPositionImpl = this.GetCursorPosition(mouse, cursorAbsolutePos, zoomMultiplier);
+ this.CursorPositionImpl = this.GetCursorPosition(this.LastMouse, cursorAbsolutePos, zoomMultiplier);
}
}
catch (InvalidOperationException)
@@ -154,15 +147,19 @@ namespace StardewModdingAPI.Framework.Input
/// <summary>Apply input overrides to the current state.</summary>
public void ApplyOverrides()
{
- GamePadState newController = this.LastController;
- KeyboardState newKeyboard = this.LastKeyboard;
- MouseState newMouse = this.LastMouse;
-
- this.ApplyOverrides(pressed: this.CustomPressedKeys, released: this.CustomReleasedKeys, ref newKeyboard, ref newMouse, ref newController);
+ if (this.HasNewOverrides)
+ {
+ var controller = new GamePadStateBuilder(this.LastController);
+ var keyboard = new KeyboardStateBuilder(this.LastKeyboard);
+ var mouse = new MouseStateBuilder(this.LastMouse);
- this.LastController = newController;
- this.LastKeyboard = newKeyboard;
- this.LastMouse = newMouse;
+ if (this.ApplyOverrides(pressed: this.CustomPressedKeys, released: this.CustomReleasedKeys, controller, keyboard, mouse))
+ {
+ this.LastController = controller.GetState();
+ this.LastKeyboard = keyboard.GetState();
+ this.LastMouse = mouse.GetState();
+ }
+ }
}
/// <summary>Get the gamepad state visible to the game.</summary>
@@ -231,11 +228,11 @@ namespace StardewModdingAPI.Framework.Input
/// <summary>Apply input overrides to the given states.</summary>
/// <param name="pressed">The buttons to mark pressed.</param>
/// <param name="released">The buttons to mark released.</param>
- /// <param name="keyboardState">The game's keyboard state for the current tick.</param>
- /// <param name="mouseState">The game's mouse state for the current tick.</param>
- /// <param name="gamePadState">The game's controller state for the current tick.</param>
+ /// <param name="controller">The game's controller state for the current tick.</param>
+ /// <param name="keyboard">The game's keyboard state for the current tick.</param>
+ /// <param name="mouse">The game's mouse state for the current tick.</param>
/// <returns>Returns whether any overrides were applied.</returns>
- private bool ApplyOverrides(ISet<SButton> pressed, ISet<SButton> released, ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState)
+ private bool ApplyOverrides(ISet<SButton> pressed, ISet<SButton> released, GamePadStateBuilder controller, KeyboardStateBuilder keyboard, MouseStateBuilder mouse)
{
if (pressed.Count == 0 && released.Count == 0)
return false;
@@ -255,17 +252,17 @@ namespace StardewModdingAPI.Framework.Input
mouseOverrides[button] = newState;
else if (button.TryGetKeyboard(out Keys _))
keyboardOverrides[button] = newState;
- else if (gamePadState.IsConnected && button.TryGetController(out Buttons _))
+ else if (controller.IsConnected && button.TryGetController(out Buttons _))
controllerOverrides[button] = newState;
}
// override states
if (keyboardOverrides.Any())
- keyboardState = new KeyboardStateBuilder(keyboardState).OverrideButtons(keyboardOverrides).ToState();
- if (gamePadState.IsConnected && controllerOverrides.Any())
- gamePadState = new GamePadStateBuilder(gamePadState).OverrideButtons(controllerOverrides).ToState();
+ keyboard.OverrideButtons(keyboardOverrides);
+ if (controller.IsConnected && controllerOverrides.Any())
+ controller.OverrideButtons(controllerOverrides);
if (mouseOverrides.Any())
- mouseState = new MouseStateBuilder(mouseState).OverrideButtons(mouseOverrides).ToMouseState();
+ mouse.OverrideButtons(mouseOverrides);
return true;
}
@@ -273,10 +270,7 @@ namespace StardewModdingAPI.Framework.Input
/// <summary>Get the state of all pressed or released buttons relative to their previous state.</summary>
/// <param name="previousStates">The previous button states.</param>
/// <param name="pressedButtons">The currently pressed buttons.</param>
- /// <param name="keyboard">The keyboard state.</param>
- /// <param name="mouse">The mouse state.</param>
- /// <param name="controller">The controller state.</param>
- private IDictionary<SButton, SButtonState> DeriveStates(IDictionary<SButton, SButtonState> previousStates, HashSet<SButton> pressedButtons, KeyboardState keyboard, MouseState mouse, GamePadState controller)
+ private IDictionary<SButton, SButtonState> DeriveStates(IDictionary<SButton, SButtonState> previousStates, HashSet<SButton> pressedButtons)
{
IDictionary<SButton, SButtonState> activeButtons = new Dictionary<SButton, SButtonState>();
@@ -319,101 +313,12 @@ namespace StardewModdingAPI.Framework.Input
/// <param name="mouse">The mouse state.</param>
/// <param name="controller">The controller state.</param>
/// <remarks>Thumbstick direction logic derived from <see cref="ButtonCollection"/>.</remarks>
- private IEnumerable<SButton> GetPressedButtons(KeyboardState keyboard, MouseState mouse, GamePadState controller)
- {
- // keyboard
- foreach (Keys key in keyboard.GetPressedKeys())
- yield return key.ToSButton();
-
- // mouse
- if (mouse.LeftButton == ButtonState.Pressed)
- yield return SButton.MouseLeft;
- if (mouse.RightButton == ButtonState.Pressed)
- yield return SButton.MouseRight;
- if (mouse.MiddleButton == ButtonState.Pressed)
- yield return SButton.MouseMiddle;
- if (mouse.XButton1 == ButtonState.Pressed)
- yield return SButton.MouseX1;
- if (mouse.XButton2 == ButtonState.Pressed)
- yield return SButton.MouseX2;
-
- // controller
- if (controller.IsConnected)
- {
- // main buttons
- if (controller.Buttons.A == ButtonState.Pressed)
- yield return SButton.ControllerA;
- if (controller.Buttons.B == ButtonState.Pressed)
- yield return SButton.ControllerB;
- if (controller.Buttons.X == ButtonState.Pressed)
- yield return SButton.ControllerX;
- if (controller.Buttons.Y == ButtonState.Pressed)
- yield return SButton.ControllerY;
- if (controller.Buttons.LeftStick == ButtonState.Pressed)
- yield return SButton.LeftStick;
- if (controller.Buttons.RightStick == ButtonState.Pressed)
- yield return SButton.RightStick;
- if (controller.Buttons.Start == ButtonState.Pressed)
- yield return SButton.ControllerStart;
-
- // directional pad
- if (controller.DPad.Up == ButtonState.Pressed)
- yield return SButton.DPadUp;
- if (controller.DPad.Down == ButtonState.Pressed)
- yield return SButton.DPadDown;
- if (controller.DPad.Left == ButtonState.Pressed)
- yield return SButton.DPadLeft;
- if (controller.DPad.Right == ButtonState.Pressed)
- yield return SButton.DPadRight;
-
- // secondary buttons
- if (controller.Buttons.Back == ButtonState.Pressed)
- yield return SButton.ControllerBack;
- if (controller.Buttons.BigButton == ButtonState.Pressed)
- yield return SButton.BigButton;
-
- // shoulders
- if (controller.Buttons.LeftShoulder == ButtonState.Pressed)
- yield return SButton.LeftShoulder;
- if (controller.Buttons.RightShoulder == ButtonState.Pressed)
- yield return SButton.RightShoulder;
-
- // triggers
- if (controller.Triggers.Left > 0.2f)
- yield return SButton.LeftTrigger;
- if (controller.Triggers.Right > 0.2f)
- yield return SButton.RightTrigger;
-
- // left thumbstick direction
- if (controller.ThumbSticks.Left.Y > SInputState.LeftThumbstickDeadZone)
- yield return SButton.LeftThumbstickUp;
- if (controller.ThumbSticks.Left.Y < -SInputState.LeftThumbstickDeadZone)
- yield return SButton.LeftThumbstickDown;
- if (controller.ThumbSticks.Left.X > SInputState.LeftThumbstickDeadZone)
- yield return SButton.LeftThumbstickRight;
- if (controller.ThumbSticks.Left.X < -SInputState.LeftThumbstickDeadZone)
- yield return SButton.LeftThumbstickLeft;
-
- // right thumbstick direction
- if (this.IsRightThumbstickOutsideDeadZone(controller.ThumbSticks.Right))
- {
- if (controller.ThumbSticks.Right.Y > 0)
- yield return SButton.RightThumbstickUp;
- if (controller.ThumbSticks.Right.Y < 0)
- yield return SButton.RightThumbstickDown;
- if (controller.ThumbSticks.Right.X > 0)
- yield return SButton.RightThumbstickRight;
- if (controller.ThumbSticks.Right.X < 0)
- yield return SButton.RightThumbstickLeft;
- }
- }
- }
-
- /// <summary>Get whether the right thumbstick should be considered outside the dead zone.</summary>
- /// <param name="direction">The right thumbstick value.</param>
- private bool IsRightThumbstickOutsideDeadZone(Vector2 direction)
+ private IEnumerable<SButton> GetPressedButtons(KeyboardStateBuilder keyboard, MouseStateBuilder mouse, GamePadStateBuilder controller)
{
- return direction.Length() > 0.9f;
+ return keyboard
+ .GetPressedButtons()
+ .Concat(mouse.GetPressedButtons())
+ .Concat(controller.GetPressedButtons());
}
}
}