diff --git a/docs/release-notes.md b/docs/release-notes.md
index ece388c7..d1a78aaa 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -23,6 +23,7 @@
* Fixed error if a mod loads a PNG while the game is loading (e.g. custom map tilesheets via `IAssetLoader`).
* Fixed assets loaded by temporary content managers not being editable by mods.
* Fixed assets not reloaded consistently when the player switches language.
+ * Fixed input suppression not working consistently for clicks.
* Fixed console command input not saved to the log.
* Fixed `helper.ModRegistry.GetApi` interface validation errors not mentioning which interface caused the issue.
* **Breaking changes** (see [migration guide](https://stardewvalleywiki.com/Modding:Migrate_to_Stardew_Valley_1.3)):
diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs
index 1b224737..5e8efa62 100644
--- a/src/SMAPI/Framework/Input/SInputState.cs
+++ b/src/SMAPI/Framework/Input/SInputState.cs
@@ -81,22 +81,16 @@ namespace StardewModdingAPI.Framework.Input
Point mousePosition = new Point((int)(this.RealMouse.X * (1.0 / Game1.options.zoomLevel)), (int)(this.RealMouse.Y * (1.0 / Game1.options.zoomLevel))); // derived from Game1::getMouseX
var activeButtons = this.DeriveStatuses(this.ActiveButtons, realKeyboard, realMouse, realController);
- // get suppressed states
- GamePadState suppressedController = realController;
- KeyboardState suppressedKeyboard = realKeyboard;
- MouseState suppressedMouse = realMouse;
- if (this.SuppressButtons.Count > 0)
- this.UpdateSuppression(activeButtons, ref suppressedKeyboard, ref suppressedMouse, ref suppressedController);
-
- // update
+ // update real states
this.ActiveButtons = activeButtons;
this.RealController = realController;
this.RealKeyboard = realKeyboard;
this.RealMouse = realMouse;
- this.SuppressedController = suppressedController;
- this.SuppressedKeyboard = suppressedKeyboard;
- this.SuppressedMouse = suppressedMouse;
this.MousePosition = mousePosition;
+
+ // update suppressed states
+ this.SuppressButtons.RemoveWhere(p => !this.GetStatus(activeButtons, p).IsDown());
+ this.UpdateSuppression();
}
catch (InvalidOperationException)
{
@@ -104,6 +98,20 @@ namespace StardewModdingAPI.Framework.Input
}
}
+ /// Apply input suppression to current input.
+ public void UpdateSuppression()
+ {
+ GamePadState suppressedController = this.RealController;
+ KeyboardState suppressedKeyboard = this.RealKeyboard;
+ MouseState suppressedMouse = this.RealMouse;
+
+ this.SuppressGivenStates(this.ActiveButtons, ref suppressedKeyboard, ref suppressedMouse, ref suppressedController);
+
+ this.SuppressedController = suppressedController;
+ this.SuppressedKeyboard = suppressedKeyboard;
+ this.SuppressedMouse = suppressedMouse;
+ }
+
/// Get the gamepad state visible to the game.
[Obsolete("This method should only be called by the game itself.")]
public override GamePadState GetGamePadState()
@@ -145,61 +153,6 @@ namespace StardewModdingAPI.Framework.Input
return buttons.Any(button => this.IsDown(button.ToSButton()));
}
- /// Apply input suppression for the given input states.
- /// The current button states to check.
- /// The game's keyboard state for the current tick.
- /// The game's mouse state for the current tick.
- /// The game's controller state for the current tick.
- public void UpdateSuppression(IDictionary activeButtons, ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState)
- {
- // stop suppressing buttons once released
- if (this.SuppressButtons.Count != 0)
- this.SuppressButtons.RemoveWhere(p => !this.GetStatus(activeButtons, p).IsDown());
- if (this.SuppressButtons.Count == 0)
- return;
-
- // gather info
- HashSet keyboardButtons = new HashSet();
- HashSet controllerButtons = new HashSet();
- HashSet mouseButtons = new HashSet();
- foreach (SButton button in this.SuppressButtons)
- {
- if (button == SButton.MouseLeft || button == SButton.MouseMiddle || button == SButton.MouseRight || button == SButton.MouseX1 || button == SButton.MouseX2)
- mouseButtons.Add(button);
- else if (button.TryGetKeyboard(out Keys key))
- keyboardButtons.Add(key);
- else if (gamePadState.IsConnected && button.TryGetController(out Buttons _))
- controllerButtons.Add(button);
- }
-
- // suppress keyboard keys
- if (keyboardState.GetPressedKeys().Any() && keyboardButtons.Any())
- keyboardState = new KeyboardState(keyboardState.GetPressedKeys().Except(keyboardButtons).ToArray());
-
- // suppress controller keys
- if (gamePadState.IsConnected && controllerButtons.Any())
- {
- GamePadStateBuilder builder = new GamePadStateBuilder(gamePadState);
- builder.SuppressButtons(controllerButtons);
- gamePadState = builder.ToGamePadState();
- }
-
- // suppress mouse buttons
- if (mouseButtons.Any())
- {
- mouseState = new MouseState(
- x: mouseState.X,
- y: mouseState.Y,
- scrollWheel: mouseState.ScrollWheelValue,
- leftButton: mouseButtons.Contains(SButton.MouseLeft) ? ButtonState.Pressed : mouseState.LeftButton,
- middleButton: mouseButtons.Contains(SButton.MouseMiddle) ? ButtonState.Pressed : mouseState.MiddleButton,
- rightButton: mouseButtons.Contains(SButton.MouseRight) ? ButtonState.Pressed : mouseState.RightButton,
- xButton1: mouseButtons.Contains(SButton.MouseX1) ? ButtonState.Pressed : mouseState.XButton1,
- xButton2: mouseButtons.Contains(SButton.MouseX2) ? ButtonState.Pressed : mouseState.XButton2
- );
- }
- }
-
/*********
** Private methods
@@ -210,6 +163,58 @@ namespace StardewModdingAPI.Framework.Input
return Game1.chatBox != null && !Game1.chatBox.isActive();
}
+ /// Apply input suppression to the given input states.
+ /// The current button states to check.
+ /// The game's keyboard state for the current tick.
+ /// The game's mouse state for the current tick.
+ /// The game's controller state for the current tick.
+ private void SuppressGivenStates(IDictionary activeButtons, ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState)
+ {
+ if (this.SuppressButtons.Count == 0)
+ return;
+
+ // gather info
+ HashSet suppressKeys = new HashSet();
+ HashSet suppressButtons = new HashSet();
+ HashSet suppressMouse = new HashSet();
+ foreach (SButton button in this.SuppressButtons)
+ {
+ if (button == SButton.MouseLeft || button == SButton.MouseMiddle || button == SButton.MouseRight || button == SButton.MouseX1 || button == SButton.MouseX2)
+ suppressMouse.Add(button);
+ else if (button.TryGetKeyboard(out Keys key))
+ suppressKeys.Add(key);
+ else if (gamePadState.IsConnected && button.TryGetController(out Buttons _))
+ suppressButtons.Add(button);
+ }
+
+ // suppress keyboard keys
+ if (keyboardState.GetPressedKeys().Any() && suppressKeys.Any())
+ keyboardState = new KeyboardState(keyboardState.GetPressedKeys().Except(suppressKeys).ToArray());
+
+ // suppress controller keys
+ if (gamePadState.IsConnected && suppressButtons.Any())
+ {
+ GamePadStateBuilder builder = new GamePadStateBuilder(gamePadState);
+ builder.SuppressButtons(suppressButtons);
+ gamePadState = builder.ToGamePadState();
+ }
+
+ // suppress mouse buttons
+ if (suppressMouse.Any())
+ {
+ mouseState = new MouseState(
+ x: mouseState.X,
+ y: mouseState.Y,
+ scrollWheel: mouseState.ScrollWheelValue,
+ leftButton: suppressMouse.Contains(SButton.MouseLeft) ? ButtonState.Released : mouseState.LeftButton,
+ middleButton: suppressMouse.Contains(SButton.MouseMiddle) ? ButtonState.Released : mouseState.MiddleButton,
+ rightButton: suppressMouse.Contains(SButton.MouseRight) ? ButtonState.Released : mouseState.RightButton,
+ xButton1: suppressMouse.Contains(SButton.MouseX1) ? ButtonState.Released : mouseState.XButton1,
+ xButton2: suppressMouse.Contains(SButton.MouseX2) ? ButtonState.Released : mouseState.XButton2
+ );
+ }
+ }
+
/// Get the status of all pressed or released buttons relative to their previous status.
/// The previous button statuses.
/// The keyboard state.
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index c8c30834..63f7f073 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -613,6 +613,7 @@ namespace StardewModdingAPI.Framework
/*********
** Game update
*********/
+ this.Input.UpdateSuppression();
try
{
base.Update(gameTime);