diff --git a/CUE.NET.csproj b/CUE.NET.csproj index d92255b..4f0102f 100644 --- a/CUE.NET.csproj +++ b/CUE.NET.csproj @@ -48,6 +48,7 @@ + diff --git a/CueSDK.cs b/CueSDK.cs index 95a1541..3034540 100644 --- a/CueSDK.cs +++ b/CueSDK.cs @@ -2,7 +2,9 @@ // ReSharper disable UnusedMember.Global using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Runtime.InteropServices; +using CUE.NET.Devices; using CUE.NET.Devices.Generic; using CUE.NET.Devices.Generic.Enums; using CUE.NET.Devices.Headset; @@ -14,7 +16,7 @@ using CUE.NET.Native; namespace CUE.NET { - public static class CueSDK + public static partial class CueSDK { #region Properties & Fields @@ -45,6 +47,11 @@ namespace CUE.NET /// public static CorsairError LastError => _CUESDK.CorsairGetLastError(); + /// + /// Gets all initialized devices managed by the CUE-SDK. + /// + public static IEnumerable InitializedDevices { get; private set; } + /// /// Gets the managed representation of a keyboard managed by the CUE-SDK. /// Note that currently only one connected keyboard is supported. @@ -155,6 +162,7 @@ namespace CUE.NET HasExclusiveAccess = true; } + IList devices = new List(); int deviceCount = _CUESDK.CorsairGetDeviceCount(); for (int i = 0; i < deviceCount; i++) { @@ -166,16 +174,16 @@ namespace CUE.NET switch (info.Type) { case CorsairDeviceType.Keyboard: - KeyboardSDK = new CorsairKeyboard(new CorsairKeyboardDeviceInfo(nativeDeviceInfo)); + devices.Add(KeyboardSDK = new CorsairKeyboard(new CorsairKeyboardDeviceInfo(nativeDeviceInfo))); break; case CorsairDeviceType.Mouse: - MouseSDK = new CorsairMouse(new CorsairMouseDeviceInfo(nativeDeviceInfo)); + devices.Add(MouseSDK = new CorsairMouse(new CorsairMouseDeviceInfo(nativeDeviceInfo))); break; case CorsairDeviceType.Headset: - HeadsetSDK = new CorsairHeadset(new CorsairHeadsetDeviceInfo(nativeDeviceInfo)); + devices.Add(HeadsetSDK = new CorsairHeadset(new CorsairHeadsetDeviceInfo(nativeDeviceInfo))); break; case CorsairDeviceType.Mousemat: - MousematSDK = new CorsairMousemat(new CorsairMousematDeviceInfo(nativeDeviceInfo)); + devices.Add(MousematSDK = new CorsairMousemat(new CorsairMousematDeviceInfo(nativeDeviceInfo))); break; // ReSharper disable once RedundantCaseLabel case CorsairDeviceType.Unknown: @@ -188,6 +196,8 @@ namespace CUE.NET Throw(error); } + InitializedDevices = new ReadOnlyCollection(devices); + IsInitialized = true; } diff --git a/CueSDKAutoUpdate.cs b/CueSDKAutoUpdate.cs new file mode 100644 index 0000000..9fe7877 --- /dev/null +++ b/CueSDKAutoUpdate.cs @@ -0,0 +1,91 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using CUE.NET.Devices; +using CUE.NET.Devices.Generic.Enums; + +namespace CUE.NET +{ + public static partial class CueSDK + { + #region Properties & Fields + + private static CancellationTokenSource _updateTokenSource; + private static CancellationToken _updateToken; + private static Task _updateTask; + + /// + /// Gets or sets the update-frequency in seconds. (Calculate by using '1f / updates per second') + /// + public static float UpdateFrequency { get; set; } = 1f / 30f; + + private static UpdateMode _updateMode = UpdateMode.Manual; + /// + /// Gets or sets the update-mode for the device. + /// + public static UpdateMode UpdateMode + { + get { return _updateMode; } + set + { + _updateMode = value; + CheckUpdateLoop(); + } + } + + #endregion + + #region Methods + + /// + /// Checks if automatic updates should occur and starts/stops the update-loop if needed. + /// + /// Thrown if the requested update-mode is not available. + private static async void CheckUpdateLoop() + { + bool shouldRun; + switch (UpdateMode) + { + case UpdateMode.Manual: + shouldRun = false; + break; + case UpdateMode.Continuous: + shouldRun = true; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + if (shouldRun && _updateTask == null) // Start task + { + _updateTokenSource?.Dispose(); + _updateTokenSource = new CancellationTokenSource(); + _updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token)); + } + else if (!shouldRun && _updateTask != null) // Stop task + { + _updateTokenSource.Cancel(); + await _updateTask; + _updateTask.Dispose(); + _updateTask = null; + } + } + + private static void UpdateLoop() + { + while (!_updateToken.IsCancellationRequested) + { + long preUpdateTicks = DateTime.Now.Ticks; + + foreach (ICueDevice device in InitializedDevices) + device.Update(); + + int sleep = (int)((UpdateFrequency * 1000f) - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f)); + if (sleep > 0) + Thread.Sleep(sleep); + } + } + + #endregion + } +} diff --git a/Devices/Generic/AbstractCueDevice.cs b/Devices/Generic/AbstractCueDevice.cs index 29410b1..aa69a43 100644 --- a/Devices/Generic/AbstractCueDevice.cs +++ b/Devices/Generic/AbstractCueDevice.cs @@ -29,35 +29,13 @@ namespace CUE.NET.Devices.Generic { #region Properties & Fields - private CancellationTokenSource _updateTokenSource; - private CancellationToken _updateToken; - private Task _updateTask; - private DateTime _lastUpdate = DateTime.Now; + private static DateTime _lastUpdate = DateTime.Now; /// /// Gets generic information provided by CUE for the device. /// public IDeviceInfo DeviceInfo { get; } - private UpdateMode _updateMode = UpdateMode.Manual; - /// - /// Gets or sets the update-mode for the device. - /// - public UpdateMode UpdateMode - { - get { return _updateMode; } - set - { - _updateMode = value; - CheckUpdateLoop(); - } - } - - /// - /// Gets or sets the update-frequency in seconds. (Calculate by using '1f / updates per second') - /// - public float UpdateFrequency { get; set; } = 1f / 30f; - /// /// Gets the rectangle containing all LEDs of the device. /// @@ -166,9 +144,7 @@ namespace CUE.NET.Devices.Generic // ReSharper disable once VirtualMemberCallInConstructor - I know, but I need this ... InitializeLeds(); - DeviceRectangle = RectangleHelper.CreateRectangleFromRectangles(((IEnumerable)this).Select(x => x.LedRectangle)); - - CheckUpdateLoop(); + DeviceRectangle = RectangleHelper.CreateRectangleFromRectangles((this).Select(x => x.LedRectangle)); } #endregion @@ -208,56 +184,6 @@ namespace CUE.NET.Devices.Generic #endregion - #region Update-Loop - - /// - /// Checks if automatic updates should occur and starts/stops the update-loop if needed. - /// - /// Thrown if the requested update-mode is not available. - protected async void CheckUpdateLoop() - { - bool shouldRun; - switch (UpdateMode) - { - case UpdateMode.Manual: - shouldRun = false; - break; - case UpdateMode.Continuous: - shouldRun = true; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - if (shouldRun && _updateTask == null) // Start task - { - _updateTokenSource?.Dispose(); - _updateTokenSource = new CancellationTokenSource(); - _updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token)); - } - else if (!shouldRun && _updateTask != null) // Stop task - { - _updateTokenSource.Cancel(); - await _updateTask; - _updateTask.Dispose(); - _updateTask = null; - } - } - - private void UpdateLoop() - { - while (!_updateToken.IsCancellationRequested) - { - long preUpdateTicks = DateTime.Now.Ticks; - Update(); - int sleep = (int)((UpdateFrequency * 1000f) - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f)); - if (sleep > 0) - Thread.Sleep(sleep); - } - } - - #endregion - #region Update /// diff --git a/Devices/ICueDevice.cs b/Devices/ICueDevice.cs index 81dcd23..75a856f 100644 --- a/Devices/ICueDevice.cs +++ b/Devices/ICueDevice.cs @@ -10,6 +10,8 @@ using CUE.NET.Groups; namespace CUE.NET.Devices { + #region EventHandler + /// /// Represents the event-handler of the Exception-event. /// @@ -45,26 +47,20 @@ namespace CUE.NET.Devices /// The arguments provided by the event. public delegate void LedsUpdatedEventHandler(object sender, LedsUpdatedEventArgs args); + #endregion + /// /// Represents a generic cue device. /// public interface ICueDevice : ILedGroup, IEnumerable { + #region Properties + /// /// Gets generic information provided by CUE for the device. /// IDeviceInfo DeviceInfo { get; } - /// - /// Gets or sets the update-mode for the device. - /// - UpdateMode UpdateMode { get; set; } - - /// - /// Gets or sets the update-frequency in seconds. (Calculate by using '1f / updates per second') - /// - float UpdateFrequency { get; set; } - /// /// Gets the rectangle containing all LEDs of the device. /// @@ -75,6 +71,10 @@ namespace CUE.NET.Devices /// IEnumerable Leds { get; } + #endregion + + #region Indexer + /// /// Gets the with the specified ID. /// @@ -97,6 +97,10 @@ namespace CUE.NET.Devices /// IEnumerable this[RectangleF referenceRect, float minOverlayPercentage = 0.5f] { get; } + #endregion + + #region Events + // ReSharper disable EventNeverSubscribedTo.Global /// @@ -126,12 +130,21 @@ namespace CUE.NET.Devices // ReSharper restore EventNeverSubscribedTo.Global + #endregion + + #region Methods + /// /// Perform an update for all dirty keys, or all keys if flushLeds is set to true. /// /// Specifies whether all keys (including clean ones) should be updated. void Update(bool flushLeds = false); + /// + /// Attaches the given ledgroup. + /// + /// The ledgroup to attach. + /// true if the ledgroup could be attached; otherwise, false. bool AttachLedGroup(ILedGroup ledGroup); /// @@ -140,5 +153,7 @@ namespace CUE.NET.Devices /// The ledgroup to detached. /// true if the ledgroup could be detached; otherwise, false. bool DetachLedGroup(ILedGroup ledGroup); + + #endregion } } diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioAnalyzerExample.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioAnalyzerExample.cs index f6c4bc2..16980ee 100644 --- a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioAnalyzerExample.cs +++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioAnalyzerExample.cs @@ -62,7 +62,7 @@ namespace Example_AudioAnalyzer_full public void Run() { - _keyboard.UpdateMode = UpdateMode.Continuous; + CueSDK.UpdateMode = UpdateMode.Continuous; // Add a black background. We want this to be semi-transparent to add some sort of fade-effect - this will smooth everything out a bit // Note that this isn't a 'real effect' since it's update-rate dependent. A real effect would do always the same thing not mather how fast the keyboard updates. _keyboard.Brush = new SolidColorBrush(Color.FromArgb(96, 0, 0, 0)); diff --git a/Examples/SimpleDevTest/Program.cs b/Examples/SimpleDevTest/Program.cs index fa5d975..80f5383 100644 --- a/Examples/SimpleDevTest/Program.cs +++ b/Examples/SimpleDevTest/Program.cs @@ -36,9 +36,13 @@ namespace SimpleDevTest CueSDK.Initialize(); Console.WriteLine("Initialized with " + CueSDK.LoadedArchitecture + "-SDK"); + CueSDK.UpdateMode = UpdateMode.Continuous; + IBrush rainbowBrush = new LinearGradientBrush(new RainbowGradient()); rainbowBrush.AddEffect(new FlashEffect()); + AddTestBrush(CueSDK.KeyboardSDK, rainbowBrush); + AddTestBrush(CueSDK.KeyboardSDK, rainbowBrush); AddTestBrush(CueSDK.KeyboardSDK, rainbowBrush); AddTestBrush(CueSDK.MouseSDK, rainbowBrush); AddTestBrush(CueSDK.HeadsetSDK, rainbowBrush); @@ -378,7 +382,6 @@ namespace SimpleDevTest { if (device == null) return; - device.UpdateMode = UpdateMode.Continuous; device.Brush = (SolidColorBrush)Color.Black; ILedGroup leds = new ListLedGroup(device, device); leds.Brush = brush;