From 7e280a066db92c74e957e2a694c922d4c3eae017 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 19 Jan 2021 21:47:05 -0500 Subject: add Input.ButtonsChanged event (#744) --- src/SMAPI/Events/ButtonsChangedEventArgs.cs | 67 ++++++++++++++++++++++++++++ src/SMAPI/Events/IInputEvents.cs | 3 ++ src/SMAPI/Framework/Events/EventManager.cs | 4 ++ src/SMAPI/Framework/Events/ModInputEvents.cs | 7 +++ src/SMAPI/Framework/SCore.cs | 31 +++++++------ 5 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 src/SMAPI/Events/ButtonsChangedEventArgs.cs (limited to 'src') diff --git a/src/SMAPI/Events/ButtonsChangedEventArgs.cs b/src/SMAPI/Events/ButtonsChangedEventArgs.cs new file mode 100644 index 00000000..dda41692 --- /dev/null +++ b/src/SMAPI/Events/ButtonsChangedEventArgs.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewModdingAPI.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// Event arguments when any buttons were pressed or released. + public class ButtonsChangedEventArgs : EventArgs + { + /********* + ** Fields + *********/ + /// The buttons that were pressed, held, or released since the previous tick. + private readonly Lazy> ButtonsByState; + + + /********* + ** Accessors + *********/ + /// The current cursor position. + public ICursorPosition Cursor { get; } + + /// The buttons which were pressed since the previous tick. + public IEnumerable Pressed => this.ButtonsByState.Value[SButtonState.Pressed]; + + /// The buttons which were held since the previous tick. + public IEnumerable Held => this.ButtonsByState.Value[SButtonState.Held]; + + /// The buttons which were released since the previous tick. + public IEnumerable Released => this.ButtonsByState.Value[SButtonState.Released]; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The cursor position. + /// The game's current input state. + internal ButtonsChangedEventArgs(ICursorPosition cursor, SInputState inputState) + { + this.Cursor = cursor; + this.ButtonsByState = new Lazy>(() => this.GetButtonsByState(inputState)); + } + + + /********* + ** Private methods + *********/ + /// Get the buttons that were pressed, held, or released since the previous tick. + /// The game's current input state. + private Dictionary GetButtonsByState(SInputState inputState) + { + Dictionary lookup = inputState.ButtonStates + .GroupBy(p => p.Value) + .ToDictionary(p => p.Key, p => p.Select(p => p.Key).ToArray()); + + foreach (var state in new[] { SButtonState.Pressed, SButtonState.Held, SButtonState.Released }) + { + if (!lookup.ContainsKey(state)) + lookup[state] = new SButton[0]; + } + + return lookup; + } + } +} diff --git a/src/SMAPI/Events/IInputEvents.cs b/src/SMAPI/Events/IInputEvents.cs index 5c40a438..081c40c0 100644 --- a/src/SMAPI/Events/IInputEvents.cs +++ b/src/SMAPI/Events/IInputEvents.cs @@ -5,6 +5,9 @@ namespace StardewModdingAPI.Events /// Events raised when the player provides input using a controller, keyboard, or mouse. public interface IInputEvents { + /// Raised after the player presses or releases any buttons on the keyboard, controller, or mouse. + event EventHandler ButtonsChanged; + /// Raised after the player presses a button on the keyboard, controller, or mouse. event EventHandler ButtonPressed; diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 665dbfe3..f4abfffe 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -93,6 +93,9 @@ namespace StardewModdingAPI.Framework.Events /**** ** Input ****/ + /// Raised after the player presses or releases any buttons on the keyboard, controller, or mouse. + public readonly ManagedEvent ButtonsChanged; + /// Raised after the player presses a button on the keyboard, controller, or mouse. public readonly ManagedEvent ButtonPressed; @@ -212,6 +215,7 @@ namespace StardewModdingAPI.Framework.Events this.TimeChanged = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.TimeChanged)); this.ReturnedToTitle = ManageEventOf(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.ReturnedToTitle)); + this.ButtonsChanged = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonsChanged)); this.ButtonPressed = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed)); this.ButtonReleased = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased)); this.CursorMoved = ManageEventOf(nameof(IModEvents.Input), nameof(IInputEvents.CursorMoved), isPerformanceCritical: true); diff --git a/src/SMAPI/Framework/Events/ModInputEvents.cs b/src/SMAPI/Framework/Events/ModInputEvents.cs index ab26ab3e..6f423e5d 100644 --- a/src/SMAPI/Framework/Events/ModInputEvents.cs +++ b/src/SMAPI/Framework/Events/ModInputEvents.cs @@ -9,6 +9,13 @@ namespace StardewModdingAPI.Framework.Events /********* ** Accessors *********/ + /// Raised after the player presses or releases any buttons on the keyboard, controller, or mouse. + public event EventHandler ButtonsChanged + { + add => this.EventManager.ButtonsChanged.Add(value, this.Mod); + remove => this.EventManager.ButtonsChanged.Remove(value); + } + /// Raised after the player presses a button on the keyboard, controller, or mouse. public event EventHandler ButtonPressed { diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 0c55164c..1ac361cd 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -817,24 +817,29 @@ namespace StardewModdingAPI.Framework } // raise input button events - foreach (var pair in inputState.ButtonStates) + if (inputState.ButtonStates.Count > 0) { - SButton button = pair.Key; - SButtonState status = pair.Value; + events.ButtonsChanged.Raise(new ButtonsChangedEventArgs(cursor, inputState)); - if (status == SButtonState.Pressed) + foreach (var pair in inputState.ButtonStates) { - if (this.Monitor.IsVerbose) - this.Monitor.Log($"Events: button {button} pressed."); + SButton button = pair.Key; + SButtonState status = pair.Value; - events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState)); - } - else if (status == SButtonState.Released) - { - if (this.Monitor.IsVerbose) - this.Monitor.Log($"Events: button {button} released."); + if (status == SButtonState.Pressed) + { + if (this.Monitor.IsVerbose) + this.Monitor.Log($"Events: button {button} pressed."); - events.ButtonReleased.Raise(new ButtonReleasedEventArgs(button, cursor, inputState)); + events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState)); + } + else if (status == SButtonState.Released) + { + if (this.Monitor.IsVerbose) + this.Monitor.Log($"Events: button {button} released."); + + events.ButtonReleased.Raise(new ButtonReleasedEventArgs(button, cursor, inputState)); + } } } } -- cgit