diff --git a/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
new file mode 100644
index 0000000..48213e0
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
@@ -0,0 +1,176 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Runtime.InteropServices;
+using RGB.NET.Core;
+using RGB.NET.Core.Exceptions;
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a device provider responsible for corsair (CUE) devices.
+ ///
+ public class CorsairDeviceProvider : IDeviceProvider
+ {
+ #region Properties & Fields
+
+ ///
+ /// Indicates if the SDK is initialized and ready to use.
+ ///
+ public bool IsInitialized { get; private set; }
+
+ ///
+ /// Gets the loaded architecture (x64/x86).
+ ///
+ public string LoadedArchitecture => _CUESDK.LoadedArchitecture;
+
+ ///
+ /// Gets the protocol details for the current SDK-connection.
+ ///
+ public CorsairProtocolDetails ProtocolDetails { get; private set; }
+
+ ///
+ /// Gets whether the application has exclusive access to the SDK or not.
+ ///
+ public bool HasExclusiveAccess { get; private set; }
+
+ ///
+ /// Gets the last error documented by CUE.
+ ///
+ public CorsairError LastError => _CUESDK.CorsairGetLastError();
+
+ ///
+ public IEnumerable Devices { get; private set; }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Thrown if the SDK is already initialized or if the SDK is not compatible to CUE.
+ /// Thrown if the CUE-SDK provides an error.
+ public bool Initialize(bool exclusiveAccessIfPossible = false, bool throwExceptions = false)
+ {
+ _CUESDK.Reload();
+
+ ProtocolDetails = new CorsairProtocolDetails(_CUESDK.CorsairPerformProtocolHandshake());
+
+ CorsairError error = LastError;
+ if (error != CorsairError.Success)
+ {
+ Reset();
+ if (throwExceptions)
+ throw new CUEException(error);
+ else
+ return false;
+ }
+
+ if (ProtocolDetails.BreakingChanges)
+ {
+ Reset();
+ if (throwExceptions)
+ throw new RGBDeviceException("The SDK currently used isn't compatible with the installed version of CUE.\r\n"
+ + $"CUE-Version: {ProtocolDetails.ServerVersion} (Protocol {ProtocolDetails.ServerProtocolVersion})\r\n"
+ + $"SDK-Version: {ProtocolDetails.SdkVersion} (Protocol {ProtocolDetails.SdkProtocolVersion})");
+ else
+ return false;
+ }
+
+ if (exclusiveAccessIfPossible)
+ {
+ if (!_CUESDK.CorsairRequestControl(CorsairAccessMode.ExclusiveLightingControl))
+ {
+ Reset();
+ if (throwExceptions)
+ throw new CUEException(LastError);
+ else
+ return false;
+ }
+ HasExclusiveAccess = true;
+ }
+ else
+ HasExclusiveAccess = false;
+
+ IList devices = new List();
+ int deviceCount = _CUESDK.CorsairGetDeviceCount();
+ for (int i = 0; i < deviceCount; i++)
+ {
+ _CorsairDeviceInfo nativeDeviceInfo =
+ (_CorsairDeviceInfo)Marshal.PtrToStructure(_CUESDK.CorsairGetDeviceInfo(i), typeof(_CorsairDeviceInfo));
+ CorsairRGBDeviceInfo info = new CorsairRGBDeviceInfo(i, DeviceType.Unknown, nativeDeviceInfo);
+ if (!info.CapsMask.HasFlag(CorsairDeviceCaps.Lighting))
+ continue; // Everything that doesn't support lighting control is useless
+
+ CorsairRGBDevice device;
+ switch (info.CorsairDeviceType)
+ {
+ case CorsairDeviceType.Keyboard:
+ device = new CorsairKeyboardRGBDevice(new CorsairKeyboardRGBDeviceInfo(i, nativeDeviceInfo));
+ break;
+ case CorsairDeviceType.Mouse:
+ device = new CorsairMouseRGBDevice(new CorsairMouseRGBDeviceInfo(i, nativeDeviceInfo));
+ break;
+ case CorsairDeviceType.Headset:
+ device = new CorsairHeadsetRGBDevice(new CorsairHeadsetRGBDeviceInfo(i, nativeDeviceInfo));
+ break;
+ case CorsairDeviceType.Mousemat:
+ device = new CorsairMousematRGBDevice(new CorsairMousematRGBDeviceInfo(i, nativeDeviceInfo));
+ break;
+ // ReSharper disable once RedundantCaseLabel
+ case CorsairDeviceType.Unknown:
+ default:
+ if (throwExceptions)
+ throw new RGBDeviceException("Unknown Device-Type");
+ else
+ continue;
+ }
+
+ try
+ {
+ device.Initialize();
+ }
+ catch
+ {
+ if (throwExceptions)
+ throw;
+ else
+ continue;
+ }
+ devices.Add(device);
+
+ error = LastError;
+ if (error != CorsairError.Success)
+ {
+ Reset();
+ if (throwExceptions)
+ throw new CUEException(error);
+ else
+ return false;
+ }
+ }
+
+ Devices = new ReadOnlyCollection(devices);
+
+ IsInitialized = true;
+
+ return true;
+ }
+
+ ///
+ public void ResetDevices()
+ {
+ if (IsInitialized)
+ _CUESDK.Reload();
+ }
+
+ private void Reset()
+ {
+ ProtocolDetails = null;
+ HasExclusiveAccess = false;
+ Devices = null;
+ IsInitialized = false;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairAccessMode.cs b/RGB.NET.Devices.Corsair/Enum/CorsairAccessMode.cs
new file mode 100644
index 0000000..af8a87c
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairAccessMode.cs
@@ -0,0 +1,15 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+
+#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Contains list of available SDK access modes.
+ ///
+ public enum CorsairAccessMode
+ {
+ ExclusiveLightingControl = 0
+ };
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairDeviceCaps.cs b/RGB.NET.Devices.Corsair/Enum/CorsairDeviceCaps.cs
new file mode 100644
index 0000000..1693b85
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairDeviceCaps.cs
@@ -0,0 +1,24 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+
+using System;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Contains list of corsair device capabilities.
+ ///
+ [Flags]
+ public enum CorsairDeviceCaps
+ {
+ ///
+ /// For devices that do not support any SDK functions.
+ ///
+ None = 0,
+
+ ///
+ /// For devices that has controlled lighting.
+ ///
+ Lighting = 1
+ };
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairDeviceType.cs b/RGB.NET.Devices.Corsair/Enum/CorsairDeviceType.cs
new file mode 100644
index 0000000..ffa502b
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairDeviceType.cs
@@ -0,0 +1,20 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+
+
+#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Contains list of available corsair device types.
+ ///
+ public enum CorsairDeviceType
+ {
+ Unknown = 0,
+ Mouse = 1,
+ Keyboard = 2,
+ Headset = 3,
+ Mousemat = 4
+ };
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairError.cs b/RGB.NET.Devices.Corsair/Enum/CorsairError.cs
new file mode 100644
index 0000000..e0ae1c9
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairError.cs
@@ -0,0 +1,42 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Shared list of all errors which could happen during calling of Corsair* functions.
+ ///
+ public enum CorsairError
+ {
+ ///
+ /// If previously called function completed successfully.
+ ///
+ Success,
+
+ ///
+ /// CUE is not running or was shut down or third-party control is disabled in CUE settings. (runtime error)
+ ///
+ ServerNotFound,
+
+ ///
+ /// If some other client has or took over exclusive control. (runtime error)
+ ///
+ NoControl,
+
+ ///
+ /// If developer did not perform protocol handshake. (developer error)
+ ///
+ ProtocolHandshakeMissing,
+
+ ///
+ /// If developer is calling the function that is not supported by the server (either because protocol has broken by server or client or because the function is new and server is too old.
+ /// Check CorsairProtocolDetails for details). (developer error)
+ ///
+ IncompatibleProtocol,
+
+ ///
+ /// If developer supplied invalid arguments to the function (for specifics look at function descriptions). (developer error)
+ ///
+ InvalidArguments
+ };
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairLedIds.cs b/RGB.NET.Devices.Corsair/Enum/CorsairLedIds.cs
new file mode 100644
index 0000000..7604d0a
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairLedIds.cs
@@ -0,0 +1,187 @@
+// ReSharper disable InconsistentNaming
+
+#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Contains list of all LEDs available for all corsair devices.
+ ///
+ public enum CorsairLedIds
+ {
+ Invalid = 0,
+ Escape = 1,
+ F1 = 2,
+ F2 = 3,
+ F3 = 4,
+ F4 = 5,
+ F5 = 6,
+ F6 = 7,
+ F7 = 8,
+ F8 = 9,
+ F9 = 10,
+ F10 = 11,
+ F11 = 12,
+ GraveAccentAndTilde = 13,
+ D1 = 14,
+ D2 = 15,
+ D3 = 16,
+ D4 = 17,
+ D5 = 18,
+ D6 = 19,
+ D7 = 20,
+ D8 = 21,
+ D9 = 22,
+ D0 = 23,
+ MinusAndUnderscore = 24,
+ Tab = 25,
+ Q = 26,
+ W = 27,
+ E = 28,
+ R = 29,
+ T = 30,
+ Y = 31,
+ U = 32,
+ I = 33,
+ O = 34,
+ P = 35,
+ BracketLeft = 36,
+ CapsLock = 37,
+ A = 38,
+ S = 39,
+ D = 40,
+ F = 41,
+ G = 42,
+ H = 43,
+ J = 44,
+ K = 45,
+ L = 46,
+ SemicolonAndColon = 47,
+ ApostropheAndDoubleQuote = 48,
+ LeftShift = 49,
+ NonUsBackslash = 50,
+ Z = 51,
+ X = 52,
+ C = 53,
+ V = 54,
+ B = 55,
+ N = 56,
+ M = 57,
+ CommaAndLessThan = 58,
+ PeriodAndBiggerThan = 59,
+ SlashAndQuestionMark = 60,
+ LeftCtrl = 61,
+ LeftGui = 62,
+ LeftAlt = 63,
+ Lang2 = 64,
+ Space = 65,
+ Lang1 = 66,
+ International2 = 67,
+ RightAlt = 68,
+ RightGui = 69,
+ Application = 70,
+ LedProgramming = 71,
+ Brightness = 72,
+ F12 = 73,
+ PrintScreen = 74,
+ ScrollLock = 75,
+ PauseBreak = 76,
+ Insert = 77,
+ Home = 78,
+ PageUp = 79,
+ BracketRight = 80,
+ Backslash = 81,
+ NonUsTilde = 82,
+ Enter = 83,
+ International1 = 84,
+ EqualsAndPlus = 85,
+ International3 = 86,
+ Backspace = 87,
+ Delete = 88,
+ End = 89,
+ PageDown = 90,
+ RightShift = 91,
+ RightCtrl = 92,
+ UpArrow = 93,
+ LeftArrow = 94,
+ DownArrow = 95,
+ RightArrow = 96,
+ WinLock = 97,
+ Mute = 98,
+ Stop = 99,
+ ScanPreviousTrack = 100,
+ PlayPause = 101,
+ ScanNextTrack = 102,
+ NumLock = 103,
+ KeypadSlash = 104,
+ KeypadAsterisk = 105,
+ KeypadMinus = 106,
+ KeypadPlus = 107,
+ KeypadEnter = 108,
+ Keypad7 = 109,
+ Keypad8 = 110,
+ Keypad9 = 111,
+ KeypadComma = 112,
+ Keypad4 = 113,
+ Keypad5 = 114,
+ Keypad6 = 115,
+ Keypad1 = 116,
+ Keypad2 = 117,
+ Keypad3 = 118,
+ Keypad0 = 119,
+ KeypadPeriodAndDelete = 120,
+ G1 = 121,
+ G2 = 122,
+ G3 = 123,
+ G4 = 124,
+ G5 = 125,
+ G6 = 126,
+ G7 = 127,
+ G8 = 128,
+ G9 = 129,
+ G10 = 130,
+ VolumeUp = 131,
+ VolumeDown = 132,
+ MR = 133,
+ M1 = 134,
+ M2 = 135,
+ M3 = 136,
+ G11 = 137,
+ G12 = 138,
+ G13 = 139,
+ G14 = 140,
+ G15 = 141,
+ G16 = 142,
+ G17 = 143,
+ G18 = 144,
+ International5 = 145,
+ International4 = 146,
+ Fn = 147,
+
+ B1 = 148,
+ B2 = 149,
+ B3 = 150,
+ B4 = 151,
+
+ LeftLogo = 152,
+ RightLogo = 153,
+
+ Logo = 154,
+
+ Zone1 = 155,
+ Zone2 = 156,
+ Zone3 = 157,
+ Zone4 = 158,
+ Zone5 = 159,
+ Zone6 = 160,
+ Zone7 = 161,
+ Zone8 = 162,
+ Zone9 = 163,
+ Zone10 = 164,
+ Zone11 = 165,
+ Zone12 = 166,
+ Zone13 = 167,
+ Zone14 = 168,
+ Zone15 = 169
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairLogicalKeyboardLayout.cs b/RGB.NET.Devices.Corsair/Enum/CorsairLogicalKeyboardLayout.cs
new file mode 100644
index 0000000..6217571
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairLogicalKeyboardLayout.cs
@@ -0,0 +1,32 @@
+// ReSharper disable InconsistentNaming
+// ReSharper disable UnusedMember.Global
+
+#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Contains list of available logical layouts for corsair keyboards.
+ ///
+ public enum CorsairLogicalKeyboardLayout
+ {
+ US_Int = 1,
+ NA = 2,
+ EU = 3,
+ UK = 4,
+ BE = 5,
+ BR = 6,
+ CH = 7,
+ CN = 8,
+ DE = 9,
+ ES = 10,
+ FR = 11,
+ IT = 12,
+ ND = 13,
+ RU = 14,
+ JP = 15,
+ KR = 16,
+ TW = 17,
+ MEX = 18
+ };
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairPhysicalKeyboardLayout.cs b/RGB.NET.Devices.Corsair/Enum/CorsairPhysicalKeyboardLayout.cs
new file mode 100644
index 0000000..0905b96
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairPhysicalKeyboardLayout.cs
@@ -0,0 +1,36 @@
+// ReSharper disable UnusedMember.Global
+// ReSharper disable InconsistentNaming
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Contains list of available physical layouts for corsair keyboards.
+ ///
+ public enum CorsairPhysicalKeyboardLayout
+ {
+ ///
+ /// US-Keyboard
+ ///
+ US = 1,
+
+ ///
+ /// UK-Keyboard
+ ///
+ UK = 2,
+
+ ///
+ /// BR-Keyboard
+ ///
+ BR = 3,
+
+ ///
+ /// JP-Keyboard
+ ///
+ JP = 4,
+
+ ///
+ /// KR-Keyboard
+ ///
+ KR = 5
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Enum/CorsairPhysicalMouseLayout.cs b/RGB.NET.Devices.Corsair/Enum/CorsairPhysicalMouseLayout.cs
new file mode 100644
index 0000000..88ee5d4
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Enum/CorsairPhysicalMouseLayout.cs
@@ -0,0 +1,28 @@
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Contains list of available physical layouts for mice.
+ ///
+ public enum CorsairPhysicalMouseLayout
+ {
+ ///
+ /// Zone1-Mouse
+ ///
+ Zones1 = 6,
+
+ ///
+ /// Zone2-Mouse
+ ///
+ Zones2 = 7,
+
+ ///
+ /// Zone3-Mouse
+ ///
+ Zones3 = 8,
+
+ ///
+ /// Zone4-Mouse
+ ///
+ Zones4 = 9
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Exceptions/CUEException.cs b/RGB.NET.Devices.Corsair/Exceptions/CUEException.cs
new file mode 100644
index 0000000..4337536
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Exceptions/CUEException.cs
@@ -0,0 +1,35 @@
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable MemberCanBePrivate.Global
+
+using System;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents an exception thrown by the CUE.
+ ///
+ public class CUEException : ApplicationException
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets the provided by CUE.
+ ///
+ public CorsairError Error { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The provided by CUE, which leads to this exception.
+ public CUEException(CorsairError error)
+ {
+ this.Error = error;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairLedId.cs b/RGB.NET.Devices.Corsair/Generic/CorsairLedId.cs
new file mode 100644
index 0000000..145198f
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Generic/CorsairLedId.cs
@@ -0,0 +1,102 @@
+using System.Diagnostics;
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a Id of a on a .
+ ///
+ [DebuggerDisplay("{_ledId}")]
+ public class CorsairLedId : ILedId
+ {
+ #region Properties & Fields
+
+ private readonly CorsairLedIds _ledId;
+
+ ///
+ public bool IsValid => _ledId != CorsairLedIds.Invalid;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The corsair-id of the represented .
+ public CorsairLedId(CorsairLedIds ledId)
+ {
+ this._ledId = ledId;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Converts the Id of this to a human-readable string.
+ ///
+ /// A string that contains the Id of this . For example "Enter".
+ public override string ToString()
+ {
+ return _ledId.ToString();
+ }
+
+ ///
+ /// Tests whether the specified object is a and is equivalent to this .
+ ///
+ /// The object to test.
+ /// true if is a equivalent to this ; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ CorsairLedId compareLedId = obj as CorsairLedId;
+ if (ReferenceEquals(compareLedId, null))
+ return false;
+
+ if (ReferenceEquals(this, compareLedId))
+ return true;
+
+ if (GetType() != compareLedId.GetType())
+ return false;
+
+ return compareLedId._ledId == _ledId;
+ }
+
+ ///
+ /// Returns a hash code for this .
+ ///
+ /// An integer value that specifies the hash code for this .
+ public override int GetHashCode()
+ {
+ return _ledId.GetHashCode();
+ }
+
+ #endregion
+
+ #region Operators
+
+ ///
+ /// Returns a value that indicates whether two specified are equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if and are equal; otherwise, false.
+ public static bool operator ==(CorsairLedId ledId1, CorsairLedId ledId2)
+ {
+ return ReferenceEquals(ledId1, null) ? ReferenceEquals(ledId2, null) : ledId1.Equals(ledId2);
+ }
+
+ ///
+ /// Returns a value that indicates whether two specified are equal.
+ ///
+ /// The first to compare.
+ /// The second to compare.
+ /// true if and are not equal; otherwise, false.
+ public static bool operator !=(CorsairLedId ledId1, CorsairLedId ledId2)
+ {
+ return !(ledId1 == ledId2);
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairProtocolDetails.cs b/RGB.NET.Devices.Corsair/Generic/CorsairProtocolDetails.cs
new file mode 100644
index 0000000..3f66761
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Generic/CorsairProtocolDetails.cs
@@ -0,0 +1,66 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+
+using System;
+using System.Runtime.InteropServices;
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Managed wrapper for CorsairProtocolDetails.
+ ///
+ public class CorsairProtocolDetails
+ {
+ #region Properties & Fields
+
+ ///
+ /// String containing version of SDK(like "1.0.0.1").
+ /// Always contains valid value even if there was no CUE found.
+ ///
+ public string SdkVersion { get; }
+
+ ///
+ /// String containing version of CUE(like "1.0.0.1") or NULL if CUE was not found.
+ ///
+ public string ServerVersion { get; }
+
+ ///
+ /// Integer that specifies version of protocol that is implemented by current SDK.
+ /// Numbering starts from 1.
+ /// Always contains valid value even if there was no CUE found.
+ ///
+ public int SdkProtocolVersion { get; }
+
+ ///
+ /// Integer that specifies version of protocol that is implemented by CUE.
+ /// Numbering starts from 1.
+ /// If CUE was not found then this value will be 0.
+ ///
+ public int ServerProtocolVersion { get; }
+
+ ///
+ /// Boolean that specifies if there were breaking changes between version of protocol implemented by server and client.
+ ///
+ public bool BreakingChanges { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Internal constructor of managed CorsairProtocolDetails.
+ ///
+ /// The native CorsairProtocolDetails-struct
+ internal CorsairProtocolDetails(_CorsairProtocolDetails nativeDetails)
+ {
+ this.SdkVersion = nativeDetails.sdkVersion == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(nativeDetails.sdkVersion);
+ this.ServerVersion = nativeDetails.serverVersion == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(nativeDetails.serverVersion);
+ this.SdkProtocolVersion = nativeDetails.sdkProtocolVersion;
+ this.ServerProtocolVersion = nativeDetails.serverProtocolVersion;
+ this.BreakingChanges = nativeDetails.breakingChanges != 0;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairRGBDevice.cs b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDevice.cs
new file mode 100644
index 0000000..bd7f584
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDevice.cs
@@ -0,0 +1,56 @@
+using System.Linq;
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a generic CUE-device. (keyboard, mouse, headset, mousmat).
+ ///
+ public abstract class CorsairRGBDevice : AbstractRGBDevice
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets information about the .
+ ///
+ public override IRGBDeviceInfo DeviceInfo { get; }
+
+ private Rectangle _deviceRectangle;
+ ///
+ public override Rectangle DeviceRectangle => _deviceRectangle;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The generic information provided by CUE for the device.
+ protected CorsairRGBDevice(IRGBDeviceInfo info)
+ {
+ this.DeviceInfo = info;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Initializes the device.
+ ///
+ internal void Initialize()
+ {
+ InitializeLeds();
+
+ _deviceRectangle = new Rectangle(this.Select(x => x.LedRectangle));
+ }
+
+ ///
+ /// Initializes the of the device.
+ ///
+ protected abstract void InitializeLeds();
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairRGBDeviceInfo.cs b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDeviceInfo.cs
new file mode 100644
index 0000000..d4ea7c9
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Generic/CorsairRGBDeviceInfo.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Runtime.InteropServices;
+using RGB.NET.Core;
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a generic information for a Corsair-.
+ ///
+ public class CorsairRGBDeviceInfo : IRGBDeviceInfo
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets the corsair specific device type.
+ ///
+ public CorsairDeviceType CorsairDeviceType { get; }
+
+ ///
+ /// Gets the index of the .
+ ///
+ public int CorsairDeviceIndex { get; }
+
+ ///
+ public DeviceType DeviceType { get; }
+
+ ///
+ public string Manufacturer => "Corsair";
+
+ ///
+ public string Model { get; }
+
+ ///
+ /// Gets a flag that describes device capabilities. ()
+ ///
+ public CorsairDeviceCaps CapsMask { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Internal constructor of managed .
+ ///
+ /// The index of the .
+ /// The type of the .
+ /// The native -struct
+ internal CorsairRGBDeviceInfo(int deviceIndex, DeviceType deviceType, _CorsairDeviceInfo nativeInfo)
+ {
+ this.CorsairDeviceIndex = deviceIndex;
+ this.DeviceType = deviceType;
+ this.CorsairDeviceType = nativeInfo.type;
+ this.Model = nativeInfo.model == IntPtr.Zero ? null : Marshal.PtrToStringAnsi(nativeInfo.model);
+ this.CapsMask = (CorsairDeviceCaps)nativeInfo.capsMask;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Headset/CorsairHeadsetRGBDevice.cs b/RGB.NET.Devices.Corsair/Headset/CorsairHeadsetRGBDevice.cs
new file mode 100644
index 0000000..07c56c5
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Headset/CorsairHeadsetRGBDevice.cs
@@ -0,0 +1,46 @@
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a corsair headset.
+ ///
+ public class CorsairHeadsetRGBDevice : CorsairRGBDevice
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets information about the .
+ ///
+ public CorsairHeadsetRGBDeviceInfo HeadsetDeviceInfo { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The specific information provided by CUE for the headset
+ internal CorsairHeadsetRGBDevice(CorsairHeadsetRGBDeviceInfo info)
+ : base(info)
+ {
+ this.HeadsetDeviceInfo = info;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Initializes the of the headset.
+ ///
+ protected override void InitializeLeds()
+ {
+ InitializeLed(new CorsairLedId(CorsairLedIds.LeftLogo), new Rectangle(0, 0, 10, 10));
+ InitializeLed(new CorsairLedId(CorsairLedIds.RightLogo), new Rectangle(10, 0, 10, 10));
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Headset/CorsairHeadsetRGBDeviceInfo.cs b/RGB.NET.Devices.Corsair/Headset/CorsairHeadsetRGBDeviceInfo.cs
new file mode 100644
index 0000000..161a214
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Headset/CorsairHeadsetRGBDeviceInfo.cs
@@ -0,0 +1,23 @@
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a generic information for a .
+ ///
+ public class CorsairHeadsetRGBDeviceInfo : CorsairRGBDeviceInfo
+ {
+ #region Constructors
+
+ ///
+ /// Internal constructor of managed .
+ ///
+ /// The index of the .
+ /// The native -struct
+ internal CorsairHeadsetRGBDeviceInfo(int deviceIndex, _CorsairDeviceInfo nativeInfo)
+ : base(deviceIndex, Core.DeviceType.Headset, nativeInfo)
+ { }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Keyboard/CorsairKeyboardRGBDevice.cs b/RGB.NET.Devices.Corsair/Keyboard/CorsairKeyboardRGBDevice.cs
new file mode 100644
index 0000000..883486e
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Keyboard/CorsairKeyboardRGBDevice.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Runtime.InteropServices;
+using RGB.NET.Core;
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a corsair keyboard.
+ ///
+ public class CorsairKeyboardRGBDevice : CorsairRGBDevice
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets information about the .
+ ///
+ public CorsairKeyboardRGBDeviceInfo KeyboardDeviceInfo { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The specific information provided by CUE for the keyboard
+ internal CorsairKeyboardRGBDevice(CorsairKeyboardRGBDeviceInfo info)
+ : base(info)
+ {
+ this.KeyboardDeviceInfo = info;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Initializes the of the keyboard.
+ ///
+ protected override void InitializeLeds()
+ {
+ _CorsairLedPositions nativeLedPositions =
+ (_CorsairLedPositions)
+ Marshal.PtrToStructure(_CUESDK.CorsairGetLedPositionsByDeviceIndex(KeyboardDeviceInfo.CorsairDeviceIndex),
+ typeof(_CorsairLedPositions));
+
+ int structSize = Marshal.SizeOf(typeof(_CorsairLedPosition));
+ IntPtr ptr = nativeLedPositions.pLedPosition;
+
+ for (int i = 0; i < nativeLedPositions.numberOfLed; i++)
+ {
+ _CorsairLedPosition ledPosition = (_CorsairLedPosition)Marshal.PtrToStructure(ptr, typeof(_CorsairLedPosition));
+ InitializeLed(new CorsairLedId(ledPosition.ledId),
+ new Rectangle(ledPosition.left, ledPosition.top, ledPosition.width, ledPosition.height));
+
+ ptr = new IntPtr(ptr.ToInt64() + structSize);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Keyboard/CorsairKeyboardRGBDeviceInfo.cs b/RGB.NET.Devices.Corsair/Keyboard/CorsairKeyboardRGBDeviceInfo.cs
new file mode 100644
index 0000000..3af41ef
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Keyboard/CorsairKeyboardRGBDeviceInfo.cs
@@ -0,0 +1,40 @@
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a generic information for a .
+ ///
+ public class CorsairKeyboardRGBDeviceInfo : CorsairRGBDeviceInfo
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets the physical layout of the keyboard.
+ ///
+ public CorsairPhysicalKeyboardLayout PhysicalLayout { get; }
+
+ ///
+ /// Gets the logical layout of the keyboard as set in CUE settings.
+ ///
+ public CorsairLogicalKeyboardLayout LogicalLayout { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Internal constructor of managed .
+ ///
+ /// The index of the .
+ /// The native -struct
+ internal CorsairKeyboardRGBDeviceInfo(int deviceIndex, _CorsairDeviceInfo nativeInfo)
+ : base(deviceIndex, Core.DeviceType.Keyboard, nativeInfo)
+ {
+ this.PhysicalLayout = (CorsairPhysicalKeyboardLayout)nativeInfo.physicalLayout;
+ this.LogicalLayout = (CorsairLogicalKeyboardLayout)nativeInfo.logicalLayout;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Mouse/CorsairMouseRGBDevice.cs b/RGB.NET.Devices.Corsair/Mouse/CorsairMouseRGBDevice.cs
new file mode 100644
index 0000000..5351cce
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Mouse/CorsairMouseRGBDevice.cs
@@ -0,0 +1,68 @@
+using RGB.NET.Core;
+using RGB.NET.Core.Exceptions;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a corsair mouse.
+ ///
+ public class CorsairMouseRGBDevice : CorsairRGBDevice
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets information about the .
+ ///
+ public CorsairMouseRGBDeviceInfo MouseDeviceInfo { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The specific information provided by CUE for the mouse
+ internal CorsairMouseRGBDevice(CorsairMouseRGBDeviceInfo info)
+ : base(info)
+ {
+ this.MouseDeviceInfo = info;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Initializes the of the mouse.
+ ///
+ protected override void InitializeLeds()
+ {
+ switch (MouseDeviceInfo.PhysicalLayout)
+ {
+ case CorsairPhysicalMouseLayout.Zones1:
+ InitializeLed(new CorsairLedId(CorsairLedIds.B1), new Rectangle(0, 0, 10, 10));
+ break;
+ case CorsairPhysicalMouseLayout.Zones2:
+ InitializeLed(new CorsairLedId(CorsairLedIds.B1), new Rectangle(0, 0, 10, 10));
+ InitializeLed(new CorsairLedId(CorsairLedIds.B2), new Rectangle(10, 0, 10, 10));
+ break;
+ case CorsairPhysicalMouseLayout.Zones3:
+ InitializeLed(new CorsairLedId(CorsairLedIds.B1), new Rectangle(0, 0, 10, 10));
+ InitializeLed(new CorsairLedId(CorsairLedIds.B2), new Rectangle(10, 0, 10, 10));
+ InitializeLed(new CorsairLedId(CorsairLedIds.B3), new Rectangle(20, 0, 10, 10));
+ break;
+ case CorsairPhysicalMouseLayout.Zones4:
+ InitializeLed(new CorsairLedId(CorsairLedIds.B1), new Rectangle(0, 0, 10, 10));
+ InitializeLed(new CorsairLedId(CorsairLedIds.B2), new Rectangle(10, 0, 10, 10));
+ InitializeLed(new CorsairLedId(CorsairLedIds.B3), new Rectangle(20, 0, 10, 10));
+ InitializeLed(new CorsairLedId(CorsairLedIds.B4), new Rectangle(30, 0, 10, 10));
+ break;
+ default:
+ throw new RGBDeviceException($"Can't initial mouse with layout '{MouseDeviceInfo.PhysicalLayout}'");
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Mouse/CorsairMouseRGBDeviceInfo.cs b/RGB.NET.Devices.Corsair/Mouse/CorsairMouseRGBDeviceInfo.cs
new file mode 100644
index 0000000..656053e
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Mouse/CorsairMouseRGBDeviceInfo.cs
@@ -0,0 +1,34 @@
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a generic information for a .
+ ///
+ public class CorsairMouseRGBDeviceInfo : CorsairRGBDeviceInfo
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets the physical layout of the mouse.
+ ///
+ public CorsairPhysicalMouseLayout PhysicalLayout { get; private set; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Internal constructor of managed .
+ ///
+ /// The index of the .
+ /// The native -struct
+ internal CorsairMouseRGBDeviceInfo(int deviceIndex, _CorsairDeviceInfo nativeInfo)
+ : base(deviceIndex, Core.DeviceType.Mouse, nativeInfo)
+ {
+ this.PhysicalLayout = (CorsairPhysicalMouseLayout)nativeInfo.physicalLayout;
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Mousmat/CorsairMousematRGBDevice.cs b/RGB.NET.Devices.Corsair/Mousmat/CorsairMousematRGBDevice.cs
new file mode 100644
index 0000000..998c7ef
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Mousmat/CorsairMousematRGBDevice.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using RGB.NET.Core;
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a corsair mousemat.
+ ///
+ public class CorsairMousematRGBDevice : CorsairRGBDevice
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets information about the .
+ ///
+ public CorsairMousematRGBDeviceInfo MousematDeviceInfo { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The specific information provided by CUE for the mousemat
+ internal CorsairMousematRGBDevice(CorsairMousematRGBDeviceInfo info)
+ : base(info)
+ {
+ this.MousematDeviceInfo = info;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Initializes the of the mousemat.
+ ///
+ protected override void InitializeLeds()
+ {
+ _CorsairLedPositions nativeLedPositions =
+ (_CorsairLedPositions)
+ Marshal.PtrToStructure(_CUESDK.CorsairGetLedPositionsByDeviceIndex(MousematDeviceInfo.CorsairDeviceIndex),
+ typeof(_CorsairLedPositions));
+
+ int structSize = Marshal.SizeOf(typeof(_CorsairLedPosition));
+ IntPtr ptr = nativeLedPositions.pLedPosition;
+
+ List<_CorsairLedPosition> positions = new List<_CorsairLedPosition>();
+ for (int i = 0; i < nativeLedPositions.numberOfLed; i++)
+ {
+ _CorsairLedPosition ledPosition = (_CorsairLedPosition)Marshal.PtrToStructure(ptr, typeof(_CorsairLedPosition));
+ ptr = new IntPtr(ptr.ToInt64() + structSize);
+ positions.Add(ledPosition);
+ }
+
+ foreach (_CorsairLedPosition ledPosition in positions.OrderBy(p => p.ledId))
+ InitializeLed(new CorsairLedId(ledPosition.ledId),
+ new Rectangle(ledPosition.left, ledPosition.top, ledPosition.width, ledPosition.height));
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Mousmat/CorsairMousematRGBDeviceInfo.cs b/RGB.NET.Devices.Corsair/Mousmat/CorsairMousematRGBDeviceInfo.cs
new file mode 100644
index 0000000..83932f7
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Mousmat/CorsairMousematRGBDeviceInfo.cs
@@ -0,0 +1,23 @@
+using RGB.NET.Devices.Corsair.Native;
+
+namespace RGB.NET.Devices.Corsair
+{
+ ///
+ /// Represents a generic information for a .
+ ///
+ public class CorsairMousematRGBDeviceInfo : CorsairRGBDeviceInfo
+ {
+ #region Constructors
+
+ ///
+ /// Internal constructor of managed .
+ ///
+ /// The index if the .
+ /// The native -struct
+ internal CorsairMousematRGBDeviceInfo(int deviceIndex, _CorsairDeviceInfo nativeInfo)
+ : base(deviceIndex, Core.DeviceType.Mousemat, nativeInfo)
+ { }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Native/_CUESDK.cs b/RGB.NET.Devices.Corsair/Native/_CUESDK.cs
new file mode 100644
index 0000000..b24db79
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CUESDK.cs
@@ -0,0 +1,242 @@
+// ReSharper disable UnusedMethodReturnValue.Global
+// ReSharper disable UnusedMember.Global
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using RGB.NET.Core.Exceptions;
+
+namespace RGB.NET.Devices.Corsair.Native
+{
+ // ReSharper disable once InconsistentNaming
+ internal static class _CUESDK
+ {
+ #region Libary Management
+
+ private static IntPtr _dllHandle = IntPtr.Zero;
+
+ ///
+ /// Gets the loaded architecture (x64/x86).
+ ///
+ internal static string LoadedArchitecture { get; private set; }
+
+ ///
+ /// Reloads the SDK.
+ ///
+ internal static void Reload()
+ {
+ UnloadCUESDK();
+ LoadCUESDK();
+ }
+
+ private static void LoadCUESDK()
+ {
+ if (_dllHandle != IntPtr.Zero) return;
+
+ // HACK: Load library at runtime to support both, x86 and x64 with one managed dll
+ string dllPath = (LoadedArchitecture = Environment.Is64BitProcess ? "x64" : "x86") + "/CUESDK_2015.dll";
+ if (!File.Exists(dllPath))
+ throw new RGBDeviceException($"Can't find the CUE-SDK at the expected location '{Path.GetFullPath(dllPath)}'");
+
+ _dllHandle = LoadLibrary(dllPath);
+
+ _corsairSetLedsColorsPointer =
+ (CorsairSetLedsColorsPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairSetLedsColors"),
+ typeof(CorsairSetLedsColorsPointer));
+ _corsairGetDeviceCountPointer =
+ (CorsairGetDeviceCountPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetDeviceCount"),
+ typeof(CorsairGetDeviceCountPointer));
+ _corsairGetDeviceInfoPointer =
+ (CorsairGetDeviceInfoPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetDeviceInfo"),
+ typeof(CorsairGetDeviceInfoPointer));
+ _corsairGetLedPositionsPointer =
+ (CorsairGetLedPositionsPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLedPositions"),
+ typeof(CorsairGetLedPositionsPointer));
+ _corsairGetLedPositionsByDeviceIndexPointer =
+ (CorsairGetLedPositionsByDeviceIndexPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLedPositionsByDeviceIndex"),
+ typeof(CorsairGetLedPositionsByDeviceIndexPointer));
+ _corsairGetLedIdForKeyNamePointer =
+ (CorsairGetLedIdForKeyNamePointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLedIdForKeyName"),
+ typeof(CorsairGetLedIdForKeyNamePointer));
+ _corsairRequestControlPointer =
+ (CorsairRequestControlPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairRequestControl"),
+ typeof(CorsairRequestControlPointer));
+ _corsairReleaseControlPointer =
+ (CorsairReleaseControlPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairReleaseControl"),
+ typeof(CorsairReleaseControlPointer));
+ _corsairPerformProtocolHandshakePointer =
+ (CorsairPerformProtocolHandshakePointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairPerformProtocolHandshake"),
+ typeof(CorsairPerformProtocolHandshakePointer));
+ _corsairGetLastErrorPointer =
+ (CorsairGetLastErrorPointer)
+ Marshal.GetDelegateForFunctionPointer(GetProcAddress(_dllHandle, "CorsairGetLastError"), typeof(CorsairGetLastErrorPointer));
+ }
+
+ private static void UnloadCUESDK()
+ {
+ if (_dllHandle == IntPtr.Zero) return;
+
+ // ReSharper disable once EmptyEmbeddedStatement - DarthAffe 20.02.2016: We might need to reduce the internal reference counter more than once to set the library free
+ while (FreeLibrary(_dllHandle)) ;
+ _dllHandle = IntPtr.Zero;
+ }
+
+ [DllImport("kernel32.dll")]
+ private static extern IntPtr LoadLibrary(string dllToLoad);
+
+ [DllImport("kernel32.dll")]
+ private static extern bool FreeLibrary(IntPtr dllHandle);
+
+ [DllImport("kernel32.dll")]
+ private static extern IntPtr GetProcAddress(IntPtr dllHandle, string name);
+
+ #endregion
+
+ #region SDK-METHODS
+
+ #region Pointers
+
+ private static CorsairSetLedsColorsPointer _corsairSetLedsColorsPointer;
+ private static CorsairGetDeviceCountPointer _corsairGetDeviceCountPointer;
+ private static CorsairGetDeviceInfoPointer _corsairGetDeviceInfoPointer;
+ private static CorsairGetLedPositionsPointer _corsairGetLedPositionsPointer;
+ private static CorsairGetLedIdForKeyNamePointer _corsairGetLedIdForKeyNamePointer;
+ private static CorsairGetLedPositionsByDeviceIndexPointer _corsairGetLedPositionsByDeviceIndexPointer;
+ private static CorsairRequestControlPointer _corsairRequestControlPointer;
+ private static CorsairReleaseControlPointer _corsairReleaseControlPointer;
+ private static CorsairPerformProtocolHandshakePointer _corsairPerformProtocolHandshakePointer;
+ private static CorsairGetLastErrorPointer _corsairGetLastErrorPointer;
+
+ #endregion
+
+ #region Delegates
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate bool CorsairSetLedsColorsPointer(int size, IntPtr ledsColors);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate int CorsairGetDeviceCountPointer();
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate IntPtr CorsairGetDeviceInfoPointer(int deviceIndex);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate IntPtr CorsairGetLedPositionsPointer();
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate IntPtr CorsairGetLedPositionsByDeviceIndexPointer(int deviceIndex);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate CorsairLedIds CorsairGetLedIdForKeyNamePointer(char keyName);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate bool CorsairRequestControlPointer(CorsairAccessMode accessMode);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate bool CorsairReleaseControlPointer(CorsairAccessMode accessMode);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate _CorsairProtocolDetails CorsairPerformProtocolHandshakePointer();
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate CorsairError CorsairGetLastErrorPointer();
+
+ #endregion
+
+ // ReSharper disable EventExceptionNotDocumented
+
+ ///
+ /// CUE-SDK: set specified leds to some colors. The color is retained until changed by successive calls. This function does not take logical layout into account.
+ ///
+ internal static bool CorsairSetLedsColors(int size, IntPtr ledsColors)
+ {
+ return _corsairSetLedsColorsPointer(size, ledsColors);
+ }
+
+ ///
+ /// CUE-SDK: returns number of connected Corsair devices that support lighting control.
+ ///
+ internal static int CorsairGetDeviceCount()
+ {
+ return _corsairGetDeviceCountPointer();
+ }
+
+ ///
+ /// CUE-SDK: returns information about device at provided index.
+ ///
+ internal static IntPtr CorsairGetDeviceInfo(int deviceIndex)
+ {
+ return _corsairGetDeviceInfoPointer(deviceIndex);
+ }
+
+ ///
+ /// CUE-SDK: provides list of keyboard LEDs with their physical positions.
+ ///
+ internal static IntPtr CorsairGetLedPositions()
+ {
+ return _corsairGetLedPositionsPointer();
+ }
+
+ ///
+ /// CUE-SDK: provides list of keyboard or mousemat LEDs with their physical positions.
+ ///
+ internal static IntPtr CorsairGetLedPositionsByDeviceIndex(int deviceIndex)
+ {
+ return _corsairGetLedPositionsByDeviceIndexPointer(deviceIndex);
+ }
+
+ ///
+ /// CUE-SDK: retrieves led id for key name taking logical layout into account.
+ ///
+ internal static CorsairLedIds CorsairGetLedIdForKeyName(char keyName)
+ {
+ return _corsairGetLedIdForKeyNamePointer(keyName);
+ }
+
+ ///
+ /// CUE-SDK: requestes control using specified access mode.
+ /// By default client has shared control over lighting so there is no need to call CorsairRequestControl unless client requires exclusive control.
+ ///
+ internal static bool CorsairRequestControl(CorsairAccessMode accessMode)
+ {
+ return _corsairRequestControlPointer(accessMode);
+ }
+
+ ///
+ /// CUE-SDK: releases previously requested control for specified access mode.
+ ///
+ internal static bool CorsairReleaseControl(CorsairAccessMode accessMode)
+ {
+ return _corsairReleaseControlPointer(accessMode);
+ }
+
+ ///
+ /// CUE-SDK: checks file and protocol version of CUE to understand which of SDK functions can be used with this version of CUE.
+ ///
+ internal static _CorsairProtocolDetails CorsairPerformProtocolHandshake()
+ {
+ return _corsairPerformProtocolHandshakePointer();
+ }
+
+ ///
+ /// CUE-SDK: returns last error that occured while using any of Corsair* functions.
+ ///
+ internal static CorsairError CorsairGetLastError()
+ {
+ return _corsairGetLastErrorPointer();
+ }
+
+ // ReSharper restore EventExceptionNotDocumented
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairDeviceInfo.cs b/RGB.NET.Devices.Corsair/Native/_CorsairDeviceInfo.cs
new file mode 100644
index 0000000..4f52e88
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairDeviceInfo.cs
@@ -0,0 +1,47 @@
+#pragma warning disable 169 // Field 'x' is never used
+#pragma warning disable 414 // Field 'x' is assigned but its value never used
+#pragma warning disable 649 // Field 'x' is never assigned
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace RGB.NET.Devices.Corsair.Native
+{
+ // ReSharper disable once InconsistentNaming
+ ///
+ /// CUE-SDK: contains information about device
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ internal class _CorsairDeviceInfo
+ {
+ ///
+ /// CUE-SDK: enum describing device type
+ ///
+ internal CorsairDeviceType type;
+
+ ///
+ /// CUE-SDK: null - terminated device model(like “K95RGB”)
+ ///
+ internal IntPtr model;
+
+ ///
+ /// CUE-SDK: enum describing physical layout of the keyboard or mouse
+ ///
+ internal int physicalLayout;
+
+ ///
+ /// CUE-SDK: enum describing logical layout of the keyboard as set in CUE settings
+ ///
+ internal int logicalLayout;
+
+ ///
+ /// CUE-SDK: mask that describes device capabilities, formed as logical “or” of CorsairDeviceCaps enum values
+ ///
+ internal int capsMask;
+
+ ///
+ /// CUE-SDK: number of controllable LEDs on the device
+ ///
+ internal int ledsCount;
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairLedColor.cs b/RGB.NET.Devices.Corsair/Native/_CorsairLedColor.cs
new file mode 100644
index 0000000..349b6c1
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairLedColor.cs
@@ -0,0 +1,36 @@
+#pragma warning disable 169 // Field 'x' is never used
+#pragma warning disable 414 // Field 'x' is assigned but its value never used
+#pragma warning disable 649 // Field 'x' is never assigned
+
+using System.Runtime.InteropServices;
+
+namespace RGB.NET.Devices.Corsair.Native
+{
+ // ReSharper disable once InconsistentNaming
+ ///
+ /// CUE-SDK: contains information about led and its color
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ internal class _CorsairLedColor
+ {
+ ///
+ /// CUE-SDK: identifier of LED to set
+ ///
+ internal int ledId;
+
+ ///
+ /// CUE-SDK: red brightness[0..255]
+ ///
+ internal int r;
+
+ ///
+ /// CUE-SDK: green brightness[0..255]
+ ///
+ internal int g;
+
+ ///
+ /// CUE-SDK: blue brightness[0..255]
+ ///
+ internal int b;
+ };
+}
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairLedPosition.cs b/RGB.NET.Devices.Corsair/Native/_CorsairLedPosition.cs
new file mode 100644
index 0000000..99d2acd
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairLedPosition.cs
@@ -0,0 +1,42 @@
+#pragma warning disable 169 // Field 'x' is never used
+#pragma warning disable 414 // Field 'x' is assigned but its value never used
+#pragma warning disable 649 // Field 'x' is never assigned
+
+using System.Runtime.InteropServices;
+
+namespace RGB.NET.Devices.Corsair.Native
+{
+ // ReSharper disable once InconsistentNaming
+ ///
+ /// CUE-SDK: contains led id and position of led rectangle.Most of the keys are rectangular.
+ /// In case if key is not rectangular(like Enter in ISO / UK layout) it returns the smallest rectangle that fully contains the key
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ internal class _CorsairLedPosition
+ {
+ ///
+ /// CUE-SDK: identifier of led
+ ///
+ internal CorsairLedIds ledId;
+
+ ///
+ /// CUE-SDK: values in mm
+ ///
+ internal double top;
+
+ ///
+ /// CUE-SDK: values in mm
+ ///
+ internal double left;
+
+ ///
+ /// CUE-SDK: values in mm
+ ///
+ internal double height;
+
+ ///
+ /// CUE-SDK: values in mm
+ ///
+ internal double width;
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairLedPositions.cs b/RGB.NET.Devices.Corsair/Native/_CorsairLedPositions.cs
new file mode 100644
index 0000000..afb8565
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairLedPositions.cs
@@ -0,0 +1,27 @@
+#pragma warning disable 169 // Field 'x' is never used
+#pragma warning disable 414 // Field 'x' is assigned but its value never used
+#pragma warning disable 649 // Field 'x' is never assigned
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace RGB.NET.Devices.Corsair.Native
+{
+ // ReSharper disable once InconsistentNaming
+ ///
+ /// CUE-SDK: contains number of leds and arrays with their positions
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ internal class _CorsairLedPositions
+ {
+ ///
+ /// CUE-SDK: integer value.Number of elements in following array
+ ///
+ internal int numberOfLed;
+
+ ///
+ /// CUE-SDK: array of led positions
+ ///
+ internal IntPtr pLedPosition;
+ }
+}
diff --git a/RGB.NET.Devices.Corsair/Native/_CorsairProtocolDetails.cs b/RGB.NET.Devices.Corsair/Native/_CorsairProtocolDetails.cs
new file mode 100644
index 0000000..9fc731b
--- /dev/null
+++ b/RGB.NET.Devices.Corsair/Native/_CorsairProtocolDetails.cs
@@ -0,0 +1,44 @@
+#pragma warning disable 169 // Field 'x' is never used
+#pragma warning disable 414 // Field 'x' is assigned but its value never used
+#pragma warning disable 649 // Field 'x' is never assigned
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace RGB.NET.Devices.Corsair.Native
+{
+ // ReSharper disable once InconsistentNaming
+ ///
+ /// CUE-SDK: contains information about SDK and CUE versions
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct _CorsairProtocolDetails
+ {
+ ///
+ /// CUE-SDK: null - terminated string containing version of SDK(like “1.0.0.1”). Always contains valid value even if there was no CUE found
+ ///
+ internal IntPtr sdkVersion;
+
+ ///
+ /// CUE-SDK: null - terminated string containing version of CUE(like “1.0.0.1”) or NULL if CUE was not found.
+ ///
+ internal IntPtr serverVersion;
+
+ ///
+ /// CUE-SDK: integer number that specifies version of protocol that is implemented by current SDK.
+ /// Numbering starts from 1. Always contains valid value even if there was no CUE found
+ ///
+ internal int sdkProtocolVersion;
+
+ ///
+ /// CUE-SDK: integer number that specifies version of protocol that is implemented by CUE.
+ /// Numbering starts from 1. If CUE was not found then this value will be 0
+ ///
+ internal int serverProtocolVersion;
+
+ ///
+ /// CUE-SDK: boolean value that specifies if there were breaking changes between version of protocol implemented by server and client
+ ///
+ internal byte breakingChanges;
+ };
+}
diff --git a/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj b/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj
index 5b1adf0..af89164 100644
--- a/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj
+++ b/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj
@@ -31,6 +31,10 @@
4
+
+ ..\packages\RGB.NET.Core.1.0.0\lib\net45\RGB.NET.Core.dll
+ True
+
@@ -41,8 +45,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+