diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 535679d63..9fdf31866 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -39,11 +39,11 @@ END TEMPLATE-->
### New features
-*None yet*
+* Added `BoundKeyEventArgs.IsRepeat`.
### Bugfixes
-*None yet*
+* Fix assert trip when holding repeatable keybinds.
### Other
diff --git a/Robust.Client/Input/InputManager.cs b/Robust.Client/Input/InputManager.cs
index a9641d594..4f7d8e8e8 100644
--- a/Robust.Client/Input/InputManager.cs
+++ b/Robust.Client/Input/InputManager.cs
@@ -346,7 +346,7 @@ namespace Robust.Client.Input
{
if (binding.CanRepeat)
{
- return SetBindState(binding, BoundKeyState.Down, uiOnly);
+ return SetBindState(binding, BoundKeyState.Down, uiOnly, isRepeat);
}
return true;
@@ -375,7 +375,7 @@ namespace Robust.Client.Input
SetBindState(binding, BoundKeyState.Up);
}
- private bool SetBindState(KeyBinding binding, BoundKeyState state, bool uiOnly = false)
+ private bool SetBindState(KeyBinding binding, BoundKeyState state, bool uiOnly = false, bool isRepeat = false)
{
if (binding.BindingType == KeyBindingType.Command && state == BoundKeyState.Down)
{
@@ -387,6 +387,7 @@ namespace Robust.Client.Input
// I honestly have no idea what the best solution here is.
// note from the future: context switches won't cause re-entrancy anymore because InputContextContainer defers context switches
DebugTools.Assert(!_currentlyFindingViewport, "Re-entrant key events??");
+ DebugTools.Assert(!isRepeat || binding.CanRepeat);
try
{
@@ -399,7 +400,7 @@ namespace Robust.Client.Input
binding.State = state;
var eventArgs = new BoundKeyEventArgs(binding.Function, binding.State,
- MouseScreenPosition, binding.CanFocus);
+ MouseScreenPosition, binding.CanFocus, isRepeat);
// UI returns true here into blockPass if it wants to prevent us from giving input events
// to the viewport, but doesn't want it hard-handled so we keep processing possible key actions.
diff --git a/Robust.Client/UserInterface/UserInterfaceManager.Input.cs b/Robust.Client/UserInterface/UserInterfaceManager.Input.cs
index 3df130bb3..a82b4c2a1 100644
--- a/Robust.Client/UserInterface/UserInterfaceManager.Input.cs
+++ b/Robust.Client/UserInterface/UserInterfaceManager.Input.cs
@@ -114,8 +114,10 @@ internal partial class UserInterfaceManager
args.Handle();
}
- // Attempt to ensure that keybind-up events only get raised after a single keybind-down.
- DebugTools.Assert(!_focusedControls.ContainsKey(args.Function));
+ // Attempt to ensure that keybind-up events get raised after a keybind-down.
+ DebugTools.Assert(!_focusedControls.TryGetValue(args.Function, out var existing)
+ || !existing.VisibleInTree
+ || args.IsRepeat && existing == control);
_focusedControls[args.Function] = control;
OnKeyBindDown?.Invoke(control);
@@ -124,7 +126,7 @@ internal partial class UserInterfaceManager
public void KeyBindUp(BoundKeyEventArgs args)
{
// Only raise keybind-up for the control on which we previously raised keybind-down
- if (!_focusedControls.Remove(args.Function, out var control) || control.Disposed)
+ if (!_focusedControls.Remove(args.Function, out var control) || !control.VisibleInTree)
return;
var guiArgs = new GUIBoundKeyEventArgs(args.Function, args.State, args.PointerLocation, args.CanFocus,
diff --git a/Robust.Shared/Input/BoundKeyEventArgs.cs b/Robust.Shared/Input/BoundKeyEventArgs.cs
index 555cc453c..cf6a0cb86 100644
--- a/Robust.Shared/Input/BoundKeyEventArgs.cs
+++ b/Robust.Shared/Input/BoundKeyEventArgs.cs
@@ -33,6 +33,11 @@ namespace Robust.Shared.Input
public bool Handled { get; private set; }
+ ///
+ /// Is this a repeated keypress (i.e., are they holding down the key)?
+ ///
+ public readonly bool IsRepeat;
+
///
/// Constructs a new instance of .
///
@@ -47,6 +52,23 @@ namespace Robust.Shared.Input
CanFocus = canFocus;
}
+ ///
+ /// Constructs a new instance of .
+ ///
+ /// Bound key that that is changing.
+ /// New state of the function.
+ /// Current Pointer location in screen coordinates.
+ ///
+ public BoundKeyEventArgs(
+ BoundKeyFunction function,
+ BoundKeyState state,
+ ScreenCoordinates pointerLocation,
+ bool canFocus,
+ bool isRepeat = false) : this(function, state, pointerLocation, canFocus)
+ {
+ IsRepeat = isRepeat;
+ }
+
///
/// Mark this event as handled.
///