From a8d6c294abca40b47dcf3da45359130b9151252a Mon Sep 17 00:00:00 2001
From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
Date: Wed, 21 Aug 2019 08:13:48 -0700
Subject: [PATCH] Input System Refactor (#840)
* Fixes right click menu stopping input
Removed a flag change when the modal stack was showing, which preventing the click from getting passed to the next function.
* Added parsing for mod2 and mod3 from Keybind YAML
* Fixes a crash on context change when a keybind is not defined in keybinds.yml
* Implemented ShowDebugConsole Hotkey
* Refactored input system
Refactored input system to run Key and Mouse input through the InputManager before doing stuff.
* Upgraded LineEdit and classes that use it. Fixed input while KeyboardFocused.
Upgraded LineEdit to use Keybinds.
Upgraded DebugConsole to use Keybinds.
Replaced all references to MouseDown, MouseUp, KeyDown, and KeyUp with KeyBindUp and KeyBindDown.
Moved UserInterfaceManager call from GameController.Input to InputManager event.
Stopped input going to simulation while a control has focus in UserInterfaceManager.
* Some fixes for input system
Fixed keybinds getting stuck when selecting a LineEdit.
Changed MenuBar to not error.
Fixed a few cases where LineEdit would eat input if you hovered over it and where mouse input got eaten when clicking in the world while a LineEdit was selected.
* Removed extra dependencies
* Added GUIBoundKeyEventArgs to ButtonEventArgs
* Fixes for input with LineEdit selected
Fixed multiple keybinds mapped to the same key not triggering.
Fixed keybind input not getting to LineEdit when hovering over a control.
* Implemented Key Repeat for LineEdit
* Fix for input on Robust.Lite Launcher
* Renames NonFocusKeybinds to EnableAllKeybinds
Renamed NonFocusKeybinds to EnableAllKeybinds and added comment to clarify usage
* Adds repeating keybinds
Used for TextBackspace, TextCursorLeft, and TextCursorRight
Reverts a change to LineEdit that implemented repeating keys
Adds some documentation comments
---
.../GameController/GameController.Input.cs | 31 +---
Robust.Client/Graphics/Clyde/Clyde.cs | 21 +--
Robust.Client/Input/EngineContexts.cs | 13 ++
Robust.Client/Input/InputManager.cs | 97 +++++++---
Robust.Client/Interfaces/IGameController.cs | 4 +-
.../Interfaces/Input/IInputManager.cs | 13 ++
.../UserInterface/IUserInterfaceManager.cs | 11 +-
Robust.Client/State/States/GameScreen.cs | 1 +
Robust.Client/State/States/MainMenu.cs | 2 +
Robust.Client/UserInterface/Control.Input.cs | 71 +++-----
Robust.Client/UserInterface/Control.cs | 2 +-
.../UserInterface/Controls/BaseButton.cs | 38 ++--
.../UserInterface/Controls/ItemList.cs | 47 ++---
.../UserInterface/Controls/LineEdit.cs | 157 ++++++++--------
.../UserInterface/Controls/MenuBar.cs | 2 +-
.../UserInterface/Controls/ScrollBar.cs | 61 ++++---
.../UserInterface/Controls/TabContainer.cs | 8 +-
Robust.Client/UserInterface/Controls/Tree.cs | 9 +-
.../CustomControls/DebugConsole.cs | 84 ++++-----
.../CustomControls/SS14Window.cs | 22 ++-
.../UserInterface/UserInterfaceManager.cs | 172 ++++++++++--------
.../ViewVariablesPropertyControl.cs | 9 +-
Robust.Lite/LiteGameController.cs | 22 +--
Robust.Shared/Input/BoundKeyEventArgs.cs | 18 +-
Robust.Shared/Input/KeyFunctions.cs | 13 ++
.../UserInterface/UserInterfaceManagerTest.cs | 41 +++--
Robust.UnitTesting/GameControllerDummy.cs | 10 +-
27 files changed, 544 insertions(+), 435 deletions(-)
diff --git a/Robust.Client/GameController/GameController.Input.cs b/Robust.Client/GameController/GameController.Input.cs
index 0dd1c66c8..55fab3a71 100644
--- a/Robust.Client/GameController/GameController.Input.cs
+++ b/Robust.Client/GameController/GameController.Input.cs
@@ -5,27 +5,18 @@ namespace Robust.Client
internal sealed partial class GameController
{
///
- /// Invoked when a key on the keyboard is pressed down.
+ /// Invoked when a key on the keyboard or a mouse button is pressed down.
///
public void KeyDown(KeyEventArgs keyEvent)
{
- _userInterfaceManager.KeyDown(keyEvent);
-
- if (keyEvent.Handled)
- {
- return;
- }
_inputManager.KeyDown(keyEvent);
}
///
- /// Invoked when a key on the keyboard is released.
+ /// Invoked when a key on the keyboard or a mouse button is released.
///
public void KeyUp(KeyEventArgs keyEvent)
{
- // Unlike KeyDown, InputManager still gets key ups.
- // My logic is that it should be fine dealing with redundant key ups and this *might* prevent edge cases.
- _userInterfaceManager.KeyUp(keyEvent);
_inputManager.KeyUp(keyEvent);
}
@@ -34,24 +25,6 @@ namespace Robust.Client
_userInterfaceManager.TextEntered(textEvent);
}
- ///
- /// Invoked when a button on the mouse is pressed down.
- ///
- public void MouseDown(MouseButtonEventArgs mouseEvent)
- {
- _userInterfaceManager.MouseDown(mouseEvent);
- _stateManager.MouseDown(mouseEvent);
- }
-
- ///
- /// Invoked when a button on the mouse is released.
- ///
- public void MouseUp(MouseButtonEventArgs mouseButtonEventArgs)
- {
- _userInterfaceManager.MouseUp(mouseButtonEventArgs);
- _stateManager.MouseUp(mouseButtonEventArgs);
- }
-
///
/// Invoked when the mouse is moved inside the game window.
///
diff --git a/Robust.Client/Graphics/Clyde/Clyde.cs b/Robust.Client/Graphics/Clyde/Clyde.cs
index 74cd67126..699f63f3e 100644
--- a/Robust.Client/Graphics/Clyde/Clyde.cs
+++ b/Robust.Client/Graphics/Clyde/Clyde.cs
@@ -200,7 +200,6 @@ namespace Robust.Client.Graphics.Clyde
_mainThread = Thread.CurrentThread;
_window.KeyDown += (sender, eventArgs) => { _gameController.KeyDown((KeyEventArgs) eventArgs); };
-
_window.KeyUp += (sender, eventArgs) => { _gameController.KeyUp((KeyEventArgs) eventArgs); };
_window.Closed += _onWindowClosed;
_window.Resize += (sender, eventArgs) =>
@@ -211,24 +210,8 @@ namespace Robust.Client.Graphics.Clyde
_regenerateLightRenderTarget();
OnWindowResized?.Invoke(new WindowResizedEventArgs(oldSize, _windowSize));
};
- _window.MouseDown += (sender, eventArgs) =>
- {
- var mouseButtonEventArgs = (MouseButtonEventArgs) eventArgs;
- _gameController.MouseDown(mouseButtonEventArgs);
- if (!mouseButtonEventArgs.Handled)
- {
- _gameController.KeyDown((KeyEventArgs) eventArgs);
- }
- };
- _window.MouseUp += (sender, eventArgs) =>
- {
- var mouseButtonEventArgs = (MouseButtonEventArgs) eventArgs;
- _gameController.MouseUp(mouseButtonEventArgs);
- if (!mouseButtonEventArgs.Handled)
- {
- _gameController.KeyUp((KeyEventArgs) eventArgs);
- }
- };
+ _window.MouseDown += (sender, eventArgs) => { _gameController.KeyDown((KeyEventArgs) eventArgs); };
+ _window.MouseUp += (sender, eventArgs) => { _gameController.KeyUp((KeyEventArgs) eventArgs); };
_window.MouseMove += (sender, eventArgs) =>
{
MouseScreenPosition = new Vector2(eventArgs.X, eventArgs.Y);
diff --git a/Robust.Client/Input/EngineContexts.cs b/Robust.Client/Input/EngineContexts.cs
index 6b4fe6ac9..ac8bafa3d 100644
--- a/Robust.Client/Input/EngineContexts.cs
+++ b/Robust.Client/Input/EngineContexts.cs
@@ -14,8 +14,11 @@ namespace Robust.Client.Input
public static void SetupContexts(IInputContextContainer contexts)
{
var common = contexts.GetContext(InputContextContainer.DefaultContextName);
+ common.AddFunction(EngineKeyFunctions.Use);
+
common.AddFunction(EngineKeyFunctions.EscapeMenu);
common.AddFunction(EngineKeyFunctions.HideUI);
+ common.AddFunction(EngineKeyFunctions.ShowDebugConsole);
common.AddFunction(EngineKeyFunctions.ShowDebugMonitors);
common.AddFunction(EngineKeyFunctions.MoveUp);
common.AddFunction(EngineKeyFunctions.MoveDown);
@@ -23,6 +26,16 @@ namespace Robust.Client.Input
common.AddFunction(EngineKeyFunctions.MoveRight);
common.AddFunction(EngineKeyFunctions.Run);
+ common.AddFunction(EngineKeyFunctions.TextCursorLeft);
+ common.AddFunction(EngineKeyFunctions.TextCursorRight);
+ common.AddFunction(EngineKeyFunctions.TextBackspace);
+ common.AddFunction(EngineKeyFunctions.TextSubmit);
+ common.AddFunction(EngineKeyFunctions.TextPaste);
+ common.AddFunction(EngineKeyFunctions.TextHistoryPrev);
+ common.AddFunction(EngineKeyFunctions.TextHistoryNext);
+ common.AddFunction(EngineKeyFunctions.TextReleaseFocus);
+ common.AddFunction(EngineKeyFunctions.TextScrollToBottom);
+
var editor = contexts.New("editor", common);
editor.AddFunction(EngineKeyFunctions.EditorLinePlace);
editor.AddFunction(EngineKeyFunctions.EditorGridPlace);
diff --git a/Robust.Client/Input/InputManager.cs b/Robust.Client/Input/InputManager.cs
index 55a33ff6a..26e14f865 100644
--- a/Robust.Client/Input/InputManager.cs
+++ b/Robust.Client/Input/InputManager.cs
@@ -2,11 +2,12 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Text;
+using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
+using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.IoC;
@@ -24,13 +25,9 @@ namespace Robust.Client.Input
public virtual Vector2 MouseScreenPosition => Vector2.Zero;
- [Dependency]
#pragma warning disable 649
- private readonly IUserInterfaceManager _uiManager;
- [Dependency]
- private readonly IResourceManager _resourceMan;
- [Dependency]
- private readonly IReflectionManager _reflectionManager;
+ [Dependency] private readonly IResourceManager _resourceMan;
+ [Dependency] private readonly IReflectionManager _reflectionManager;
#pragma warning restore 649
private readonly Dictionary _commands = new Dictionary();
@@ -43,6 +40,9 @@ namespace Robust.Client.Input
///
public IInputContextContainer Contexts { get; } = new InputContextContainer();
+ ///
+ public event Action UIKeyBindStateChanged;
+
///
public event Action KeyBindStateChanged;
@@ -72,6 +72,10 @@ namespace Robust.Client.Input
foreach (var function in args.OldContext.Except(args.NewContext))
{
var bind = _bindings.Find(binding => binding.Function == function);
+ if (bind == null)
+ {
+ continue;
+ }
SetBindState(bind, BoundKeyState.Up);
}
}
@@ -79,7 +83,7 @@ namespace Robust.Client.Input
///
public void KeyDown(KeyEventArgs args)
{
- if (!Enabled || UIBlocked() || args.Key == Keyboard.Key.Unknown || args.IsRepeat)
+ if (!Enabled || args.Key == Keyboard.Key.Unknown)
{
return;
}
@@ -99,11 +103,14 @@ namespace Robust.Client.Input
if (PackedMatchesPressedState(binding.PackedKeyCombo))
{
// this statement *should* always be true first
- if (matchedCombo == 0 && PackedContainsKey(binding.PackedKeyCombo, internalKey)) // first key match becomes pressed
+ // Keep triggering keybinds of the same PackedKeyCombo until Handled or no bindings left
+ if ((matchedCombo == 0 || binding.PackedKeyCombo == matchedCombo) &&
+ PackedContainsKey(binding.PackedKeyCombo, internalKey))
{
matchedCombo = binding.PackedKeyCombo;
- DownBind(binding);
+ if (DownBind(binding))
+ break;
}
else if (PackedIsSubPattern(matchedCombo, binding.PackedKeyCombo))
{
@@ -137,19 +144,24 @@ namespace Robust.Client.Input
_keysPressed[internalKey] = false;
}
- private void DownBind(KeyBinding binding)
+ private bool DownBind(KeyBinding binding)
{
if (binding.State == BoundKeyState.Down)
{
if (binding.BindingType == KeyBindingType.Toggle)
{
- SetBindState(binding, BoundKeyState.Up);
+ return SetBindState(binding, BoundKeyState.Up);
+ }
+ else if (binding.CanRepeat)
+ {
+ return SetBindState(binding, BoundKeyState.Down);
}
}
else
{
- SetBindState(binding, BoundKeyState.Down);
+ return SetBindState(binding, BoundKeyState.Down);
}
+ return false;
}
private void UpBind(KeyBinding binding)
@@ -162,11 +174,17 @@ namespace Robust.Client.Input
SetBindState(binding, BoundKeyState.Up);
}
- private void SetBindState(KeyBinding binding, BoundKeyState state)
+ private bool SetBindState(KeyBinding binding, BoundKeyState state)
{
binding.State = state;
- KeyBindStateChanged?.Invoke(new BoundKeyEventArgs(binding.Function, binding.State, new ScreenCoordinates(MouseScreenPosition)));
+ var eventArgs = new BoundKeyEventArgs(binding.Function, binding.State, new ScreenCoordinates(MouseScreenPosition), binding.CanFocus);
+
+ UIKeyBindStateChanged?.Invoke(eventArgs);
+ if (state == BoundKeyState.Up || !eventArgs.Handled)
+ {
+ KeyBindStateChanged?.Invoke(eventArgs);
+ }
var cmd = GetInputCommand(binding.Function);
if (state == BoundKeyState.Up)
@@ -177,6 +195,7 @@ namespace Robust.Client.Input
{
cmd?.Enabled(null);
}
+ return (eventArgs.Handled);
}
private bool PackedMatchesPressedState(int packedKeyCombo)
@@ -254,27 +273,46 @@ namespace Robust.Client.Input
}
var key = keyMapping.GetNode("key").AsEnum();
+ var canFocus = false;
+ if (keyMapping.TryGetNode("canFocus", out var canFocusName))
+ {
+ canFocus = canFocusName.AsBool();
+ }
+
+ var canRepeat = false;
+ if (keyMapping.TryGetNode("canRepeat", out var canRepeatName))
+ {
+ canRepeat = canRepeatName.AsBool();
+ }
+
var mod1 = Keyboard.Key.Unknown;
if (keyMapping.TryGetNode("mod1", out var mod1Name))
{
mod1 = mod1Name.AsEnum();
}
+ var mod2 = Keyboard.Key.Unknown;
+ if (keyMapping.TryGetNode("mod2", out var mod2Name))
+ {
+ mod2 = mod2Name.AsEnum();
+ }
+
+ var mod3 = Keyboard.Key.Unknown;
+ if (keyMapping.TryGetNode("mod3", out var mod3Name))
+ {
+ mod3 = mod3Name.AsEnum();
+ }
+
var type = keyMapping.GetNode("type").AsEnum();
- var binding = new KeyBinding(function, type, key, mod1);
+ var binding = new KeyBinding(function, type, key, canFocus, canRepeat, mod1, mod2, mod3);
RegisterBinding(binding);
}
}
- // Don't take input if we're focused on a LineEdit.
- // LineEdits don't intercept keydowns when typing properly.
- // NOTE: macOS specific!
- // https://github.com/godotengine/godot/issues/15071
- // So if we didn't do this, the DebugConsole wouldn't block movement (for example).
- private bool UIBlocked()
+ public void AddClickBind()
{
- return _uiManager.KeyboardFocused is LineEdit;
+ RegisterBinding(new KeyBinding(EngineKeyFunctions.Use, KeyBindingType.State, Keyboard.Key.MouseLeft, true, false));
}
private void RegisterBinding(KeyBinding binding)
@@ -328,15 +366,28 @@ namespace Robust.Client.Input
public BoundKeyFunction Function { get; }
public KeyBindingType BindingType { get; }
+ ///
+ /// Whether the BoundKey can change the focused control.
+ ///
+ public bool CanFocus { get; internal set; }
+
+ ///
+ /// Whether the BoundKey still triggers while held down.
+ ///
+ public bool CanRepeat { get; internal set; }
+
public KeyBinding(BoundKeyFunction function,
KeyBindingType bindingType,
Keyboard.Key baseKey,
+ bool canFocus, bool canRepeat,
Keyboard.Key mod1 = Keyboard.Key.Unknown,
Keyboard.Key mod2 = Keyboard.Key.Unknown,
Keyboard.Key mod3 = Keyboard.Key.Unknown)
{
Function = function;
BindingType = bindingType;
+ CanFocus = canFocus;
+ CanRepeat = canRepeat;
PackedKeyCombo = PackKeyCombo(baseKey, mod1, mod2, mod3);
}
diff --git a/Robust.Client/Interfaces/IGameController.cs b/Robust.Client/Interfaces/IGameController.cs
index b5692c2ff..a6ece0618 100644
--- a/Robust.Client/Interfaces/IGameController.cs
+++ b/Robust.Client/Interfaces/IGameController.cs
@@ -1,4 +1,4 @@
-using Robust.Client.Input;
+using Robust.Client.Input;
using Robust.Shared.Timing;
namespace Robust.Client.Interfaces
@@ -17,8 +17,6 @@ namespace Robust.Client.Interfaces
void KeyDown(KeyEventArgs keyEvent);
void KeyUp(KeyEventArgs keyEvent);
void TextEntered(TextEventArgs textEvent);
- void MouseDown(MouseButtonEventArgs mouseEvent);
- void MouseUp(MouseButtonEventArgs mouseButtonEventArgs);
void MouseMove(MouseMoveEventArgs mouseMoveEventArgs);
void MouseWheel(MouseWheelEventArgs mouseWheelEventArgs);
void OverrideMainLoop(IGameLoop gameLoop);
diff --git a/Robust.Client/Interfaces/Input/IInputManager.cs b/Robust.Client/Interfaces/Input/IInputManager.cs
index 212189ef8..97f47c81c 100644
--- a/Robust.Client/Interfaces/Input/IInputManager.cs
+++ b/Robust.Client/Interfaces/Input/IInputManager.cs
@@ -22,6 +22,11 @@ namespace Robust.Client.Interfaces.Input
void Initialize();
+ ///
+ /// Adds the Use keybind for Keyboard.Key.MouseLeft for Robust.Lite Launcher.
+ ///
+ void AddClickBind();
+
void KeyDown(KeyEventArgs e);
void KeyUp(KeyEventArgs e);
@@ -42,6 +47,14 @@ namespace Robust.Client.Interfaces.Input
void SetInputCommand(BoundKeyFunction function, InputCmdHandler cmdHandler);
+ ///
+ /// UIKeyBindStateChanged is called when a keybind is found.
+ ///
+ event Action UIKeyBindStateChanged;
+
+ ///
+ /// If UIKeyBindStateChanged did not handle the BoundKeyEvent, KeyBindStateChanged is called.
+ ///
event Action KeyBindStateChanged;
}
}
diff --git a/Robust.Client/Interfaces/UserInterface/IUserInterfaceManager.cs b/Robust.Client/Interfaces/UserInterface/IUserInterfaceManager.cs
index ebbc1f843..08371a480 100644
--- a/Robust.Client/Interfaces/UserInterface/IUserInterfaceManager.cs
+++ b/Robust.Client/Interfaces/UserInterface/IUserInterfaceManager.cs
@@ -1,7 +1,8 @@
-using System;
+using System;
using Robust.Client.Input;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.UserInterface;
+using Robust.Shared.Input;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
@@ -76,9 +77,9 @@ namespace Robust.Client.Interfaces.UserInterface
void FrameUpdate(FrameEventArgs args);
- void MouseDown(MouseButtonEventArgs args);
+ void KeyBindDown(BoundKeyEventArgs args);
- void MouseUp(MouseButtonEventArgs args);
+ void KeyBindUp(BoundKeyEventArgs args);
void MouseMove(MouseMoveEventArgs mouseMoveEventArgs);
@@ -86,10 +87,6 @@ namespace Robust.Client.Interfaces.UserInterface
void TextEntered(TextEventArgs textEvent);
- void KeyDown(KeyEventArgs keyEvent);
-
- void KeyUp(KeyEventArgs keyEvent);
-
void ControlHidden(Control control);
void ControlRemovedFromTree(Control control);
diff --git a/Robust.Client/State/States/GameScreen.cs b/Robust.Client/State/States/GameScreen.cs
index 64b716b75..c65e05037 100644
--- a/Robust.Client/State/States/GameScreen.cs
+++ b/Robust.Client/State/States/GameScreen.cs
@@ -7,6 +7,7 @@ using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.Placement;
+using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
diff --git a/Robust.Client/State/States/MainMenu.cs b/Robust.Client/State/States/MainMenu.cs
index e4b5c044b..ce91c5451 100644
--- a/Robust.Client/State/States/MainMenu.cs
+++ b/Robust.Client/State/States/MainMenu.cs
@@ -16,6 +16,8 @@ using Robust.Shared.Interfaces.Network;
using Robust.Shared.Localization;
using Robust.Shared.Network;
using Robust.Shared.Utility;
+using Robust.Shared.Input;
+using Robust.Client.Interfaces.Input;
namespace Robust.Client.State.States
{
diff --git a/Robust.Client/UserInterface/Control.Input.cs b/Robust.Client/UserInterface/Control.Input.cs
index 51df99e56..065d87f43 100644
--- a/Robust.Client/UserInterface/Control.Input.cs
+++ b/Robust.Client/UserInterface/Control.Input.cs
@@ -1,5 +1,7 @@
using Robust.Client.Input;
using Robust.Client.Utility;
+using Robust.Shared.Input;
+using Robust.Shared.Map;
using Robust.Shared.Maths;
using System;
@@ -19,14 +21,14 @@ namespace Robust.Client.UserInterface
{
}
- public event Action OnMouseDown;
+ public event Action OnKeyBindDown;
- protected internal virtual void MouseDown(GUIMouseButtonEventArgs args)
+ protected internal virtual void KeyBindDown(GUIBoundKeyEventArgs args)
{
- OnMouseDown?.Invoke(args);
+ OnKeyBindDown?.Invoke(args);
}
- protected internal virtual void MouseUp(GUIMouseButtonEventArgs args)
+ protected internal virtual void KeyBindUp(GUIBoundKeyEventArgs args)
{
}
@@ -34,17 +36,6 @@ namespace Robust.Client.UserInterface
{
}
- public event Action OnKeyDown;
-
- protected internal virtual void KeyDown(GUIKeyEventArgs args)
- {
- OnKeyDown?.Invoke(args);
- }
-
- protected internal virtual void KeyUp(GUIKeyEventArgs args)
- {
- }
-
protected internal virtual void KeyHeld(GUIKeyEventArgs args)
{
}
@@ -54,6 +45,24 @@ namespace Robust.Client.UserInterface
}
}
+ public class GUIBoundKeyEventArgs : BoundKeyEventArgs
+ {
+ ///
+ /// Position of the mouse, relative to the current control.
+ ///
+ public Vector2 RelativePosition { get; internal set; }
+
+ public Vector2 RelativePixelPosition { get; internal set; }
+
+ public GUIBoundKeyEventArgs(BoundKeyFunction function, BoundKeyState state, ScreenCoordinates pointerLocation,
+ bool canFocus, Vector2 relativePosition, Vector2 relativePixelPosition)
+ : base(function, state, pointerLocation, canFocus)
+ {
+ RelativePosition = relativePosition;
+ RelativePixelPosition = relativePixelPosition;
+ }
+ }
+
public class GUIKeyEventArgs : KeyEventArgs
{
///
@@ -137,38 +146,6 @@ namespace Robust.Client.UserInterface
}
}
- public class GUIMouseButtonEventArgs : GUIMouseEventArgs
- {
- ///
- /// The mouse button that has been pressed or released.
- ///
- public Mouse.Button Button { get; }
-
- ///
- /// True if this action was a double click.
- /// Can't be true if this was a release event.
- ///
- public bool DoubleClick { get; }
-
- public GUIMouseButtonEventArgs(Mouse.Button button,
- bool doubleClick,
- Control sourceControl,
- Mouse.ButtonMask buttonMask,
- Vector2 globalPosition,
- Vector2 globalPixelPosition,
- Vector2 relativePosition,
- Vector2 relativePixelPosition,
- bool alt,
- bool control,
- bool shift,
- bool system)
- : base(sourceControl, buttonMask, globalPosition, globalPixelPosition, relativePosition, relativePixelPosition, alt, control, shift, system)
- {
- Button = button;
- DoubleClick = doubleClick;
- }
- }
-
public class GUIMouseMoveEventArgs : GUIMouseEventArgs
{
///
diff --git a/Robust.Client/UserInterface/Control.cs b/Robust.Client/UserInterface/Control.cs
index 960457e9f..60d7e78e5 100644
--- a/Robust.Client/UserInterface/Control.cs
+++ b/Robust.Client/UserInterface/Control.cs
@@ -416,7 +416,7 @@ namespace Robust.Client.UserInterface
DisposeAllChildren();
Parent?.RemoveChild(this);
- OnKeyDown = null;
+ OnKeyBindDown = null;
}
~Control()
diff --git a/Robust.Client/UserInterface/Controls/BaseButton.cs b/Robust.Client/UserInterface/Controls/BaseButton.cs
index c824ee1c9..3c24ab739 100644
--- a/Robust.Client/UserInterface/Controls/BaseButton.cs
+++ b/Robust.Client/UserInterface/Controls/BaseButton.cs
@@ -1,4 +1,5 @@
using System;
+using Robust.Shared.Input;
using Robust.Shared.ViewVariables;
namespace Robust.Client.UserInterface.Controls
@@ -15,6 +16,7 @@ namespace Robust.Client.UserInterface.Controls
private bool _beingHovered;
private bool _disabled;
private bool _pressed;
+ private bool _enableAllKeybinds;
///
/// Controls mode of operation in relation to press/release events.
@@ -61,6 +63,15 @@ namespace Robust.Client.UserInterface.Controls
}
}
+ ///
+ /// Whether a button enables Keybinds without GUIBoundKeyEventArgs.CanFocus to trigger the button.
+ ///
+ public bool EnableAllKeybinds
+ {
+ get => _enableAllKeybinds;
+ set => _enableAllKeybinds = value;
+ }
+
///
/// If true, this button functions as a toggle, not as a regular push button.
///
@@ -124,16 +135,16 @@ namespace Robust.Client.UserInterface.Controls
{
}
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
{
- base.MouseDown(args);
+ base.KeyBindDown(args);
- if (Disabled)
+ if (Disabled || (!_enableAllKeybinds && !args.CanFocus))
{
return;
}
- var buttonEventArgs = new ButtonEventArgs(this);
+ var buttonEventArgs = new ButtonEventArgs(this, args);
OnButtonDown?.Invoke(buttonEventArgs);
var drawMode = DrawMode;
@@ -147,7 +158,7 @@ namespace Robust.Client.UserInterface.Controls
{
_pressed = !_pressed;
OnPressed?.Invoke(buttonEventArgs);
- OnToggled?.Invoke(new ButtonToggledEventArgs(Pressed, this));
+ OnToggled?.Invoke(new ButtonToggledEventArgs(Pressed, this, args));
}
else
{
@@ -162,16 +173,16 @@ namespace Robust.Client.UserInterface.Controls
}
}
- protected internal override void MouseUp(GUIMouseButtonEventArgs args)
+ protected internal override void KeyBindUp(GUIBoundKeyEventArgs args)
{
- base.MouseUp(args);
+ base.KeyBindUp(args);
if (Disabled)
{
return;
}
- var buttonEventArgs = new ButtonEventArgs(this);
+ var buttonEventArgs = new ButtonEventArgs(this, args);
OnButtonUp?.Invoke(buttonEventArgs);
var drawMode = DrawMode;
@@ -183,9 +194,9 @@ namespace Robust.Client.UserInterface.Controls
}
OnPressed?.Invoke(buttonEventArgs);
- if (ToggleMode)
+ if (ToggleMode && args.CanFocus)
{
- OnToggled?.Invoke(new ButtonToggledEventArgs(Pressed, this));
+ OnToggled?.Invoke(new ButtonToggledEventArgs(Pressed, this, args));
}
}
@@ -235,9 +246,12 @@ namespace Robust.Client.UserInterface.Controls
///
public BaseButton Button { get; }
- public ButtonEventArgs(BaseButton button)
+ public GUIBoundKeyEventArgs Event { get; }
+
+ public ButtonEventArgs(BaseButton button, GUIBoundKeyEventArgs args)
{
Button = button;
+ Event = args;
}
}
@@ -251,7 +265,7 @@ namespace Robust.Client.UserInterface.Controls
///
public bool Pressed { get; }
- public ButtonToggledEventArgs(bool pressed, BaseButton button) : base(button)
+ public ButtonToggledEventArgs(bool pressed, BaseButton button, GUIBoundKeyEventArgs args) : base(button, args)
{
Pressed = pressed;
}
diff --git a/Robust.Client/UserInterface/Controls/ItemList.cs b/Robust.Client/UserInterface/Controls/ItemList.cs
index 31ee744ec..b31c37f10 100644
--- a/Robust.Client/UserInterface/Controls/ItemList.cs
+++ b/Robust.Client/UserInterface/Controls/ItemList.cs
@@ -4,6 +4,7 @@ using System.Diagnostics.Contracts;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Input;
+using Robust.Shared.Input;
using Robust.Shared.Maths;
namespace Robust.Client.UserInterface.Controls
@@ -379,6 +380,30 @@ namespace Robust.Client.UserInterface.Controls
return size;
}
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
+ {
+ base.KeyBindDown(args);
+
+ if (SelectMode == ItemListSelectMode.None || args.Function != EngineKeyFunctions.Use)
+ {
+ return;
+ }
+
+ foreach (var item in _itemList)
+ {
+ if (item.Region == null)
+ continue;
+ if (!item.Region.Value.Contains(args.RelativePosition))
+ continue;
+ if (item.Selectable && !item.Disabled)
+ if (item.Selected)
+ Unselect(item);
+ else
+ Select(item, SelectMode == ItemListSelectMode.Single);
+ break;
+ }
+ }
+
protected internal override void MouseMove(GUIMouseMoveEventArgs args)
{
base.MouseMove(args);
@@ -406,28 +431,6 @@ namespace Robust.Client.UserInterface.Controls
_isAtBottom = _scrollBar.IsAtEnd;
}
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
- {
- base.MouseDown(args);
-
- if (SelectMode == ItemListSelectMode.None || args.Button != Mouse.Button.Left)
- {
- return;
- }
-
- foreach (var item in _itemList)
- {
- if (item.Region == null) continue;
- if (!item.Region.Value.Contains(args.RelativePosition)) continue;
- if (item.Selectable && !item.Disabled)
- if (item.Selected)
- Unselect(item);
- else
- Select(item, SelectMode == ItemListSelectMode.Single);
- break;
- }
- }
-
[Pure]
private int _getScrollSpeed()
{
diff --git a/Robust.Client/UserInterface/Controls/LineEdit.cs b/Robust.Client/UserInterface/Controls/LineEdit.cs
index 11a33976f..c766f6165 100644
--- a/Robust.Client/UserInterface/Controls/LineEdit.cs
+++ b/Robust.Client/UserInterface/Controls/LineEdit.cs
@@ -1,10 +1,14 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
+using Robust.Client.GameObjects.EntitySystems;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Input;
+using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.UserInterface;
+using Robust.Shared.Input;
+using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
@@ -82,6 +86,22 @@ namespace Robust.Client.UserInterface.Controls
}
}
+ public int CursorPos
+ {
+ set
+ {
+ if (value < 0)
+ {
+ value = 0;
+ }
+ else if (value > _text.Length)
+ {
+ value = _text.Length;
+ }
+ _cursorPosition = value;
+ }
+ }
+
public bool IgnoreNext { get; set; }
// TODO:
@@ -236,16 +256,14 @@ namespace Robust.Client.UserInterface.Controls
_updatePseudoClass();
}
- protected internal override void KeyDown(GUIKeyEventArgs args)
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
{
- base.KeyDown(args);
+ base.KeyBindDown(args);
- // Just eat all keyboard input.
- args.Handle();
-
- switch (args.Key)
+ if (!args.CanFocus)
{
- case Keyboard.Key.BackSpace:
+ if (args.Function == EngineKeyFunctions.TextBackspace)
+ {
if (_cursorPosition == 0 || !Editable)
{
return;
@@ -255,37 +273,35 @@ namespace Robust.Client.UserInterface.Controls
OnTextChanged?.Invoke(new LineEditEventArgs(this, _text));
_cursorPosition -= 1;
_updatePseudoClass();
- break;
-
- case Keyboard.Key.Left:
+ }
+ else if (args.Function == EngineKeyFunctions.TextCursorLeft)
+ {
if (_cursorPosition == 0)
{
return;
}
_cursorPosition -= 1;
- break;
-
- case Keyboard.Key.Right:
+ }
+ else if (args.Function == EngineKeyFunctions.TextCursorRight)
+ {
if (_cursorPosition == _text.Length)
{
return;
}
_cursorPosition += 1;
- break;
-
- case Keyboard.Key.NumpadEnter:
- case Keyboard.Key.Return:
+ }
+ else if (args.Function == EngineKeyFunctions.TextSubmit)
+ {
if (Editable)
{
OnTextEntered?.Invoke(new LineEditEventArgs(this, _text));
}
-
- break;
-
- case Keyboard.Key.V:
- if (Editable && args.Control)
+ }
+ else if (args.Function == EngineKeyFunctions.TextPaste)
+ {
+ if (Editable)
{
var clipboard = IoCManager.Resolve();
if (!clipboard.Available)
@@ -296,63 +312,57 @@ namespace Robust.Client.UserInterface.Controls
InsertAtCursor(clipboard.GetText());
}
-
- break;
+ }
}
- }
-
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
- {
- base.MouseDown(args);
-
- // Find closest cursor position under mouse.
- var style = _getStyleBox();
- var contentBox = style.GetContentBox(PixelSizeBox);
-
- var clickPosX = args.RelativePosition.X * UIScale;
-
- var font = _getFont();
- var index = 0;
- var chrPosX = contentBox.Left;
- var lastChrPostX = contentBox.Left;
- foreach (var chr in _text)
+ else
{
- if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
+ // Find closest cursor position under mouse.
+ var style = _getStyleBox();
+ var contentBox = style.GetContentBox(PixelSizeBox);
+
+ var clickPosX = args.RelativePosition.X * UIScale;
+
+ var font = _getFont();
+ var index = 0;
+ var chrPosX = contentBox.Left;
+ var lastChrPostX = contentBox.Left;
+ foreach (var chr in _text)
{
+ if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
+ {
+ index += 1;
+ continue;
+ }
+
+ if (chrPosX > clickPosX)
+ {
+ break;
+ }
+
+ lastChrPostX = chrPosX;
+ chrPosX += metrics.Advance;
index += 1;
- continue;
+
+ if (chrPosX > contentBox.Right)
+ {
+ break;
+ }
}
- if (chrPosX > clickPosX)
+ // Distance between the right side of the glyph overlapping the mouse and the mouse.
+ var distanceRight = chrPosX - clickPosX;
+ // Same but left side.
+ var distanceLeft = clickPosX - lastChrPostX;
+ // If the mouse is closer to the left of the glyph we lower the index one, so we select before that glyph.
+ if (distanceRight > distanceLeft)
{
- break;
+ index -= 1;
}
- lastChrPostX = chrPosX;
- chrPosX += metrics.Advance;
- index += 1;
-
- if (chrPosX > contentBox.Right)
- {
- break;
- }
+ _cursorPosition = index;
}
-
- // Distance between the right side of the glyph overlapping the mouse and the mouse.
- var distanceRight = chrPosX - clickPosX;
- // Same but left side.
- var distanceLeft = clickPosX - lastChrPostX;
- // If the mouse is closer to the left of the glyph we lower the index one, so we select before that glyph.
- if (distanceRight > distanceLeft)
- {
- index -= 1;
- }
-
- _cursorPosition = index;
-
- // Reset this so the cursor is always visible immediately after a click.
- _cursorCurrentlyLit = true;
- _cursorBlinkTimer = BlinkTime;
+ // Reset this so the cursor is always visible immediately after a keybind is pressed.
+ _resetCursorBlink();
}
protected internal override void FocusEntered()
@@ -360,8 +370,7 @@ namespace Robust.Client.UserInterface.Controls
base.FocusEntered();
// Reset this so the cursor is always visible immediately after gaining focus..
- _cursorCurrentlyLit = true;
- _cursorBlinkTimer = BlinkTime;
+ _resetCursorBlink();
}
[Pure]
@@ -420,5 +429,11 @@ namespace Robust.Client.UserInterface.Controls
Text = text;
}
}
+
+ private void _resetCursorBlink()
+ {
+ _cursorCurrentlyLit = true;
+ _cursorBlinkTimer = BlinkTime;
+ }
}
}
diff --git a/Robust.Client/UserInterface/Controls/MenuBar.cs b/Robust.Client/UserInterface/Controls/MenuBar.cs
index 112ab860c..e36ce793c 100644
--- a/Robust.Client/UserInterface/Controls/MenuBar.cs
+++ b/Robust.Client/UserInterface/Controls/MenuBar.cs
@@ -42,7 +42,7 @@ namespace Robust.Client.UserInterface.Controls
_buttons.Add(button);
_hBox.AddChild(button);
- button.OnMouseDown += _ => OpenPopupFor(button);
+ button.OnKeyBindDown += _ => OpenPopupFor(button);
button.OnMouseEntered += () =>
{
diff --git a/Robust.Client/UserInterface/Controls/ScrollBar.cs b/Robust.Client/UserInterface/Controls/ScrollBar.cs
index 074e7d675..1a4996fcc 100644
--- a/Robust.Client/UserInterface/Controls/ScrollBar.cs
+++ b/Robust.Client/UserInterface/Controls/ScrollBar.cs
@@ -2,6 +2,7 @@
using JetBrains.Annotations;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Input;
+using Robust.Shared.Input;
using Robust.Shared.Maths;
namespace Robust.Client.UserInterface.Controls
@@ -53,6 +54,38 @@ namespace Robust.Client.UserInterface.Controls
_updatePseudoClass();
}
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
+ {
+ base.KeyBindDown(args);
+
+ if (args.Function != EngineKeyFunctions.Use)
+ {
+ return;
+ }
+
+ var box = _getGrabberBox();
+ if (!box.Contains(args.RelativePosition))
+ {
+ return;
+ }
+
+ _grabData = (args.RelativePosition, Value);
+ _updatePseudoClass();
+ }
+
+ protected internal override void KeyBindUp(GUIBoundKeyEventArgs args)
+ {
+ base.KeyBindUp(args);
+
+ if (args.Function != EngineKeyFunctions.Use)
+ {
+ return;
+ }
+
+ _grabData = null;
+ _updatePseudoClass();
+ }
+
protected internal override void MouseMove(GUIMouseMoveEventArgs args)
{
if (_grabData == null)
@@ -82,34 +115,6 @@ namespace Robust.Client.UserInterface.Controls
Value = movedValue;
}
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
- {
- if (args.Button != Mouse.Button.Left)
- {
- return;
- }
-
- var box = _getGrabberBox();
- if (!box.Contains(args.RelativePosition))
- {
- return;
- }
-
- _grabData = (args.RelativePosition, Value);
- _updatePseudoClass();
- }
-
- protected internal override void MouseUp(GUIMouseButtonEventArgs args)
- {
- if (args.Button != Mouse.Button.Left)
- {
- return;
- }
-
- _grabData = null;
- _updatePseudoClass();
- }
-
[System.Diagnostics.Contracts.Pure]
private UIBox2 _getGrabberBox()
{
diff --git a/Robust.Client/UserInterface/Controls/TabContainer.cs b/Robust.Client/UserInterface/Controls/TabContainer.cs
index 9132d640f..13e966109 100644
--- a/Robust.Client/UserInterface/Controls/TabContainer.cs
+++ b/Robust.Client/UserInterface/Controls/TabContainer.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Client.Graphics;
@@ -234,11 +234,11 @@ namespace Robust.Client.UserInterface.Controls
_fixChildMargins(control);
}
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
{
- base.MouseDown(args);
+ base.KeyBindDown(args);
- if (!TabsVisible)
+ if (!TabsVisible || !args.CanFocus)
{
return;
}
diff --git a/Robust.Client/UserInterface/Controls/Tree.cs b/Robust.Client/UserInterface/Controls/Tree.cs
index 57ce8913c..a96b4a5e3 100644
--- a/Robust.Client/UserInterface/Controls/Tree.cs
+++ b/Robust.Client/UserInterface/Controls/Tree.cs
@@ -80,9 +80,14 @@ namespace Robust.Client.UserInterface.Controls
return item;
}
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
{
- base.MouseDown(args);
+ base.KeyBindDown(args);
+
+ if (!args.CanFocus)
+ {
+ return;
+ }
var item = _tryFindItemAtPosition(args.RelativePosition);
diff --git a/Robust.Client/UserInterface/CustomControls/DebugConsole.cs b/Robust.Client/UserInterface/CustomControls/DebugConsole.cs
index 069e4352c..815694e7f 100644
--- a/Robust.Client/UserInterface/CustomControls/DebugConsole.cs
+++ b/Robust.Client/UserInterface/CustomControls/DebugConsole.cs
@@ -7,6 +7,7 @@ using Robust.Client.Graphics.Drawing;
using Robust.Client.Input;
using Robust.Client.Interfaces.Console;
using Robust.Client.UserInterface.Controls;
+using Robust.Shared.Input;
using Robust.Shared.Interfaces.Resources;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
@@ -71,7 +72,7 @@ namespace Robust.Client.UserInterface.CustomControls
CommandBar = new LineEdit {PlaceHolder = "Command Here"};
boxContainer.AddChild(CommandBar);
- CommandBar.OnKeyDown += CommandBarOnOnKeyDown;
+ CommandBar.OnKeyBindDown += CommandBarOnOnKeyBindDown;
CommandBar.OnTextEntered += CommandEntered;
CommandBar.OnTextChanged += CommandBarOnOnTextChanged;
@@ -156,54 +157,55 @@ namespace Robust.Client.UserInterface.CustomControls
}
}
- private void CommandBarOnOnKeyDown(GUIKeyEventArgs obj)
+ private void CommandBarOnOnKeyBindDown(GUIBoundKeyEventArgs args)
{
- switch (obj.Key)
+ if (args.Function == EngineKeyFunctions.TextReleaseFocus)
{
- case Keyboard.Key.Up:
+ CommandBar.ReleaseKeyboardFocus();
+ args.Handle();
+ Toggle();
+ return;
+ }
+ else if (args.Function == EngineKeyFunctions.TextHistoryPrev)
+ {
+ args.Handle();
+ var current = CommandBar.Text;
+ if (!string.IsNullOrWhiteSpace(current) && _currentCommandEdited)
{
- obj.Handle();
- var current = CommandBar.Text;
- if (!string.IsNullOrWhiteSpace(current) && _currentCommandEdited)
- {
- // Block up/down if something is typed in.
- return;
- }
-
- if (_historyPosition <= 0)
- {
- return;
- }
-
- CommandBar.Text = CommandHistory[--_historyPosition];
- break;
+ // Block up/down if something is typed in.
+ return;
}
- case Keyboard.Key.Down:
+
+ if (_historyPosition <= 0)
{
- obj.Handle();
- var current = CommandBar.Text;
- if (!string.IsNullOrWhiteSpace(current) && _currentCommandEdited)
- {
- // Block up/down if something is typed in.
- return;
- }
-
- if (++_historyPosition >= CommandHistory.Count)
- {
- CommandBar.Text = "";
- _historyPosition = CommandHistory.Count;
- return;
- }
-
- CommandBar.Text = CommandHistory[_historyPosition];
- break;
+ return;
}
- case Keyboard.Key.PageDown:
+
+ CommandBar.Text = CommandHistory[--_historyPosition];
+ }
+ else if (args.Function == EngineKeyFunctions.TextHistoryNext)
+ {
+ args.Handle();
+ var current = CommandBar.Text;
+ if (!string.IsNullOrWhiteSpace(current) && _currentCommandEdited)
{
- obj.Handle();
- Output.ScrollToBottom();
- break;
+ // Block up/down if something is typed in.
+ return;
}
+
+ if (++_historyPosition >= CommandHistory.Count)
+ {
+ CommandBar.Text = "";
+ _historyPosition = CommandHistory.Count;
+ return;
+ }
+
+ CommandBar.Text = CommandHistory[_historyPosition];
+ }
+ else if (args.Function == EngineKeyFunctions.TextScrollToBottom)
+ {
+ args.Handle();
+ Output.ScrollToBottom();
}
}
diff --git a/Robust.Client/UserInterface/CustomControls/SS14Window.cs b/Robust.Client/UserInterface/CustomControls/SS14Window.cs
index 4406ab8b7..d7b3d407b 100644
--- a/Robust.Client/UserInterface/CustomControls/SS14Window.cs
+++ b/Robust.Client/UserInterface/CustomControls/SS14Window.cs
@@ -156,24 +156,34 @@ namespace Robust.Client.UserInterface.CustomControls
OnClose?.Invoke();
}
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
{
- base.MouseDown(args);
+ base.KeyBindDown(args);
+
+ if (!args.CanFocus)
+ {
+ return;
+ }
CurrentDrag = GetDragModeFor(args.RelativePosition);
if (CurrentDrag != DragMode.None)
{
- DragOffsetTopLeft = args.GlobalPosition - Position;
- DragOffsetBottomRight = Position + Size - args.GlobalPosition;
+ DragOffsetTopLeft = args.PointerLocation.Position - Position;
+ DragOffsetBottomRight = Position + Size - args.PointerLocation.Position;
}
MoveToFront();
}
- protected internal override void MouseUp(GUIMouseButtonEventArgs args)
+ protected internal override void KeyBindUp(GUIBoundKeyEventArgs args)
{
- base.MouseUp(args);
+ base.KeyBindUp(args);
+
+ if (!args.CanFocus)
+ {
+ return;
+ }
DragOffsetTopLeft = DragOffsetBottomRight = Vector2.Zero;
CurrentDrag = DragMode.None;
diff --git a/Robust.Client/UserInterface/UserInterfaceManager.cs b/Robust.Client/UserInterface/UserInterfaceManager.cs
index cc9533c23..31d974ca2 100644
--- a/Robust.Client/UserInterface/UserInterfaceManager.cs
+++ b/Robust.Client/UserInterface/UserInterfaceManager.cs
@@ -45,7 +45,7 @@ namespace Robust.Client.UserInterface
// When a control receives a mouse down it must also receive a mouse up and mouse moves, always.
// So we keep track of which control is "focused" by the mouse.
- private Control _mouseFocused;
+ private Control _controlFocused;
public Control StateRoot { get; private set; }
public Control ModalRoot { get; private set; }
@@ -80,6 +80,9 @@ namespace Robust.Client.UserInterface
_debugMonitors = new DebugMonitors(_gameTiming, _playerManager, _eyeManager, _inputManager, _stateManager, _displayManager, _netManager, _mapManager);
RootControl.AddChild(_debugMonitors);
+ _inputManager.SetInputCommand(EngineKeyFunctions.ShowDebugConsole,
+ InputCmdHandler.FromDelegate(session => DebugConsole.Toggle()));
+
_inputManager.SetInputCommand(EngineKeyFunctions.ShowDebugMonitors,
InputCmdHandler.FromDelegate(enabled: session => { DebugMonitors.Visible = true; },
disabled: session => { DebugMonitors.Visible = false; }));
@@ -88,6 +91,8 @@ namespace Robust.Client.UserInterface
InputCmdHandler.FromDelegate(
enabled: session => _rendering = false,
disabled: session => _rendering = true));
+
+ _inputManager.UIKeyBindStateChanged += OnUIKeyBindStateChanged;
}
private void _initializeCommon()
@@ -177,63 +182,72 @@ namespace Robust.Client.UserInterface
}
}
- public void MouseDown(MouseButtonEventArgs args)
+ public void KeyBindDown(BoundKeyEventArgs args)
{
- // If we have a modal open and the mouse down was outside it, close said modal.
- if (_modalStack.Count != 0)
+ var control = MouseGetControl(args.PointerLocation.Position);
+ if (args.CanFocus)
{
- var top = _modalStack[_modalStack.Count - 1];
- var offset = args.Position - top.GlobalPixelPosition;
- if (!top.HasPoint(offset / UIScale))
+ // If we have a modal open and the mouse down was outside it, close said modal.
+ if (_modalStack.Count != 0)
{
- RemoveModal(top);
- args.Handle();
+ var top = _modalStack[_modalStack.Count - 1];
+ var offset = args.PointerLocation.Position - top.GlobalPixelPosition;
+ if (!top.HasPoint(offset / UIScale))
+ {
+ RemoveModal(top);
+ return;
+ }
+ }
+
+ if (control == null)
+ {
+ ReleaseKeyboardFocus();
return;
}
+
+ _controlFocused = control;
+
+ if (_controlFocused.CanKeyboardFocus && _controlFocused.KeyboardFocusOnClick)
+ {
+ _controlFocused.GrabKeyboardFocus();
+ }
+ }
+ else if (KeyboardFocused != null)
+ {
+ control = KeyboardFocused;
}
- var control = MouseGetControl(args.Position);
if (control == null)
{
- ReleaseKeyboardFocus();
return;
}
- _mouseFocused = control;
+ var guiArgs = new GUIBoundKeyEventArgs(args.Function, args.State, args.PointerLocation, args.CanFocus,
+ args.PointerLocation.Position / UIScale - control.GlobalPosition,
+ args.PointerLocation.Position - control.GlobalPixelPosition);
- if (_mouseFocused.CanKeyboardFocus && _mouseFocused.KeyboardFocusOnClick)
+ _doGuiInput(control, guiArgs, (c, ev) => c.KeyBindDown(ev));
+
+ if (args.CanFocus)
{
- _mouseFocused.GrabKeyboardFocus();
+ args.Handle();
}
-
- var guiArgs = new GUIMouseButtonEventArgs(args.Button, args.DoubleClick, control, Mouse.ButtonMask.None,
- args.Position / UIScale, args.Position, args.Position / UIScale - control.GlobalPosition,
- args.Position - control.GlobalPixelPosition, args.Alt, args.Control, args.Shift,
- args.System);
-
- _doMouseGuiInput(control, guiArgs, (c, ev) => c.MouseDown(ev));
-
- // Always mark this as handled.
- // The only case it should not be is if we do not have a control to click on,
- // in which case we never reach this.
- args.Handle();
}
- public void MouseUp(MouseButtonEventArgs args)
+ public void KeyBindUp(BoundKeyEventArgs args)
{
- if (_mouseFocused == null)
+ var control = _controlFocused ?? KeyboardFocused ?? MouseGetControl(args.PointerLocation.Position);
+ if (control == null)
{
return;
}
- var guiArgs = new GUIMouseButtonEventArgs(args.Button, args.DoubleClick, _mouseFocused,
- Mouse.ButtonMask.None,
- args.Position / UIScale, args.Position, args.Position / UIScale - _mouseFocused.GlobalPosition,
- args.Position - _mouseFocused.GlobalPixelPosition, args.Alt, args.Control, args.Shift,
- args.System);
+ var guiArgs = new GUIBoundKeyEventArgs(args.Function, args.State, args.PointerLocation, args.CanFocus,
+ args.PointerLocation.Position / UIScale - control.GlobalPosition,
+ args.PointerLocation.Position - control.GlobalPixelPosition);
- _doMouseGuiInput(_mouseFocused, guiArgs, (c, ev) => c.MouseUp(ev));
- _mouseFocused = null;
+ _doGuiInput(control, guiArgs, (c, ev) => c.KeyBindUp(ev));
+ _controlFocused = null;
// Always mark this as handled.
// The only case it should not be is if we do not have a control to click on,
@@ -245,7 +259,7 @@ namespace Robust.Client.UserInterface
{
_resetTooltipTimer();
// Update which control is considered hovered.
- var newHovered = _mouseFocused ?? MouseGetControl(mouseMoveEventArgs.Position);
+ var newHovered = _controlFocused ?? MouseGetControl(mouseMoveEventArgs.Position);
if (newHovered != CurrentlyHovered)
{
_clearTooltip();
@@ -254,7 +268,7 @@ namespace Robust.Client.UserInterface
CurrentlyHovered?.MouseEntered();
}
- var target = _mouseFocused ?? newHovered;
+ var target = _controlFocused ?? newHovered;
if (target != null)
{
var guiArgs = new GUIMouseMoveEventArgs(mouseMoveEventArgs.Relative / UIScale,
@@ -298,43 +312,6 @@ namespace Robust.Client.UserInterface
KeyboardFocused.TextEntered(guiArgs);
}
- public void KeyDown(KeyEventArgs keyEvent)
- {
- // TODO: This is ugly.
- if (keyEvent.Key == Keyboard.Key.Tilde)
- {
- keyEvent.Handle();
- DebugConsole.Toggle();
- return;
- }
-
- if (KeyboardFocused == null)
- {
- return;
- }
-
- var guiArgs = new GUIKeyEventArgs(KeyboardFocused, keyEvent.Key, keyEvent.IsRepeat, keyEvent.Alt,
- keyEvent.Control, keyEvent.Shift, keyEvent.System);
- KeyboardFocused.KeyDown(guiArgs);
-
- if (guiArgs.Handled)
- {
- keyEvent.Handle();
- }
- }
-
- public void KeyUp(KeyEventArgs keyEvent)
- {
- if (KeyboardFocused == null)
- {
- return;
- }
-
- var guiArgs = new GUIKeyEventArgs(KeyboardFocused, keyEvent.Key, keyEvent.IsRepeat, keyEvent.Alt,
- keyEvent.Control, keyEvent.Shift, keyEvent.System);
- KeyboardFocused.KeyUp(guiArgs);
- }
-
public void DisposeAllComponents()
{
RootControl.DisposeAllChildren();
@@ -356,6 +333,7 @@ namespace Robust.Client.UserInterface
return _mouseFindControlAtPos(RootControl, coordinates);
}
+ ///
public void GrabKeyboardFocus(Control control)
{
if (control == null)
@@ -416,9 +394,9 @@ namespace Robust.Client.UserInterface
CurrentlyHovered = null;
}
- if (control == _mouseFocused)
+ if (control == _controlFocused)
{
- _mouseFocused = null;
+ _controlFocused = null;
}
}
@@ -564,6 +542,28 @@ namespace Robust.Client.UserInterface
}
}
+ private static void _doGuiInput(Control control, T guiEvent, Action action,
+ bool ignoreStop = false)
+ where T : GUIBoundKeyEventArgs
+ {
+ while (control != null)
+ {
+ if (control.MouseFilter != Control.MouseFilterMode.Ignore)
+ {
+ action(control, guiEvent);
+
+ if (guiEvent.Handled || (!ignoreStop && control.MouseFilter == Control.MouseFilterMode.Stop))
+ {
+ break;
+ }
+ }
+
+ guiEvent.RelativePosition += control.Position;
+ guiEvent.RelativePixelPosition += control.PixelPosition;
+ control = control.Parent;
+ }
+ }
+
private void _clearTooltip()
{
_tooltip.Visible = false;
@@ -633,5 +633,25 @@ namespace Robust.Client.UserInterface
{
RootControl.Size = _displayManager.ScreenSize / UIScale;
}
+
+ ///
+ /// Converts
+ ///
+ /// Event data values for a bound key state change.
+ private void OnUIKeyBindStateChanged(BoundKeyEventArgs args)
+ {
+ if (!args.CanFocus && KeyboardFocused != null)
+ {
+ args.Handle();
+ }
+ if (args.State == BoundKeyState.Down)
+ {
+ KeyBindDown(args);
+ }
+ else
+ {
+ KeyBindUp(args);
+ }
+ }
}
}
diff --git a/Robust.Client/ViewVariables/ViewVariablesPropertyControl.cs b/Robust.Client/ViewVariables/ViewVariablesPropertyControl.cs
index 883a838ce..d4dc5a54e 100644
--- a/Robust.Client/ViewVariables/ViewVariablesPropertyControl.cs
+++ b/Robust.Client/ViewVariables/ViewVariablesPropertyControl.cs
@@ -140,9 +140,14 @@ namespace Robust.Client.ViewVariables
return box;
}
- protected internal override void MouseDown(GUIMouseButtonEventArgs args)
+ protected internal override void KeyBindDown(GUIBoundKeyEventArgs args)
{
- base.MouseDown(args);
+ base.KeyBindDown(args);
+
+ if (!args.CanFocus)
+ {
+ return;
+ }
BottomContainer.Visible = !BottomContainer.Visible;
args.Handle();
diff --git a/Robust.Lite/LiteGameController.cs b/Robust.Lite/LiteGameController.cs
index 162d7c3d9..2295781a9 100644
--- a/Robust.Lite/LiteGameController.cs
+++ b/Robust.Lite/LiteGameController.cs
@@ -1,10 +1,11 @@
-using System;
+using System;
using System.Globalization;
using Robust.Client;
using Robust.Client.Input;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Graphics;
using Robust.Client.Interfaces.Graphics.ClientEye;
+using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.UserInterface;
using Robust.Shared;
@@ -38,6 +39,7 @@ namespace Robust.Lite
[Dependency] private readonly ITaskManager _taskManager;
[Dependency] private readonly ITimerManager _timerManager;
[Dependency] private readonly IUserInterfaceManagerInternal _userInterfaceManager;
+ [Dependency] private readonly IInputManager _inputManager;
#pragma warning restore 649
public bool LoadConfigAndUserData { get; set; }
@@ -96,6 +98,10 @@ namespace Robust.Lite
_userInterfaceManager.Initialize();
+ _inputManager.Initialize();
+
+ _inputManager.AddClickBind();
+
_clyde.Ready();
}
@@ -153,12 +159,12 @@ namespace Robust.Lite
public void KeyDown(KeyEventArgs keyEvent)
{
- _userInterfaceManager.KeyDown(keyEvent);
+ _inputManager.KeyDown(keyEvent);
}
public void KeyUp(KeyEventArgs keyEvent)
{
- _userInterfaceManager.KeyUp(keyEvent);
+ _inputManager.KeyUp(keyEvent);
}
public void TextEntered(TextEventArgs textEvent)
@@ -166,16 +172,6 @@ namespace Robust.Lite
_userInterfaceManager.TextEntered(textEvent);
}
- public void MouseDown(MouseButtonEventArgs mouseEvent)
- {
- _userInterfaceManager.MouseDown(mouseEvent);
- }
-
- public void MouseUp(MouseButtonEventArgs mouseButtonEventArgs)
- {
- _userInterfaceManager.MouseUp(mouseButtonEventArgs);
- }
-
public void MouseMove(MouseMoveEventArgs mouseMoveEventArgs)
{
_userInterfaceManager.MouseMove(mouseMoveEventArgs);
diff --git a/Robust.Shared/Input/BoundKeyEventArgs.cs b/Robust.Shared/Input/BoundKeyEventArgs.cs
index d11938969..9cbc927c8 100644
--- a/Robust.Shared/Input/BoundKeyEventArgs.cs
+++ b/Robust.Shared/Input/BoundKeyEventArgs.cs
@@ -23,17 +23,33 @@ namespace Robust.Shared.Input
///
public ScreenCoordinates PointerLocation { get; }
+ ///
+ /// Whether the Bound key can change the focused control.
+ ///
+ public bool CanFocus { get; internal set; }
+
+ public bool Handled { get; private set; }
+
///
/// 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)
+ public BoundKeyEventArgs(BoundKeyFunction function, BoundKeyState state, ScreenCoordinates pointerLocation, bool canFocus)
{
Function = function;
State = state;
PointerLocation = pointerLocation;
+ CanFocus = canFocus;
+ }
+
+ ///
+ /// Mark this event as handled.
+ ///
+ public void Handle()
+ {
+ Handled = true;
}
}
}
diff --git a/Robust.Shared/Input/KeyFunctions.cs b/Robust.Shared/Input/KeyFunctions.cs
index 219dfd0f5..3882f7714 100644
--- a/Robust.Shared/Input/KeyFunctions.cs
+++ b/Robust.Shared/Input/KeyFunctions.cs
@@ -18,6 +18,9 @@ namespace Robust.Shared.Input
public static readonly BoundKeyFunction MoveRight = "MoveRight";
public static readonly BoundKeyFunction Run = "Run";
+ public static readonly BoundKeyFunction Use = "Use";
+
+ public static readonly BoundKeyFunction ShowDebugConsole = "ShowDebugConsole";
public static readonly BoundKeyFunction ShowDebugMonitors = "ShowDebugMonitors";
public static readonly BoundKeyFunction HideUI = "HideUI";
public static readonly BoundKeyFunction EscapeMenu = "ShowEscapeMenu";
@@ -27,6 +30,16 @@ namespace Robust.Shared.Input
public static readonly BoundKeyFunction EditorPlaceObject = "EditorPlaceObject";
public static readonly BoundKeyFunction EditorCancelPlace = "EditorCancelPlace";
public static readonly BoundKeyFunction EditorRotateObject = "EditorRotateObject";
+
+ public static readonly BoundKeyFunction TextCursorLeft = "TextCursorLeft";
+ public static readonly BoundKeyFunction TextCursorRight = "TextCursorRight";
+ public static readonly BoundKeyFunction TextBackspace = "TextBackspace";
+ public static readonly BoundKeyFunction TextSubmit = "TextSubmit";
+ public static readonly BoundKeyFunction TextPaste = "TextPaste";
+ public static readonly BoundKeyFunction TextHistoryPrev = "TextHistoryPrev";
+ public static readonly BoundKeyFunction TextHistoryNext = "TextHistoryNext";
+ public static readonly BoundKeyFunction TextReleaseFocus = "TextReleaseFocus";
+ public static readonly BoundKeyFunction TextScrollToBottom = "TextScrollToBottom";
}
[Serializable, NetSerializable]
diff --git a/Robust.UnitTesting/Client/UserInterface/UserInterfaceManagerTest.cs b/Robust.UnitTesting/Client/UserInterface/UserInterfaceManagerTest.cs
index 75f4e773b..59debbecb 100644
--- a/Robust.UnitTesting/Client/UserInterface/UserInterfaceManagerTest.cs
+++ b/Robust.UnitTesting/Client/UserInterface/UserInterfaceManagerTest.cs
@@ -1,8 +1,9 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
using NUnit.Framework;
using Robust.Client.Input;
using Robust.Client.Interfaces.UserInterface;
using Robust.Client.UserInterface;
+using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
@@ -60,15 +61,15 @@ namespace Robust.UnitTesting.Client.UserInterface
control3.AddChild(control4);
control4.Position = new Vector2(5, 5);
- var mouseEvent = new MouseButtonEventArgs(Mouse.Button.Left, false, Mouse.ButtonMask.None,
- new Vector2(30, 30), false, false, false, false);
+ var mouseEvent = new BoundKeyEventArgs(EngineKeyFunctions.Use, BoundKeyState.Down,
+ new Robust.Shared.Map.ScreenCoordinates(30, 30), true);
var control2Fired = false;
var control3Fired = false;
- control1.OnMouseDown += _ => Assert.Fail("Control 1 should not get a mouse event.");
+ control1.OnKeyBindDown += _ => Assert.Fail("Control 1 should not get a mouse event.");
- void Control2MouseDown(GUIMouseButtonEventArgs ev)
+ void Control2MouseDown(GUIBoundKeyEventArgs ev)
{
Assert.That(control2Fired, Is.False);
Assert.That(control3Fired, Is.True);
@@ -78,9 +79,9 @@ namespace Robust.UnitTesting.Client.UserInterface
control2Fired = true;
}
- control2.OnMouseDown += Control2MouseDown;
+ control2.OnKeyBindDown += Control2MouseDown;
- control3.OnMouseDown += ev =>
+ control3.OnKeyBindDown += ev =>
{
Assert.That(control2Fired, Is.False);
Assert.That(control3Fired, Is.False);
@@ -90,9 +91,9 @@ namespace Robust.UnitTesting.Client.UserInterface
control3Fired = true;
};
- control4.OnMouseDown += _ => Assert.Fail("Control 4 should not get a mouse event.");
+ control4.OnKeyBindDown += _ => Assert.Fail("Control 4 should not get a mouse event.");
- _userInterfaceManager.MouseDown(mouseEvent);
+ _userInterfaceManager.KeyBindDown(mouseEvent);
Assert.Multiple(() =>
{
@@ -106,8 +107,8 @@ namespace Robust.UnitTesting.Client.UserInterface
control2Fired = false;
control3Fired = false;
- control2.OnMouseDown -= Control2MouseDown;
- control2.OnMouseDown += ev =>
+ control2.OnKeyBindDown -= Control2MouseDown;
+ control2.OnKeyBindDown += ev =>
{
Assert.That(control2Fired, Is.False);
Assert.That(control3Fired, Is.True);
@@ -119,7 +120,7 @@ namespace Robust.UnitTesting.Client.UserInterface
};
control2.MouseFilter = Control.MouseFilterMode.Pass;
- _userInterfaceManager.MouseDown(mouseEvent);
+ _userInterfaceManager.KeyBindDown(mouseEvent);
Assert.Multiple(() =>
{
@@ -214,10 +215,12 @@ namespace Robust.UnitTesting.Client.UserInterface
_userInterfaceManager.RootControl.ForceRunLayoutUpdate();
- var mouseEvent = new MouseButtonEventArgs(Mouse.Button.Left, false, Mouse.ButtonMask.None,
- new Vector2(30, 30), false, false, false, false);
+ var pos = new Robust.Shared.Map.ScreenCoordinates(30, 30);
- _userInterfaceManager.MouseDown(mouseEvent);
+ var mouseEvent = new GUIBoundKeyEventArgs(EngineKeyFunctions.Use, BoundKeyState.Down,
+ pos, true, pos.Position / 1 - control.GlobalPosition, pos.Position - control.GlobalPixelPosition);
+
+ _userInterfaceManager.KeyBindDown(mouseEvent);
Assert.That(_userInterfaceManager.KeyboardFocused, Is.EqualTo(control));
_userInterfaceManager.ReleaseKeyboardFocus();
@@ -240,10 +243,12 @@ namespace Robust.UnitTesting.Client.UserInterface
_userInterfaceManager.RootControl.AddChild(control);
- var mouseEvent = new MouseButtonEventArgs(Mouse.Button.Left, false, Mouse.ButtonMask.None,
- new Vector2(30, 30), false, false, false, false);
+ var pos = new Robust.Shared.Map.ScreenCoordinates(30, 30);
- _userInterfaceManager.MouseDown(mouseEvent);
+ var mouseEvent = new GUIBoundKeyEventArgs(EngineKeyFunctions.Use, BoundKeyState.Down,
+ pos, true, pos.Position / 1 - control.GlobalPosition, pos.Position - control.GlobalPixelPosition);
+
+ _userInterfaceManager.KeyBindDown(mouseEvent);
Assert.That(_userInterfaceManager.KeyboardFocused, Is.Null);
diff --git a/Robust.UnitTesting/GameControllerDummy.cs b/Robust.UnitTesting/GameControllerDummy.cs
index a6638d430..5e526e8a8 100644
--- a/Robust.UnitTesting/GameControllerDummy.cs
+++ b/Robust.UnitTesting/GameControllerDummy.cs
@@ -1,4 +1,4 @@
-using Robust.Client;
+using Robust.Client;
using Robust.Client.Input;
using Robust.Client.Interfaces;
using Robust.Shared.Timing;
@@ -37,14 +37,6 @@ namespace Robust.UnitTesting
{
}
- public void MouseDown(MouseButtonEventArgs mouseEvent)
- {
- }
-
- public void MouseUp(MouseButtonEventArgs mouseButtonEventArgs)
- {
- }
-
public void MouseMove(MouseMoveEventArgs mouseMoveEventArgs)
{
}