diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-03-08 14:53:41 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-03-08 14:53:41 -0400 |
commit | e80b7712f7e4c78a5b016289ca19efaf7d39cd8b (patch) | |
tree | 5ca5277b1755504a1e95b655b16ff696114d26b8 /src/SMAPI/Framework/Input | |
parent | e39b9e0d699079edfbcf8595d7499aff894578b6 (diff) | |
download | SMAPI-e80b7712f7e4c78a5b016289ca19efaf7d39cd8b.tar.gz SMAPI-e80b7712f7e4c78a5b016289ca19efaf7d39cd8b.tar.bz2 SMAPI-e80b7712f7e4c78a5b016289ca19efaf7d39cd8b.zip |
encapsulate logic for each input type
Diffstat (limited to 'src/SMAPI/Framework/Input')
-rw-r--r-- | src/SMAPI/Framework/Input/GamePadStateBuilder.cs | 177 | ||||
-rw-r--r-- | src/SMAPI/Framework/Input/IInputStateBuilder.cs | 29 | ||||
-rw-r--r-- | src/SMAPI/Framework/Input/KeyboardStateBuilder.cs | 45 | ||||
-rw-r--r-- | src/SMAPI/Framework/Input/MouseStateBuilder.cs | 93 | ||||
-rw-r--r-- | src/SMAPI/Framework/Input/SInputState.cs | 185 |
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()); } } } |