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) { }