diff --git a/Brushes/AbstractBrush.cs b/Brushes/AbstractBrush.cs
index 56d78ac..5160433 100644
--- a/Brushes/AbstractBrush.cs
+++ b/Brushes/AbstractBrush.cs
@@ -1,4 +1,6 @@
-using System.Drawing;
+// ReSharper disable VirtualMemberNeverOverriden.Global
+
+using System.Drawing;
using CUE.NET.Helper;
namespace CUE.NET.Brushes
diff --git a/Brushes/IBrush.cs b/Brushes/IBrush.cs
index f441aca..54558af 100644
--- a/Brushes/IBrush.cs
+++ b/Brushes/IBrush.cs
@@ -1,3 +1,5 @@
+// ReSharper disable UnusedMemberInSuper.Global
+
using System.Drawing;
namespace CUE.NET.Brushes
diff --git a/Brushes/LinearGradientBrush.cs b/Brushes/LinearGradientBrush.cs
index e3a851d..672cc2d 100644
--- a/Brushes/LinearGradientBrush.cs
+++ b/Brushes/LinearGradientBrush.cs
@@ -2,6 +2,7 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable ReturnTypeCanBeEnumerable.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedMember.Global
using System.Drawing;
using CUE.NET.Gradients;
diff --git a/Brushes/ProfileBrush.cs b/Brushes/ProfileBrush.cs
new file mode 100644
index 0000000..815672b
--- /dev/null
+++ b/Brushes/ProfileBrush.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+using System.Drawing;
+using CUE.NET.Devices.Keyboard.Enums;
+using CUE.NET.Devices.Keyboard.Keys;
+
+namespace CUE.NET.Brushes
+{
+ ///
+ /// Represents a brush drawing the lighting of a CUE profile.
+ ///
+ public class ProfileBrush : AbstractBrush
+ {
+ #region Properties & Fields
+
+ private Dictionary _keyLights;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The light settings of the CUE profile.
+ internal ProfileBrush(Dictionary keyLights)
+ {
+ this._keyLights = keyLights;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Gets the color at an specific point getting the color of the key at the given point.
+ ///
+ /// The rectangle in which the brush should be drawn.
+ /// The point from which the color should be taken.
+ /// The color of the key at the specified point.
+ public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
+ {
+ CorsairKey key = CueSDK.KeyboardSDK[point];
+ if (key == null) return Color.Transparent;
+
+ Color color;
+ if (!_keyLights.TryGetValue(key.KeyId, out color))
+ return Color.Transparent;
+
+ return FinalizeColor(color);
+ }
+
+ #endregion
+ }
+}
diff --git a/Brushes/RadialGradientBrush.cs b/Brushes/RadialGradientBrush.cs
index d3b20b7..0b97af3 100644
--- a/Brushes/RadialGradientBrush.cs
+++ b/Brushes/RadialGradientBrush.cs
@@ -1,5 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedMember.Global
using System;
using System.Drawing;
diff --git a/Brushes/RandomColorBrush.cs b/Brushes/RandomColorBrush.cs
index 6a4c184..5037854 100644
--- a/Brushes/RandomColorBrush.cs
+++ b/Brushes/RandomColorBrush.cs
@@ -1,4 +1,6 @@
-using System;
+// ReSharper disable UnusedMember.Global
+
+using System;
using System.Drawing;
using CUE.NET.Helper;
diff --git a/CUE.NET.csproj b/CUE.NET.csproj
index 141a06d..299d8a2 100644
--- a/CUE.NET.csproj
+++ b/CUE.NET.csproj
@@ -45,6 +45,7 @@
+
@@ -97,6 +98,10 @@
+
+
+
+
diff --git a/Devices/Generic/AbstractCueDevice.cs b/Devices/Generic/AbstractCueDevice.cs
index f58b846..7d3ce60 100644
--- a/Devices/Generic/AbstractCueDevice.cs
+++ b/Devices/Generic/AbstractCueDevice.cs
@@ -1,4 +1,7 @@
-using System;
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMethodReturnValue.Global
+
+using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
diff --git a/Devices/Headset/CorsairHeadset.cs b/Devices/Headset/CorsairHeadset.cs
index 5e3eac0..b674634 100644
--- a/Devices/Headset/CorsairHeadset.cs
+++ b/Devices/Headset/CorsairHeadset.cs
@@ -1,5 +1,6 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
using System.Collections;
using System.Collections.Generic;
diff --git a/Devices/ICueDevice.cs b/Devices/ICueDevice.cs
index 2ad8a14..fc6a763 100644
--- a/Devices/ICueDevice.cs
+++ b/Devices/ICueDevice.cs
@@ -1,4 +1,7 @@
-using CUE.NET.Devices.Generic;
+// ReSharper disable UnusedMemberInSuper.Global
+// ReSharper disable UnusedMember.Global
+
+using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices
diff --git a/Devices/IDeviceInfo.cs b/Devices/IDeviceInfo.cs
index 4034ae8..6cadcf1 100644
--- a/Devices/IDeviceInfo.cs
+++ b/Devices/IDeviceInfo.cs
@@ -1,4 +1,7 @@
-using CUE.NET.Devices.Generic.Enums;
+// ReSharper disable UnusedMemberInSuper.Global
+// ReSharper disable UnusedMember.Global
+
+using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices
{
diff --git a/Devices/Keyboard/Extensions/KeyGroupExtension.cs b/Devices/Keyboard/Extensions/KeyGroupExtension.cs
index e1f5976..629974b 100644
--- a/Devices/Keyboard/Extensions/KeyGroupExtension.cs
+++ b/Devices/Keyboard/Extensions/KeyGroupExtension.cs
@@ -1,4 +1,5 @@
// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
using System.Linq;
using CUE.NET.Devices.Keyboard.Enums;
diff --git a/Devices/Keyboard/Keys/IKeyGroup.cs b/Devices/Keyboard/Keys/IKeyGroup.cs
index 96ab7cf..58891b2 100644
--- a/Devices/Keyboard/Keys/IKeyGroup.cs
+++ b/Devices/Keyboard/Keys/IKeyGroup.cs
@@ -1,4 +1,7 @@
-using System.Collections.Generic;
+// ReSharper disable UnusedMemberInSuper.Global
+// ReSharper disable UnusedMember.Global
+
+using System.Collections.Generic;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
diff --git a/Devices/Keyboard/Keys/ListKeyGroup.cs b/Devices/Keyboard/Keys/ListKeyGroup.cs
index bafae08..7fc5b84 100644
--- a/Devices/Keyboard/Keys/ListKeyGroup.cs
+++ b/Devices/Keyboard/Keys/ListKeyGroup.cs
@@ -1,4 +1,5 @@
// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedMember.Global
using System.Collections.Generic;
using CUE.NET.Devices.Keyboard.Enums;
diff --git a/Devices/Keyboard/Keys/RectangleKeyGroup.cs b/Devices/Keyboard/Keys/RectangleKeyGroup.cs
index 2d187dd..4185a78 100644
--- a/Devices/Keyboard/Keys/RectangleKeyGroup.cs
+++ b/Devices/Keyboard/Keys/RectangleKeyGroup.cs
@@ -1,5 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedMember.Global
using System.Collections.Generic;
using System.Drawing;
diff --git a/Devices/Mouse/CorsairMouse.cs b/Devices/Mouse/CorsairMouse.cs
index 8ff3888..1b181c3 100644
--- a/Devices/Mouse/CorsairMouse.cs
+++ b/Devices/Mouse/CorsairMouse.cs
@@ -2,7 +2,6 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable UnusedMember.Global
-using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
diff --git a/Effects/FlashEffect.cs b/Effects/FlashEffect.cs
index 7228bd6..d026cd0 100644
--- a/Effects/FlashEffect.cs
+++ b/Effects/FlashEffect.cs
@@ -1,5 +1,6 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedMember.Global
using System;
using System.Drawing;
diff --git a/Effects/IEffect.cs b/Effects/IEffect.cs
index 6e9ce35..4cce82c 100644
--- a/Effects/IEffect.cs
+++ b/Effects/IEffect.cs
@@ -1,4 +1,7 @@
-using System.Collections.Generic;
+// ReSharper disable UnusedMember.Global
+// ReSharper disable UnusedMemberInSuper.Global
+
+using System.Collections.Generic;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
diff --git a/Examples/SimpleDevTest/Program.cs b/Examples/SimpleDevTest/Program.cs
index 119a98c..ad9274c 100644
--- a/Examples/SimpleDevTest/Program.cs
+++ b/Examples/SimpleDevTest/Program.cs
@@ -11,6 +11,7 @@ using CUE.NET.Devices.Keyboard.Extensions;
using CUE.NET.Devices.Keyboard.Keys;
using CUE.NET.Exceptions;
using CUE.NET.Gradients;
+using CUE.NET.Profiles;
namespace SimpleDevTest
{
@@ -38,6 +39,40 @@ namespace SimpleDevTest
if (keyboard == null)
throw new WrapperException("No keyboard found");
+ keyboard.Brush = new SolidColorBrush(Color.Black);
+ keyboard.Update();
+
+ Wait(3);
+
+ keyboard.Brush = CueProfiles.LoadProfileByID()[null];
+ keyboard.Update();
+
+ Wait(3);
+
+ // My Profile 'K95 RGB Default 2' is all black - this could lead to different behavior than cue has since transparent isn't black in CUE.NET
+ // To swap a profile like CUE does we would need to black out the keyboard before
+ // OR work with a key group containing all keys and leave the background black - this should be always the prefered solution
+ keyboard.Brush = new SolidColorBrush(Color.Black);
+ keyboard.Update();
+ keyboard.Brush = CueProfiles.LoadProfileByID()["K95 RGB Default 2"];
+ keyboard.Update();
+
+ Wait(3);
+
+ return;
+
+ ListKeyGroup keyGroup = new ListKeyGroup(keyboard, keyboard['R'].KeyId);
+ keyGroup.Brush = new SolidColorBrush(Color.White);
+ keyboard.Update();
+ Wait(2);
+ keyGroup.RemoveKey(keyboard['R'].KeyId);
+ keyboard['R'].Led.Color = Color.Black;
+ keyGroup.AddKey(keyboard['T'].KeyId);
+ keyboard.Update();
+
+ Wait(10);
+
+ return;
// ---------------------------------------------------------------------------
// First we'll look at some basic coloring
diff --git a/Gradients/LinearGradient.cs b/Gradients/LinearGradient.cs
index f3ffd7a..5ac8b21 100644
--- a/Gradients/LinearGradient.cs
+++ b/Gradients/LinearGradient.cs
@@ -1,4 +1,6 @@
-using System.Drawing;
+// ReSharper disable UnusedMember.Global
+
+using System.Drawing;
using System.Linq;
namespace CUE.NET.Gradients
diff --git a/Profiles/CueProfile.cs b/Profiles/CueProfile.cs
new file mode 100644
index 0000000..638ae32
--- /dev/null
+++ b/Profiles/CueProfile.cs
@@ -0,0 +1,105 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable UnusedMember.Global
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+using CUE.NET.Brushes;
+
+namespace CUE.NET.Profiles
+{
+ ///
+ /// Represents a CUE profile.
+ ///
+ public class CueProfile
+ {
+ #region Properties & Fields
+
+ private Dictionary _devices;
+
+ ///
+ /// Gets the Id of the profile.
+ ///
+ public string Id { get; }
+
+ ///
+ /// Gets the Name of the profile.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Returns a list of strings containing the name of all modes available.
+ ///
+ public IEnumerable Modes
+ {
+ get
+ {
+ string device = _devices.Keys.FirstOrDefault();
+ CueProfileDevice cpd;
+ return (device != null && _devices.TryGetValue(device, out cpd)) ? cpd.Modes : new string[0];
+ }
+ }
+
+ ///
+ /// Returns the for the given mode.
+ ///
+ /// The mode to select.
+ /// The of the given mode.
+ public ProfileBrush this[string mode]
+ {
+ get
+ {
+ string device = CueSDK.KeyboardSDK?.KeyboardDeviceInfo?.Model;
+ CueProfileDevice cpd;
+ return (device != null && _devices.TryGetValue(device, out cpd)) ? cpd[mode] : null;
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ private CueProfile(string id, string name)
+ {
+ this.Id = id;
+ this.Name = name;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Loads a CUE profile from the given file.
+ ///
+ /// The profile-file.
+ /// The loaded or null.
+ internal static CueProfile Load(string file)
+ {
+ // ReSharper disable PossibleNullReferenceException - Just let it fail - no need to check anything here ...
+ try
+ {
+ if (!File.Exists(file)) return null;
+
+ XElement profileRoot = XDocument.Load(file).Root;
+ return new CueProfile(profileRoot.Element("id").Value, profileRoot.Element("name").Value)
+ {
+ _devices = profileRoot.Element("devices").Elements("device")
+ .Select(CueProfileDevice.Load)
+ .Where(x => x != null)
+ .ToDictionary(x => x.Name)
+ };
+ }
+ // ReSharper disable once CatchAllClause - I have no idea how the factory pattern should handle such a case - time to read :p
+ catch
+ {
+ return null;
+ }
+ // ReSharper restore PossibleNullReferenceException
+ }
+
+ #endregion
+ }
+}
diff --git a/Profiles/CueProfileDevice.cs b/Profiles/CueProfileDevice.cs
new file mode 100644
index 0000000..eda8958
--- /dev/null
+++ b/Profiles/CueProfileDevice.cs
@@ -0,0 +1,91 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+using CUE.NET.Brushes;
+
+namespace CUE.NET.Profiles
+{
+ ///
+ /// Represents a device of a CUE profile.
+ ///
+ internal class CueProfileDevice
+ {
+ #region Properties & Fields
+
+ ///
+ /// The name of the device.
+ ///
+ internal string Name { get; }
+
+ ///
+ /// Returns a list of strings containing the name of all modes available for this device.
+ ///
+ internal IEnumerable Modes => _modes.Keys.ToList();
+
+ private Dictionary _modes;
+
+ #endregion
+
+ #region Brush Conversion
+
+ ///
+ /// Returns the for the given mode.
+ ///
+ /// The mode to select.
+ /// The of the given mode.
+ internal ProfileBrush this[string mode]
+ {
+ get
+ {
+ if (mode == null)
+ mode = _modes.Keys.FirstOrDefault();
+
+ CueProfileMode cpm;
+ return (mode != null && _modes.TryGetValue(mode, out cpm)) ? cpm : null;
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ private CueProfileDevice(string name)
+ {
+ this.Name = name;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Loads a device of a CUE profile from the given XML-node.
+ ///
+ /// The node containing the device.
+ /// The loaded or null.
+ internal static CueProfileDevice Load(XElement deviceRoot)
+ {
+ // ReSharper disable PossibleNullReferenceException - Just let it fail - no need to check anything here ...
+ try
+ {
+ if (deviceRoot == null) return null;
+
+ return new CueProfileDevice(deviceRoot.Element("modelName").Value)
+ {
+ _modes = deviceRoot.Element("modes").Elements("mode")
+ .Select(CueProfileMode.Load)
+ .Where(x => x != null)
+ .ToDictionary(x => x.Name)
+ };
+ }
+ // ReSharper disable once CatchAllClause - I have no idea how the factory pattern should handle such a case - time to read :p
+ catch
+ {
+ return null;
+ }
+ // ReSharper restore PossibleNullReferenceException
+ }
+
+ #endregion
+ }
+}
diff --git a/Profiles/CueProfileMode.cs b/Profiles/CueProfileMode.cs
new file mode 100644
index 0000000..5075225
--- /dev/null
+++ b/Profiles/CueProfileMode.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Xml.Linq;
+using CUE.NET.Brushes;
+using CUE.NET.Devices.Keyboard.Enums;
+
+namespace CUE.NET.Profiles
+{
+ ///
+ /// Represents a mode of a CUE profile.
+ ///
+ internal class CueProfileMode
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets the name of the mode.
+ ///
+ internal string Name { get; }
+
+ private Dictionary _keyLights;
+
+ #endregion
+
+ #region Brush Conversion
+
+ ///
+ /// Converts a to a .
+ ///
+ /// The profile mode to convert.
+ public static implicit operator ProfileBrush(CueProfileMode profile)
+ {
+ return profile != null ? new ProfileBrush(profile._keyLights) : null;
+ }
+
+ #endregion
+
+ #region Constructors
+
+ private CueProfileMode(string name)
+ {
+ this.Name = name;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Loads a mode of a CUE profile from the given XML-node.
+ ///
+ /// The node containing the mode.
+ /// The loaded or null.
+ internal static CueProfileMode Load(XElement modeRoot)
+ {
+ // ReSharper disable PossibleNullReferenceException - Just let it fail - no need to check anything here ...
+ try
+ {
+ if (modeRoot == null) return null;
+
+ return new CueProfileMode(modeRoot.Element("name").Value)
+ {
+ _keyLights = modeRoot.Element("lightBackgrounds").Element("keyBgLights").Elements("lightBackground")
+ .Select(x =>
+ {
+ string name = x.Attribute("key").Value;
+ if (name.Length == 1 && char.IsDigit(name[0])) // Our enum names can't be digit only so we need to map them
+ name = 'D' + name;
+
+ return new
+ {
+ key = (CorsairKeyboardKeyId)Enum.Parse(typeof(CorsairKeyboardKeyId), name),
+ color = ColorTranslator.FromHtml(x.Attribute("color").Value)
+ };
+ })
+ .ToDictionary(x => x.key, x => x.color)
+ };
+ }
+ // ReSharper disable once CatchAllClause - I have no idea how the factory pattern should handle such a case - time to read :p
+ catch
+ {
+ return null;
+ }
+ // ReSharper restore PossibleNullReferenceException
+ }
+
+ #endregion
+ }
+}
diff --git a/Profiles/CueProfiles.cs b/Profiles/CueProfiles.cs
new file mode 100644
index 0000000..54596c9
--- /dev/null
+++ b/Profiles/CueProfiles.cs
@@ -0,0 +1,124 @@
+// ReSharper disable UnusedMember.Global
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace CUE.NET.Profiles
+{
+ ///
+ /// Represents the SDK for CUE profiles.
+ ///
+ public static class CueProfiles
+ {
+ #region Constants
+
+ private const string PROFILE_EXTENSION = ".prf";
+ private static readonly string PROFILE_FOLDER = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Corsair", "HID", "Profiles");
+ private static readonly string CONFIG_FILE = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Corsair", "HID", "config.cfg");
+
+ #endregion
+
+ #region Properties & Fields
+
+ private static Dictionary _profileNameMapping = new Dictionary();
+
+ ///
+ /// Gets a list containing the names of all existing profiles.
+ ///
+ public static List ProfileNames
+ {
+ get
+ {
+ LoadProfileNames();
+ return _profileNameMapping.Keys.ToList();
+ }
+ }
+
+ ///
+ /// Gets a list containing the ids of all existing profiles.
+ ///
+ public static List ProfileIds
+ {
+ get
+ {
+ LoadProfileNames();
+ return _profileNameMapping.Values.ToList();
+ }
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Loads the profile with the given name.
+ ///
+ /// The name (the one given in CUE, not the filename) of the profile.
+ /// The loaded or null if it couldn't be loaded.
+ public static CueProfile LoadProfileByName(string name = null)
+ {
+ string id = null;
+ if (name != null && !_profileNameMapping.TryGetValue(name, out id))
+ {
+ LoadProfileNames(); // Reload and try again
+ if (!_profileNameMapping.TryGetValue(name, out id))
+ return null;
+ }
+
+ return LoadProfileByID(id);
+ }
+
+ ///
+ /// Loads the profile with the given id.
+ ///
+ /// The id of the profile.
+ /// The loaded or null if it couldn't be loaded.
+ public static CueProfile LoadProfileByID(string id = null)
+ {
+ if (id == null) id = GetDefaultProfileId();
+ return CueProfile.Load(Path.Combine(PROFILE_FOLDER, id + PROFILE_EXTENSION));
+ }
+
+ private static string GetDefaultProfileId()
+ {
+ try
+ {
+ return XDocument.Load(CONFIG_FILE).Root?.Elements("value").FirstOrDefault(x => string.Equals(x.Attribute("name")?.Value, "InitialProfile", StringComparison.OrdinalIgnoreCase))?.Value;
+ }
+ // ReSharper disable once CatchAllClause - This shouldn't happen but you never know ...
+ catch
+ {
+ return null;
+ }
+ }
+
+ private static void LoadProfileNames()
+ {
+ try
+ {
+ IEnumerable profileFiles = Directory.GetFiles(PROFILE_FOLDER).Where(x => x.EndsWith(PROFILE_EXTENSION));
+ foreach (string profileFile in profileFiles)
+ {
+ XElement profileNode = XDocument.Load(profileFile).Root;
+ if (profileNode == null) continue;
+
+ string name = profileNode.Element("name")?.Value;
+ string id = profileNode.Element("id")?.Value;
+
+ if (!string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(id) && !_profileNameMapping.ContainsKey(name)) // I think duplicates are an error case
+ _profileNameMapping.Add(name, id);
+ }
+ }
+ // ReSharper disable once CatchAllClause - This shouldn't happen but you never know ...
+ catch
+ {
+ _profileNameMapping.Clear();
+ }
+ }
+
+ #endregion
+ }
+}