mirror of
https://github.com/DarthAffe/CUE.NET.git
synced 2025-12-13 00:58:31 +00:00
Merge pull request #21 from DarthAffe/Development
Merge effect engine to resolve #11
This commit is contained in:
commit
e3c885b664
@ -55,10 +55,15 @@
|
|||||||
<Compile Include="Devices\Keyboard\Brushes\RadialGradientBrush.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\RadialGradientBrush.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Brushes\RandomColorBrush.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\RandomColorBrush.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Brushes\SolidColorBrush.cs" />
|
<Compile Include="Devices\Keyboard\Brushes\SolidColorBrush.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Effects\AbstractEffect.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Effects\FlashEffect.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Effects\IEffect.cs" />
|
||||||
|
<Compile Include="Devices\Keyboard\Effects\EffectTimeContainer.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Enums\CorsairLogicalKeyboardLayout.cs" />
|
<Compile Include="Devices\Keyboard\Enums\CorsairLogicalKeyboardLayout.cs" />
|
||||||
<Compile Include="Devices\Headset\Enums\CorsairHeadsetLedId.cs" />
|
<Compile Include="Devices\Headset\Enums\CorsairHeadsetLedId.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Enums\CorsairKeyboardKeyId.cs" />
|
<Compile Include="Devices\Keyboard\Enums\CorsairKeyboardKeyId.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Enums\CorsairPhysicalKeyboardLayout.cs" />
|
<Compile Include="Devices\Keyboard\Enums\CorsairPhysicalKeyboardLayout.cs" />
|
||||||
|
<Compile Include="Devices\Generic\Enums\UpdateMode.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Keys\BaseKeyGroup.cs" />
|
<Compile Include="Devices\Keyboard\Keys\BaseKeyGroup.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Keys\IKeyGroup.cs" />
|
<Compile Include="Devices\Keyboard\Keys\IKeyGroup.cs" />
|
||||||
<Compile Include="Devices\Keyboard\Keys\RectangleKeyGroup.cs" />
|
<Compile Include="Devices\Keyboard\Keys\RectangleKeyGroup.cs" />
|
||||||
|
|||||||
@ -3,18 +3,40 @@ using System.Collections.Generic;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CUE.NET.Devices.Generic.Enums;
|
||||||
using CUE.NET.Native;
|
using CUE.NET.Native;
|
||||||
|
|
||||||
namespace CUE.NET.Devices.Generic
|
namespace CUE.NET.Devices.Generic
|
||||||
{
|
{
|
||||||
public abstract class AbstractCueDevice : ICueDevice
|
public abstract class AbstractCueDevice : ICueDevice
|
||||||
{
|
{
|
||||||
|
private UpdateMode _updateMode = UpdateMode.AutoOnEffect;
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
public IDeviceInfo DeviceInfo { get; }
|
public IDeviceInfo DeviceInfo { get; }
|
||||||
|
|
||||||
|
public UpdateMode UpdateMode
|
||||||
|
{
|
||||||
|
get { return _updateMode; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_updateMode = value;
|
||||||
|
CheckUpdateLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public float UpdateFrequency { get; set; } = 1f / 30f;
|
||||||
|
|
||||||
private Dictionary<int, CorsairLed> Leds { get; } = new Dictionary<int, CorsairLed>();
|
private Dictionary<int, CorsairLed> Leds { get; } = new Dictionary<int, CorsairLed>();
|
||||||
|
|
||||||
|
protected abstract bool HasEffect { get; }
|
||||||
|
|
||||||
|
private CancellationTokenSource _updateTokenSource;
|
||||||
|
private CancellationToken _updateToken;
|
||||||
|
private Task _updateTask;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
@ -22,6 +44,8 @@ namespace CUE.NET.Devices.Generic
|
|||||||
protected AbstractCueDevice(IDeviceInfo info)
|
protected AbstractCueDevice(IDeviceInfo info)
|
||||||
{
|
{
|
||||||
this.DeviceInfo = info;
|
this.DeviceInfo = info;
|
||||||
|
|
||||||
|
CheckUpdateLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -36,16 +60,61 @@ namespace CUE.NET.Devices.Generic
|
|||||||
return Leds[ledId];
|
return Leds[ledId];
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void UpdateLeds(bool forceUpdate = false)
|
protected async void CheckUpdateLoop()
|
||||||
{
|
{
|
||||||
IList<KeyValuePair<int, CorsairLed>> ledsToUpdate = (forceUpdate ? Leds : Leds.Where(x => x.Value.IsDirty)).ToList();
|
bool shouldRun;
|
||||||
|
switch (UpdateMode)
|
||||||
|
{
|
||||||
|
case UpdateMode.Manual:
|
||||||
|
shouldRun = false;
|
||||||
|
break;
|
||||||
|
case UpdateMode.AutoOnEffect:
|
||||||
|
shouldRun = HasEffect;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Update(bool flushLeds = false)
|
||||||
|
{
|
||||||
|
IList<KeyValuePair<int, CorsairLed>> ledsToUpdate = (flushLeds ? Leds : Leds.Where(x => x.Value.IsDirty)).ToList();
|
||||||
|
|
||||||
foreach (CorsairLed led in Leds.Values)
|
foreach (CorsairLed led in Leds.Values)
|
||||||
led.Update();
|
led.Update();
|
||||||
|
|
||||||
UpdateLeds(ledsToUpdate);
|
UpdateLeds(ledsToUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateLeds(ICollection<KeyValuePair<int, CorsairLed>> ledsToUpdate)
|
private static void UpdateLeds(ICollection<KeyValuePair<int, CorsairLed>> ledsToUpdate)
|
||||||
{
|
{
|
||||||
ledsToUpdate = ledsToUpdate.Where(x => x.Value.Color != Color.Transparent).ToList();
|
ledsToUpdate = ledsToUpdate.Where(x => x.Value.Color != Color.Transparent).ToList();
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
using System.Drawing;
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
using CUE.NET.Helper;
|
using CUE.NET.Helper;
|
||||||
|
|
||||||
namespace CUE.NET.Devices.Generic
|
namespace CUE.NET.Devices.Generic
|
||||||
@ -28,8 +32,6 @@ namespace CUE.NET.Devices.Generic
|
|||||||
|
|
||||||
public bool IsLocked { get; set; } = false;
|
public bool IsLocked { get; set; } = false;
|
||||||
|
|
||||||
//TODO DarthAffe 19.09.2015: Add effects and stuff
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|||||||
9
Devices/Generic/Enums/UpdateMode.cs
Normal file
9
Devices/Generic/Enums/UpdateMode.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace CUE.NET.Devices.Generic.Enums
|
||||||
|
{
|
||||||
|
public enum UpdateMode
|
||||||
|
{
|
||||||
|
Manual,
|
||||||
|
AutoOnEffect,
|
||||||
|
Continuous
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,8 @@ namespace CUE.NET.Devices.Headset
|
|||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
|
protected override bool HasEffect => false;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
namespace CUE.NET.Devices
|
using CUE.NET.Devices.Generic.Enums;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices
|
||||||
{
|
{
|
||||||
public interface ICueDevice
|
public interface ICueDevice
|
||||||
{
|
{
|
||||||
IDeviceInfo DeviceInfo { get; }
|
IDeviceInfo DeviceInfo { get; }
|
||||||
|
|
||||||
void UpdateLeds(bool forceUpdate = false);
|
UpdateMode UpdateMode { get; set; }
|
||||||
|
|
||||||
|
float UpdateFrequency { get; set; }
|
||||||
|
|
||||||
|
void Update(bool flushLeds = false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
// ReSharper disable MemberCanBeProtected.Global
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@ -14,10 +16,10 @@ namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
|||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public AbstractGradient()
|
protected AbstractGradient()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public AbstractGradient(params GradientStop[] gradientStops)
|
protected AbstractGradient(params GradientStop[] gradientStops)
|
||||||
{
|
{
|
||||||
foreach (GradientStop gradientStop in gradientStops)
|
foreach (GradientStop gradientStop in gradientStops)
|
||||||
GradientStops.Add(gradientStop);
|
GradientStops.Add(gradientStop);
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
using System.Drawing;
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
namespace CUE.NET.Devices.Keyboard.Brushes.Gradient
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// ReSharper disable CollectionNeverUpdated.Global
|
// ReSharper disable CollectionNeverUpdated.Global
|
||||||
// ReSharper disable MemberCanBePrivate.Global
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using CUE.NET.Devices.Keyboard.Brushes.Gradient;
|
using CUE.NET.Devices.Keyboard.Brushes.Gradient;
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
using System;
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using CUE.NET.Devices.Keyboard.Brushes.Gradient;
|
using CUE.NET.Devices.Keyboard.Brushes.Gradient;
|
||||||
using CUE.NET.Helper;
|
using CUE.NET.Helper;
|
||||||
@ -39,6 +42,7 @@ namespace CUE.NET.Devices.Keyboard.Brushes
|
|||||||
PointF centerPoint = new PointF(rectangle.X + rectangle.Width * Center.X, rectangle.Y + rectangle.Height * Center.Y);
|
PointF centerPoint = new PointF(rectangle.X + rectangle.Width * Center.X, rectangle.Y + rectangle.Height * Center.Y);
|
||||||
|
|
||||||
// Calculate the distance to the farthest point from the center as reference (this has to be a corner)
|
// Calculate the distance to the farthest point from the center as reference (this has to be a corner)
|
||||||
|
// ReSharper disable once RedundantCast - never trust this ...
|
||||||
float refDistance = (float)Math.Max(Math.Max(Math.Max(GradientHelper.CalculateDistance(rectangle.Location, centerPoint),
|
float refDistance = (float)Math.Max(Math.Max(Math.Max(GradientHelper.CalculateDistance(rectangle.Location, centerPoint),
|
||||||
GradientHelper.CalculateDistance(new PointF(rectangle.X + rectangle.Width, rectangle.Y), centerPoint)),
|
GradientHelper.CalculateDistance(new PointF(rectangle.X + rectangle.Width, rectangle.Y), centerPoint)),
|
||||||
GradientHelper.CalculateDistance(new PointF(rectangle.X, rectangle.Y + rectangle.Height), centerPoint)),
|
GradientHelper.CalculateDistance(new PointF(rectangle.X, rectangle.Y + rectangle.Height), centerPoint)),
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
using System;
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
@ -7,6 +11,7 @@ using System.Linq;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using CUE.NET.Devices.Generic;
|
using CUE.NET.Devices.Generic;
|
||||||
using CUE.NET.Devices.Keyboard.Brushes;
|
using CUE.NET.Devices.Keyboard.Brushes;
|
||||||
|
using CUE.NET.Devices.Keyboard.Effects;
|
||||||
using CUE.NET.Devices.Keyboard.Enums;
|
using CUE.NET.Devices.Keyboard.Enums;
|
||||||
using CUE.NET.Devices.Keyboard.Keys;
|
using CUE.NET.Devices.Keyboard.Keys;
|
||||||
using CUE.NET.Helper;
|
using CUE.NET.Helper;
|
||||||
@ -18,11 +23,8 @@ namespace CUE.NET.Devices.Keyboard
|
|||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
public CorsairKeyboardDeviceInfo KeyboardDeviceInfo { get; }
|
#region Indexer
|
||||||
|
|
||||||
public RectangleF KeyboardRectangle { get; private set; }
|
|
||||||
|
|
||||||
private Dictionary<CorsairKeyboardKeyId, CorsairKey> _keys = new Dictionary<CorsairKeyboardKeyId, CorsairKey>();
|
|
||||||
public CorsairKey this[CorsairKeyboardKeyId keyId]
|
public CorsairKey this[CorsairKeyboardKeyId keyId]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -30,32 +32,34 @@ namespace CUE.NET.Devices.Keyboard
|
|||||||
CorsairKey key;
|
CorsairKey key;
|
||||||
return _keys.TryGetValue(keyId, out key) ? key : null;
|
return _keys.TryGetValue(keyId, out key) ? key : null;
|
||||||
}
|
}
|
||||||
private set { throw new NotSupportedException(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CorsairKey this[char key]
|
public CorsairKey this[char key] => this[_CUESDK.CorsairGetLedIdForKeyName(key)];
|
||||||
{
|
|
||||||
get { return this[_CUESDK.CorsairGetLedIdForKeyName(key)]; }
|
|
||||||
private set { throw new NotSupportedException(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public CorsairKey this[PointF location]
|
public CorsairKey this[PointF location] => _keys.Values.FirstOrDefault(x => x.KeyRectangle.Contains(location));
|
||||||
{
|
|
||||||
get { return _keys.Values.FirstOrDefault(x => x.KeyRectangle.Contains(location)); }
|
|
||||||
private set { throw new NotSupportedException(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<CorsairKey> this[RectangleF referenceRect, float minOverlayPercentage = 0.5f]
|
public IEnumerable<CorsairKey> this[RectangleF referenceRect, float minOverlayPercentage = 0.5f] => _keys.Values.Where(x => RectangleHelper.CalculateIntersectPercentage(x.KeyRectangle, referenceRect) >= minOverlayPercentage);
|
||||||
{
|
|
||||||
get { return _keys.Values.Where(x => RectangleHelper.CalculateIntersectPercentage(x.KeyRectangle, referenceRect) >= minOverlayPercentage); }
|
|
||||||
private set { throw new NotSupportedException(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private readonly LinkedList<IKeyGroup> _keyGroups = new LinkedList<IKeyGroup>();
|
||||||
|
private readonly LinkedList<EffectTimeContainer> _effects = new LinkedList<EffectTimeContainer>();
|
||||||
|
|
||||||
|
private Dictionary<CorsairKeyboardKeyId, CorsairKey> _keys = new Dictionary<CorsairKeyboardKeyId, CorsairKey>();
|
||||||
public IEnumerable<CorsairKey> Keys => new ReadOnlyCollection<CorsairKey>(_keys.Values.ToList());
|
public IEnumerable<CorsairKey> Keys => new ReadOnlyCollection<CorsairKey>(_keys.Values.ToList());
|
||||||
|
|
||||||
|
public CorsairKeyboardDeviceInfo KeyboardDeviceInfo { get; }
|
||||||
|
public RectangleF KeyboardRectangle { get; private set; }
|
||||||
public IBrush Brush { get; set; }
|
public IBrush Brush { get; set; }
|
||||||
|
|
||||||
private readonly IList<IKeyGroup> _keyGroups = new List<IKeyGroup>();
|
protected override bool HasEffect
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_effects)
|
||||||
|
return _effects.Any();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -74,21 +78,62 @@ namespace CUE.NET.Devices.Keyboard
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
public override void UpdateLeds(bool forceUpdate = false)
|
#region Update
|
||||||
{
|
|
||||||
// Apply all KeyGroups
|
|
||||||
|
|
||||||
|
public override void Update(bool flushLeds = false)
|
||||||
|
{
|
||||||
|
UpdateKeyGroups();
|
||||||
|
UpdateEffects();
|
||||||
|
|
||||||
|
// Perform 'real' update
|
||||||
|
base.Update(flushLeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEffects()
|
||||||
|
{
|
||||||
|
List<IEffect> effectsToRemove = new List<IEffect>();
|
||||||
|
lock (_effects)
|
||||||
|
{
|
||||||
|
long currentTicks = DateTime.Now.Ticks;
|
||||||
|
foreach (EffectTimeContainer effect in _effects)
|
||||||
|
{
|
||||||
|
float deltaTime;
|
||||||
|
if (effect.TicksAtLastUpdate < 0)
|
||||||
|
{
|
||||||
|
effect.TicksAtLastUpdate = currentTicks;
|
||||||
|
deltaTime = 0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
deltaTime = (currentTicks - effect.TicksAtLastUpdate) / 10000000f;
|
||||||
|
|
||||||
|
effect.TicksAtLastUpdate = currentTicks;
|
||||||
|
effect.Effect.Update(deltaTime);
|
||||||
|
|
||||||
|
ApplyBrush((effect.Effect.KeyList ?? this).ToList(), effect.Effect.EffectBrush);
|
||||||
|
|
||||||
|
if (effect.Effect.IsDone)
|
||||||
|
effectsToRemove.Add(effect.Effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (IEffect effect in effectsToRemove)
|
||||||
|
DetachEffect(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateKeyGroups()
|
||||||
|
{
|
||||||
if (Brush != null)
|
if (Brush != null)
|
||||||
ApplyBrush(this.ToList(), Brush);
|
ApplyBrush(this.ToList(), Brush);
|
||||||
|
|
||||||
//TODO DarthAffe 20.09.2015: Add some sort of priority
|
lock (_keyGroups)
|
||||||
foreach (IKeyGroup keyGroup in _keyGroups)
|
{
|
||||||
ApplyBrush(keyGroup.Keys.ToList(), keyGroup.Brush);
|
//TODO DarthAffe 20.09.2015: Add some sort of priority
|
||||||
|
foreach (IKeyGroup keyGroup in _keyGroups)
|
||||||
// Perform 'real' update
|
ApplyBrush(keyGroup.Keys.ToList(), keyGroup.Brush);
|
||||||
base.UpdateLeds(forceUpdate);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once MemberCanBeMadeStatic.Local - idc
|
||||||
private void ApplyBrush(ICollection<CorsairKey> keys, IBrush brush)
|
private void ApplyBrush(ICollection<CorsairKey> keys, IBrush brush)
|
||||||
{
|
{
|
||||||
RectangleF brushRectangle = RectangleHelper.CreateRectangleFromRectangles(keys.Select(x => x.KeyRectangle));
|
RectangleF brushRectangle = RectangleHelper.CreateRectangleFromRectangles(keys.Select(x => x.KeyRectangle));
|
||||||
@ -96,20 +141,68 @@ namespace CUE.NET.Devices.Keyboard
|
|||||||
key.Led.Color = brush.GetColorAtPoint(brushRectangle, key.KeyRectangle.GetCenter());
|
key.Led.Color = brush.GetColorAtPoint(brushRectangle, key.KeyRectangle.GetCenter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public bool AttachKeyGroup(IKeyGroup keyGroup)
|
public bool AttachKeyGroup(IKeyGroup keyGroup)
|
||||||
{
|
{
|
||||||
if (keyGroup == null || _keyGroups.Contains(keyGroup)) return false;
|
lock (_keyGroups)
|
||||||
|
{
|
||||||
|
if (keyGroup == null || _keyGroups.Contains(keyGroup)) return false;
|
||||||
|
|
||||||
_keyGroups.Add(keyGroup);
|
_keyGroups.AddLast(keyGroup);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DetachKeyGroup(IKeyGroup keyGroup)
|
public bool DetachKeyGroup(IKeyGroup keyGroup)
|
||||||
{
|
{
|
||||||
if (keyGroup == null || !_keyGroups.Contains(keyGroup)) return false;
|
lock (_keyGroups)
|
||||||
|
{
|
||||||
|
if (keyGroup == null) return false;
|
||||||
|
|
||||||
_keyGroups.Remove(keyGroup);
|
LinkedListNode<IKeyGroup> node = _keyGroups.Find(keyGroup);
|
||||||
return true;
|
if (node == null) return false;
|
||||||
|
|
||||||
|
_keyGroups.Remove(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AttachEffect(IEffect effect)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
lock (_effects)
|
||||||
|
{
|
||||||
|
if (effect != null && _effects.All(x => x.Effect != effect))
|
||||||
|
{
|
||||||
|
effect.OnAttach();
|
||||||
|
_effects.AddLast(new EffectTimeContainer(effect, -1));
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckUpdateLoop();
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DetachEffect(IEffect effect)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
lock (_effects)
|
||||||
|
{
|
||||||
|
if (effect != null)
|
||||||
|
{
|
||||||
|
EffectTimeContainer val = _effects.FirstOrDefault(x => x.Effect == effect);
|
||||||
|
if (val != null)
|
||||||
|
{
|
||||||
|
effect.OnDetach();
|
||||||
|
_effects.Remove(val);
|
||||||
|
retVal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CheckUpdateLoop();
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeKeys()
|
private void InitializeKeys()
|
||||||
|
|||||||
39
Devices/Keyboard/Effects/AbstractEffect.cs
Normal file
39
Devices/Keyboard/Effects/AbstractEffect.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using CUE.NET.Devices.Keyboard.Brushes;
|
||||||
|
using CUE.NET.Devices.Keyboard.Keys;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Effects
|
||||||
|
{
|
||||||
|
public abstract class AbstractEffect : IEffect
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public abstract IBrush EffectBrush { get; }
|
||||||
|
|
||||||
|
public IEnumerable<CorsairKey> KeyList { get; protected set; }
|
||||||
|
|
||||||
|
public bool IsDone { get; protected set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public void SetTarget(IKeyGroup keyGroup)
|
||||||
|
{
|
||||||
|
KeyList = keyGroup.Keys.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void Update(float deltaTime);
|
||||||
|
|
||||||
|
public virtual void OnAttach()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public virtual void OnDetach()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Devices/Keyboard/Effects/EffectTimeContainer.cs
Normal file
26
Devices/Keyboard/Effects/EffectTimeContainer.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Effects
|
||||||
|
{
|
||||||
|
internal class EffectTimeContainer
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
internal IEffect Effect { get; set; }
|
||||||
|
|
||||||
|
internal long TicksAtLastUpdate { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
internal EffectTimeContainer(IEffect effect, long ticksAtLastUpdate)
|
||||||
|
{
|
||||||
|
this.Effect = effect;
|
||||||
|
this.TicksAtLastUpdate = ticksAtLastUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
126
Devices/Keyboard/Effects/FlashEffect.cs
Normal file
126
Devices/Keyboard/Effects/FlashEffect.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using CUE.NET.Devices.Keyboard.Brushes;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Effects
|
||||||
|
{
|
||||||
|
public class FlashEffect : AbstractEffect
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public override IBrush EffectBrush { get; }
|
||||||
|
|
||||||
|
// Settings are close to a synthesizer envelope (sustain is different for consequent naming): https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope
|
||||||
|
public float Attack { get; set; } = 0.2f;
|
||||||
|
public float Decay { get; set; } = 0f;
|
||||||
|
public float Sustain { get; set; } = 0.3f;
|
||||||
|
public float Release { get; set; } = 0.2f;
|
||||||
|
|
||||||
|
public float SustainValue { get; set; } = 1f;
|
||||||
|
public float AttackValue { get; set; } = 1f;
|
||||||
|
|
||||||
|
public float Interval { get; set; } = 1f;
|
||||||
|
|
||||||
|
public int Repetitions { get; set; } = 0;
|
||||||
|
|
||||||
|
private ADSRPhase _currentPhase;
|
||||||
|
private float _currentPhaseValue;
|
||||||
|
private int _repetitionCount;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public FlashEffect(Color flashColor)
|
||||||
|
: this(new SolidColorBrush(flashColor))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public FlashEffect(IBrush effectBrush)
|
||||||
|
{
|
||||||
|
this.EffectBrush = effectBrush;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public override void Update(float deltaTime)
|
||||||
|
{
|
||||||
|
_currentPhaseValue -= deltaTime;
|
||||||
|
|
||||||
|
// Using ifs instead of a switch allows to skip phases with time 0.
|
||||||
|
|
||||||
|
if (_currentPhase == ADSRPhase.Attack)
|
||||||
|
if (_currentPhaseValue > 0f)
|
||||||
|
EffectBrush.Opacity = Math.Min(1f, (Attack - _currentPhaseValue) / Attack) * AttackValue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentPhaseValue = Decay;
|
||||||
|
_currentPhase = ADSRPhase.Decay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentPhase == ADSRPhase.Decay)
|
||||||
|
if (_currentPhaseValue > 0f)
|
||||||
|
EffectBrush.Opacity = SustainValue + (Math.Min(1f, _currentPhaseValue / Decay) * (AttackValue - SustainValue));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentPhaseValue = Sustain;
|
||||||
|
_currentPhase = ADSRPhase.Sustain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentPhase == ADSRPhase.Sustain)
|
||||||
|
if (_currentPhaseValue > 0f)
|
||||||
|
EffectBrush.Opacity = SustainValue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentPhaseValue = Release;
|
||||||
|
_currentPhase = ADSRPhase.Release;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentPhase == ADSRPhase.Release)
|
||||||
|
if (_currentPhaseValue > 0f)
|
||||||
|
EffectBrush.Opacity = Math.Min(1f, _currentPhaseValue / Release) * SustainValue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentPhaseValue = Interval;
|
||||||
|
_currentPhase = ADSRPhase.Pause;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentPhase == ADSRPhase.Pause)
|
||||||
|
if (_currentPhaseValue > 0f)
|
||||||
|
EffectBrush.Opacity = 0f;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (++_repetitionCount >= Repetitions && Repetitions > 0)
|
||||||
|
IsDone = true;
|
||||||
|
_currentPhaseValue = Attack;
|
||||||
|
_currentPhase = ADSRPhase.Attack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnAttach()
|
||||||
|
{
|
||||||
|
base.OnAttach();
|
||||||
|
|
||||||
|
_currentPhase = ADSRPhase.Attack;
|
||||||
|
_currentPhaseValue = Attack;
|
||||||
|
_repetitionCount = 0;
|
||||||
|
EffectBrush.Opacity = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
private enum ADSRPhase
|
||||||
|
{
|
||||||
|
Attack,
|
||||||
|
Decay,
|
||||||
|
Sustain,
|
||||||
|
Release,
|
||||||
|
Pause
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Devices/Keyboard/Effects/IEffect.cs
Normal file
29
Devices/Keyboard/Effects/IEffect.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using CUE.NET.Devices.Keyboard.Brushes;
|
||||||
|
using CUE.NET.Devices.Keyboard.Keys;
|
||||||
|
|
||||||
|
namespace CUE.NET.Devices.Keyboard.Effects
|
||||||
|
{
|
||||||
|
public interface IEffect
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
IBrush EffectBrush { get; }
|
||||||
|
|
||||||
|
IEnumerable<CorsairKey> KeyList { get; }
|
||||||
|
|
||||||
|
bool IsDone { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
void Update(float deltaTime);
|
||||||
|
|
||||||
|
void OnAttach();
|
||||||
|
|
||||||
|
void OnDetach();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
using System.Linq;
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using CUE.NET.Devices.Keyboard.Enums;
|
using CUE.NET.Devices.Keyboard.Enums;
|
||||||
using CUE.NET.Devices.Keyboard.Keys;
|
using CUE.NET.Devices.Keyboard.Keys;
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ namespace CUE.NET.Devices.Keyboard.Extensions
|
|||||||
return simpleKeyGroup;
|
return simpleKeyGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||||
public static bool Attach(this BaseKeyGroup keyGroup)
|
public static bool Attach(this BaseKeyGroup keyGroup)
|
||||||
{
|
{
|
||||||
return keyGroup.Keyboard?.AttachKeyGroup(keyGroup) ?? false;
|
return keyGroup.Keyboard?.AttachKeyGroup(keyGroup) ?? false;
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
using System.Drawing;
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
using CUE.NET.Devices.Generic;
|
using CUE.NET.Devices.Generic;
|
||||||
using CUE.NET.Devices.Keyboard.Enums;
|
using CUE.NET.Devices.Keyboard.Enums;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using CUE.NET.Devices.Keyboard.Enums;
|
using CUE.NET.Devices.Keyboard.Enums;
|
||||||
|
|
||||||
namespace CUE.NET.Devices.Keyboard.Keys
|
namespace CUE.NET.Devices.Keyboard.Keys
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CUE.NET.Devices.Keyboard.Enums;
|
using CUE.NET.Devices.Keyboard.Enums;
|
||||||
|
|||||||
@ -9,6 +9,8 @@ namespace CUE.NET.Devices.Mouse
|
|||||||
|
|
||||||
public CorsairMouseDeviceInfo MouseDeviceInfo { get; }
|
public CorsairMouseDeviceInfo MouseDeviceInfo { get; }
|
||||||
|
|
||||||
|
protected override bool HasEffect => false;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|||||||
@ -36,6 +36,7 @@ namespace CUE.NET.Helper
|
|||||||
|
|
||||||
private static byte GetIntColorFromFloat(float f)
|
private static byte GetIntColorFromFloat(float f)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable once RedundantCast - never trust this ...
|
||||||
float calcF = (float)Math.Max(0f, Math.Min(1f, f));
|
float calcF = (float)Math.Max(0f, Math.Min(1f, f));
|
||||||
return (byte)(calcF.Equals(1f) ? 255 : calcF * 256f);
|
return (byte)(calcF.Equals(1f) ? 255 : calcF * 256f);
|
||||||
}
|
}
|
||||||
@ -69,7 +70,9 @@ namespace CUE.NET.Helper
|
|||||||
int max = Math.Max(color.R, Math.Max(color.G, color.B));
|
int max = Math.Max(color.R, Math.Max(color.G, color.B));
|
||||||
int min = Math.Min(color.R, Math.Min(color.G, color.B));
|
int min = Math.Min(color.R, Math.Min(color.G, color.B));
|
||||||
|
|
||||||
|
// ReSharper disable RedundantCast - never trust this ...
|
||||||
return (max == 0) ? 0 : 1f - ((float)min / (float)max);
|
return (max == 0) ? 0 : 1f - ((float)min / (float)max);
|
||||||
|
// ReSharper restore RedundantCast
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float GetHSVValue(this Color color)
|
public static float GetHSVValue(this Color color)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user