From 4e1a1d11bd4290402cbaeaef0d3d09adf98f180f Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Sep 2015 12:16:24 +0200 Subject: [PATCH] Improved the led update mechanism --- Devices/Generic/AbstractCueDevice.cs | 15 ++++++-- Devices/Generic/CorsairLed.cs | 28 +++++++++++---- Devices/Generic/GenericDeviceInfo.cs | 3 +- Devices/ICueDevice.cs | 2 +- Devices/Keyboard/CorsairKeyboard.cs | 42 +++++++++++++++++++--- Devices/Keyboard/Keys/BaseKeyGroup.cs | 13 ++++--- Devices/Keyboard/Keys/IKeyGroup.cs | 2 +- Devices/Keyboard/Keys/RectangleKeyGroup.cs | 16 ++++----- Examples/SimpleDevTest/Program.cs | 36 +++++++++++-------- 9 files changed, 112 insertions(+), 45 deletions(-) diff --git a/Devices/Generic/AbstractCueDevice.cs b/Devices/Generic/AbstractCueDevice.cs index d1d4b32..138cb3f 100644 --- a/Devices/Generic/AbstractCueDevice.cs +++ b/Devices/Generic/AbstractCueDevice.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using CUE.NET.Native; @@ -35,9 +36,19 @@ namespace CUE.NET.Devices.Generic return Leds[ledId]; } - public virtual void UpdateLeds(bool fullUpdate = false) + public virtual void UpdateLeds(bool forceUpdate = false) { - IList> ledsToUpdate = (fullUpdate ? Leds : Leds.Where(x => x.Value.IsDirty)).ToList(); + IList> ledsToUpdate = (forceUpdate ? Leds : Leds.Where(x => x.Value.IsDirty)).ToList(); + + foreach (CorsairLed led in Leds.Values) + led.Update(); + + UpdateLeds(ledsToUpdate); + } + + private static void UpdateLeds(ICollection> ledsToUpdate) + { + ledsToUpdate = ledsToUpdate.Where(x => x.Value.Color != Color.Transparent).ToList(); if (!ledsToUpdate.Any()) return; // CUE seems to crash if 'CorsairSetLedsColors' is called with a zero length array diff --git a/Devices/Generic/CorsairLed.cs b/Devices/Generic/CorsairLed.cs index 4a6e609..41a75e2 100644 --- a/Devices/Generic/CorsairLed.cs +++ b/Devices/Generic/CorsairLed.cs @@ -6,21 +6,27 @@ namespace CUE.NET.Devices.Generic { #region Properties & Fields - public bool IsDirty { get; private set; } = false; + public bool IsDirty => RequestedColor != _color; + public bool IsUpdated { get; private set; } - private Color _color = Color.Black; + public Color RequestedColor { get; private set; } = Color.Transparent; + + private Color _color = Color.Transparent; public Color Color { get { return _color; } set { - if (_color != value) - IsDirty = true; - - _color = value; + if (!IsLocked) + { + RequestedColor = value; + IsUpdated = true; + } } } + public bool IsLocked { get; set; } = false; + //TODO DarthAffe 19.09.2015: Add effects and stuff #endregion @@ -30,5 +36,15 @@ namespace CUE.NET.Devices.Generic internal CorsairLed() { } #endregion + + #region Methods + + internal void Update() + { + _color = RequestedColor; + IsUpdated = false; + } + + #endregion } } diff --git a/Devices/Generic/GenericDeviceInfo.cs b/Devices/Generic/GenericDeviceInfo.cs index 4b979ef..0d70704 100644 --- a/Devices/Generic/GenericDeviceInfo.cs +++ b/Devices/Generic/GenericDeviceInfo.cs @@ -13,8 +13,7 @@ namespace CUE.NET.Devices.Generic /// Device type. /// public CorsairDeviceType Type { get; } - - //TODO DarthAffe 17.09.2015: This could be an Enum + /// /// Device model (like “K95RGB”). /// diff --git a/Devices/ICueDevice.cs b/Devices/ICueDevice.cs index 7224e1c..c1bab11 100644 --- a/Devices/ICueDevice.cs +++ b/Devices/ICueDevice.cs @@ -4,6 +4,6 @@ { IDeviceInfo DeviceInfo { get; } - void UpdateLeds(bool fullUpdate = false); + void UpdateLeds(bool forceUpdate = false); } } diff --git a/Devices/Keyboard/CorsairKeyboard.cs b/Devices/Keyboard/CorsairKeyboard.cs index cbf5e33..054e7f2 100644 --- a/Devices/Keyboard/CorsairKeyboard.cs +++ b/Devices/Keyboard/CorsairKeyboard.cs @@ -51,6 +51,10 @@ namespace CUE.NET.Devices.Keyboard } public IEnumerable Keys => new ReadOnlyCollection(_keys.Values.ToList()); + + public Color Color { get; set; } = Color.Transparent; + + private readonly IList _keyGroups = new List(); #endregion @@ -69,10 +73,38 @@ namespace CUE.NET.Devices.Keyboard #region Methods - public void SetColor(Color color) + public override void UpdateLeds(bool forceUpdate = false) { - foreach (CorsairKey key in this) - key.Led.Color = color; + // Apply all KeyGroups first + // Update only 'clean' leds, manual set should always override groups + IEnumerable cleanKeys = this.Where(x => !x.Led.IsUpdated).ToList(); + + if (Color != Color.Transparent) + foreach (CorsairKey key in cleanKeys) + key.Led.Color = Color; + + //TODO DarthAffe 20.09.2015: Add some sort of priority + foreach (IKeyGroup keyGroup in _keyGroups) + foreach (CorsairKey key in keyGroup.Keys.Where(key => cleanKeys.Contains(key))) + key.Led.Color = keyGroup.Color; + + // Perform 'real' update + base.UpdateLeds(forceUpdate); + } + + public void AttachKeyGroup(IKeyGroup keyGroup) + { + if (keyGroup == null) return; + + if (!_keyGroups.Contains(keyGroup)) + _keyGroups.Add(keyGroup); + } + + public void DetachKeyGroup(IKeyGroup keyGroup) + { + if (keyGroup == null) return; + + _keyGroups.Remove(keyGroup); } private void InitializeKeys() @@ -83,9 +115,11 @@ namespace CUE.NET.Devices.Keyboard for (int i = 0; i < nativeLedPositions.numberOfLed; i++) { _CorsairLedPosition ledPosition = Marshal.PtrToStructure<_CorsairLedPosition>(ptr); - _keys.Add(ledPosition.ledId, new CorsairKey(ledPosition.ledId, GetLed((int)ledPosition.ledId), + CorsairLed led = GetLed((int)ledPosition.ledId); + _keys.Add(ledPosition.ledId, new CorsairKey(ledPosition.ledId, led, //TODO DarthAffe 19.09.2015: Is something like RectangleD needed? I don't think so ... new RectangleF((float)ledPosition.left, (float)ledPosition.top, (float)ledPosition.width, (float)ledPosition.height))); + ptr = new IntPtr(ptr.ToInt64() + structSize); } } diff --git a/Devices/Keyboard/Keys/BaseKeyGroup.cs b/Devices/Keyboard/Keys/BaseKeyGroup.cs index 7ba3462..24d2b3b 100644 --- a/Devices/Keyboard/Keys/BaseKeyGroup.cs +++ b/Devices/Keyboard/Keys/BaseKeyGroup.cs @@ -13,25 +13,24 @@ namespace CUE.NET.Devices.Keyboard.Keys public IEnumerable Keys => new ReadOnlyCollection(GroupKeys); protected IList GroupKeys { get; } = new List(); + public Color Color { get; set; } = Color.Transparent; + #endregion #region Constructors - protected BaseKeyGroup(CorsairKeyboard keyboard) + protected BaseKeyGroup(CorsairKeyboard keyboard, bool autoAttach = true) { this.Keyboard = keyboard; + + if (autoAttach) + keyboard.AttachKeyGroup(this); } #endregion #region Methods - public virtual void SetColor(Color color) - { - foreach (CorsairKey key in GroupKeys) - key.Led.Color = color; - } - public void MergeKeys(IKeyGroup groupToMerge) { foreach (CorsairKey key in groupToMerge.Keys) diff --git a/Devices/Keyboard/Keys/IKeyGroup.cs b/Devices/Keyboard/Keys/IKeyGroup.cs index 1c5d354..07a5119 100644 --- a/Devices/Keyboard/Keys/IKeyGroup.cs +++ b/Devices/Keyboard/Keys/IKeyGroup.cs @@ -7,6 +7,6 @@ namespace CUE.NET.Devices.Keyboard.Keys { IEnumerable Keys { get; } - void SetColor(Color color); + Color Color { get; set; } } } diff --git a/Devices/Keyboard/Keys/RectangleKeyGroup.cs b/Devices/Keyboard/Keys/RectangleKeyGroup.cs index 7c2635c..66bd4e4 100644 --- a/Devices/Keyboard/Keys/RectangleKeyGroup.cs +++ b/Devices/Keyboard/Keys/RectangleKeyGroup.cs @@ -16,20 +16,20 @@ namespace CUE.NET.Devices.Keyboard.Keys #region Constructors - public RectangleKeyGroup(CorsairKeyboard keyboard, CorsairKeyboardKeyId fromKey, CorsairKeyboardKeyId toKey, float minOverlayPercentage = 0.5f) - : this(keyboard, keyboard[fromKey], keyboard[toKey], minOverlayPercentage) + public RectangleKeyGroup(CorsairKeyboard keyboard, CorsairKeyboardKeyId fromKey, CorsairKeyboardKeyId toKey, float minOverlayPercentage = 0.5f, bool autoAttach = true) + : this(keyboard, keyboard[fromKey], keyboard[toKey], minOverlayPercentage, autoAttach) { } - public RectangleKeyGroup(CorsairKeyboard keyboard, CorsairKey fromKey, CorsairKey toKey, float minOverlayPercentage = 0.5f) - : this(keyboard, RectangleHelper.CreateRectangleFromRectangles(fromKey.KeyRectangle, toKey.KeyRectangle), minOverlayPercentage) + public RectangleKeyGroup(CorsairKeyboard keyboard, CorsairKey fromKey, CorsairKey toKey, float minOverlayPercentage = 0.5f, bool autoAttach = true) + : this(keyboard, RectangleHelper.CreateRectangleFromRectangles(fromKey.KeyRectangle, toKey.KeyRectangle), minOverlayPercentage, autoAttach) { } - public RectangleKeyGroup(CorsairKeyboard keyboard, PointF fromPoint, PointF toPoint, float minOverlayPercentage = 0.5f) - : this(keyboard, RectangleHelper.CreateRectangleFromPoints(fromPoint, toPoint), minOverlayPercentage) + public RectangleKeyGroup(CorsairKeyboard keyboard, PointF fromPoint, PointF toPoint, float minOverlayPercentage = 0.5f, bool autoAttach = true) + : this(keyboard, RectangleHelper.CreateRectangleFromPoints(fromPoint, toPoint), minOverlayPercentage, autoAttach) { } - public RectangleKeyGroup(CorsairKeyboard keyboard, RectangleF requestedRectangle, float minOverlayPercentage = 0.5f) - : base(keyboard) + public RectangleKeyGroup(CorsairKeyboard keyboard, RectangleF requestedRectangle, float minOverlayPercentage = 0.5f, bool autoAttach = true) + : base(keyboard, autoAttach) { this.RequestedRectangle = requestedRectangle; this.MinOverlayPercentage = minOverlayPercentage; diff --git a/Examples/SimpleDevTest/Program.cs b/Examples/SimpleDevTest/Program.cs index 30fc880..f1afef2 100644 --- a/Examples/SimpleDevTest/Program.cs +++ b/Examples/SimpleDevTest/Program.cs @@ -35,8 +35,8 @@ namespace SimpleDevTest throw new WrapperException("No keyboard found"); //Ink all numbers on the keypad purple - RectangleKeyGroup centerGroup = new RectangleKeyGroup(keyboard, CorsairKeyboardKeyId.Keypad7, CorsairKeyboardKeyId.Keypad3); - centerGroup.SetColor(Color.Purple); + RectangleKeyGroup purpleGroup = new RectangleKeyGroup(keyboard, CorsairKeyboardKeyId.Keypad7, CorsairKeyboardKeyId.Keypad3) + { Color = Color.Purple }; // Ink the Keys 'r', 'g', 'b' in their respective color // The char access seems to fail for everything except letters (SDK doesn't return a valid keyId) @@ -44,17 +44,21 @@ namespace SimpleDevTest keyboard[CorsairKeyboardKeyId.G].Led.Color = Color.Green; keyboard['B'].Led.Color = Color.Blue; + // Lock the 'r', 'g', 'b' keys. We want them to stay like this forever + keyboard['R'].Led.IsLocked = true; + keyboard['G'].Led.IsLocked = true; + keyboard['B'].Led.IsLocked = true; + // Ink the letters of 'white' white - SimpleKeyGroup whiteGroup = new SimpleKeyGroup(keyboard, CorsairKeyboardKeyId.W, CorsairKeyboardKeyId.H, CorsairKeyboardKeyId.I, CorsairKeyboardKeyId.T, CorsairKeyboardKeyId.E); - whiteGroup.SetColor(Color.White); + SimpleKeyGroup whiteGroup = new SimpleKeyGroup(keyboard, CorsairKeyboardKeyId.W, CorsairKeyboardKeyId.H, CorsairKeyboardKeyId.I, CorsairKeyboardKeyId.T, CorsairKeyboardKeyId.E) + { Color = Color.White }; // Ink the keys '1' to '0' yellow - RectangleKeyGroup numberGroup = new RectangleKeyGroup(keyboard, CorsairKeyboardKeyId.D1, CorsairKeyboardKeyId.D0); - numberGroup.SetColor(Color.Yellow); + RectangleKeyGroup yellowGroup = new RectangleKeyGroup(keyboard, CorsairKeyboardKeyId.D1, CorsairKeyboardKeyId.D0) + { Color = Color.Yellow }; - // Update the keyboard to show the configured colors, the parameter 'true' overrides the whole keyboard (default: black), - // 'false' (or nothing) overrides only changed keys (your CUE settings defines the rest) - this default behaviour might change soon - keyboard.UpdateLeds(true); + // Update the keyboard to show the configured colors, (your CUE settings defines the rest) + keyboard.UpdateLeds(); // Wait 5 sec for (int i = 5; i > 0; i--) @@ -72,19 +76,25 @@ namespace SimpleDevTest const float SPEED = 8f; // mm/tick Random random = new Random(); - // Cover whole keyboard as Group to be able to reset (I'll fix this tomorrow) + // Remove all the groups we created above to clear the keyboard + keyboard.DetachKeyGroup(purpleGroup); + keyboard.DetachKeyGroup(whiteGroup); + keyboard.DetachKeyGroup(yellowGroup); // Flash whole keyboard three times to ... well ... just to make it happen for (int i = 0; i < 3; i++) { - keyboard.SetColor(Color.Aquamarine); + keyboard.Color = Color.Aquamarine; keyboard.UpdateLeds(); Thread.Sleep(160); - keyboard.SetColor(Color.Black); + keyboard.Color = Color.Black; keyboard.UpdateLeds(); Thread.Sleep(200); } + // Set keyboard 'background' to something fancy + keyboard.Color = Color.DarkSlateBlue; + // Spawn our point (rectangle since circles are too hard to calculate :p) in the top-left corner (right over G1 or on ESC depending on your keyboard) RectangleF point = new RectangleF(keyboard.KeyboardRectangle.X, keyboard.KeyboardRectangle.Y, 40, 40); // Target of our movement @@ -98,8 +108,6 @@ namespace SimpleDevTest else point.Location = Interpolate(point.Location, target, SPEED); // It would be better to calculate from the center of our rectangle but the easy way is enough here - keyboard.SetColor(Color.Black); - IEnumerable keys = keyboard[point, 0.1f]; if (keys != null) foreach (CorsairKey key in keys)