diff --git a/RGB.NET.Devices.OpenRGB/Abstract/AbstractOpenRGBDevice.cs b/RGB.NET.Devices.OpenRGB/Abstract/AbstractOpenRGBDevice.cs
new file mode 100644
index 0000000..78f3f1f
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/Abstract/AbstractOpenRGBDevice.cs
@@ -0,0 +1,24 @@
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+///
+/// Represents a generic OpenRGB Device.
+///
+public abstract class AbstractOpenRGBDevice : AbstractRGBDevice, IOpenRGBDevice
+ where TDeviceInfo : OpenRGBDeviceInfo
+{
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The generic information provided by OpenRGB for this device.
+ /// The queue used to update this device.
+ protected AbstractOpenRGBDevice(TDeviceInfo info, IUpdateQueue updateQueue)
+ : base(info, updateQueue)
+ { }
+
+ #endregion
+}
diff --git a/RGB.NET.Devices.OpenRGB/Abstract/IOpenRGBDevice.cs b/RGB.NET.Devices.OpenRGB/Abstract/IOpenRGBDevice.cs
new file mode 100644
index 0000000..7659d94
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/Abstract/IOpenRGBDevice.cs
@@ -0,0 +1,9 @@
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+/// Represents a generic OpenRGB Device.
+///
+public interface IOpenRGBDevice : IRGBDevice
+{ }
diff --git a/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs b/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs
new file mode 100644
index 0000000..05afff3
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/Abstract/OpenRGBDeviceInfo.cs
@@ -0,0 +1,52 @@
+using RGB.NET.Core;
+using OpenRGBDevice = OpenRGB.NET.Models.Device;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+/// Represents generic information for an OpenRGB Device
+///
+public class OpenRGBDeviceInfo : IRGBDeviceInfo
+{
+ #region Properties & Fields
+
+ ///
+ public RGBDeviceType DeviceType { get; }
+
+ ///
+ public string DeviceName { get; }
+
+ ///
+ public string Manufacturer { get; }
+
+ ///
+ public string Model { get; }
+
+ ///
+ public object? LayoutMetadata { get; set; }
+
+ ///
+ /// Gets the OpenRGB device.
+ ///
+ public OpenRGBDevice OpenRGBDevice { get; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The OpenRGB device to extract information from.
+ internal OpenRGBDeviceInfo(OpenRGBDevice openRGBDevice)
+ {
+ this.OpenRGBDevice = openRGBDevice;
+
+ DeviceType = Helper.GetRgbNetDeviceType(openRGBDevice.Type);
+ Manufacturer = Helper.GetVendorName(openRGBDevice);
+ Model = Helper.GetModelName(openRGBDevice);
+ DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model);
+ }
+
+ #endregion
+}
diff --git a/RGB.NET.Devices.OpenRGB/Generic/LedMappings.cs b/RGB.NET.Devices.OpenRGB/Generic/LedMappings.cs
new file mode 100644
index 0000000..d6deb99
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/Generic/LedMappings.cs
@@ -0,0 +1,145 @@
+using RGB.NET.Core;
+using System.Collections.Generic;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+internal static class LedMappings
+{
+ public static readonly Dictionary DEFAULT = new()
+ {
+ ["Key: A"] = LedId.Keyboard_A,
+ ["Key: B"] = LedId.Keyboard_B,
+ ["Key: C"] = LedId.Keyboard_C,
+ ["Key: D"] = LedId.Keyboard_D,
+ ["Key: E"] = LedId.Keyboard_E,
+ ["Key: F"] = LedId.Keyboard_F,
+ ["Key: G"] = LedId.Keyboard_G,
+ ["Key: H"] = LedId.Keyboard_H,
+ ["Key: I"] = LedId.Keyboard_I,
+ ["Key: J"] = LedId.Keyboard_J,
+ ["Key: K"] = LedId.Keyboard_K,
+ ["Key: L"] = LedId.Keyboard_L,
+ ["Key: M"] = LedId.Keyboard_M,
+ ["Key: N"] = LedId.Keyboard_N,
+ ["Key: O"] = LedId.Keyboard_O,
+ ["Key: P"] = LedId.Keyboard_P,
+ ["Key: Q"] = LedId.Keyboard_Q,
+ ["Key: R"] = LedId.Keyboard_R,
+ ["Key: S"] = LedId.Keyboard_S,
+ ["Key: T"] = LedId.Keyboard_T,
+ ["Key: U"] = LedId.Keyboard_U,
+ ["Key: V"] = LedId.Keyboard_V,
+ ["Key: W"] = LedId.Keyboard_W,
+ ["Key: X"] = LedId.Keyboard_X,
+ ["Key: Y"] = LedId.Keyboard_Y,
+ ["Key: Z"] = LedId.Keyboard_Z,
+ ["Key: 1"] = LedId.Keyboard_1,
+ ["Key: 2"] = LedId.Keyboard_2,
+ ["Key: 3"] = LedId.Keyboard_3,
+ ["Key: 4"] = LedId.Keyboard_4,
+ ["Key: 5"] = LedId.Keyboard_5,
+ ["Key: 6"] = LedId.Keyboard_6,
+ ["Key: 7"] = LedId.Keyboard_7,
+ ["Key: 8"] = LedId.Keyboard_8,
+ ["Key: 9"] = LedId.Keyboard_9,
+ ["Key: 0"] = LedId.Keyboard_0,
+ ["Key: Enter"] = LedId.Keyboard_Enter,
+ ["Key: Enter (ISO)"] = LedId.Keyboard_Enter,
+ ["Key: Escape"] = LedId.Keyboard_Escape,
+ ["Key: Backspace"] = LedId.Keyboard_Backspace,
+ ["Key: Tab"] = LedId.Keyboard_Tab,
+ ["Key: Space"] = LedId.Keyboard_Space,
+ ["Key: -"] = LedId.Keyboard_MinusAndUnderscore,
+ ["Key: ="] = LedId.Keyboard_EqualsAndPlus,
+ ["Key: ["] = LedId.Keyboard_BracketLeft,
+ ["Key: ]"] = LedId.Keyboard_BracketRight,
+ ["Key: \\ (ANSI)"] = LedId.Keyboard_Backslash,
+ ["Key: #"] = LedId.Keyboard_NonUsTilde,
+ ["Key: ;"] = LedId.Keyboard_SemicolonAndColon,
+ ["Key: '"] = LedId.Keyboard_ApostropheAndDoubleQuote,
+ ["Key: `"] = LedId.Keyboard_GraveAccentAndTilde,
+ ["Key: ,"] = LedId.Keyboard_CommaAndLessThan,
+ ["Key: ."] = LedId.Keyboard_PeriodAndBiggerThan,
+ ["Key: /"] = LedId.Keyboard_SlashAndQuestionMark,
+ ["Key: Caps Lock"] = LedId.Keyboard_CapsLock,
+ ["Key: F1"] = LedId.Keyboard_F1,
+ ["Key: F2"] = LedId.Keyboard_F2,
+ ["Key: F3"] = LedId.Keyboard_F3,
+ ["Key: F4"] = LedId.Keyboard_F4,
+ ["Key: F5"] = LedId.Keyboard_F5,
+ ["Key: F6"] = LedId.Keyboard_F6,
+ ["Key: F7"] = LedId.Keyboard_F7,
+ ["Key: F8"] = LedId.Keyboard_F8,
+ ["Key: F9"] = LedId.Keyboard_F9,
+ ["Key: F10"] = LedId.Keyboard_F10,
+ ["Key: F11"] = LedId.Keyboard_F11,
+ ["Key: F12"] = LedId.Keyboard_F12,
+ ["Key: Print Screen"] = LedId.Keyboard_PrintScreen,
+ ["Key: Scroll Lock"] = LedId.Keyboard_ScrollLock,
+ ["Key: Pause/Break"] = LedId.Keyboard_PauseBreak,
+ ["Key: Insert"] = LedId.Keyboard_Insert,
+ ["Key: Home"] = LedId.Keyboard_Home,
+ ["Key: Page Up"] = LedId.Keyboard_PageUp,
+ ["Key: Delete"] = LedId.Keyboard_Delete,
+ ["Key: End"] = LedId.Keyboard_End,
+ ["Key: Page Down"] = LedId.Keyboard_PageDown,
+ ["Key: Right Arrow"] = LedId.Keyboard_ArrowRight,
+ ["Key: Left Arrow"] = LedId.Keyboard_ArrowLeft,
+ ["Key: Down Arrow"] = LedId.Keyboard_ArrowDown,
+ ["Key: Up Arrow"] = LedId.Keyboard_ArrowUp,
+ ["Key: Num Lock"] = LedId.Keyboard_NumLock,
+ ["Key: Number Pad /"] = LedId.Keyboard_NumSlash,
+ ["Key: Number Pad *"] = LedId.Keyboard_NumAsterisk,
+ ["Key: Number Pad -"] = LedId.Keyboard_NumMinus,
+ ["Key: Number Pad +"] = LedId.Keyboard_NumPlus,
+ ["Key: Number Pad Enter"] = LedId.Keyboard_NumEnter,
+ ["Key: Number Pad 1"] = LedId.Keyboard_Num1,
+ ["Key: Number Pad 2"] = LedId.Keyboard_Num2,
+ ["Key: Number Pad 3"] = LedId.Keyboard_Num3,
+ ["Key: Number Pad 4"] = LedId.Keyboard_Num4,
+ ["Key: Number Pad 5"] = LedId.Keyboard_Num5,
+ ["Key: Number Pad 6"] = LedId.Keyboard_Num6,
+ ["Key: Number Pad 7"] = LedId.Keyboard_Num7,
+ ["Key: Number Pad 8"] = LedId.Keyboard_Num8,
+ ["Key: Number Pad 9"] = LedId.Keyboard_Num9,
+ ["Key: Number Pad 0"] = LedId.Keyboard_Num0,
+ ["Key: Number Pad ."] = LedId.Keyboard_NumPeriodAndDelete,
+ ["Key: Left Fn"] = LedId.Keyboard_Function,
+ ["Key: Right Fn"] = LedId.Keyboard_Function,
+ ["Key: \\ (ISO)"] = LedId.Keyboard_NonUsBackslash,
+ ["Key: Menu"] = LedId.Keyboard_Application,
+ ["Key: Left Control"] = LedId.Keyboard_LeftCtrl,
+ ["Key: Left Shift"] = LedId.Keyboard_LeftShift,
+ ["Key: Left Alt"] = LedId.Keyboard_LeftAlt,
+ ["Key: Left Windows"] = LedId.Keyboard_LeftGui,
+ ["Key: Right Control"] = LedId.Keyboard_RightCtrl,
+ ["Key: Right Shift"] = LedId.Keyboard_RightShift,
+ ["Key: Right Alt"] = LedId.Keyboard_RightAlt,
+ ["Key: Right Windows"] = LedId.Keyboard_RightGui,
+ ["Key: Media Next"] = LedId.Keyboard_MediaNextTrack,
+ ["Key: Media Previous"] = LedId.Keyboard_MediaPreviousTrack,
+ ["Key: Media Stop"] = LedId.Keyboard_MediaStop,
+ ["Key: Media Pause"] = LedId.Keyboard_MediaPlay,
+ ["Key: Media Play"] = LedId.Keyboard_MediaPlay,
+ ["Key: Media Play/Pause"] = LedId.Keyboard_MediaPlay,
+ ["Key: Media Mute"] = LedId.Keyboard_MediaMute,
+ ["Logo"] = LedId.Logo,
+ ["Key: Brightness"] = LedId.Keyboard_Brightness,
+ ["Key: M1"] = LedId.Keyboard_Macro1,
+ ["Key: M2"] = LedId.Keyboard_Macro2,
+ ["Key: M3"] = LedId.Keyboard_Macro3,
+ ["Key: M4"] = LedId.Keyboard_Macro4,
+ ["Key: M5"] = LedId.Keyboard_Macro5,
+ ["Key: G1"] = LedId.Keyboard_Programmable1,
+ ["Key: G2"] = LedId.Keyboard_Programmable2,
+ ["Key: G3"] = LedId.Keyboard_Programmable3,
+ ["Key: G4"] = LedId.Keyboard_Programmable4,
+ ["Key: G5"] = LedId.Keyboard_Programmable5,
+ ["Key: G6"] = LedId.Keyboard_Programmable6,
+ ["Key: G7"] = LedId.Keyboard_Programmable7,
+ ["Key: G8"] = LedId.Keyboard_Programmable8,
+ ["Key: G9"] = LedId.Keyboard_Programmable9,
+ ["Lighting"] = LedId.Keyboard_Brightness,
+ ["Game Mode"] = LedId.Keyboard_WinLock,
+ };
+}
diff --git a/RGB.NET.Devices.OpenRGB/Generic/OpenRGBGenericDevice.cs b/RGB.NET.Devices.OpenRGB/Generic/OpenRGBGenericDevice.cs
new file mode 100644
index 0000000..8f19c5a
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/Generic/OpenRGBGenericDevice.cs
@@ -0,0 +1,83 @@
+using OpenRGB.NET.Enums;
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+public class OpenRGBGenericDevice : AbstractOpenRGBDevice
+{
+ #region Constructors
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Generic information for the device.
+ /// The queue used to update the device.
+ public OpenRGBGenericDevice(OpenRGBDeviceInfo info, IUpdateQueue updateQueue)
+ : base(info, updateQueue)
+ {
+ InitializeLayout();
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Initializes the LEDs of the device based on the data provided by the SDK.
+ ///
+ private void InitializeLayout()
+ {
+ LedId initial = Helper.GetInitialLedIdForDeviceType(DeviceInfo.DeviceType);
+
+ int y = 0;
+ Size ledSize = new(19);
+ int zoneLedIndex = 0;
+ const int LED_SPACING = 20;
+
+ foreach (global::OpenRGB.NET.Models.Zone? zone in DeviceInfo.OpenRGBDevice.Zones)
+ {
+ if (zone.Type == ZoneType.Matrix)
+ {
+ for (int row = 0; row < zone.MatrixMap.Height; row++)
+ {
+ for (int column = 0; column < zone.MatrixMap.Width; column++)
+ {
+ uint index = zone.MatrixMap.Matrix[row, column];
+
+ //will be max value if the position does not have an associated key
+ if (index == uint.MaxValue)
+ continue;
+
+ LedId ledId = LedMappings.DEFAULT.TryGetValue(DeviceInfo.OpenRGBDevice.Leds[zoneLedIndex + index].Name, out LedId id)
+ ? id
+ : initial++;
+
+ //HACK: doing this because some different Led Names are mapped to the same LedId
+ //for example, "Enter" and "ISO Enter".
+ //this way, at least they'll be controllable as CustomX
+ while (AddLed(ledId, new Point(LED_SPACING * column, y + (LED_SPACING * row)), ledSize, zoneLedIndex + (int)index) == null)
+ ledId = initial++;
+ }
+ }
+ y += (int)(zone.MatrixMap.Height * LED_SPACING);
+ }
+ else
+ {
+ for (int i = 0; i < zone.LedCount; i++)
+ {
+ LedId ledId = initial++;
+
+ while (AddLed(ledId, new Point(LED_SPACING * i, y), ledSize, zoneLedIndex + i) == null)
+ ledId = initial++;
+ }
+ }
+
+ //we'll just set each zone in its own row for now,
+ //with each led for that zone being horizontally distributed
+ y += LED_SPACING;
+ zoneLedIndex += (int)zone.LedCount;
+ }
+ }
+
+ #endregion
+}
diff --git a/RGB.NET.Devices.OpenRGB/Generic/OpenRGBUpdateQueue.cs b/RGB.NET.Devices.OpenRGB/Generic/OpenRGBUpdateQueue.cs
new file mode 100644
index 0000000..aab78d4
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/Generic/OpenRGBUpdateQueue.cs
@@ -0,0 +1,61 @@
+using OpenRGB.NET;
+using RGB.NET.Core;
+using System;
+using System.Linq;
+using OpenRGBColor = OpenRGB.NET.Models.Color;
+using OpenRGBDevice = OpenRGB.NET.Models.Device;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+///
+/// Represents the update-queue performing updates for OpenRGB devices.
+///
+public class OpenRGBUpdateQueue : UpdateQueue
+{
+ #region Properties & Fields
+
+ private readonly int _deviceid;
+
+ private readonly OpenRGBClient _openRGB;
+ private readonly OpenRGBDevice _device;
+ private readonly OpenRGBColor[] _colors;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The update trigger used by this queue.
+ /// The index used to identify the device.
+ /// The OpenRGB client used to send updates to the OpenRGB server.
+ /// The OpenRGB Device containing device-specific information.
+ public OpenRGBUpdateQueue(IDeviceUpdateTrigger updateTrigger, int deviceid, OpenRGBClient client, OpenRGBDevice device)
+ : base(updateTrigger)
+ {
+ this._deviceid = deviceid;
+ this._openRGB = client;
+ this._device = device;
+
+ _colors = Enumerable.Range(0, _device.Colors.Length)
+ .Select(_ => new OpenRGBColor())
+ .ToArray();
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ protected override void Update(in ReadOnlySpan<(object key, Color color)> dataSet)
+ {
+ foreach ((object key, Color color) in dataSet)
+ _colors[(int)key] = new OpenRGBColor(color.GetR(), color.GetG(), color.GetB());
+
+ _openRGB.UpdateLeds(_deviceid, _colors);
+ }
+
+ #endregion
+}
diff --git a/RGB.NET.Devices.OpenRGB/Helper.cs b/RGB.NET.Devices.OpenRGB/Helper.cs
new file mode 100644
index 0000000..02c81f2
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/Helper.cs
@@ -0,0 +1,55 @@
+using OpenRGB.NET.Enums;
+using RGB.NET.Core;
+using OpenRGBDevice = OpenRGB.NET.Models.Device;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+internal static class Helper
+{
+ public static LedId GetInitialLedIdForDeviceType(RGBDeviceType type)
+ => type switch
+ {
+ RGBDeviceType.Mouse => LedId.Mouse1,
+ RGBDeviceType.Headset => LedId.Headset1,
+ RGBDeviceType.Mousepad => LedId.Mousepad1,
+ RGBDeviceType.LedStripe => LedId.LedStripe1,
+ RGBDeviceType.LedMatrix => LedId.LedMatrix1,
+ RGBDeviceType.Mainboard => LedId.Mainboard1,
+ RGBDeviceType.GraphicsCard => LedId.GraphicsCard1,
+ RGBDeviceType.DRAM => LedId.DRAM1,
+ RGBDeviceType.HeadsetStand => LedId.HeadsetStand1,
+ RGBDeviceType.Keypad => LedId.Keypad1,
+ RGBDeviceType.Fan => LedId.Fan1,
+ RGBDeviceType.Speaker => LedId.Speaker1,
+ RGBDeviceType.Cooler => LedId.Cooler1,
+ RGBDeviceType.Keyboard => LedId.Keyboard_Custom1,
+ _ => LedId.Custom1
+ };
+
+ public static RGBDeviceType GetRgbNetDeviceType(DeviceType type)
+ => type switch
+ {
+ DeviceType.Motherboard => RGBDeviceType.Mainboard,
+ DeviceType.Dram => RGBDeviceType.DRAM,
+ DeviceType.Gpu => RGBDeviceType.GraphicsCard,
+ DeviceType.Cooler => RGBDeviceType.Cooler,
+ DeviceType.Ledstrip => RGBDeviceType.LedStripe,
+ DeviceType.Keyboard => RGBDeviceType.Keyboard,
+ DeviceType.Mouse => RGBDeviceType.Mouse,
+ DeviceType.Mousemat => RGBDeviceType.Mousepad,
+ DeviceType.Headset => RGBDeviceType.Headset,
+ DeviceType.HeadsetStand => RGBDeviceType.HeadsetStand,
+ _ => RGBDeviceType.Unknown
+ };
+
+ public static LedId GetInitialLedIdForDeviceType(DeviceType type)
+ => GetInitialLedIdForDeviceType(GetRgbNetDeviceType(type));
+
+ public static string GetVendorName(OpenRGBDevice openRGBDevice) => string.IsNullOrWhiteSpace(openRGBDevice.Vendor)
+ ? "OpenRGB"
+ : openRGBDevice.Vendor;
+
+ public static string GetModelName(OpenRGBDevice openRGBDevice) => string.IsNullOrWhiteSpace(openRGBDevice.Vendor)
+ ? openRGBDevice.Name
+ : openRGBDevice.Name.Replace(openRGBDevice.Vendor, "").Trim();
+}
diff --git a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs
new file mode 100644
index 0000000..a9fd3b4
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs
@@ -0,0 +1,138 @@
+using OpenRGB.NET;
+using OpenRGB.NET.Models;
+using RGB.NET.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+///
+/// Represents a device provider responsible for OpenRGB devices.
+///
+public class OpenRGBDeviceProvider : AbstractRGBDeviceProvider
+{
+ #region Properties & Fields
+
+ private readonly List _clients = new();
+
+ private static OpenRGBDeviceProvider? _instance;
+
+ ///
+ /// Gets the singleton instance.
+ ///
+ public static OpenRGBDeviceProvider Instance => _instance ?? new OpenRGBDeviceProvider();
+
+ ///
+ /// Gets a list of all defined device-definitions.
+ ///
+ public List DeviceDefinitions { get; } = new();
+
+ ///
+ /// Indicates whether all devices will be added, or just the ones with a 'Direct' mode. Defaults to false.
+ ///
+ public bool ForceAddAllDevices { get; set; } = false;
+
+ ///
+ /// Defines which device types will be separated by zones. Defaults to | .
+ ///
+ public RGBDeviceType PerZoneDeviceFlag { get; } = RGBDeviceType.LedStripe | RGBDeviceType.Mainboard;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Thrown if this constructor is called even if there is already an instance of this class.
+ public OpenRGBDeviceProvider()
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(OpenRGBDeviceProvider)}");
+ _instance = this;
+ }
+
+ #endregion
+
+ #region Methods
+ ///
+ protected override void InitializeSDK()
+ {
+ foreach (OpenRGBServerDefinition? deviceDefinition in DeviceDefinitions)
+ {
+ try
+ {
+ OpenRGBClient? openRgb = new(ip: deviceDefinition.Ip, port: deviceDefinition.Port, name: deviceDefinition.ClientName, autoconnect: true);
+ _clients.Add(openRgb);
+ deviceDefinition.Connected = true;
+ }
+ catch (Exception e)
+ {
+ deviceDefinition.Connected = false;
+ deviceDefinition.LastError = e.Message;
+ Throw(e);
+ }
+ }
+ }
+
+ ///
+ protected override IEnumerable LoadDevices()
+ {
+ foreach (OpenRGBClient? openRgb in _clients)
+ {
+ int deviceCount = openRgb.GetControllerCount();
+
+ for (int i = 0; i < deviceCount; i++)
+ {
+ Device? device = openRgb.GetControllerData(i);
+
+ int directModeIndex = Array.FindIndex(device.Modes, d => d.Name == "Direct");
+ if (directModeIndex != -1)
+ {
+ //set the device to direct mode if it has it
+ openRgb.SetMode(i, directModeIndex);
+ }
+ else if (!ForceAddAllDevices)
+ {
+ //if direct mode does not exist
+ //and if we're not forcing, continue to the next device.
+ continue;
+ }
+
+ OpenRGBUpdateQueue? updateQueue = new(GetUpdateTrigger(), i, openRgb, device);
+
+ if (PerZoneDeviceFlag.HasFlag(Helper.GetRgbNetDeviceType(device.Type)))
+ {
+ int totalLedCount = 0;
+
+ foreach (Zone zone in device.Zones)
+ if (zone.LedCount > 0)
+ {
+ yield return new OpenRGBZoneDevice(new OpenRGBDeviceInfo(device), totalLedCount, zone, updateQueue);
+ totalLedCount += (int)zone.LedCount;
+ }
+ }
+ else
+ yield return new OpenRGBGenericDevice(new OpenRGBDeviceInfo(device), updateQueue);
+ }
+ }
+ }
+
+ ///
+ public override void Dispose()
+ {
+ base.Dispose();
+
+ foreach (OpenRGBClient client in _clients)
+ {
+ try { client.Dispose(); }
+ catch { /* at least we tried */ }
+ }
+
+ _clients.Clear();
+ DeviceDefinitions.Clear();
+ Devices = Enumerable.Empty();
+ }
+ #endregion
+}
diff --git a/RGB.NET.Devices.OpenRGB/OpenRGBServerDefinition.cs b/RGB.NET.Devices.OpenRGB/OpenRGBServerDefinition.cs
new file mode 100644
index 0000000..7d81033
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/OpenRGBServerDefinition.cs
@@ -0,0 +1,32 @@
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+/// Represents a definition of an OpenRGB server.
+///
+public class OpenRGBServerDefinition
+{
+ ///
+ /// The name of the client that will appear in the OpenRGB interface.
+ ///
+ public string? ClientName { get; set; }
+
+ ///
+ /// The ip address of the server.
+ ///
+ public string? Ip { get; set; }
+
+ ///
+ /// The port of the server.
+ ///
+ public int Port { get; set; }
+
+ ///
+ /// Whether the provider is connected to this server definition or not.
+ ///
+ public bool Connected { get; set; }
+
+ ///
+ /// The error that occurred when connecting, if this failed.
+ ///
+ public string? LastError { get; set; }
+}
\ No newline at end of file
diff --git a/RGB.NET.Devices.OpenRGB/PerZone/OpenRGBZoneDevice.cs b/RGB.NET.Devices.OpenRGB/PerZone/OpenRGBZoneDevice.cs
new file mode 100644
index 0000000..42ab433
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/PerZone/OpenRGBZoneDevice.cs
@@ -0,0 +1,79 @@
+using OpenRGB.NET.Enums;
+using OpenRGB.NET.Models;
+using RGB.NET.Core;
+
+namespace RGB.NET.Devices.OpenRGB;
+
+///
+public class OpenRGBZoneDevice : AbstractOpenRGBDevice
+{
+ #region Properties & Fields
+
+ private readonly int _initialLed;
+ private readonly Zone _zone;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The information provided by OpenRGB
+ /// The ledId of the first led in the device that belongs to this zone.
+ /// The Zone information provided by OpenRGB.
+ /// The queue used to update this zone.
+ public OpenRGBZoneDevice(OpenRGBDeviceInfo info, int initialLed, Zone zone, IUpdateQueue updateQueue)
+ : base(info, updateQueue)
+ {
+ _initialLed = initialLed;
+ _zone = zone;
+
+ InitializeLayout();
+ }
+
+ #endregion
+
+ #region Methods
+
+ private void InitializeLayout()
+ {
+ Size ledSize = new(19);
+ const int LED_SPACING = 20;
+ LedId initialId = Helper.GetInitialLedIdForDeviceType(DeviceInfo.DeviceType) + _initialLed;
+
+ if (_zone.Type == ZoneType.Matrix)
+ {
+ for (int row = 0; row < _zone.MatrixMap.Height; row++)
+ {
+ for (int column = 0; column < _zone.MatrixMap.Width; column++)
+ {
+ uint index = _zone.MatrixMap.Matrix[row, column];
+
+ //will be max value if the position does not have an associated key
+ if (index == uint.MaxValue)
+ continue;
+
+ LedId ledId = LedMappings.DEFAULT.TryGetValue(DeviceInfo.OpenRGBDevice.Leds[_initialLed + index].Name, out LedId id)
+ ? id
+ : initialId++;
+
+ while (AddLed(ledId, new Point(LED_SPACING * column, LED_SPACING * row), ledSize, _initialLed + (int)index) == null)
+ ledId = initialId++;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < _zone.LedCount; i++)
+ {
+ LedId ledId = initialId++;
+
+ while (AddLed(ledId, new Point(LED_SPACING * i, 0), ledSize, _initialLed + i) == null)
+ ledId = initialId++;
+ }
+ }
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj b/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj
new file mode 100644
index 0000000..546e1f7
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj
@@ -0,0 +1,65 @@
+
+
+ net6.0;net5.0
+ latest
+ enable
+
+ diogotr7
+ Wyrez
+ en-US
+ en-US
+ RGB.NET.Devices.OpenRGB
+ RGB.NET.Devices.OpenRGB
+ RGB.NET.Devices.OpenRGB
+ RGB.NET.Devices.OpenRGB
+ RGB.NET.Devices.OpenRGB
+ OpenRGB-Device-Implementations of RGB.NET
+ OpenRGB-Device-Implementations of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals
+ Copyright © Darth Affe 2022
+ Copyright © Darth Affe 2022
+ icon.png
+ https://github.com/DarthAffe/RGB.NET
+ LGPL-2.1-only
+ Github
+ https://github.com/DarthAffe/RGB.NET
+ True
+
+
+
+ 0.0.1
+ 0.0.1
+ 0.0.1
+
+ ..\bin\
+ true
+ True
+ True
+ portable
+ snupkg
+
+
+
+ $(DefineConstants);TRACE;DEBUG
+ true
+ false
+
+
+
+ true
+ $(NoWarn);CS1591;CS1572;CS1573
+ $(DefineConstants);RELEASE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj.DotSettings b/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj.DotSettings
new file mode 100644
index 0000000..f79e29d
--- /dev/null
+++ b/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj.DotSettings
@@ -0,0 +1,4 @@
+
+ True
+ True
+ True
\ No newline at end of file
diff --git a/RGB.NET.sln b/RGB.NET.sln
index 9dca4b4..afbcb67 100644
--- a/RGB.NET.sln
+++ b/RGB.NET.sln
@@ -45,6 +45,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.PicoPi", "R
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Presets.Tests", "Tests\RGB.NET.Presets.Tests\RGB.NET.Presets.Tests.csproj", "{EDBA49D6-AE96-4E96-9E6A-30154D93BD5F}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.OpenRGB", "RGB.NET.Devices.OpenRGB\RGB.NET.Devices.OpenRGB.csproj", "{F29A96E5-CDD0-469F-A871-A35A7519BC49}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -127,6 +129,10 @@ Global
{EDBA49D6-AE96-4E96-9E6A-30154D93BD5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDBA49D6-AE96-4E96-9E6A-30154D93BD5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDBA49D6-AE96-4E96-9E6A-30154D93BD5F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F29A96E5-CDD0-469F-A871-A35A7519BC49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F29A96E5-CDD0-469F-A871-A35A7519BC49}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F29A96E5-CDD0-469F-A871-A35A7519BC49}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F29A96E5-CDD0-469F-A871-A35A7519BC49}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -147,6 +153,7 @@ Global
{DD46DB2D-85BE-4962-86AE-E38C9053A548} = {D13032C6-432E-4F43-8A32-071133C22B16}
{7FC5C7A8-7B27-46E7-A8E8-DB80568F49C5} = {D13032C6-432E-4F43-8A32-071133C22B16}
{EDBA49D6-AE96-4E96-9E6A-30154D93BD5F} = {92D7C263-D4C9-4D26-93E2-93C1F9C2CD16}
+ {F29A96E5-CDD0-469F-A871-A35A7519BC49} = {D13032C6-432E-4F43-8A32-071133C22B16}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7F222AD4-1F9E-4AAB-9D69-D62372D4C1BA}