summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/release-notes.md1
-rw-r--r--src/SMAPI/Events/ButtonsChangedEventArgs.cs67
-rw-r--r--src/SMAPI/Events/IInputEvents.cs3
-rw-r--r--src/SMAPI/Framework/Events/EventManager.cs4
-rw-r--r--src/SMAPI/Framework/Events/ModInputEvents.cs7
-rw-r--r--src/SMAPI/Framework/SCore.cs31
6 files changed, 100 insertions, 13 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md
index edf4481d..5e0e05b6 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -13,6 +13,7 @@
* For modders:
* Added [API for multi-key bindings](https://stardewcommunitywiki.com/Modding:Modder_Guide/APIs/Input#KeybindList).
+ * Added a new [`Input.ButtonsChanged` event](https://stardewcommunitywiki.com/Modding:Modder_Guide/APIs/Events#Input.ButtonsChanged).
* Improved multiplayer APIs:
* `PerScreen<T>` now lets you get/set the value for any screen, get all active values, or clear all values.
* Peer data for the multiplayer API/events now includes `IsSplitScreen` and `ScreenID` fields.
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
+{
+ /// <summary>Event arguments when any buttons were pressed or released.</summary>
+ public class ButtonsChangedEventArgs : EventArgs
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <summary>The buttons that were pressed, held, or released since the previous tick.</summary>
+ private readonly Lazy<Dictionary<SButtonState, SButton[]>> ButtonsByState;
+
+
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>The current cursor position.</summary>
+ public ICursorPosition Cursor { get; }
+
+ /// <summary>The buttons which were pressed since the previous tick.</summary>
+ public IEnumerable<SButton> Pressed => this.ButtonsByState.Value[SButtonState.Pressed];
+
+ /// <summary>The buttons which were held since the previous tick.</summary>
+ public IEnumerable<SButton> Held => this.ButtonsByState.Value[SButtonState.Held];
+
+ /// <summary>The buttons which were released since the previous tick.</summary>
+ public IEnumerable<SButton> Released => this.ButtonsByState.Value[SButtonState.Released];
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="cursor">The cursor position.</param>
+ /// <param name="inputState">The game's current input state.</param>
+ internal ButtonsChangedEventArgs(ICursorPosition cursor, SInputState inputState)
+ {
+ this.Cursor = cursor;
+ this.ButtonsByState = new Lazy<Dictionary<SButtonState, SButton[]>>(() => this.GetButtonsByState(inputState));
+ }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Get the buttons that were pressed, held, or released since the previous tick.</summary>
+ /// <param name="inputState">The game's current input state.</param>
+ private Dictionary<SButtonState, SButton[]> GetButtonsByState(SInputState inputState)
+ {
+ Dictionary<SButtonState, SButton[]> 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
/// <summary>Events raised when the player provides input using a controller, keyboard, or mouse.</summary>
public interface IInputEvents
{
+ /// <summary>Raised after the player presses or releases any buttons on the keyboard, controller, or mouse.</summary>
+ event EventHandler<ButtonsChangedEventArgs> ButtonsChanged;
+
/// <summary>Raised after the player presses a button on the keyboard, controller, or mouse.</summary>
event EventHandler<ButtonPressedEventArgs> 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
****/
+ /// <summary>Raised after the player presses or releases any buttons on the keyboard, controller, or mouse.</summary>
+ public readonly ManagedEvent<ButtonsChangedEventArgs> ButtonsChanged;
+
/// <summary>Raised after the player presses a button on the keyboard, controller, or mouse.</summary>
public readonly ManagedEvent<ButtonPressedEventArgs> ButtonPressed;
@@ -212,6 +215,7 @@ namespace StardewModdingAPI.Framework.Events
this.TimeChanged = ManageEventOf<TimeChangedEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.TimeChanged));
this.ReturnedToTitle = ManageEventOf<ReturnedToTitleEventArgs>(nameof(IModEvents.GameLoop), nameof(IGameLoopEvents.ReturnedToTitle));
+ this.ButtonsChanged = ManageEventOf<ButtonsChangedEventArgs>(nameof(IModEvents.Input), nameof(IInputEvents.ButtonsChanged));
this.ButtonPressed = ManageEventOf<ButtonPressedEventArgs>(nameof(IModEvents.Input), nameof(IInputEvents.ButtonPressed));
this.ButtonReleased = ManageEventOf<ButtonReleasedEventArgs>(nameof(IModEvents.Input), nameof(IInputEvents.ButtonReleased));
this.CursorMoved = ManageEventOf<CursorMovedEventArgs>(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
*********/
+ /// <summary>Raised after the player presses or releases any buttons on the keyboard, controller, or mouse.</summary>
+ public event EventHandler<ButtonsChangedEventArgs> ButtonsChanged
+ {
+ add => this.EventManager.ButtonsChanged.Add(value, this.Mod);
+ remove => this.EventManager.ButtonsChanged.Remove(value);
+ }
+
/// <summary>Raised after the player presses a button on the keyboard, controller, or mouse.</summary>
public event EventHandler<ButtonPressedEventArgs> 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));
+ }
}
}
}