From 0d3ed19edbaaffad81d7cd2c36edf19525b43cf9 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Mon, 21 Dec 2020 22:42:12 +0100 Subject: [PATCH] Input - Added keyboard toggle status (for caps, numlock etc) --- .../Events/ArtemisKeyboardKeyEventArgs.cs | 2 +- .../Events/ArtemisKeyboardToggleStatusArgs.cs | 26 ++++++++++++++ .../Events/InputProviderKeyboardEventArgs.cs | 1 + .../InputProviderKeyboardToggleEventArgs.cs | 24 +++++++++++++ .../Services/Input/InputProvider.cs | 23 ++++++++++++ .../Services/Input/InputService.cs | 26 ++++++++++++++ .../Input/Interfaces/IInputService.cs | 10 ++++++ .../Services/Input/KeyboardToggleStatus.cs | 36 +++++++++++++++++++ .../NativeWindowInputProvider.cs | 26 +++++++++++--- 9 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 src/Artemis.Core/Services/Input/Events/ArtemisKeyboardToggleStatusArgs.cs create mode 100644 src/Artemis.Core/Services/Input/Events/InputProviderKeyboardToggleEventArgs.cs create mode 100644 src/Artemis.Core/Services/Input/KeyboardToggleStatus.cs diff --git a/src/Artemis.Core/Services/Input/Events/ArtemisKeyboardKeyEventArgs.cs b/src/Artemis.Core/Services/Input/Events/ArtemisKeyboardKeyEventArgs.cs index c4d626494..9118906b5 100644 --- a/src/Artemis.Core/Services/Input/Events/ArtemisKeyboardKeyEventArgs.cs +++ b/src/Artemis.Core/Services/Input/Events/ArtemisKeyboardKeyEventArgs.cs @@ -21,7 +21,7 @@ namespace Artemis.Core.Services public ArtemisDevice? Device { get; } /// - /// Gets the LED that corresponds to the pressed key + /// Gets the LED that corresponds to the pressed key /// public ArtemisLed? Led { get; } diff --git a/src/Artemis.Core/Services/Input/Events/ArtemisKeyboardToggleStatusArgs.cs b/src/Artemis.Core/Services/Input/Events/ArtemisKeyboardToggleStatusArgs.cs new file mode 100644 index 000000000..f25558953 --- /dev/null +++ b/src/Artemis.Core/Services/Input/Events/ArtemisKeyboardToggleStatusArgs.cs @@ -0,0 +1,26 @@ +using System; + +namespace Artemis.Core.Services +{ + /// + /// Contains data for keyboard input events + /// + public class ArtemisKeyboardToggleStatusArgs : EventArgs + { + internal ArtemisKeyboardToggleStatusArgs(KeyboardToggleStatus oldStatus, KeyboardToggleStatus newStatus) + { + OldStatus = oldStatus; + NewStatus = newStatus; + } + + /// + /// Gets the keyboard status before the change + /// + public KeyboardToggleStatus OldStatus { get; } + + /// + /// Gets the keyboard status after the change + /// + public KeyboardToggleStatus NewStatus { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Input/Events/InputProviderKeyboardEventArgs.cs b/src/Artemis.Core/Services/Input/Events/InputProviderKeyboardEventArgs.cs index 313cd593f..f235e171c 100644 --- a/src/Artemis.Core/Services/Input/Events/InputProviderKeyboardEventArgs.cs +++ b/src/Artemis.Core/Services/Input/Events/InputProviderKeyboardEventArgs.cs @@ -8,6 +8,7 @@ namespace Artemis.Core.Services public class InputProviderKeyboardEventArgs : EventArgs { /// + /// Creates a new instance of the class /// /// The device that triggered the event /// The key that triggered the event diff --git a/src/Artemis.Core/Services/Input/Events/InputProviderKeyboardToggleEventArgs.cs b/src/Artemis.Core/Services/Input/Events/InputProviderKeyboardToggleEventArgs.cs new file mode 100644 index 000000000..db66523c0 --- /dev/null +++ b/src/Artemis.Core/Services/Input/Events/InputProviderKeyboardToggleEventArgs.cs @@ -0,0 +1,24 @@ +using System; + +namespace Artemis.Core.Services +{ + /// + /// Contains data for input provider keyboard status toggle events + /// + public class InputProviderKeyboardToggleEventArgs : EventArgs + { + /// + /// Creates a new instance of the class + /// + /// The toggle status of the keyboard + public InputProviderKeyboardToggleEventArgs(KeyboardToggleStatus keyboardToggleStatus) + { + KeyboardToggleStatus = keyboardToggleStatus; + } + + /// + /// Gets the toggle status of the keyboard + /// + public KeyboardToggleStatus KeyboardToggleStatus { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Input/InputProvider.cs b/src/Artemis.Core/Services/Input/InputProvider.cs index b71722309..b10db3d6f 100644 --- a/src/Artemis.Core/Services/Input/InputProvider.cs +++ b/src/Artemis.Core/Services/Input/InputProvider.cs @@ -8,11 +8,23 @@ namespace Artemis.Core.Services /// public abstract class InputProvider : IDisposable { + /// + /// Called when the input service requests a event + /// + public virtual void OnKeyboardToggleStatusRequested() + { + } + /// /// Occurs when the input provided has received keyboard data /// public event EventHandler? KeyboardDataReceived; + /// + /// Occurs when the input provider has received new toggle data for keyboards + /// + public event EventHandler? KeyboardToggleStatusReceived; + /// /// Occurs when the input provided has received mouse button data /// @@ -95,6 +107,17 @@ namespace Artemis.Core.Services IdentifierReceived?.Invoke(this, new InputProviderIdentifierEventArgs(identifier, deviceType)); } + /// + /// Invokes the event which the listens to as + /// long as + /// this provider is registered + /// + /// The toggle status of the keyboard + protected virtual void OnKeyboardToggleStatusReceived(KeyboardToggleStatus keyboardToggleStatus) + { + KeyboardToggleStatusReceived?.Invoke(this, new InputProviderKeyboardToggleEventArgs(keyboardToggleStatus)); + } + #region IDisposable /// diff --git a/src/Artemis.Core/Services/Input/InputService.cs b/src/Artemis.Core/Services/Input/InputService.cs index fa280e4a3..7a03343a3 100644 --- a/src/Artemis.Core/Services/Input/InputService.cs +++ b/src/Artemis.Core/Services/Input/InputService.cs @@ -36,16 +36,22 @@ namespace Artemis.Core.Services private readonly List _inputProviders = new(); + public KeyboardToggleStatus KeyboardToggleStatus { get; private set; } = new(false, false, false); + public void AddInputProvider(InputProvider inputProvider) { inputProvider.IdentifierReceived += InputProviderOnIdentifierReceived; inputProvider.KeyboardDataReceived += InputProviderOnKeyboardDataReceived; + inputProvider.KeyboardToggleStatusReceived += InputProviderOnKeyboardToggleStatusReceived; inputProvider.MouseButtonDataReceived += InputProviderOnMouseButtonDataReceived; inputProvider.MouseScrollDataReceived += InputProviderOnMouseScrollDataReceived; inputProvider.MouseMoveDataReceived += InputProviderOnMouseMoveDataReceived; _inputProviders.Add(inputProvider); + + inputProvider.OnKeyboardToggleStatusRequested(); } + public void RemoveInputProvider(InputProvider inputProvider) { if (!_inputProviders.Contains(inputProvider)) @@ -54,6 +60,7 @@ namespace Artemis.Core.Services _inputProviders.Remove(inputProvider); inputProvider.IdentifierReceived -= InputProviderOnIdentifierReceived; inputProvider.KeyboardDataReceived -= InputProviderOnKeyboardDataReceived; + inputProvider.KeyboardToggleStatusReceived -= InputProviderOnKeyboardToggleStatusReceived; inputProvider.MouseButtonDataReceived -= InputProviderOnMouseButtonDataReceived; inputProvider.MouseScrollDataReceived -= InputProviderOnMouseScrollDataReceived; inputProvider.MouseMoveDataReceived -= InputProviderOnMouseMoveDataReceived; @@ -209,6 +216,18 @@ namespace Artemis.Core.Services // _logger.Verbose("Keyboard data: LED ID: {ledId}, key: {key}, is down: {isDown}, modifiers: {modifiers}, device: {device} ", ledId, e.Key, e.IsDown, keyboardModifierKey, e.Device); } + private void InputProviderOnKeyboardToggleStatusReceived(object? sender, InputProviderKeyboardToggleEventArgs e) + { + KeyboardToggleStatus old = KeyboardToggleStatus; + if (KeyboardToggleStatus.CapsLock == e.KeyboardToggleStatus.CapsLock && + KeyboardToggleStatus.NumLock == e.KeyboardToggleStatus.NumLock && + KeyboardToggleStatus.ScrollLock == e.KeyboardToggleStatus.ScrollLock) + return; + + KeyboardToggleStatus = e.KeyboardToggleStatus; + OnKeyboardToggleStatusChanged(new ArtemisKeyboardToggleStatusArgs(old, KeyboardToggleStatus)); + } + private bool UpdatePressedKeys(ArtemisDevice? device, KeyboardKey key, bool isDown) { if (device != null) @@ -318,6 +337,8 @@ namespace Artemis.Core.Services public event EventHandler? KeyboardKeyUpDown; public event EventHandler? KeyboardKeyDown; public event EventHandler? KeyboardKeyUp; + public event EventHandler? KeyboardToggleStatusChanged; + public event EventHandler? MouseButtonUpDown; public event EventHandler? MouseButtonDown; public event EventHandler? MouseButtonUp; @@ -340,6 +361,11 @@ namespace Artemis.Core.Services KeyboardKeyUp?.Invoke(this, e); } + protected virtual void OnKeyboardToggleStatusChanged(ArtemisKeyboardToggleStatusArgs e) + { + KeyboardToggleStatusChanged?.Invoke(this, e); + } + protected virtual void OnMouseButtonUpDown(ArtemisMouseButtonUpDownEventArgs e) { MouseButtonUpDown?.Invoke(this, e); diff --git a/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs b/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs index df20fc14f..46c042e1f 100644 --- a/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs +++ b/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs @@ -7,6 +7,11 @@ namespace Artemis.Core.Services /// public interface IInputService : IArtemisService, IDisposable { + /// + /// Gets the current keyboard toggle status + /// + KeyboardToggleStatus KeyboardToggleStatus { get; } + /// /// Adds an input provided /// @@ -47,6 +52,11 @@ namespace Artemis.Core.Services /// event EventHandler KeyboardKeyUp; + /// + /// Occurs whenever a one or more of the keyboard toggle statuses changed + /// + event EventHandler KeyboardToggleStatusChanged; + /// /// Occurs whenever a button on a mouse was pressed or released /// diff --git a/src/Artemis.Core/Services/Input/KeyboardToggleStatus.cs b/src/Artemis.Core/Services/Input/KeyboardToggleStatus.cs new file mode 100644 index 000000000..b0d366bd3 --- /dev/null +++ b/src/Artemis.Core/Services/Input/KeyboardToggleStatus.cs @@ -0,0 +1,36 @@ +namespace Artemis.Core.Services +{ + /// + /// Represents the status of a keyboards special toggles + /// + public readonly struct KeyboardToggleStatus + { + /// + /// Creates a new + /// + /// A boolean indicating whether num lock is on + /// A boolean indicating whether caps lock is on + /// A boolean indicating whether scroll lock is on + public KeyboardToggleStatus(bool numLock, bool capsLock, bool scrollLock) + { + NumLock = numLock; + CapsLock = capsLock; + ScrollLock = scrollLock; + } + + /// + /// Gets a boolean indicating whether num lock is on + /// + public bool NumLock { get; } + + /// + /// Gets a boolean indicating whether caps lock is on + /// + public bool CapsLock { get; } + + /// + /// Gets a boolean indicating whether scroll lock is on + /// + public bool ScrollLock { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/InputProviders/NativeWindowInputProvider.cs b/src/Artemis.UI/InputProviders/NativeWindowInputProvider.cs index 804a6c3b4..38da46058 100644 --- a/src/Artemis.UI/InputProviders/NativeWindowInputProvider.cs +++ b/src/Artemis.UI/InputProviders/NativeWindowInputProvider.cs @@ -14,9 +14,9 @@ namespace Artemis.UI.InputProviders public class NativeWindowInputProvider : InputProvider { private const int WM_INPUT = 0x00FF; + private readonly IInputService _inputService; private readonly ILogger _logger; - private readonly IInputService _inputService; private DateTime _lastMouseUpdate; private SpongeWindow _sponge; @@ -32,6 +32,16 @@ namespace Artemis.UI.InputProviders RawInputDevice.RegisterDevice(HidUsageAndPage.Mouse, RawInputDeviceFlags.InputSink, _sponge.Handle); } + #region Overrides of InputProvider + + /// + public override void OnKeyboardToggleStatusRequested() + { + UpdateToggleStatus(); + } + + #endregion + #region IDisposable /// @@ -88,7 +98,6 @@ namespace Artemis.UI.InputProviders ArtemisDevice device = null; if (identifier != null) - { try { device = _inputService.GetDeviceByIdentifier(this, identifier, InputDeviceType.Keyboard); @@ -97,7 +106,6 @@ namespace Artemis.UI.InputProviders { _logger.Warning(e, "Failed to retrieve input device by its identifier"); } - } // Duplicate keys with different positions can be identified by the LeftKey flag (even though its set of the key that's physically on the right) if (keyboardData.Keyboard.Flags == RawKeyboardFlags.LeftKey || keyboardData.Keyboard.Flags == (RawKeyboardFlags.LeftKey | RawKeyboardFlags.Up)) @@ -118,6 +126,16 @@ namespace Artemis.UI.InputProviders keyboardData.Keyboard.Flags != (RawKeyboardFlags.Up | RawKeyboardFlags.RightKey); OnKeyboardDataReceived(device, key, isDown); + UpdateToggleStatus(); + } + + private void UpdateToggleStatus() + { + OnKeyboardToggleStatusReceived(new KeyboardToggleStatus( + Keyboard.IsKeyToggled(Key.NumLock), + Keyboard.IsKeyToggled(Key.CapsLock), + Keyboard.IsKeyToggled(Key.Scroll) + )); } #endregion @@ -142,7 +160,6 @@ namespace Artemis.UI.InputProviders ArtemisDevice device = null; string identifier = data.Device?.DevicePath; if (identifier != null) - { try { device = _inputService.GetDeviceByIdentifier(this, identifier, InputDeviceType.Keyboard); @@ -151,7 +168,6 @@ namespace Artemis.UI.InputProviders { _logger.Warning(e, "Failed to retrieve input device by its identifier"); } - } // Debug.WriteLine($"Buttons: {data.Mouse.Buttons}, Data: {data.Mouse.ButtonData}, Flags: {data.Mouse.Flags}, XY: {data.Mouse.LastX},{data.Mouse.LastY}");